3cd68313f6c341c6a25a62e780862c2c5978171a
[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   mResourceDestructionCallback()
93 {
94   DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
95
96   GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
97   mEglGraphics = static_cast<EglGraphics *>(graphics);
98
99   mTbmSurface = GetSurfaceFromAny( nativeImageSource );
100
101   if( mTbmSurface != NULL )
102   {
103     tbm_surface_internal_ref( mTbmSurface );
104     mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
105     mWidth = tbm_surface_get_width( mTbmSurface );
106     mHeight = tbm_surface_get_height( mTbmSurface );
107   }
108 }
109
110 void NativeImageSourceTizen::Initialize()
111 {
112   if( mTbmSurface != NULL || mWidth == 0 || mHeight == 0 )
113   {
114     return;
115   }
116
117   tbm_format format = TBM_FORMAT_RGB888;
118   int depth = 0;
119
120   switch( mColorDepth )
121   {
122     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
123     {
124       format = TBM_FORMAT_ARGB8888;
125       depth = 32;
126       break;
127     }
128     case Dali::NativeImageSource::COLOR_DEPTH_8:
129     {
130       format = TBM_FORMAT_C8;
131       depth = 8;
132       break;
133     }
134     case Dali::NativeImageSource::COLOR_DEPTH_16:
135     {
136       format = TBM_FORMAT_RGB565;
137       depth = 16;
138       break;
139     }
140     case Dali::NativeImageSource::COLOR_DEPTH_24:
141     {
142       format = TBM_FORMAT_RGB888;
143       depth = 24;
144       break;
145     }
146     case Dali::NativeImageSource::COLOR_DEPTH_32:
147     {
148       format = TBM_FORMAT_ARGB8888;
149       depth = 32;
150       break;
151     }
152     default:
153     {
154       DALI_LOG_WARNING( "Wrong color depth.\n" );
155       return;
156     }
157   }
158
159   // set whether blending is required according to pixel format based on the depth
160   /* default pixel format is RGB888
161      If depth = 8, Pixel::A8;
162      If depth = 16, Pixel::RGB565;
163      If depth = 32, Pixel::RGBA8888 */
164   mBlendingRequired = ( depth == 32 || depth == 8 );
165
166   mTbmSurface = tbm_surface_create( mWidth, mHeight, format );
167   mOwnTbmSurface = true;
168 }
169
170 tbm_surface_h NativeImageSourceTizen::GetSurfaceFromAny( Any source ) const
171 {
172   if( source.Empty() )
173   {
174     return NULL;
175   }
176
177   if( source.GetType() == typeid( tbm_surface_h ) )
178   {
179     return AnyCast< tbm_surface_h >( source );
180   }
181   else
182   {
183     return NULL;
184   }
185 }
186
187 void NativeImageSourceTizen::DestroySurface()
188 {
189   if( mTbmSurface )
190   {
191     if( mIsBufferAcquired )
192     {
193       ReleaseBuffer();
194     }
195     if( mOwnTbmSurface )
196     {
197       if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
198       {
199         DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
200       }
201     }
202     else
203     {
204       tbm_surface_internal_unref( mTbmSurface );
205     }
206   }
207 }
208
209 NativeImageSourceTizen::~NativeImageSourceTizen()
210 {
211   DestroySurface();
212 }
213
214 Any NativeImageSourceTizen::GetNativeImageSource() const
215 {
216   return Any( mTbmSurface );
217 }
218
219 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
220 {
221   Dali::Mutex::ScopedLock lock( mMutex );
222   if( mTbmSurface != NULL )
223   {
224     tbm_surface_info_s surface_info;
225
226     if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE )
227     {
228       DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
229
230       width = 0;
231       height = 0;
232
233       return false;
234     }
235
236     tbm_format format = surface_info.format;
237     uint32_t stride = surface_info.planes[0].stride;
238     unsigned char* ptr = surface_info.planes[0].ptr;
239
240     width = mWidth;
241     height = mHeight;
242     size_t lineSize;
243     size_t offset;
244     size_t cOffset;
245
246     switch( format )
247     {
248       case TBM_FORMAT_RGB888:
249       {
250         lineSize = width*3;
251         pixelFormat = Pixel::RGB888;
252         pixbuf.resize( lineSize*height );
253         unsigned char* bufptr = &pixbuf[0];
254
255         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
256         {
257           for( unsigned int c = 0; c < width; ++c )
258           {
259             cOffset = c*3;
260             offset = cOffset + r*stride;
261             *(bufptr+cOffset) = ptr[offset+2];
262             *(bufptr+cOffset+1) = ptr[offset+1];
263             *(bufptr+cOffset+2) = ptr[offset];
264           }
265         }
266         break;
267       }
268       case TBM_FORMAT_RGBA8888:
269       {
270         lineSize = width*4;
271         pixelFormat = Pixel::RGBA8888;
272         pixbuf.resize( lineSize*height );
273         unsigned char* bufptr = &pixbuf[0];
274
275         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
276         {
277           for( unsigned int c = 0; c < width; ++c )
278           {
279             cOffset = c*4;
280             offset = cOffset + r*stride;
281             *(bufptr+cOffset) = ptr[offset+3];
282             *(bufptr+cOffset+1) = ptr[offset+2];
283             *(bufptr+cOffset+2) = ptr[offset+1];
284             *(bufptr+cOffset+3) = ptr[offset];
285           }
286         }
287         break;
288       }
289       case TBM_FORMAT_ARGB8888:
290       {
291         lineSize = width*4;
292         pixelFormat = Pixel::RGBA8888;
293         pixbuf.resize( lineSize*height );
294         unsigned char* bufptr = &pixbuf[0];
295
296         for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
297         {
298           for( unsigned int c = 0; c < width; ++c )
299           {
300             cOffset = c*4;
301             offset = cOffset + r*stride;
302             *(bufptr+cOffset)   = ptr[offset+2];
303             *(bufptr+cOffset+1) = ptr[offset+1];
304             *(bufptr+cOffset+2) = ptr[offset];
305             *(bufptr+cOffset+3) = ptr[offset+3];
306           }
307         }
308         break;
309       }
310       default:
311       {
312         DALI_ASSERT_ALWAYS( 0 && "Tbm surface has unsupported pixel format.\n" );
313
314         return false;
315       }
316     }
317
318     if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
319     {
320       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
321     }
322
323     return true;
324   }
325
326   DALI_LOG_WARNING( "TBM surface does not exist.\n" );
327
328   width = 0;
329   height = 0;
330
331   return false;
332 }
333
334 void NativeImageSourceTizen::SetSource( Any source )
335 {
336   Dali::Mutex::ScopedLock lock( mMutex );
337
338   DestroySurface();
339
340   mOwnTbmSurface = false;
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_ARGB8888;
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_ARGB8888;
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::CreateResource()
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 || !tbm_surface_internal_is_valid( mTbmSurface ) )
410   {
411     return false;
412   }
413
414   mEglImageExtensions = mEglGraphics->GetImageExtensions();
415   DALI_ASSERT_DEBUG( mEglImageExtensions );
416
417   mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
418
419   return mEglImageKHR != NULL;
420 }
421
422 void NativeImageSourceTizen::DestroyResource()
423 {
424   Dali::Mutex::ScopedLock lock( mMutex );
425   if( mEglImageKHR )
426   {
427     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
428
429     mEglImageKHR = NULL;
430   }
431
432   if(mResourceDestructionCallback)
433   {
434     mResourceDestructionCallback->Trigger();
435   }
436 }
437
438 uint32_t NativeImageSourceTizen::TargetTexture()
439 {
440   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
441
442   return 0;
443 }
444
445 void NativeImageSourceTizen::PrepareTexture()
446 {
447   Dali::Mutex::ScopedLock lock( mMutex );
448   if( mSetSource )
449   {
450     void* eglImage = mEglImageKHR;
451
452     if( CreateResource() )
453     {
454       TargetTexture();
455     }
456
457     mEglImageExtensions->DestroyImageKHR( eglImage );
458
459     mSetSource = false;
460   }
461 }
462
463 const char* NativeImageSourceTizen::GetCustomFragmentPrefix() const
464 {
465   return FRAGMENT_PREFIX;
466 }
467
468 const char* NativeImageSourceTizen::GetCustomSamplerTypename() const
469 {
470   return SAMPLER_TYPE;
471 }
472
473 int NativeImageSourceTizen::GetTextureTarget() const
474 {
475   return GL_TEXTURE_EXTERNAL_OES;
476 }
477
478 Any NativeImageSourceTizen::GetNativeImageHandle() const
479 {
480   return GetNativeImageSource();
481 }
482
483 bool NativeImageSourceTizen::SourceChanged() const
484 {
485   return false;
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 void NativeImageSourceTizen::SetResourceDestructionCallback(EventThreadCallback* callback)
553 {
554   mResourceDestructionCallback = std::unique_ptr<EventThreadCallback>(callback);
555 }
556
557 } // namespace Adaptor
558
559 } // namespace internal
560
561 } // namespace Dali