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