There was a bug in the conditional statement.
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / tizen / native-image-source-impl-tizen.cpp
1 /*
2  * Copyright (c) 2020 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/adaptor-framework/render-surface-interface.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   mIsBufferAcquired( false )
95 {
96   DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
97
98   GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
99   mEglGraphics = static_cast<EglGraphics *>(graphics);
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 NativeImageSourceTizen::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_ARGB8888;
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_ARGB8888;
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 NativeImageSourceTizen::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 void NativeImageSourceTizen::DestroySurface()
190 {
191   if( mTbmSurface )
192   {
193     if( mIsBufferAcquired )
194     {
195       ReleaseBuffer();
196     }
197     if( mOwnTbmSurface )
198     {
199       if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
200       {
201         DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
202       }
203     }
204     else
205     {
206       tbm_surface_internal_unref( mTbmSurface );
207     }
208   }
209 }
210
211 NativeImageSourceTizen::~NativeImageSourceTizen()
212 {
213   DestroySurface();
214 }
215
216 Any NativeImageSourceTizen::GetNativeImageSource() const
217 {
218   return Any( mTbmSurface );
219 }
220
221 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
222 {
223   Dali::Mutex::ScopedLock lock( mMutex );
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       case TBM_FORMAT_ARGB8888:
292       {
293         lineSize = width*4;
294         pixelFormat = Pixel::RGBA8888;
295         pixbuf.resize( lineSize*height );
296         unsigned char* bufptr = &pixbuf[0];
297
298         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
299         {
300           for( unsigned int c = 0; c < width; ++c )
301           {
302             cOffset = c*4;
303             offset = cOffset + r*stride;
304             *(bufptr+cOffset) = ptr[offset];
305             *(bufptr+cOffset+1) = ptr[offset+3];
306             *(bufptr+cOffset+2) = ptr[offset+2];
307             *(bufptr+cOffset+3) = ptr[offset+1];
308           }
309         }
310         break;
311       }
312       default:
313       {
314         DALI_ASSERT_ALWAYS( 0 && "Tbm surface has unsupported pixel format.\n" );
315
316         return false;
317       }
318     }
319
320     if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
321     {
322       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
323     }
324
325     return true;
326   }
327
328   DALI_LOG_WARNING( "TBM surface does not exist.\n" );
329
330   width = 0;
331   height = 0;
332
333   return false;
334 }
335
336 bool NativeImageSourceTizen::EncodeToFile(const std::string& filename) const
337 {
338   std::vector< unsigned char > pixbuf;
339   unsigned int width(0), height(0);
340   Pixel::Format pixelFormat;
341
342   if(GetPixels(pixbuf, width, height, pixelFormat))
343   {
344     return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
345   }
346   return false;
347 }
348
349 void NativeImageSourceTizen::SetSource( Any source )
350 {
351   Dali::Mutex::ScopedLock lock( mMutex );
352
353   DestroySurface();
354
355   mOwnTbmSurface = false;
356   mTbmSurface = GetSurfaceFromAny( source );
357
358   if( mTbmSurface != NULL )
359   {
360     mSetSource = true;
361     tbm_surface_internal_ref( mTbmSurface );
362     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
363     mWidth = tbm_surface_get_width( mTbmSurface );
364     mHeight = tbm_surface_get_height( mTbmSurface );
365   }
366 }
367
368 bool NativeImageSourceTizen::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
369 {
370   uint32_t* formats;
371   uint32_t formatNum;
372   tbm_format format = TBM_FORMAT_RGB888;
373
374   switch( colorDepth )
375   {
376     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
377     {
378       format = TBM_FORMAT_ARGB8888;
379       break;
380     }
381     case Dali::NativeImageSource::COLOR_DEPTH_8:
382     {
383       format = TBM_FORMAT_C8;
384       break;
385     }
386     case Dali::NativeImageSource::COLOR_DEPTH_16:
387     {
388       format = TBM_FORMAT_RGB565;
389       break;
390     }
391     case Dali::NativeImageSource::COLOR_DEPTH_24:
392     {
393       format = TBM_FORMAT_RGB888;
394       break;
395     }
396     case Dali::NativeImageSource::COLOR_DEPTH_32:
397     {
398       format = TBM_FORMAT_ARGB8888;
399       break;
400     }
401   }
402
403   if( tbm_surface_query_formats( &formats, &formatNum ) )
404   {
405     for( unsigned int i = 0; i < formatNum; i++ )
406     {
407       if( formats[i] == format )
408       {
409         free( formats );
410         return true;
411       }
412     }
413   }
414
415   free( formats );
416   return false;
417 }
418
419 bool NativeImageSourceTizen::GlExtensionCreate()
420 {
421   // casting from an unsigned int to a void *, which should then be cast back
422   // to an unsigned int in the driver.
423   EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer >(mTbmSurface);
424   if( !eglBuffer || !tbm_surface_internal_is_valid( mTbmSurface ) )
425   {
426     return false;
427   }
428
429   mEglImageExtensions = mEglGraphics->GetImageExtensions();
430   DALI_ASSERT_DEBUG( mEglImageExtensions );
431
432   mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
433
434   return mEglImageKHR != NULL;
435 }
436
437 void NativeImageSourceTizen::GlExtensionDestroy()
438 {
439   Dali::Mutex::ScopedLock lock( mMutex );
440   if( mEglImageKHR )
441   {
442     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
443
444     mEglImageKHR = NULL;
445   }
446 }
447
448 uint32_t NativeImageSourceTizen::TargetTexture()
449 {
450   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
451
452   return 0;
453 }
454
455 void NativeImageSourceTizen::PrepareTexture()
456 {
457   Dali::Mutex::ScopedLock lock( mMutex );
458   if( mSetSource )
459   {
460     void* eglImage = mEglImageKHR;
461
462     if( GlExtensionCreate() )
463     {
464       TargetTexture();
465     }
466
467     mEglImageExtensions->DestroyImageKHR( eglImage );
468
469     mSetSource = false;
470   }
471 }
472
473 const char* NativeImageSourceTizen::GetCustomFragmentPreFix()
474 {
475   return FRAGMENT_PREFIX;
476 }
477
478 const char* NativeImageSourceTizen::GetCustomSamplerTypename()
479 {
480   return SAMPLER_TYPE;
481 }
482
483 int NativeImageSourceTizen::GetEglImageTextureTarget()
484 {
485   return GL_TEXTURE_EXTERNAL_OES;
486 }
487
488 bool NativeImageSourceTizen::CheckBlending( tbm_format format )
489 {
490   if( mTbmFormat != format )
491   {
492     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
493     {
494       if( format == FORMATS_BLENDING_REQUIRED[i] )
495       {
496         mBlendingRequired = true;
497         break;
498       }
499     }
500     mTbmFormat = format;
501   }
502
503   return mBlendingRequired;
504 }
505
506 uint8_t* NativeImageSourceTizen::AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride )
507 {
508   Dali::Mutex::ScopedLock lock( mMutex );
509   if( mTbmSurface != NULL )
510   {
511     tbm_surface_info_s info;
512
513     if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &info) != TBM_SURFACE_ERROR_NONE )
514     {
515       DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
516
517       width = 0;
518       height = 0;
519
520       return NULL;
521     }
522     tbm_surface_internal_ref( mTbmSurface );
523     mIsBufferAcquired = true;
524
525     stride = info.planes[0].stride;
526     width = mWidth;
527     height = mHeight;
528
529     return info.planes[0].ptr;
530   }
531   return NULL;
532 }
533
534
535 bool NativeImageSourceTizen::ReleaseBuffer()
536 {
537   Dali::Mutex::ScopedLock lock( mMutex );
538   bool ret = false;
539   if( mTbmSurface != NULL )
540   {
541     ret = ( tbm_surface_unmap( mTbmSurface ) == TBM_SURFACE_ERROR_NONE );
542     if( !ret )
543     {
544       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
545     }
546     tbm_surface_internal_unref( mTbmSurface );
547     mIsBufferAcquired = false;
548   }
549   return ret;
550 }
551
552
553 } // namespace Adaptor
554
555 } // namespace internal
556
557 } // namespace Dali