Merge "Merge branch 'devel/master' into devel/graphics" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / tizen / native-image-source-impl-tizen.cpp
1 /*
2  * Copyright (c) 2021 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 <tbm_surface_internal.h>
25 #include <cstring>
26
27 // INTERNAL INCLUDES
28 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30 #include <dali/internal/graphics/common/egl-image-extensions.h>
31 #include <dali/internal/graphics/gles/egl-graphics.h>
32
33 namespace Dali
34 {
35 namespace Internal
36 {
37 namespace Adaptor
38 {
39 namespace
40 {
41 const char* SAMPLER_TYPE = "samplerExternalOES";
42
43 // clang-format off
44 tbm_format FORMATS_BLENDING_REQUIRED[] = {
45   TBM_FORMAT_ARGB4444, TBM_FORMAT_ABGR4444,
46   TBM_FORMAT_RGBA4444, TBM_FORMAT_BGRA4444,
47   TBM_FORMAT_RGBX5551, TBM_FORMAT_BGRX5551,
48   TBM_FORMAT_ARGB1555, TBM_FORMAT_ABGR1555,
49   TBM_FORMAT_RGBA5551, TBM_FORMAT_BGRA5551,
50   TBM_FORMAT_ARGB8888, TBM_FORMAT_ABGR8888,
51   TBM_FORMAT_RGBA8888, TBM_FORMAT_BGRA8888,
52   TBM_FORMAT_ARGB2101010, TBM_FORMAT_ABGR2101010,
53   TBM_FORMAT_RGBA1010102, TBM_FORMAT_BGRA1010102
54 };
55 // clang-format on
56
57 const int NUM_FORMATS_BLENDING_REQUIRED = 18;
58
59 } // namespace
60
61 using Dali::Integration::PixelBuffer;
62
63 NativeImageSourceTizen* NativeImageSourceTizen::New(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
64 {
65   NativeImageSourceTizen* image = new NativeImageSourceTizen(width, height, depth, nativeImageSource);
66   DALI_ASSERT_DEBUG(image && "NativeImageSource allocation failed.");
67
68   if(image)
69   {
70     image->Initialize();
71   }
72
73   return image;
74 }
75
76 NativeImageSourceTizen::NativeImageSourceTizen(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
77 : mCustomFragmentPrefix(),
78   mWidth(width),
79   mHeight(height),
80   mOwnTbmSurface(false),
81   mTbmSurface(NULL),
82   mTbmFormat(0),
83   mBlendingRequired(false),
84   mColorDepth(depth),
85   mEglImageKHR(NULL),
86   mEglGraphics(NULL),
87   mEglImageExtensions(NULL),
88   mSetSource(false),
89   mMutex(),
90   mIsBufferAcquired(false)
91 {
92   DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
93
94   GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
95   mEglGraphics                = static_cast<EglGraphics*>(graphics);
96
97   mCustomFragmentPrefix = mEglGraphics->GetEglImageExtensionString();
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   // if resource of egl was not destroyed, destroy it first
418   DestroyResource();
419
420   mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
421
422   return mEglImageKHR != NULL;
423 }
424
425 void NativeImageSourceTizen::DestroyResource()
426 {
427   Dali::Mutex::ScopedLock lock(mMutex);
428   if(mEglImageKHR)
429   {
430     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
431
432     mEglImageKHR = NULL;
433   }
434 }
435
436 uint32_t NativeImageSourceTizen::TargetTexture()
437 {
438   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
439
440   return 0;
441 }
442
443 void NativeImageSourceTizen::PrepareTexture()
444 {
445   Dali::Mutex::ScopedLock lock(mMutex);
446   if(mSetSource)
447   {
448     void* eglImage = mEglImageKHR;
449
450     if(CreateResource())
451     {
452       TargetTexture();
453     }
454
455     mEglImageExtensions->DestroyImageKHR(eglImage);
456
457     mSetSource = false;
458   }
459 }
460
461 const char* NativeImageSourceTizen::GetCustomFragmentPrefix() const
462 {
463   return mCustomFragmentPrefix;
464 }
465
466 const char* NativeImageSourceTizen::GetCustomSamplerTypename() const
467 {
468   return SAMPLER_TYPE;
469 }
470
471 int NativeImageSourceTizen::GetTextureTarget() const
472 {
473   return GL_TEXTURE_EXTERNAL_OES;
474 }
475
476 Any NativeImageSourceTizen::GetNativeImageHandle() const
477 {
478   return GetNativeImageSource();
479 }
480
481 bool NativeImageSourceTizen::SourceChanged() const
482 {
483   return false;
484 }
485
486 bool NativeImageSourceTizen::CheckBlending(tbm_format format)
487 {
488   if(mTbmFormat != format)
489   {
490     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
491     {
492       if(format == FORMATS_BLENDING_REQUIRED[i])
493       {
494         mBlendingRequired = true;
495         break;
496       }
497     }
498     mTbmFormat = format;
499   }
500
501   return mBlendingRequired;
502 }
503
504 uint8_t* NativeImageSourceTizen::AcquireBuffer(uint16_t& width, uint16_t& height, uint16_t& stride)
505 {
506   Dali::Mutex::ScopedLock lock(mMutex);
507   if(mTbmSurface != NULL)
508   {
509     tbm_surface_info_s info;
510
511     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
512     {
513       DALI_LOG_ERROR("Fail to map tbm_surface\n");
514
515       width  = 0;
516       height = 0;
517
518       return NULL;
519     }
520     tbm_surface_internal_ref(mTbmSurface);
521     mIsBufferAcquired = true;
522
523     stride = info.planes[0].stride;
524     width  = mWidth;
525     height = mHeight;
526
527     return info.planes[0].ptr;
528   }
529   return NULL;
530 }
531
532 bool NativeImageSourceTizen::ReleaseBuffer()
533 {
534   Dali::Mutex::ScopedLock lock(mMutex);
535   bool                    ret = false;
536   if(mTbmSurface != NULL)
537   {
538     ret = (tbm_surface_unmap(mTbmSurface) == TBM_SURFACE_ERROR_NONE);
539     if(!ret)
540     {
541       DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
542     }
543     tbm_surface_internal_unref(mTbmSurface);
544     mIsBufferAcquired = false;
545   }
546   return ret;
547 }
548
549 } // namespace Adaptor
550
551 } // namespace Internal
552
553 } // namespace Dali