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