096944ce92ed3cba67f86f74fe76924d21f5fa08
[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 namespace Dali
34 {
35
36 namespace Internal
37 {
38
39 namespace Adaptor
40 {
41
42 namespace
43 {
44 const char* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
45 const char* SAMPLER_TYPE = "samplerExternalOES";
46
47 tbm_format FORMATS_BLENDING_REQUIRED[] = {
48   TBM_FORMAT_ARGB4444, TBM_FORMAT_ABGR4444,
49   TBM_FORMAT_RGBA4444, TBM_FORMAT_BGRA4444,
50   TBM_FORMAT_RGBX5551, TBM_FORMAT_BGRX5551,
51   TBM_FORMAT_ARGB1555, TBM_FORMAT_ABGR1555,
52   TBM_FORMAT_RGBA5551, TBM_FORMAT_BGRA5551,
53   TBM_FORMAT_ARGB8888, TBM_FORMAT_ABGR8888,
54   TBM_FORMAT_RGBA8888, TBM_FORMAT_BGRA8888,
55   TBM_FORMAT_ARGB2101010, TBM_FORMAT_ABGR2101010,
56   TBM_FORMAT_RGBA1010102, TBM_FORMAT_BGRA1010102
57 };
58
59 const int NUM_FORMATS_BLENDING_REQUIRED = 18;
60
61 }
62
63 using Dali::Integration::PixelBuffer;
64
65 NativeImageSourceTizen* NativeImageSourceTizen::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
66 {
67   NativeImageSourceTizen* image = new NativeImageSourceTizen( width, height, depth, nativeImageSource );
68   DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
69
70   if( image )
71   {
72     image->Initialize();
73   }
74
75   return image;
76 }
77
78 NativeImageSourceTizen::NativeImageSourceTizen( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
79 : mWidth( width ),
80   mHeight( height ),
81   mOwnTbmSurface( false ),
82   mTbmSurface( NULL ),
83   mTbmFormat( 0 ),
84   mBlendingRequired( false ),
85   mColorDepth( depth ),
86   mEglImageKHR( NULL ),
87   mEglGraphics( NULL ),
88   mEglImageExtensions( NULL ),
89   mSetSource( false ),
90   mMutex(),
91   mIsBufferAcquired( false )
92 {
93   DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
94
95   GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
96   mEglGraphics = static_cast<EglGraphics *>(graphics);
97
98   mTbmSurface = GetSurfaceFromAny( nativeImageSource );
99
100   if( mTbmSurface != NULL )
101   {
102     tbm_surface_internal_ref( mTbmSurface );
103     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
104     mWidth = tbm_surface_get_width( mTbmSurface );
105     mHeight = tbm_surface_get_height( mTbmSurface );
106   }
107 }
108
109 void NativeImageSourceTizen::Initialize()
110 {
111   if( mTbmSurface != NULL || mWidth == 0 || mHeight == 0 )
112   {
113     return;
114   }
115
116   tbm_format format = TBM_FORMAT_RGB888;
117   int depth = 0;
118
119   switch( mColorDepth )
120   {
121     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
122     {
123       format = TBM_FORMAT_ARGB8888;
124       depth = 32;
125       break;
126     }
127     case Dali::NativeImageSource::COLOR_DEPTH_8:
128     {
129       format = TBM_FORMAT_C8;
130       depth = 8;
131       break;
132     }
133     case Dali::NativeImageSource::COLOR_DEPTH_16:
134     {
135       format = TBM_FORMAT_RGB565;
136       depth = 16;
137       break;
138     }
139     case Dali::NativeImageSource::COLOR_DEPTH_24:
140     {
141       format = TBM_FORMAT_RGB888;
142       depth = 24;
143       break;
144     }
145     case Dali::NativeImageSource::COLOR_DEPTH_32:
146     {
147       format = TBM_FORMAT_ARGB8888;
148       depth = 32;
149       break;
150     }
151     default:
152     {
153       DALI_LOG_WARNING( "Wrong color depth.\n" );
154       return;
155     }
156   }
157
158   // set whether blending is required according to pixel format based on the depth
159   /* default pixel format is RGB888
160      If depth = 8, Pixel::A8;
161      If depth = 16, Pixel::RGB565;
162      If depth = 32, Pixel::RGBA8888 */
163   mBlendingRequired = ( depth == 32 || depth == 8 );
164
165   mTbmSurface = tbm_surface_create( mWidth, mHeight, format );
166   mOwnTbmSurface = true;
167 }
168
169 tbm_surface_h NativeImageSourceTizen::GetSurfaceFromAny( Any source ) const
170 {
171   if( source.Empty() )
172   {
173     return NULL;
174   }
175
176   if( source.GetType() == typeid( tbm_surface_h ) )
177   {
178     return AnyCast< tbm_surface_h >( source );
179   }
180   else
181   {
182     return NULL;
183   }
184 }
185
186 void NativeImageSourceTizen::DestroySurface()
187 {
188   if( mTbmSurface )
189   {
190     if( mIsBufferAcquired )
191     {
192       ReleaseBuffer();
193     }
194     if( mOwnTbmSurface )
195     {
196       if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
197       {
198         DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
199       }
200     }
201     else
202     {
203       tbm_surface_internal_unref( mTbmSurface );
204     }
205   }
206 }
207
208 NativeImageSourceTizen::~NativeImageSourceTizen()
209 {
210   DestroySurface();
211 }
212
213 Any NativeImageSourceTizen::GetNativeImageSource() const
214 {
215   return Any( mTbmSurface );
216 }
217
218 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
219 {
220   Dali::Mutex::ScopedLock lock( mMutex );
221   if( mTbmSurface != NULL )
222   {
223     tbm_surface_info_s surface_info;
224
225     if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE )
226     {
227       DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
228
229       width = 0;
230       height = 0;
231
232       return false;
233     }
234
235     tbm_format format = surface_info.format;
236     uint32_t stride = surface_info.planes[0].stride;
237     unsigned char* ptr = surface_info.planes[0].ptr;
238
239     width = mWidth;
240     height = mHeight;
241     size_t lineSize;
242     size_t offset;
243     size_t cOffset;
244
245     switch( format )
246     {
247       case TBM_FORMAT_RGB888:
248       {
249         lineSize = width*3;
250         pixelFormat = Pixel::RGB888;
251         pixbuf.resize( lineSize*height );
252         unsigned char* bufptr = &pixbuf[0];
253
254         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
255         {
256           for( unsigned int c = 0; c < width; ++c )
257           {
258             cOffset = c*3;
259             offset = cOffset + r*stride;
260             *(bufptr+cOffset) = ptr[offset+2];
261             *(bufptr+cOffset+1) = ptr[offset+1];
262             *(bufptr+cOffset+2) = ptr[offset];
263           }
264         }
265         break;
266       }
267       case TBM_FORMAT_RGBA8888:
268       {
269         lineSize = width*4;
270         pixelFormat = Pixel::RGBA8888;
271         pixbuf.resize( lineSize*height );
272         unsigned char* bufptr = &pixbuf[0];
273
274         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
275         {
276           for( unsigned int c = 0; c < width; ++c )
277           {
278             cOffset = c*4;
279             offset = cOffset + r*stride;
280             *(bufptr+cOffset) = ptr[offset+3];
281             *(bufptr+cOffset+1) = ptr[offset+2];
282             *(bufptr+cOffset+2) = ptr[offset+1];
283             *(bufptr+cOffset+3) = ptr[offset];
284           }
285         }
286         break;
287       }
288       case TBM_FORMAT_ARGB8888:
289       {
290         lineSize = width*4;
291         pixelFormat = Pixel::RGBA8888;
292         pixbuf.resize( lineSize*height );
293         unsigned char* bufptr = &pixbuf[0];
294
295         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
296         {
297           for( unsigned int c = 0; c < width; ++c )
298           {
299             cOffset = c*4;
300             offset = cOffset + r*stride;
301             *(bufptr+cOffset)   = ptr[offset+2];
302             *(bufptr+cOffset+1) = ptr[offset+1];
303             *(bufptr+cOffset+2) = ptr[offset];
304             *(bufptr+cOffset+3) = ptr[offset+3];
305           }
306         }
307         break;
308       }
309       default:
310       {
311         DALI_ASSERT_ALWAYS( 0 && "Tbm surface has unsupported pixel format.\n" );
312
313         return false;
314       }
315     }
316
317     if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
318     {
319       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
320     }
321
322     return true;
323   }
324
325   DALI_LOG_WARNING( "TBM surface does not exist.\n" );
326
327   width = 0;
328   height = 0;
329
330   return false;
331 }
332
333 void NativeImageSourceTizen::SetSource( Any source )
334 {
335   Dali::Mutex::ScopedLock lock( mMutex );
336
337   DestroySurface();
338
339   mOwnTbmSurface = false;
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_ARGB8888;
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_ARGB8888;
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 uint8_t* NativeImageSourceTizen::AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride )
491 {
492   Dali::Mutex::ScopedLock lock( mMutex );
493   if( mTbmSurface != NULL )
494   {
495     tbm_surface_info_s info;
496
497     if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &info) != TBM_SURFACE_ERROR_NONE )
498     {
499       DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
500
501       width = 0;
502       height = 0;
503
504       return NULL;
505     }
506     tbm_surface_internal_ref( mTbmSurface );
507     mIsBufferAcquired = true;
508
509     stride = info.planes[0].stride;
510     width = mWidth;
511     height = mHeight;
512
513     return info.planes[0].ptr;
514   }
515   return NULL;
516 }
517
518
519 bool NativeImageSourceTizen::ReleaseBuffer()
520 {
521   Dali::Mutex::ScopedLock lock( mMutex );
522   bool ret = false;
523   if( mTbmSurface != NULL )
524   {
525     ret = ( tbm_surface_unmap( mTbmSurface ) == TBM_SURFACE_ERROR_NONE );
526     if( !ret )
527     {
528       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
529     }
530     tbm_surface_internal_unref( mTbmSurface );
531     mIsBufferAcquired = false;
532   }
533   return ret;
534 }
535
536
537 } // namespace Adaptor
538
539 } // namespace internal
540
541 } // namespace Dali