38000a98fa535dfb0492dcde94e92120a14e3236
[platform/core/uifw/dali-adaptor.git] / adaptors / tizen / native-image-source-impl-tizen.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "native-image-source-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-defines.h>
24 #include <cstring>
25
26 // INTERNAL INCLUDES
27 #include <gl/egl-image-extensions.h>
28 #include <gl/egl-factory.h>
29 #include <adaptor-impl.h>
30 #include <render-surface.h>
31
32 // Allow this to be encoded and saved:
33 #include <platform-abstractions/tizen/resource-loader/resource-loader.h>
34 #include <bitmap-saver.h>
35
36 namespace Dali
37 {
38
39 namespace Internal
40 {
41
42 namespace Adaptor
43 {
44
45 namespace
46 {
47 const char* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
48 const char* SAMPLER_TYPE = "samplerExternalOES";
49
50 tbm_format FORMATS_BLENDING_REQUIRED[] = {
51   TBM_FORMAT_ARGB4444, TBM_FORMAT_ABGR4444,
52   TBM_FORMAT_RGBA4444, TBM_FORMAT_BGRA4444,
53   TBM_FORMAT_RGBX5551, TBM_FORMAT_BGRX5551,
54   TBM_FORMAT_ARGB1555, TBM_FORMAT_ABGR1555,
55   TBM_FORMAT_RGBA5551, TBM_FORMAT_BGRA5551,
56   TBM_FORMAT_ARGB8888, TBM_FORMAT_ABGR8888,
57   TBM_FORMAT_RGBA8888, TBM_FORMAT_BGRA8888,
58   TBM_FORMAT_ARGB2101010, TBM_FORMAT_ABGR2101010,
59   TBM_FORMAT_RGBA1010102, TBM_FORMAT_BGRA1010102
60 };
61
62 const int NUM_FORMATS_BLENDING_REQUIRED = 18;
63
64 }
65
66 using Dali::Integration::PixelBuffer;
67
68 NativeImageSource* NativeImageSource::New(unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
69 {
70   NativeImageSource* image = new NativeImageSource( width, height, depth, nativeImageSource );
71   DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
72
73   if( image )
74   {
75     image->Initialize();
76   }
77
78   return image;
79 }
80
81 NativeImageSource::NativeImageSource( unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
82 : mWidth( width ),
83   mHeight( height ),
84   mOwnTbmSurface( false ),
85   mTbmSurface( NULL ),
86   mBlendingRequired( false ),
87   mColorDepth( depth ),
88   mEglImageKHR( NULL ),
89   mEglImageExtensions( NULL ),
90   mSetSource( false )
91 {
92   DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
93   EglFactory& eglFactory = Adaptor::GetImplementation( Adaptor::Get() ).GetEGLFactory();
94   mEglImageExtensions = eglFactory.GetImageExtensions();
95   DALI_ASSERT_DEBUG( mEglImageExtensions );
96
97   mTbmSurface = GetSurfaceFromAny( nativeImageSource );
98
99   if( mTbmSurface != NULL )
100   {
101     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
102     mWidth = tbm_surface_get_width( mTbmSurface );
103     mHeight = tbm_surface_get_height( mTbmSurface );
104   }
105 }
106
107 void NativeImageSource::Initialize()
108 {
109   if( mTbmSurface != NULL || mWidth == 0 || mHeight == 0 )
110   {
111     return;
112   }
113
114   tbm_format format = TBM_FORMAT_RGB888;
115   int depth = 0;
116
117   switch( mColorDepth )
118   {
119     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
120     {
121       format = TBM_FORMAT_RGBA8888;
122       depth = 32;
123       break;
124     }
125     case Dali::NativeImageSource::COLOR_DEPTH_8:
126     {
127       format = TBM_FORMAT_C8;
128       depth = 8;
129       break;
130     }
131     case Dali::NativeImageSource::COLOR_DEPTH_16:
132     {
133       format = TBM_FORMAT_RGB565;
134       depth = 16;
135       break;
136     }
137     case Dali::NativeImageSource::COLOR_DEPTH_24:
138     {
139       format = TBM_FORMAT_RGB888;
140       depth = 24;
141       break;
142     }
143     case Dali::NativeImageSource::COLOR_DEPTH_32:
144     {
145       format = TBM_FORMAT_RGBA8888;
146       depth = 32;
147       break;
148     }
149     default:
150     {
151       DALI_LOG_WARNING( "Wrong color depth.\n" );
152       return;
153     }
154   }
155
156   // set whether blending is required according to pixel format based on the depth
157   /* default pixel format is RGB888
158      If depth = 8, Pixel::A8;
159      If depth = 16, Pixel::RGB565;
160      If depth = 32, Pixel::RGBA8888 */
161   mBlendingRequired = ( depth == 32 || depth == 8 );
162
163   mTbmSurface = tbm_surface_create( mWidth, mHeight, format );
164   mOwnTbmSurface = true;
165 }
166
167 tbm_surface_h NativeImageSource::GetSurfaceFromAny( Any source ) const
168 {
169   if( source.Empty() )
170   {
171     return NULL;
172   }
173
174   if( source.GetType() == typeid( tbm_surface_h ) )
175   {
176     return AnyCast< tbm_surface_h >( source );
177   }
178   else
179   {
180     return NULL;
181   }
182 }
183
184 NativeImageSource::~NativeImageSource()
185 {
186   if( mOwnTbmSurface && mTbmSurface != NULL )
187   {
188     if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
189     {
190       DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
191     }
192   }
193 }
194
195 Any NativeImageSource::GetNativeImageSource() const
196 {
197   return Any( mTbmSurface );
198 }
199
200 bool NativeImageSource::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
201 {
202   if( mTbmSurface != NULL )
203   {
204     tbm_surface_info_s surface_info;
205
206     if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE )
207     {
208       DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
209
210       width = 0;
211       height = 0;
212
213       return false;
214     }
215
216     tbm_format format = surface_info.format;
217     uint32_t stride = surface_info.planes[0].stride;
218     unsigned char* ptr = surface_info.planes[0].ptr;
219
220     width = mWidth;
221     height = mHeight;
222     size_t lineSize;
223     size_t offset;
224     size_t cOffset;
225
226     switch( format )
227     {
228       case TBM_FORMAT_RGB888:
229       {
230         lineSize = width*3;
231         pixelFormat = Pixel::RGB888;
232         pixbuf.resize( lineSize*height );
233         unsigned char* bufptr = &pixbuf[0];
234
235         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
236         {
237           for( unsigned int c = 0; c < width; ++c )
238           {
239             cOffset = c*3;
240             offset = cOffset + r*stride;
241             *(bufptr) = ptr[offset+2];
242             *(bufptr+cOffset+1) = ptr[offset+1];
243             *(bufptr+cOffset+2) = ptr[offset];
244           }
245         }
246         break;
247       }
248       case TBM_FORMAT_RGBA8888:
249       {
250         lineSize = width*4;
251         pixelFormat = Pixel::RGBA8888;
252         pixbuf.resize( lineSize*height );
253         unsigned char* bufptr = &pixbuf[0];
254
255         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
256         {
257           for( unsigned int c = 0; c < width; ++c )
258           {
259             cOffset = c*4;
260             offset = cOffset + r*stride;
261             *(bufptr) = ptr[offset+3];
262             *(bufptr+cOffset+1) = ptr[offset+2];
263             *(bufptr+cOffset+2) = ptr[offset+1];
264             *(bufptr+cOffset+3) = ptr[offset];
265           }
266         }
267         break;
268       }
269       default:
270       {
271         DALI_LOG_WARNING( "Tbm surface has unsupported pixel format.\n" );
272
273         pixbuf.resize( 0 );
274         width = 0;
275         height = 0;
276
277         return false;
278       }
279     }
280
281     if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
282     {
283       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
284     }
285
286     return true;
287   }
288
289   DALI_LOG_WARNING( "TBM surface does not exist.\n" );
290
291   width = 0;
292   height = 0;
293
294   return false;
295 }
296
297 bool NativeImageSource::EncodeToFile(const std::string& filename) const
298 {
299   std::vector< unsigned char > pixbuf;
300   unsigned int width(0), height(0);
301   Pixel::Format pixelFormat;
302
303   if(GetPixels(pixbuf, width, height, pixelFormat))
304   {
305     return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
306   }
307   return false;
308 }
309
310 void NativeImageSource::SetSource( Any source )
311 {
312   if( mOwnTbmSurface && mTbmSurface != NULL )
313   {
314     if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
315     {
316       DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
317     }
318
319     mTbmSurface = NULL;
320     mOwnTbmSurface = false;
321   }
322
323   mTbmSurface = GetSurfaceFromAny( source );
324   mSetSource = true;
325
326   if( mTbmSurface != NULL )
327   {
328     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
329     mWidth = tbm_surface_get_width( mTbmSurface );
330     mHeight = tbm_surface_get_height( mTbmSurface );
331   }
332
333   if( mEglImageKHRContainer.Size() > 2 )
334   {
335     mEglImageExtensions->DestroyImageKHR(mEglImageKHRContainer[0]);
336     mEglImageKHRContainer.Erase( mEglImageKHRContainer.Begin() );
337   }
338
339   mEglImageKHRContainer.PushBack( mEglImageKHR );
340 }
341
342 bool NativeImageSource::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
343 {
344   uint32_t* formats;
345   uint32_t formatNum;
346   tbm_format format = TBM_FORMAT_RGB888;
347
348   switch( colorDepth )
349   {
350     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
351     {
352       format = TBM_FORMAT_RGBA8888;
353       break;
354     }
355     case Dali::NativeImageSource::COLOR_DEPTH_8:
356     {
357       format = TBM_FORMAT_C8;
358       break;
359     }
360     case Dali::NativeImageSource::COLOR_DEPTH_16:
361     {
362       format = TBM_FORMAT_RGB565;
363       break;
364     }
365     case Dali::NativeImageSource::COLOR_DEPTH_24:
366     {
367       format = TBM_FORMAT_RGB888;
368       break;
369     }
370     case Dali::NativeImageSource::COLOR_DEPTH_32:
371     {
372       format = TBM_FORMAT_RGBA8888;
373       break;
374     }
375   }
376
377   if( tbm_surface_query_formats( &formats, &formatNum ) )
378   {
379     for( unsigned int i = 0; i < formatNum; i++ )
380     {
381       if( formats[i] == format )
382       {
383         free( formats );
384         return true;
385       }
386     }
387   }
388
389   free( formats );
390   return false;
391 }
392
393 bool NativeImageSource::GlExtensionCreate()
394 {
395   // casting from an unsigned int to a void *, which should then be cast back
396   // to an unsigned int in the driver.
397   EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mTbmSurface);
398
399   mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
400
401   return mEglImageKHR != NULL;
402 }
403
404 void NativeImageSource::GlExtensionDestroy()
405 {
406   mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
407
408   mEglImageKHR = NULL;
409 }
410
411 unsigned int NativeImageSource::TargetTexture()
412 {
413   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
414
415   return 0;
416 }
417
418 void NativeImageSource::PrepareTexture()
419 {
420   if( mSetSource && GlExtensionCreate() )
421   {
422     TargetTexture();
423     mSetSource = false;
424   }
425 }
426
427 int NativeImageSource::GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const
428 {
429   switch (depth)
430   {
431     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
432     {
433       // ToDo: Get the default screen depth
434       return 32;
435     }
436     case Dali::NativeImageSource::COLOR_DEPTH_8:
437     {
438       return 8;
439     }
440     case Dali::NativeImageSource::COLOR_DEPTH_16:
441     {
442       return 16;
443     }
444     case Dali::NativeImageSource::COLOR_DEPTH_24:
445     {
446       return 24;
447     }
448     case Dali::NativeImageSource::COLOR_DEPTH_32:
449     {
450       return 32;
451     }
452     default:
453     {
454       DALI_ASSERT_DEBUG(0 && "unknown color enum");
455       return 0;
456     }
457   }
458 }
459
460 const char* NativeImageSource::GetCustomFragmentPreFix()
461 {
462   return FRAGMENT_PREFIX;
463 }
464
465 const char* NativeImageSource::GetCustomSamplerTypename()
466 {
467   return SAMPLER_TYPE;
468 }
469
470 int NativeImageSource::GetEglImageTextureTarget()
471 {
472   return GL_TEXTURE_EXTERNAL_OES;
473 }
474
475 bool NativeImageSource::CheckBlending( tbm_format format )
476 {
477   if( mTbmFormat != format )
478   {
479     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
480     {
481       if( format == FORMATS_BLENDING_REQUIRED[i] )
482       {
483         mBlendingRequired = true;
484         break;
485       }
486     }
487     mTbmFormat = format;
488   }
489
490   return mBlendingRequired;
491 }
492
493 } // namespace Adaptor
494
495 } // namespace internal
496
497 } // namespace Dali