Merge "Temporary fix of PreInitialize, Remove FontClient" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / 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 <dali/internal/imaging/tizen/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 <dali/internal/graphics/common/egl-image-extensions.h>
29 #include <dali/internal/graphics/gles/egl-graphics.h>
30 #include <dali/internal/adaptor/common/adaptor-impl.h>
31 #include <dali/integration-api/render-surface.h>
32
33 // Allow this to be encoded and saved:
34 #include <dali/devel-api/adaptor-framework/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 NativeImageSourceTizen* NativeImageSourceTizen::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
69 {
70   NativeImageSourceTizen* image = new NativeImageSourceTizen( 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 NativeImageSourceTizen::NativeImageSourceTizen( uint32_t width, uint32_t 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   mEglGraphics( NULL ),
91   mEglImageExtensions( NULL ),
92   mSetSource( false ),
93   mMutex()
94 {
95   DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
96
97   GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
98   mEglGraphics = static_cast<EglGraphics *>(graphics);
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   }
204 }
205
206 Any NativeImageSourceTizen::GetNativeImageSource() const
207 {
208   return Any( mTbmSurface );
209 }
210
211 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
212 {
213   Dali::Mutex::ScopedLock lock( mMutex );
214   if( mTbmSurface != NULL )
215   {
216     tbm_surface_info_s surface_info;
217
218     if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE )
219     {
220       DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
221
222       width = 0;
223       height = 0;
224
225       return false;
226     }
227
228     tbm_format format = surface_info.format;
229     uint32_t stride = surface_info.planes[0].stride;
230     unsigned char* ptr = surface_info.planes[0].ptr;
231
232     width = mWidth;
233     height = mHeight;
234     size_t lineSize;
235     size_t offset;
236     size_t cOffset;
237
238     switch( format )
239     {
240       case TBM_FORMAT_RGB888:
241       {
242         lineSize = width*3;
243         pixelFormat = Pixel::RGB888;
244         pixbuf.resize( lineSize*height );
245         unsigned char* bufptr = &pixbuf[0];
246
247         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
248         {
249           for( unsigned int c = 0; c < width; ++c )
250           {
251             cOffset = c*3;
252             offset = cOffset + r*stride;
253             *(bufptr+cOffset) = ptr[offset+2];
254             *(bufptr+cOffset+1) = ptr[offset+1];
255             *(bufptr+cOffset+2) = ptr[offset];
256           }
257         }
258         break;
259       }
260       case TBM_FORMAT_RGBA8888:
261       {
262         lineSize = width*4;
263         pixelFormat = Pixel::RGBA8888;
264         pixbuf.resize( lineSize*height );
265         unsigned char* bufptr = &pixbuf[0];
266
267         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
268         {
269           for( unsigned int c = 0; c < width; ++c )
270           {
271             cOffset = c*4;
272             offset = cOffset + r*stride;
273             *(bufptr+cOffset) = ptr[offset+3];
274             *(bufptr+cOffset+1) = ptr[offset+2];
275             *(bufptr+cOffset+2) = ptr[offset+1];
276             *(bufptr+cOffset+3) = ptr[offset];
277           }
278         }
279         break;
280       }
281       default:
282       {
283         DALI_ASSERT_ALWAYS( 0 && "Tbm surface has unsupported pixel format.\n" );
284
285         return false;
286       }
287     }
288
289     if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
290     {
291       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
292     }
293
294     return true;
295   }
296
297   DALI_LOG_WARNING( "TBM surface does not exist.\n" );
298
299   width = 0;
300   height = 0;
301
302   return false;
303 }
304
305 bool NativeImageSourceTizen::EncodeToFile(const std::string& filename) const
306 {
307   std::vector< unsigned char > pixbuf;
308   unsigned int width(0), height(0);
309   Pixel::Format pixelFormat;
310
311   if(GetPixels(pixbuf, width, height, pixelFormat))
312   {
313     return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
314   }
315   return false;
316 }
317
318 void NativeImageSourceTizen::SetSource( Any source )
319 {
320   Dali::Mutex::ScopedLock lock( mMutex );
321   if( mOwnTbmSurface )
322   {
323     if( mTbmSurface != NULL && tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
324     {
325       DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
326     }
327
328     mTbmSurface = NULL;
329     mOwnTbmSurface = false;
330   }
331   else
332   {
333     if( mTbmSurface != NULL )
334     {
335       tbm_surface_internal_unref( mTbmSurface );
336       mTbmSurface = NULL;
337     }
338   }
339
340   mTbmSurface = GetSurfaceFromAny( source );
341
342   if( mTbmSurface != NULL )
343   {
344     mSetSource = true;
345     tbm_surface_internal_ref( mTbmSurface );
346     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
347     mWidth = tbm_surface_get_width( mTbmSurface );
348     mHeight = tbm_surface_get_height( mTbmSurface );
349   }
350 }
351
352 bool NativeImageSourceTizen::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
353 {
354   uint32_t* formats;
355   uint32_t formatNum;
356   tbm_format format = TBM_FORMAT_RGB888;
357
358   switch( colorDepth )
359   {
360     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
361     {
362       format = TBM_FORMAT_RGBA8888;
363       break;
364     }
365     case Dali::NativeImageSource::COLOR_DEPTH_8:
366     {
367       format = TBM_FORMAT_C8;
368       break;
369     }
370     case Dali::NativeImageSource::COLOR_DEPTH_16:
371     {
372       format = TBM_FORMAT_RGB565;
373       break;
374     }
375     case Dali::NativeImageSource::COLOR_DEPTH_24:
376     {
377       format = TBM_FORMAT_RGB888;
378       break;
379     }
380     case Dali::NativeImageSource::COLOR_DEPTH_32:
381     {
382       format = TBM_FORMAT_RGBA8888;
383       break;
384     }
385   }
386
387   if( tbm_surface_query_formats( &formats, &formatNum ) )
388   {
389     for( unsigned int i = 0; i < formatNum; i++ )
390     {
391       if( formats[i] == format )
392       {
393         free( formats );
394         return true;
395       }
396     }
397   }
398
399   free( formats );
400   return false;
401 }
402
403 bool NativeImageSourceTizen::GlExtensionCreate()
404 {
405   // casting from an unsigned int to a void *, which should then be cast back
406   // to an unsigned int in the driver.
407   EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer >(mTbmSurface);
408   if( !eglBuffer || !tbm_surface_internal_is_valid( mTbmSurface ) )
409   {
410     return false;
411   }
412
413   mEglImageExtensions = mEglGraphics->GetImageExtensions();
414   DALI_ASSERT_DEBUG( mEglImageExtensions );
415
416   mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
417
418   return mEglImageKHR != NULL;
419 }
420
421 void NativeImageSourceTizen::GlExtensionDestroy()
422 {
423   Dali::Mutex::ScopedLock lock( mMutex );
424   if( mEglImageKHR )
425   {
426     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
427
428     mEglImageKHR = NULL;
429   }
430 }
431
432 uint32_t NativeImageSourceTizen::TargetTexture()
433 {
434   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
435
436   return 0;
437 }
438
439 void NativeImageSourceTizen::PrepareTexture()
440 {
441   Dali::Mutex::ScopedLock lock( mMutex );
442   if( mSetSource )
443   {
444     void* eglImage = mEglImageKHR;
445
446     if( GlExtensionCreate() )
447     {
448       TargetTexture();
449     }
450
451     mEglImageExtensions->DestroyImageKHR( eglImage );
452
453     mSetSource = false;
454   }
455 }
456
457 const char* NativeImageSourceTizen::GetCustomFragmentPreFix()
458 {
459   return FRAGMENT_PREFIX;
460 }
461
462 const char* NativeImageSourceTizen::GetCustomSamplerTypename()
463 {
464   return SAMPLER_TYPE;
465 }
466
467 int NativeImageSourceTizen::GetEglImageTextureTarget()
468 {
469   return GL_TEXTURE_EXTERNAL_OES;
470 }
471
472 bool NativeImageSourceTizen::CheckBlending( tbm_format format )
473 {
474   if( mTbmFormat != format )
475   {
476     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
477     {
478       if( format == FORMATS_BLENDING_REQUIRED[i] )
479       {
480         mBlendingRequired = true;
481         break;
482       }
483     }
484     mTbmFormat = format;
485   }
486
487   return mBlendingRequired;
488 }
489
490 } // namespace Adaptor
491
492 } // namespace internal
493
494 } // namespace Dali