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