a6e7cc6af8503e56f0bc1f978b5569fd640d5968
[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 : mWidth(width),
78   mHeight(height),
79   mOwnTbmSurface(false),
80   mTbmSurface(NULL),
81   mTbmFormat(0),
82   mBlendingRequired(false),
83   mColorDepth(depth),
84   mEglImageKHR(NULL),
85   mEglGraphics(NULL),
86   mEglImageExtensions(NULL),
87   mSetSource(false),
88   mMutex(),
89   mIsBufferAcquired(false)
90 {
91   DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
92
93   GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
94   mEglGraphics                = static_cast<EglGraphics*>(graphics);
95
96   mTbmSurface = GetSurfaceFromAny(nativeImageSource);
97
98   if(mTbmSurface != NULL)
99   {
100     tbm_surface_internal_ref(mTbmSurface);
101     mBlendingRequired = CheckBlending(tbm_surface_get_format(mTbmSurface));
102     mWidth            = tbm_surface_get_width(mTbmSurface);
103     mHeight           = tbm_surface_get_height(mTbmSurface);
104   }
105 }
106
107 void NativeImageSourceTizen::Initialize()
108 {
109   if(mTbmSurface != NULL || mWidth == 0 || mHeight == 0)
110   {
111     return;
112   }
113
114   tbm_format format = TBM_FORMAT_RGB888;
115   int        depth  = 0;
116
117   switch(mColorDepth)
118   {
119     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
120     {
121       format = TBM_FORMAT_ARGB8888;
122       depth  = 32;
123       break;
124     }
125     case Dali::NativeImageSource::COLOR_DEPTH_8:
126     {
127       format = TBM_FORMAT_C8;
128       depth  = 8;
129       break;
130     }
131     case Dali::NativeImageSource::COLOR_DEPTH_16:
132     {
133       format = TBM_FORMAT_RGB565;
134       depth  = 16;
135       break;
136     }
137     case Dali::NativeImageSource::COLOR_DEPTH_24:
138     {
139       format = TBM_FORMAT_RGB888;
140       depth  = 24;
141       break;
142     }
143     case Dali::NativeImageSource::COLOR_DEPTH_32:
144     {
145       format = TBM_FORMAT_ARGB8888;
146       depth  = 32;
147       break;
148     }
149     default:
150     {
151       DALI_LOG_WARNING("Wrong color depth.\n");
152       return;
153     }
154   }
155
156   // set whether blending is required according to pixel format based on the depth
157   /* default pixel format is RGB888
158      If depth = 8, Pixel::A8;
159      If depth = 16, Pixel::RGB565;
160      If depth = 32, Pixel::RGBA8888 */
161   mBlendingRequired = (depth == 32 || depth == 8);
162
163   mTbmSurface    = tbm_surface_create(mWidth, mHeight, format);
164   mOwnTbmSurface = true;
165 }
166
167 tbm_surface_h NativeImageSourceTizen::GetSurfaceFromAny(Any source) const
168 {
169   if(source.Empty())
170   {
171     return NULL;
172   }
173
174   if(source.GetType() == typeid(tbm_surface_h))
175   {
176     return AnyCast<tbm_surface_h>(source);
177   }
178   else
179   {
180     return NULL;
181   }
182 }
183
184 void NativeImageSourceTizen::DestroySurface()
185 {
186   if(mTbmSurface)
187   {
188     if(mIsBufferAcquired)
189     {
190       ReleaseBuffer();
191     }
192     if(mOwnTbmSurface)
193     {
194       if(tbm_surface_destroy(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
195       {
196         DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
197       }
198     }
199     else
200     {
201       tbm_surface_internal_unref(mTbmSurface);
202     }
203   }
204 }
205
206 NativeImageSourceTizen::~NativeImageSourceTizen()
207 {
208   DestroySurface();
209 }
210
211 Any NativeImageSourceTizen::GetNativeImageSource() const
212 {
213   return Any(mTbmSurface);
214 }
215
216 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
217 {
218   Dali::Mutex::ScopedLock lock(mMutex);
219   if(mTbmSurface != NULL)
220   {
221     tbm_surface_info_s surface_info;
222
223     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE)
224     {
225       DALI_LOG_ERROR("Fail to map tbm_surface\n");
226
227       width  = 0;
228       height = 0;
229
230       return false;
231     }
232
233     tbm_format     format = surface_info.format;
234     uint32_t       stride = surface_info.planes[0].stride;
235     unsigned char* ptr    = surface_info.planes[0].ptr;
236
237     width  = mWidth;
238     height = mHeight;
239     size_t lineSize;
240     size_t offset;
241     size_t cOffset;
242
243     switch(format)
244     {
245       case TBM_FORMAT_RGB888:
246       {
247         lineSize    = width * 3;
248         pixelFormat = Pixel::RGB888;
249         pixbuf.resize(lineSize * height);
250         unsigned char* bufptr = &pixbuf[0];
251
252         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
253         {
254           for(unsigned int c = 0; c < width; ++c)
255           {
256             cOffset                 = c * 3;
257             offset                  = cOffset + r * stride;
258             *(bufptr + cOffset)     = ptr[offset + 2];
259             *(bufptr + cOffset + 1) = ptr[offset + 1];
260             *(bufptr + cOffset + 2) = ptr[offset];
261           }
262         }
263         break;
264       }
265       case TBM_FORMAT_RGBA8888:
266       {
267         lineSize    = width * 4;
268         pixelFormat = Pixel::RGBA8888;
269         pixbuf.resize(lineSize * height);
270         unsigned char* bufptr = &pixbuf[0];
271
272         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
273         {
274           for(unsigned int c = 0; c < width; ++c)
275           {
276             cOffset                 = c * 4;
277             offset                  = cOffset + r * stride;
278             *(bufptr + cOffset)     = ptr[offset + 3];
279             *(bufptr + cOffset + 1) = ptr[offset + 2];
280             *(bufptr + cOffset + 2) = ptr[offset + 1];
281             *(bufptr + cOffset + 3) = ptr[offset];
282           }
283         }
284         break;
285       }
286       case TBM_FORMAT_ARGB8888:
287       {
288         lineSize    = width * 4;
289         pixelFormat = Pixel::RGBA8888;
290         pixbuf.resize(lineSize * height);
291         unsigned char* bufptr = &pixbuf[0];
292
293         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
294         {
295           for(unsigned int c = 0; c < width; ++c)
296           {
297             cOffset                 = c * 4;
298             offset                  = cOffset + r * stride;
299             *(bufptr + cOffset)     = ptr[offset + 2];
300             *(bufptr + cOffset + 1) = ptr[offset + 1];
301             *(bufptr + cOffset + 2) = ptr[offset];
302             *(bufptr + cOffset + 3) = ptr[offset + 3];
303           }
304         }
305         break;
306       }
307       default:
308       {
309         DALI_ASSERT_ALWAYS(0 && "Tbm surface has unsupported pixel format.\n");
310
311         return false;
312       }
313     }
314
315     if(tbm_surface_unmap(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
316     {
317       DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
318     }
319
320     return true;
321   }
322
323   DALI_LOG_WARNING("TBM surface does not exist.\n");
324
325   width  = 0;
326   height = 0;
327
328   return false;
329 }
330
331 void NativeImageSourceTizen::SetSource(Any source)
332 {
333   Dali::Mutex::ScopedLock lock(mMutex);
334
335   DestroySurface();
336
337   mOwnTbmSurface = false;
338   mTbmSurface    = GetSurfaceFromAny(source);
339
340   if(mTbmSurface != NULL)
341   {
342     mSetSource = true;
343     tbm_surface_internal_ref(mTbmSurface);
344     mBlendingRequired = CheckBlending(tbm_surface_get_format(mTbmSurface));
345     mWidth            = tbm_surface_get_width(mTbmSurface);
346     mHeight           = tbm_surface_get_height(mTbmSurface);
347   }
348 }
349
350 bool NativeImageSourceTizen::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
351 {
352   uint32_t*  formats;
353   uint32_t   formatNum;
354   tbm_format format = TBM_FORMAT_RGB888;
355
356   switch(colorDepth)
357   {
358     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
359     {
360       format = TBM_FORMAT_ARGB8888;
361       break;
362     }
363     case Dali::NativeImageSource::COLOR_DEPTH_8:
364     {
365       format = TBM_FORMAT_C8;
366       break;
367     }
368     case Dali::NativeImageSource::COLOR_DEPTH_16:
369     {
370       format = TBM_FORMAT_RGB565;
371       break;
372     }
373     case Dali::NativeImageSource::COLOR_DEPTH_24:
374     {
375       format = TBM_FORMAT_RGB888;
376       break;
377     }
378     case Dali::NativeImageSource::COLOR_DEPTH_32:
379     {
380       format = TBM_FORMAT_ARGB8888;
381       break;
382     }
383   }
384
385   if(tbm_surface_query_formats(&formats, &formatNum))
386   {
387     for(unsigned int i = 0; i < formatNum; i++)
388     {
389       if(formats[i] == format)
390       {
391         free(formats);
392         return true;
393       }
394     }
395   }
396
397   free(formats);
398   return false;
399 }
400
401 bool NativeImageSourceTizen::CreateResource()
402 {
403   // If an EGL image exists, use it as it is without creating it.
404   if(mEglImageKHR != NULL)
405   {
406     return true;
407   }
408
409   // casting from an unsigned int to a void *, which should then be cast back
410   // to an unsigned int in the driver.
411   EGLClientBuffer eglBuffer = reinterpret_cast<EGLClientBuffer>(mTbmSurface);
412   if(!eglBuffer || !tbm_surface_internal_is_valid(mTbmSurface))
413   {
414     return false;
415   }
416
417   mEglImageExtensions = mEglGraphics->GetImageExtensions();
418   DALI_ASSERT_DEBUG(mEglImageExtensions);
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     // Destroy previous eglImage because use for new one.
449     // if mEglImageKHR is not to be NULL here, it will not be updated with a new eglImage.
450     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
451     mEglImageKHR = NULL;
452
453     if(CreateResource())
454     {
455       TargetTexture();
456     }
457
458     mSetSource = false;
459   }
460 }
461
462 bool NativeImageSourceTizen::ApplyNativeFragmentShader(std::string& shader)
463 {
464   return mEglGraphics->ApplyNativeFragmentShader(shader, SAMPLER_TYPE);
465 }
466
467 const char* NativeImageSourceTizen::GetCustomSamplerTypename() const
468 {
469   return SAMPLER_TYPE;
470 }
471
472 int NativeImageSourceTizen::GetTextureTarget() const
473 {
474   return GL_TEXTURE_EXTERNAL_OES;
475 }
476
477 Any NativeImageSourceTizen::GetNativeImageHandle() const
478 {
479   return GetNativeImageSource();
480 }
481
482 bool NativeImageSourceTizen::SourceChanged() const
483 {
484   return false;
485 }
486
487 bool NativeImageSourceTizen::CheckBlending(tbm_format format)
488 {
489   if(mTbmFormat != format)
490   {
491     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
492     {
493       if(format == FORMATS_BLENDING_REQUIRED[i])
494       {
495         mBlendingRequired = true;
496         break;
497       }
498     }
499     mTbmFormat = format;
500   }
501
502   return mBlendingRequired;
503 }
504
505 uint8_t* NativeImageSourceTizen::AcquireBuffer(uint16_t& width, uint16_t& height, uint16_t& stride)
506 {
507   Dali::Mutex::ScopedLock lock(mMutex);
508   if(mTbmSurface != NULL)
509   {
510     tbm_surface_info_s info;
511
512     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
513     {
514       DALI_LOG_ERROR("Fail to map tbm_surface\n");
515
516       width  = 0;
517       height = 0;
518
519       return NULL;
520     }
521     tbm_surface_internal_ref(mTbmSurface);
522     mIsBufferAcquired = true;
523
524     stride = info.planes[0].stride;
525     width  = mWidth;
526     height = mHeight;
527
528     return info.planes[0].ptr;
529   }
530   return NULL;
531 }
532
533 bool NativeImageSourceTizen::ReleaseBuffer()
534 {
535   Dali::Mutex::ScopedLock lock(mMutex);
536   bool                    ret = false;
537   if(mTbmSurface != NULL)
538   {
539     ret = (tbm_surface_unmap(mTbmSurface) == TBM_SURFACE_ERROR_NONE);
540     if(!ret)
541     {
542       DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
543     }
544     tbm_surface_internal_unref(mTbmSurface);
545     mIsBufferAcquired = false;
546   }
547   return ret;
548 }
549
550 } // namespace Adaptor
551
552 } // namespace Internal
553
554 } // namespace Dali