Added UIThreadLoader to GLIB framework
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / tizen / native-image-source-impl-tizen.cpp
1 /*
2  * Copyright (c) 2023 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   mTbmSurface(NULL),
80   mTbmBackSurface(NULL),
81   mTbmFormat(0),
82   mColorDepth(depth),
83   mMutex(),
84   mEglImageKHR(NULL),
85   mEglGraphics(NULL),
86   mEglImageExtensions(NULL),
87   mResourceDestructionCallback(),
88   mOwnTbmSurface(false),
89   mBlendingRequired(false),
90   mSetSource(false),
91   mIsBufferAcquired(false),
92   mBackBufferEnabled(false)
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       Rect<uint32_t> emptyRect{};
194       ReleaseBuffer(emptyRect);
195     }
196     if(mOwnTbmSurface)
197     {
198       if(tbm_surface_destroy(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
199       {
200         DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
201       }
202     }
203     else
204     {
205       tbm_surface_internal_unref(mTbmSurface);
206     }
207     mTbmSurface = NULL;
208
209     DestroyBackBuffer();
210   }
211 }
212
213 NativeImageSourceTizen::~NativeImageSourceTizen()
214 {
215   DestroySurface();
216 }
217
218 Any NativeImageSourceTizen::GetNativeImageSource() const
219 {
220   return Any(mTbmSurface);
221 }
222
223 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
224 {
225   std::scoped_lock lock(mMutex);
226   if(mTbmSurface != NULL)
227   {
228     tbm_surface_info_s surface_info;
229
230     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE)
231     {
232       DALI_LOG_ERROR("Fail to map tbm_surface\n");
233
234       width  = 0;
235       height = 0;
236
237       return false;
238     }
239
240     tbm_format     format = surface_info.format;
241     uint32_t       stride = surface_info.planes[0].stride;
242     unsigned char* ptr    = surface_info.planes[0].ptr;
243
244     width  = mWidth;
245     height = mHeight;
246     size_t lineSize;
247     size_t offset;
248     size_t cOffset;
249
250     switch(format)
251     {
252       case TBM_FORMAT_RGB888:
253       {
254         lineSize    = width * 3;
255         pixelFormat = Pixel::RGB888;
256         pixbuf.resize(lineSize * height);
257         unsigned char* bufptr = &pixbuf[0];
258
259         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
260         {
261           for(unsigned int c = 0; c < width; ++c)
262           {
263             cOffset                 = c * 3;
264             offset                  = cOffset + r * stride;
265             *(bufptr + cOffset)     = ptr[offset + 2];
266             *(bufptr + cOffset + 1) = ptr[offset + 1];
267             *(bufptr + cOffset + 2) = ptr[offset];
268           }
269         }
270         break;
271       }
272       case TBM_FORMAT_RGBA8888:
273       {
274         lineSize    = width * 4;
275         pixelFormat = Pixel::RGBA8888;
276         pixbuf.resize(lineSize * height);
277         unsigned char* bufptr = &pixbuf[0];
278
279         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
280         {
281           for(unsigned int c = 0; c < width; ++c)
282           {
283             cOffset                 = c * 4;
284             offset                  = cOffset + r * stride;
285             *(bufptr + cOffset)     = ptr[offset + 3];
286             *(bufptr + cOffset + 1) = ptr[offset + 2];
287             *(bufptr + cOffset + 2) = ptr[offset + 1];
288             *(bufptr + cOffset + 3) = ptr[offset];
289           }
290         }
291         break;
292       }
293       case TBM_FORMAT_ARGB8888:
294       {
295         lineSize    = width * 4;
296         pixelFormat = Pixel::RGBA8888;
297         pixbuf.resize(lineSize * height);
298         unsigned char* bufptr = &pixbuf[0];
299
300         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
301         {
302           for(unsigned int c = 0; c < width; ++c)
303           {
304             cOffset                 = c * 4;
305             offset                  = cOffset + r * stride;
306             *(bufptr + cOffset)     = ptr[offset + 2];
307             *(bufptr + cOffset + 1) = ptr[offset + 1];
308             *(bufptr + cOffset + 2) = ptr[offset];
309             *(bufptr + cOffset + 3) = ptr[offset + 3];
310           }
311         }
312         break;
313       }
314       default:
315       {
316         DALI_ASSERT_ALWAYS(0 && "Tbm surface has unsupported pixel format.\n");
317
318         return false;
319       }
320     }
321
322     if(tbm_surface_unmap(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
323     {
324       DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
325     }
326
327     return true;
328   }
329
330   DALI_LOG_WARNING("TBM surface does not exist.\n");
331
332   width  = 0;
333   height = 0;
334
335   return false;
336 }
337
338 void NativeImageSourceTizen::SetSource(Any source)
339 {
340   std::scoped_lock lock(mMutex);
341
342   DestroySurface();
343
344   mOwnTbmSurface = false;
345   mTbmSurface    = GetSurfaceFromAny(source);
346
347   if(mTbmSurface != NULL)
348   {
349     mSetSource = true;
350     tbm_surface_internal_ref(mTbmSurface);
351     mBlendingRequired = CheckBlending(tbm_surface_get_format(mTbmSurface));
352     mWidth            = tbm_surface_get_width(mTbmSurface);
353     mHeight           = tbm_surface_get_height(mTbmSurface);
354
355     if(mBackBufferEnabled)
356     {
357       DestroyBackBuffer();
358       CreateBackBuffer();
359     }
360   }
361 }
362
363 bool NativeImageSourceTizen::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
364 {
365   uint32_t*  formats;
366   uint32_t   formatNum;
367   tbm_format format = TBM_FORMAT_RGB888;
368
369   switch(colorDepth)
370   {
371     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
372     {
373       format = TBM_FORMAT_ARGB8888;
374       break;
375     }
376     case Dali::NativeImageSource::COLOR_DEPTH_8:
377     {
378       format = TBM_FORMAT_C8;
379       break;
380     }
381     case Dali::NativeImageSource::COLOR_DEPTH_16:
382     {
383       format = TBM_FORMAT_RGB565;
384       break;
385     }
386     case Dali::NativeImageSource::COLOR_DEPTH_24:
387     {
388       format = TBM_FORMAT_RGB888;
389       break;
390     }
391     case Dali::NativeImageSource::COLOR_DEPTH_32:
392     {
393       format = TBM_FORMAT_ARGB8888;
394       break;
395     }
396   }
397
398   if(tbm_surface_query_formats(&formats, &formatNum))
399   {
400     for(unsigned int i = 0; i < formatNum; i++)
401     {
402       if(formats[i] == format)
403       {
404         free(formats);
405         return true;
406       }
407     }
408   }
409
410   free(formats);
411   return false;
412 }
413
414 bool NativeImageSourceTizen::CreateResource()
415 {
416   // If an EGL image exists, use it as it is without creating it.
417   if(mEglImageKHR != NULL)
418   {
419     return true;
420   }
421
422   // casting from an unsigned int to a void *, which should then be cast back
423   // to an unsigned int in the driver.
424   EGLClientBuffer eglBuffer = mTbmBackSurface ? reinterpret_cast<EGLClientBuffer>(mTbmBackSurface) : reinterpret_cast<EGLClientBuffer>(mTbmSurface);
425   if(!eglBuffer || !tbm_surface_internal_is_valid(mTbmSurface))
426   {
427     DALI_LOG_ERROR("Invalid surface\n");
428     return false;
429   }
430
431   mEglImageExtensions = mEglGraphics->GetImageExtensions();
432   DALI_ASSERT_DEBUG(mEglImageExtensions);
433
434   mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
435   if(!mEglImageKHR)
436   {
437     DALI_LOG_ERROR("Fail to CreateImageKHR\n");
438   }
439
440   return mEglImageKHR != NULL;
441 }
442
443 void NativeImageSourceTizen::DestroyResource()
444 {
445   std::scoped_lock lock(mMutex);
446   if(mEglImageKHR)
447   {
448     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
449
450     mEglImageKHR = NULL;
451   }
452
453   if(mResourceDestructionCallback)
454   {
455     mResourceDestructionCallback->Trigger();
456   }
457 }
458
459 uint32_t NativeImageSourceTizen::TargetTexture()
460 {
461   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
462
463   return 0;
464 }
465
466 void NativeImageSourceTizen::PrepareTexture()
467 {
468   std::scoped_lock lock(mMutex);
469   if(mSetSource)
470   {
471     // Destroy previous eglImage because use for new one.
472     // if mEglImageKHR is not to be NULL here, it will not be updated with a new eglImage.
473     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
474     mEglImageKHR = NULL;
475
476     if(CreateResource())
477     {
478       TargetTexture();
479     }
480
481     mSetSource = false;
482   }
483 }
484
485 bool NativeImageSourceTizen::ApplyNativeFragmentShader(std::string& shader)
486 {
487   return mEglGraphics->ApplyNativeFragmentShader(shader, SAMPLER_TYPE);
488 }
489
490 const char* NativeImageSourceTizen::GetCustomSamplerTypename() const
491 {
492   return SAMPLER_TYPE;
493 }
494
495 int NativeImageSourceTizen::GetTextureTarget() const
496 {
497   return GL_TEXTURE_EXTERNAL_OES;
498 }
499
500 Any NativeImageSourceTizen::GetNativeImageHandle() const
501 {
502   return GetNativeImageSource();
503 }
504
505 bool NativeImageSourceTizen::SourceChanged() const
506 {
507   if(mTbmBackSurface)
508   {
509     return mUpdatedArea.IsEmpty() ? false : true;
510   }
511   return true;
512 }
513
514 Rect<uint32_t> NativeImageSourceTizen::GetUpdatedArea()
515 {
516   std::scoped_lock lock(mMutex);
517   Rect<uint32_t>   updatedArea{0, 0, mWidth, mHeight};
518   if(!mUpdatedArea.IsEmpty() && mTbmSurface != NULL && mTbmBackSurface != NULL)
519   {
520     updatedArea = mUpdatedArea;
521
522     tbm_surface_info_s info;
523     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
524     {
525       DALI_LOG_ERROR("Fail to map tbm_surface\n");
526       return updatedArea;
527     }
528
529     tbm_surface_info_s backBufferInfo;
530     if(tbm_surface_map(mTbmBackSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &backBufferInfo) != TBM_SURFACE_ERROR_NONE)
531     {
532       DALI_LOG_ERROR("Fail to map tbm_surface - backbuffer\n");
533       tbm_surface_unmap(mTbmSurface);
534       return updatedArea;
535     }
536
537     unsigned char* srcBuffer = info.planes[0].ptr;
538     unsigned char* dstBuffer = backBufferInfo.planes[0].ptr;
539
540     uint32_t stride        = info.planes[0].stride;
541     uint32_t bytesPerPixel = info.bpp >> 3;
542
543     srcBuffer += updatedArea.y * stride + updatedArea.x * bytesPerPixel;
544     dstBuffer += updatedArea.y * stride + updatedArea.x * bytesPerPixel;
545
546     // Copy to back buffer
547     for(uint32_t y = 0; y < updatedArea.height; y++)
548     {
549       memcpy(dstBuffer, srcBuffer, updatedArea.width * bytesPerPixel);
550       srcBuffer += stride;
551       dstBuffer += stride;
552     }
553
554     tbm_surface_unmap(mTbmSurface);
555     tbm_surface_unmap(mTbmBackSurface);
556
557     // Reset the updated area
558     mUpdatedArea.Set(0u, 0u, 0u, 0u);
559   }
560   return updatedArea;
561 }
562
563 bool NativeImageSourceTizen::CheckBlending(tbm_format format)
564 {
565   if(mTbmFormat != format)
566   {
567     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
568     {
569       if(format == FORMATS_BLENDING_REQUIRED[i])
570       {
571         mBlendingRequired = true;
572         break;
573       }
574     }
575     mTbmFormat = format;
576   }
577
578   return mBlendingRequired;
579 }
580
581 uint8_t* NativeImageSourceTizen::AcquireBuffer(uint32_t& width, uint32_t& height, uint32_t& stride)
582 {
583   mMutex.lock(); // We don't use std::scoped_lock here
584   if(mTbmSurface != NULL)
585   {
586     tbm_surface_info_s info;
587
588     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
589     {
590       DALI_LOG_ERROR("Fail to map tbm_surface\n");
591
592       width  = 0;
593       height = 0;
594
595       mMutex.unlock();
596       return NULL;
597     }
598     tbm_surface_internal_ref(mTbmSurface);
599     mIsBufferAcquired = true;
600
601     stride = info.planes[0].stride;
602     width  = mWidth;
603     height = mHeight;
604
605     // The lock is held until ReleaseBuffer is called
606     return info.planes[0].ptr;
607   }
608   mMutex.unlock();
609   return NULL;
610 }
611
612 bool NativeImageSourceTizen::ReleaseBuffer(const Rect<uint32_t>& updatedArea)
613 {
614   bool ret = false;
615   if(mTbmSurface != NULL)
616   {
617     if(mTbmBackSurface)
618     {
619       if(updatedArea.IsEmpty())
620       {
621         mUpdatedArea.Set(0, 0, mWidth, mHeight);
622       }
623       else
624       {
625         if(mUpdatedArea.IsEmpty())
626         {
627           mUpdatedArea = updatedArea;
628         }
629         else
630         {
631           mUpdatedArea.Merge(updatedArea);
632         }
633       }
634     }
635
636     ret = (tbm_surface_unmap(mTbmSurface) == TBM_SURFACE_ERROR_NONE);
637     if(!ret)
638     {
639       DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
640     }
641     tbm_surface_internal_unref(mTbmSurface);
642     mIsBufferAcquired = false;
643   }
644   // Unlock the mutex locked by AcquireBuffer.
645   mMutex.unlock();
646   return ret;
647 }
648
649 void NativeImageSourceTizen::SetResourceDestructionCallback(EventThreadCallback* callback)
650 {
651   std::scoped_lock lock(mMutex);
652   mResourceDestructionCallback = std::unique_ptr<EventThreadCallback>(callback);
653 }
654
655 void NativeImageSourceTizen::EnableBackBuffer(bool enable)
656 {
657   if(enable != mBackBufferEnabled)
658   {
659     mBackBufferEnabled = enable;
660
661     if(mBackBufferEnabled)
662     {
663       CreateBackBuffer();
664     }
665     else
666     {
667       DestroyBackBuffer();
668     }
669   }
670 }
671
672 void NativeImageSourceTizen::CreateBackBuffer()
673 {
674   if(!mTbmBackSurface && mTbmSurface)
675   {
676     mTbmBackSurface = tbm_surface_create(mWidth, mHeight, tbm_surface_get_format(mTbmSurface));
677   }
678 }
679
680 void NativeImageSourceTizen::DestroyBackBuffer()
681 {
682   if(mTbmBackSurface)
683   {
684     if(tbm_surface_destroy(mTbmBackSurface) != TBM_SURFACE_ERROR_NONE)
685     {
686       DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
687     }
688     mTbmBackSurface = NULL;
689   }
690 }
691
692 } // namespace Adaptor
693
694 } // namespace Internal
695
696 } // namespace Dali