[3.0] Initialize a member about tbm surface format
[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   mTbmFormat( 0 ),
87   mBlendingRequired( false ),
88   mColorDepth( depth ),
89   mEglImageKHR( NULL ),
90   mEglImageExtensions( NULL ),
91   mSetSource( false )
92 {
93   DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
94   EglFactory& eglFactory = Adaptor::GetImplementation( Adaptor::Get() ).GetEGLFactory();
95   mEglImageExtensions = eglFactory.GetImageExtensions();
96   DALI_ASSERT_DEBUG( mEglImageExtensions );
97
98   mTbmSurface = GetSurfaceFromAny( nativeImageSource );
99
100   if( mTbmSurface != NULL )
101   {
102     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
103     mWidth = tbm_surface_get_width( mTbmSurface );
104     mHeight = tbm_surface_get_height( mTbmSurface );
105   }
106 }
107
108 void NativeImageSource::Initialize()
109 {
110   if( mTbmSurface != NULL || mWidth == 0 || mHeight == 0 )
111   {
112     return;
113   }
114
115   tbm_format format = TBM_FORMAT_RGB888;
116   int depth = 0;
117
118   switch( mColorDepth )
119   {
120     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
121     {
122       format = TBM_FORMAT_RGBA8888;
123       depth = 32;
124       break;
125     }
126     case Dali::NativeImageSource::COLOR_DEPTH_8:
127     {
128       format = TBM_FORMAT_C8;
129       depth = 8;
130       break;
131     }
132     case Dali::NativeImageSource::COLOR_DEPTH_16:
133     {
134       format = TBM_FORMAT_RGB565;
135       depth = 16;
136       break;
137     }
138     case Dali::NativeImageSource::COLOR_DEPTH_24:
139     {
140       format = TBM_FORMAT_RGB888;
141       depth = 24;
142       break;
143     }
144     case Dali::NativeImageSource::COLOR_DEPTH_32:
145     {
146       format = TBM_FORMAT_RGBA8888;
147       depth = 32;
148       break;
149     }
150     default:
151     {
152       DALI_LOG_WARNING( "Wrong color depth.\n" );
153       return;
154     }
155   }
156
157   // set whether blending is required according to pixel format based on the depth
158   /* default pixel format is RGB888
159      If depth = 8, Pixel::A8;
160      If depth = 16, Pixel::RGB565;
161      If depth = 32, Pixel::RGBA8888 */
162   mBlendingRequired = ( depth == 32 || depth == 8 );
163
164   mTbmSurface = tbm_surface_create( mWidth, mHeight, format );
165   mOwnTbmSurface = true;
166 }
167
168 tbm_surface_h NativeImageSource::GetSurfaceFromAny( Any source ) const
169 {
170   if( source.Empty() )
171   {
172     return NULL;
173   }
174
175   if( source.GetType() == typeid( tbm_surface_h ) )
176   {
177     return AnyCast< tbm_surface_h >( source );
178   }
179   else
180   {
181     return NULL;
182   }
183 }
184
185 NativeImageSource::~NativeImageSource()
186 {
187   if( mOwnTbmSurface && mTbmSurface != NULL )
188   {
189     if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
190     {
191       DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
192     }
193   }
194 }
195
196 Any NativeImageSource::GetNativeImageSource() const
197 {
198   return Any( mTbmSurface );
199 }
200
201 bool NativeImageSource::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
202 {
203   if( mTbmSurface != NULL )
204   {
205     tbm_surface_info_s surface_info;
206
207     if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE )
208     {
209       DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
210
211       width = 0;
212       height = 0;
213
214       return false;
215     }
216
217     tbm_format format = surface_info.format;
218     uint32_t stride = surface_info.planes[0].stride;
219     unsigned char* ptr = surface_info.planes[0].ptr;
220
221     width = mWidth;
222     height = mHeight;
223     size_t lineSize;
224     size_t offset;
225     size_t cOffset;
226
227     switch( format )
228     {
229       case TBM_FORMAT_RGB888:
230       {
231         lineSize = width*3;
232         pixelFormat = Pixel::RGB888;
233         pixbuf.resize( lineSize*height );
234         unsigned char* bufptr = &pixbuf[0];
235
236         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
237         {
238           for( unsigned int c = 0; c < width; ++c )
239           {
240             cOffset = c*3;
241             offset = cOffset + r*stride;
242             *(bufptr) = ptr[offset+2];
243             *(bufptr+cOffset+1) = ptr[offset+1];
244             *(bufptr+cOffset+2) = ptr[offset];
245           }
246         }
247         break;
248       }
249       case TBM_FORMAT_RGBA8888:
250       {
251         lineSize = width*4;
252         pixelFormat = Pixel::RGBA8888;
253         pixbuf.resize( lineSize*height );
254         unsigned char* bufptr = &pixbuf[0];
255
256         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
257         {
258           for( unsigned int c = 0; c < width; ++c )
259           {
260             cOffset = c*4;
261             offset = cOffset + r*stride;
262             *(bufptr) = ptr[offset+3];
263             *(bufptr+cOffset+1) = ptr[offset+2];
264             *(bufptr+cOffset+2) = ptr[offset+1];
265             *(bufptr+cOffset+3) = ptr[offset];
266           }
267         }
268         break;
269       }
270       default:
271       {
272         DALI_LOG_WARNING( "Tbm surface has unsupported pixel format.\n" );
273
274         pixbuf.resize( 0 );
275         width = 0;
276         height = 0;
277
278         return false;
279       }
280     }
281
282     if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
283     {
284       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
285     }
286
287     return true;
288   }
289
290   DALI_LOG_WARNING( "TBM surface does not exist.\n" );
291
292   width = 0;
293   height = 0;
294
295   return false;
296 }
297
298 bool NativeImageSource::EncodeToFile(const std::string& filename) const
299 {
300   std::vector< unsigned char > pixbuf;
301   unsigned int width(0), height(0);
302   Pixel::Format pixelFormat;
303
304   if(GetPixels(pixbuf, width, height, pixelFormat))
305   {
306     return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
307   }
308   return false;
309 }
310
311 void NativeImageSource::SetSource( Any source )
312 {
313   if( mOwnTbmSurface && mTbmSurface != NULL )
314   {
315     if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
316     {
317       DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
318     }
319
320     mTbmSurface = NULL;
321     mOwnTbmSurface = false;
322   }
323
324   mTbmSurface = GetSurfaceFromAny( source );
325   mSetSource = true;
326
327   if( mTbmSurface != NULL )
328   {
329     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
330     mWidth = tbm_surface_get_width( mTbmSurface );
331     mHeight = tbm_surface_get_height( mTbmSurface );
332   }
333
334   if( mEglImageKHRContainer.Size() > 2 )
335   {
336     mEglImageExtensions->DestroyImageKHR(mEglImageKHRContainer[0]);
337     mEglImageKHRContainer.Erase( mEglImageKHRContainer.Begin() );
338   }
339
340   mEglImageKHRContainer.PushBack( mEglImageKHR );
341 }
342
343 bool NativeImageSource::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
344 {
345   uint32_t* formats;
346   uint32_t formatNum;
347   tbm_format format = TBM_FORMAT_RGB888;
348
349   switch( colorDepth )
350   {
351     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
352     {
353       format = TBM_FORMAT_RGBA8888;
354       break;
355     }
356     case Dali::NativeImageSource::COLOR_DEPTH_8:
357     {
358       format = TBM_FORMAT_C8;
359       break;
360     }
361     case Dali::NativeImageSource::COLOR_DEPTH_16:
362     {
363       format = TBM_FORMAT_RGB565;
364       break;
365     }
366     case Dali::NativeImageSource::COLOR_DEPTH_24:
367     {
368       format = TBM_FORMAT_RGB888;
369       break;
370     }
371     case Dali::NativeImageSource::COLOR_DEPTH_32:
372     {
373       format = TBM_FORMAT_RGBA8888;
374       break;
375     }
376   }
377
378   if( tbm_surface_query_formats( &formats, &formatNum ) )
379   {
380     for( unsigned int i = 0; i < formatNum; i++ )
381     {
382       if( formats[i] == format )
383       {
384         free( formats );
385         return true;
386       }
387     }
388   }
389
390   free( formats );
391   return false;
392 }
393
394 bool NativeImageSource::GlExtensionCreate()
395 {
396   // casting from an unsigned int to a void *, which should then be cast back
397   // to an unsigned int in the driver.
398   EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mTbmSurface);
399
400   mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
401
402   return mEglImageKHR != NULL;
403 }
404
405 void NativeImageSource::GlExtensionDestroy()
406 {
407   mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
408
409   mEglImageKHR = NULL;
410 }
411
412 unsigned int NativeImageSource::TargetTexture()
413 {
414   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
415
416   return 0;
417 }
418
419 void NativeImageSource::PrepareTexture()
420 {
421   if( mSetSource && GlExtensionCreate() )
422   {
423     TargetTexture();
424     mSetSource = false;
425   }
426 }
427
428 int NativeImageSource::GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const
429 {
430   switch (depth)
431   {
432     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
433     {
434       // ToDo: Get the default screen depth
435       return 32;
436     }
437     case Dali::NativeImageSource::COLOR_DEPTH_8:
438     {
439       return 8;
440     }
441     case Dali::NativeImageSource::COLOR_DEPTH_16:
442     {
443       return 16;
444     }
445     case Dali::NativeImageSource::COLOR_DEPTH_24:
446     {
447       return 24;
448     }
449     case Dali::NativeImageSource::COLOR_DEPTH_32:
450     {
451       return 32;
452     }
453     default:
454     {
455       DALI_ASSERT_DEBUG(0 && "unknown color enum");
456       return 0;
457     }
458   }
459 }
460
461 const char* NativeImageSource::GetCustomFragmentPreFix()
462 {
463   return FRAGMENT_PREFIX;
464 }
465
466 const char* NativeImageSource::GetCustomSamplerTypename()
467 {
468   return SAMPLER_TYPE;
469 }
470
471 int NativeImageSource::GetEglImageTextureTarget()
472 {
473   return GL_TEXTURE_EXTERNAL_OES;
474 }
475
476 bool NativeImageSource::CheckBlending( tbm_format format )
477 {
478   if( mTbmFormat != format )
479   {
480     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
481     {
482       if( format == FORMATS_BLENDING_REQUIRED[i] )
483       {
484         mBlendingRequired = true;
485         break;
486       }
487     }
488     mTbmFormat = format;
489   }
490
491   return mBlendingRequired;
492 }
493
494 } // namespace Adaptor
495
496 } // namespace internal
497
498 } // namespace Dali