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