Added UIThreadLoader to GLIB framework
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / tizen / native-image-source-queue-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-queue-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
26 // INTERNAL INCLUDES
27 #include <dali/devel-api/adaptor-framework/environment-variable.h>
28 #include <dali/internal/adaptor/common/adaptor-impl.h>
29 #include <dali/internal/graphics/common/egl-image-extensions.h>
30 #include <dali/internal/graphics/gles/egl-graphics.h>
31
32 namespace Dali
33 {
34 namespace Internal
35 {
36 namespace Adaptor
37 {
38 namespace
39 {
40 // clang-format off
41 int FORMATS_BLENDING_REQUIRED[] = {
42   TBM_FORMAT_ARGB4444, TBM_FORMAT_ABGR4444,
43   TBM_FORMAT_RGBA4444, TBM_FORMAT_BGRA4444,
44   TBM_FORMAT_RGBX5551, TBM_FORMAT_BGRX5551,
45   TBM_FORMAT_ARGB1555, TBM_FORMAT_ABGR1555,
46   TBM_FORMAT_RGBA5551, TBM_FORMAT_BGRA5551,
47   TBM_FORMAT_ARGB8888, TBM_FORMAT_ABGR8888,
48   TBM_FORMAT_RGBA8888, TBM_FORMAT_BGRA8888,
49   TBM_FORMAT_ARGB2101010, TBM_FORMAT_ABGR2101010,
50   TBM_FORMAT_RGBA1010102, TBM_FORMAT_BGRA1010102
51 };
52 // clang-format on
53
54 const char* SAMPLER_TYPE = "samplerExternalOES";
55
56 constexpr int32_t NUM_FORMATS_BLENDING_REQUIRED = 18;
57
58 constexpr int32_t DEFAULT_TBM_SURFACE_QUEUE_SIZE = 3u;
59 constexpr auto    TBM_SURFACE_QUEUE_SIZE         = "DALI_TBM_SURFACE_QUEUE_SIZE";
60
61 int32_t GetTbmSurfaceQueueSize()
62 {
63   static auto    queueSizeString = EnvironmentVariable::GetEnvironmentVariable(TBM_SURFACE_QUEUE_SIZE);
64   static int32_t queueSize       = queueSizeString ? std::atoi(queueSizeString) : DEFAULT_TBM_SURFACE_QUEUE_SIZE;
65   return queueSize;
66 }
67
68 } // namespace
69
70 NativeImageSourceQueueTizen* NativeImageSourceQueueTizen::New(uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorFormat colorFormat, Any nativeImageSourceQueue)
71 {
72   NativeImageSourceQueueTizen* image = new NativeImageSourceQueueTizen(width, height, colorFormat, nativeImageSourceQueue);
73   DALI_ASSERT_DEBUG(image && "NativeImageSourceQueueTizen allocation failed.");
74
75   if(image)
76   {
77     image->Initialize(colorFormat);
78   }
79
80   return image;
81 }
82
83 NativeImageSourceQueueTizen::NativeImageSourceQueueTizen(uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorFormat colorFormat, Any nativeImageSourceQueue)
84 : mMutex(),
85   mWidth(width),
86   mHeight(height),
87   mTbmQueue(NULL),
88   mConsumeSurface(NULL),
89   mEglImages(),
90   mBuffers(),
91   mEglGraphics(NULL),
92   mEglImageExtensions(NULL),
93   mOwnTbmQueue(false),
94   mBlendingRequired(false),
95   mIsResized(false),
96   mFreeRequest(false)
97 {
98   DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
99
100   GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
101   mEglGraphics                = static_cast<EglGraphics*>(graphics);
102
103   mTbmQueue = GetSurfaceFromAny(nativeImageSourceQueue);
104
105   if(mTbmQueue != NULL)
106   {
107     mBlendingRequired = CheckBlending(tbm_surface_queue_get_format(mTbmQueue));
108     mWidth            = tbm_surface_queue_get_width(mTbmQueue);
109     mHeight           = tbm_surface_queue_get_height(mTbmQueue);
110   }
111 }
112
113 NativeImageSourceQueueTizen::~NativeImageSourceQueueTizen()
114 {
115   if(mOwnTbmQueue)
116   {
117     if(mTbmQueue != NULL)
118     {
119       tbm_surface_queue_destroy(mTbmQueue);
120     }
121   }
122 }
123
124 void NativeImageSourceQueueTizen::Initialize(Dali::NativeImageSourceQueue::ColorFormat colorFormat)
125 {
126   if(mWidth == 0 || mHeight == 0)
127   {
128     return;
129   }
130
131   if(mTbmQueue == NULL)
132   {
133     int tbmFormat = TBM_FORMAT_ARGB8888;
134
135     switch(colorFormat)
136     {
137       case Dali::NativeImageSourceQueue::ColorFormat::RGBA8888: // TODO : Implement me after other codes fixed.
138       case Dali::NativeImageSourceQueue::ColorFormat::BGRA8888:
139       {
140         tbmFormat         = TBM_FORMAT_ARGB8888;
141         mBlendingRequired = true;
142         break;
143       }
144       case Dali::NativeImageSourceQueue::ColorFormat::RGBX8888: // TODO : Implement me after other codes fixed.
145       case Dali::NativeImageSourceQueue::ColorFormat::BGRX8888:
146       {
147         tbmFormat         = TBM_FORMAT_XRGB8888;
148         mBlendingRequired = false;
149         break;
150       }
151       case Dali::NativeImageSourceQueue::ColorFormat::RGB888: // TODO : Implement me after other codes fixed.
152       case Dali::NativeImageSourceQueue::ColorFormat::BGR888:
153       {
154         tbmFormat         = TBM_FORMAT_RGB888;
155         mBlendingRequired = false;
156         break;
157       }
158       default:
159       {
160         DALI_LOG_WARNING("Wrong color format.\n");
161         return;
162       }
163     }
164
165     mTbmQueue = tbm_surface_queue_create(GetTbmSurfaceQueueSize(), mWidth, mHeight, tbmFormat, 0);
166     if(!mTbmQueue)
167     {
168       DALI_LOG_ERROR("NativeImageSourceQueueTizen::Initialize: tbm_surface_queue_create is failed! [%p]\n", mTbmQueue);
169       return;
170     }
171
172     mOwnTbmQueue = true;
173   }
174 }
175
176 tbm_surface_queue_h NativeImageSourceQueueTizen::GetSurfaceFromAny(Any source) const
177 {
178   if(source.Empty())
179   {
180     return NULL;
181   }
182
183   if(source.GetType() == typeid(tbm_surface_queue_h))
184   {
185     return AnyCast<tbm_surface_queue_h>(source);
186   }
187   else
188   {
189     return NULL;
190   }
191 }
192
193 Any NativeImageSourceQueueTizen::GetNativeImageSourceQueue() const
194 {
195   return Any(mTbmQueue);
196 }
197
198 void NativeImageSourceQueueTizen::SetSize(uint32_t width, uint32_t height)
199 {
200   Dali::Mutex::ScopedLock lock(mMutex);
201
202   if(mWidth == width && mHeight == height)
203   {
204     return;
205   }
206
207   tbm_surface_queue_reset(mTbmQueue, width, height, tbm_surface_queue_get_format(mTbmQueue));
208
209   mWidth     = width;
210   mHeight    = height;
211   mIsResized = true;
212 }
213
214 void NativeImageSourceQueueTizen::IgnoreSourceImage()
215 {
216   Dali::Mutex::ScopedLock lock(mMutex);
217   tbm_surface_h           surface;
218
219   if(tbm_surface_queue_can_acquire(mTbmQueue, 0))
220   {
221     if(tbm_surface_queue_acquire(mTbmQueue, &surface) != TBM_SURFACE_QUEUE_ERROR_NONE)
222     {
223       DALI_LOG_ERROR("NativeImageSourceQueueTizen::IgnoreSourceImage: Failed to aquire a tbm_surface\n");
224       return;
225     }
226
227     if(tbm_surface_internal_is_valid(surface))
228     {
229       tbm_surface_queue_release(mTbmQueue, surface);
230     }
231   }
232 }
233
234 bool NativeImageSourceQueueTizen::CanDequeueBuffer()
235 {
236   Dali::Mutex::ScopedLock lock(mMutex);
237   if(tbm_surface_queue_can_dequeue(mTbmQueue, 0))
238   {
239     return true;
240   }
241   return false;
242 }
243
244 uint8_t* NativeImageSourceQueueTizen::DequeueBuffer(uint32_t& width, uint32_t& height, uint32_t& stride)
245 {
246   Dali::Mutex::ScopedLock lock(mMutex);
247   if(mTbmQueue == NULL)
248   {
249     DALI_LOG_ERROR("TbmQueue is NULL");
250     return NULL;
251   }
252
253   tbm_surface_h tbmSurface;
254   if(tbm_surface_queue_dequeue(mTbmQueue, &tbmSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
255   {
256     DALI_LOG_ERROR("Failed to dequeue a tbm_surface [%p]\n", tbmSurface);
257     return NULL;
258   }
259
260   tbm_surface_info_s info;
261   int                ret = tbm_surface_map(tbmSurface, TBM_OPTION_WRITE, &info);
262   if(ret != TBM_SURFACE_ERROR_NONE)
263   {
264     DALI_LOG_ERROR("tbm_surface_map is failed! [%d] [%p]\n", ret, tbmSurface);
265     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
266     return NULL;
267   }
268
269   unsigned char* buffer = info.planes[0].ptr;
270   if(!buffer)
271   {
272     DALI_LOG_ERROR("tbm buffer pointer is null! [%p]\n", tbmSurface);
273     tbm_surface_unmap(tbmSurface);
274     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
275     return NULL;
276   }
277
278   tbm_surface_internal_ref(tbmSurface);
279
280   stride = info.planes[0].stride;
281   width  = mWidth;
282   height = mHeight;
283
284   // Push the buffer
285   mBuffers.push_back(BufferPair(tbmSurface, buffer));
286   return buffer;
287 }
288
289 bool NativeImageSourceQueueTizen::EnqueueBuffer(uint8_t* buffer)
290 {
291   Dali::Mutex::ScopedLock lock(mMutex);
292   auto                    bufferInstance = std::find_if(mBuffers.begin(),
293                                      mBuffers.end(),
294                                      [buffer](BufferPair pair) { return (pair.second == buffer); });
295   if(bufferInstance != mBuffers.end())
296   {
297     tbm_surface_internal_unref((*bufferInstance).first);
298     tbm_surface_unmap((*bufferInstance).first);
299     tbm_surface_queue_enqueue(mTbmQueue, (*bufferInstance).first);
300     mBuffers.erase(bufferInstance);
301     return true;
302   }
303   return false;
304 }
305
306 void NativeImageSourceQueueTizen::FreeReleasedBuffers()
307 {
308   Dali::Mutex::ScopedLock lock(mMutex);
309   mFreeRequest = true;
310 }
311
312 bool NativeImageSourceQueueTizen::CreateResource()
313 {
314   mEglImageExtensions = mEglGraphics->GetImageExtensions();
315   DALI_ASSERT_DEBUG(mEglImageExtensions);
316
317   return true;
318 }
319
320 void NativeImageSourceQueueTizen::DestroyResource()
321 {
322   Dali::Mutex::ScopedLock lock(mMutex);
323
324   ResetEglImageList(true);
325 }
326
327 uint32_t NativeImageSourceQueueTizen::TargetTexture()
328 {
329   return 0;
330 }
331
332 void NativeImageSourceQueueTizen::PrepareTexture()
333 {
334   Dali::Mutex::ScopedLock lock(mMutex);
335
336   bool updated = false;
337
338   do
339   {
340     tbm_surface_h oldSurface = mConsumeSurface;
341
342     if(tbm_surface_queue_can_acquire(mTbmQueue, 0))
343     {
344       if(tbm_surface_queue_acquire(mTbmQueue, &mConsumeSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
345       {
346         DALI_LOG_ERROR("Failed to aquire a tbm_surface\n");
347         return;
348       }
349
350       if(oldSurface)
351       {
352         if(tbm_surface_internal_is_valid(oldSurface))
353         {
354           tbm_surface_queue_release(mTbmQueue, oldSurface);
355         }
356       }
357       updated = true;
358     }
359     else
360     {
361       break;
362     }
363   } while(mFreeRequest); // Get the last one if buffer free was requested
364
365   if(updated)
366   {
367     if(mIsResized)
368     {
369       ResetEglImageList(false);
370       mIsResized = false;
371     }
372
373     if(mConsumeSurface)
374     {
375       bool existing = false;
376       for(auto&& iter : mEglImages)
377       {
378         if(iter.first == mConsumeSurface)
379         {
380           // Find the surface in the existing list
381           existing = true;
382           mEglImageExtensions->TargetTextureKHR(iter.second);
383           break;
384         }
385       }
386
387       if(!existing)
388       {
389         // Push the surface
390         tbm_surface_internal_ref(mConsumeSurface);
391
392         void* eglImageKHR = mEglImageExtensions->CreateImageKHR(reinterpret_cast<EGLClientBuffer>(mConsumeSurface));
393         mEglImageExtensions->TargetTextureKHR(eglImageKHR);
394
395         mEglImages.push_back(EglImagePair(mConsumeSurface, eglImageKHR));
396       }
397     }
398   }
399
400   if(mFreeRequest)
401   {
402     auto iter = std::remove_if(mEglImages.begin(), mEglImages.end(), [&](EglImagePair& eglImage) {
403         if(mConsumeSurface == eglImage.first) return false;
404         mEglImageExtensions->DestroyImageKHR(eglImage.second);
405         tbm_surface_internal_unref(eglImage.first);
406         return true; });
407     mEglImages.erase(iter, mEglImages.end());
408
409     tbm_surface_queue_free_flush(mTbmQueue);
410     mFreeRequest = false;
411   }
412 }
413
414 bool NativeImageSourceQueueTizen::ApplyNativeFragmentShader(std::string& shader)
415 {
416   return mEglGraphics->ApplyNativeFragmentShader(shader, SAMPLER_TYPE);
417 }
418
419 const char* NativeImageSourceQueueTizen::GetCustomSamplerTypename() const
420 {
421   return SAMPLER_TYPE;
422 }
423
424 int NativeImageSourceQueueTizen::GetTextureTarget() const
425 {
426   return GL_TEXTURE_EXTERNAL_OES;
427 }
428
429 Any NativeImageSourceQueueTizen::GetNativeImageHandle() const
430 {
431   return nullptr;
432 }
433
434 bool NativeImageSourceQueueTizen::SourceChanged() const
435 {
436   return true;
437 }
438
439 void NativeImageSourceQueueTizen::ResetEglImageList(bool releaseConsumeSurface)
440 {
441   // When Tbm surface queue is reset(resized), the surface acquired before reset() is still valid, not the others.
442   // We can still use the acquired surface so that we will release it as the oldSurface in PrepareTexture() when the next surface is ready.
443   if(releaseConsumeSurface && mConsumeSurface)
444   {
445     if(tbm_surface_internal_is_valid(mConsumeSurface))
446     {
447       tbm_surface_queue_release(mTbmQueue, mConsumeSurface);
448     }
449     mConsumeSurface = NULL;
450   }
451
452   for(auto&& iter : mEglImages)
453   {
454     mEglImageExtensions->DestroyImageKHR(iter.second);
455
456     tbm_surface_internal_unref(iter.first);
457   }
458   mEglImages.clear();
459 }
460
461 bool NativeImageSourceQueueTizen::CheckBlending(int format)
462 {
463   for(int32_t i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
464   {
465     if(format == FORMATS_BLENDING_REQUIRED[i])
466     {
467       return true;
468     }
469   }
470
471   return false;
472 }
473
474 } // namespace Adaptor
475
476 } // namespace Internal
477
478 } // namespace Dali