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