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