35d4458ad46c2d04162a0cc04442c8cd0aca0c90
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / tizen / native-image-source-queue-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-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* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
42 const char* SAMPLER_TYPE    = "samplerExternalOES";
43
44 // clang-format off
45 int FORMATS_BLENDING_REQUIRED[] = {
46   TBM_FORMAT_ARGB4444, TBM_FORMAT_ABGR4444,
47   TBM_FORMAT_RGBA4444, TBM_FORMAT_BGRA4444,
48   TBM_FORMAT_RGBX5551, TBM_FORMAT_BGRX5551,
49   TBM_FORMAT_ARGB1555, TBM_FORMAT_ABGR1555,
50   TBM_FORMAT_RGBA5551, TBM_FORMAT_BGRA5551,
51   TBM_FORMAT_ARGB8888, TBM_FORMAT_ABGR8888,
52   TBM_FORMAT_RGBA8888, TBM_FORMAT_BGRA8888,
53   TBM_FORMAT_ARGB2101010, TBM_FORMAT_ABGR2101010,
54   TBM_FORMAT_RGBA1010102, TBM_FORMAT_BGRA1010102
55 };
56 // clang-format on
57
58 const int NUM_FORMATS_BLENDING_REQUIRED = 18;
59
60 } // namespace
61
62 NativeImageSourceQueueTizen* NativeImageSourceQueueTizen::New(uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue)
63 {
64   NativeImageSourceQueueTizen* image = new NativeImageSourceQueueTizen(width, height, depth, nativeImageSourceQueue);
65   DALI_ASSERT_DEBUG(image && "NativeImageSourceQueueTizen allocation failed.");
66
67   if(image)
68   {
69     image->Initialize(depth);
70   }
71
72   return image;
73 }
74
75 NativeImageSourceQueueTizen::NativeImageSourceQueueTizen(uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue)
76 : mMutex(),
77   mWidth(width),
78   mHeight(height),
79   mTbmQueue(NULL),
80   mConsumeSurface(NULL),
81   mEglImages(),
82   mBuffers(),
83   mEglGraphics(NULL),
84   mEglImageExtensions(NULL),
85   mOwnTbmQueue(false),
86   mBlendingRequired(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::ColorDepth depth)
115 {
116   if(mWidth == 0 || mHeight == 0)
117   {
118     return;
119   }
120
121   if(mTbmQueue == NULL)
122   {
123     int format = TBM_FORMAT_ARGB8888;
124
125     switch(depth)
126     {
127       case Dali::NativeImageSourceQueue::COLOR_DEPTH_DEFAULT:
128       case Dali::NativeImageSourceQueue::COLOR_DEPTH_32:
129       {
130         format            = TBM_FORMAT_ARGB8888;
131         mBlendingRequired = true;
132         break;
133       }
134       case Dali::NativeImageSourceQueue::COLOR_DEPTH_24:
135       {
136         format            = TBM_FORMAT_RGB888;
137         mBlendingRequired = false;
138         break;
139       }
140       default:
141       {
142         DALI_LOG_WARNING("Wrong color depth.\n");
143         return;
144       }
145     }
146
147     mTbmQueue = tbm_surface_queue_create(TBM_SURFACE_QUEUE_SIZE, mWidth, mHeight, format, 0);
148     if(!mTbmQueue)
149     {
150       DALI_LOG_ERROR("NativeImageSourceQueueTizen::Initialize: tbm_surface_queue_create is failed! [%p]\n", mTbmQueue);
151       return;
152     }
153
154     mOwnTbmQueue = true;
155   }
156 }
157
158 tbm_surface_queue_h NativeImageSourceQueueTizen::GetSurfaceFromAny(Any source) const
159 {
160   if(source.Empty())
161   {
162     return NULL;
163   }
164
165   if(source.GetType() == typeid(tbm_surface_queue_h))
166   {
167     return AnyCast<tbm_surface_queue_h>(source);
168   }
169   else
170   {
171     return NULL;
172   }
173 }
174
175 Any NativeImageSourceQueueTizen::GetNativeImageSourceQueue() const
176 {
177   return Any(mTbmQueue);
178 }
179
180 void NativeImageSourceQueueTizen::SetSize(uint32_t width, uint32_t height)
181 {
182   Dali::Mutex::ScopedLock lock(mMutex);
183
184   tbm_surface_queue_reset(mTbmQueue, width, height, tbm_surface_queue_get_format(mTbmQueue));
185
186   mWidth  = width;
187   mHeight = height;
188
189   ResetEglImageList();
190 }
191
192 void NativeImageSourceQueueTizen::IgnoreSourceImage()
193 {
194   Dali::Mutex::ScopedLock lock(mMutex);
195   tbm_surface_h           surface;
196
197   if(tbm_surface_queue_can_acquire(mTbmQueue, 0))
198   {
199     if(tbm_surface_queue_acquire(mTbmQueue, &surface) != TBM_SURFACE_QUEUE_ERROR_NONE)
200     {
201       DALI_LOG_ERROR("NativeImageSourceQueueTizen::IgnoreSourceImage: Failed to aquire a tbm_surface\n");
202       return;
203     }
204
205     if(tbm_surface_internal_is_valid(surface))
206     {
207       tbm_surface_queue_release(mTbmQueue, surface);
208     }
209   }
210 }
211
212 bool NativeImageSourceQueueTizen::CanDequeueBuffer()
213 {
214   Dali::Mutex::ScopedLock lock(mMutex);
215   if(tbm_surface_queue_can_dequeue(mTbmQueue, 0))
216   {
217     return true;
218   }
219   return false;
220 }
221
222 uint8_t* NativeImageSourceQueueTizen::DequeueBuffer(uint32_t& width, uint32_t& height, uint32_t& stride)
223 {
224   Dali::Mutex::ScopedLock lock(mMutex);
225   if(mTbmQueue == NULL)
226   {
227     DALI_LOG_ERROR("TbmQueue is NULL");
228     return NULL;
229   }
230
231   tbm_surface_h tbmSurface;
232   if(tbm_surface_queue_dequeue(mTbmQueue, &tbmSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
233   {
234     DALI_LOG_ERROR("Failed to dequeue a tbm_surface [%p]\n", tbmSurface);
235     return NULL;
236   }
237
238   tbm_surface_info_s info;
239   int                ret = tbm_surface_map(tbmSurface, TBM_OPTION_WRITE, &info);
240   if(ret != TBM_SURFACE_ERROR_NONE)
241   {
242     DALI_LOG_ERROR("tbm_surface_map is failed! [%d] [%p]\n", ret, tbmSurface);
243     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
244     return NULL;
245   }
246
247   unsigned char* buffer = info.planes[0].ptr;
248   if(!buffer)
249   {
250     DALI_LOG_ERROR("tbm buffer pointer is null! [%p]\n", tbmSurface);
251     tbm_surface_unmap(tbmSurface);
252     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
253     return NULL;
254   }
255
256   tbm_surface_internal_ref(tbmSurface);
257
258   stride = info.planes[0].stride;
259   width  = mWidth;
260   height = mHeight;
261
262   // Push the buffer
263   mBuffers.push_back(BufferPair(tbmSurface, buffer));
264   return buffer;
265 }
266
267 bool NativeImageSourceQueueTizen::EnqueueBuffer(uint8_t* buffer)
268 {
269   Dali::Mutex::ScopedLock lock(mMutex);
270   auto                    bufferInstance = std::find_if(mBuffers.begin(),
271                                      mBuffers.end(),
272                                      [buffer](BufferPair pair) { return (pair.second == buffer); });
273   if(bufferInstance != mBuffers.end())
274   {
275     tbm_surface_internal_unref((*bufferInstance).first);
276     tbm_surface_unmap((*bufferInstance).first);
277     tbm_surface_queue_enqueue(mTbmQueue, (*bufferInstance).first);
278     mBuffers.erase(bufferInstance);
279     return true;
280   }
281   return false;
282 }
283
284 bool NativeImageSourceQueueTizen::CreateResource()
285 {
286   mEglImageExtensions = mEglGraphics->GetImageExtensions();
287   DALI_ASSERT_DEBUG(mEglImageExtensions);
288
289   return true;
290 }
291
292 void NativeImageSourceQueueTizen::DestroyResource()
293 {
294   Dali::Mutex::ScopedLock lock(mMutex);
295
296   ResetEglImageList();
297 }
298
299 uint32_t NativeImageSourceQueueTizen::TargetTexture()
300 {
301   return 0;
302 }
303
304 void NativeImageSourceQueueTizen::PrepareTexture()
305 {
306   Dali::Mutex::ScopedLock lock(mMutex);
307
308   tbm_surface_h oldSurface = mConsumeSurface;
309
310   if(tbm_surface_queue_can_acquire(mTbmQueue, 0))
311   {
312     if(tbm_surface_queue_acquire(mTbmQueue, &mConsumeSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
313     {
314       DALI_LOG_ERROR("Failed to aquire a tbm_surface\n");
315       return;
316     }
317
318     if(oldSurface)
319     {
320       if(tbm_surface_internal_is_valid(oldSurface))
321       {
322         tbm_surface_queue_release(mTbmQueue, oldSurface);
323       }
324     }
325
326     if(mConsumeSurface)
327     {
328       bool existing = false;
329       for(auto&& iter : mEglImages)
330       {
331         if(iter.first == mConsumeSurface)
332         {
333           // Find the surface in the existing list
334           existing = true;
335           mEglImageExtensions->TargetTextureKHR(iter.second);
336           break;
337         }
338       }
339
340       if(!existing)
341       {
342         // Push the surface
343         tbm_surface_internal_ref(mConsumeSurface);
344
345         void* eglImageKHR = mEglImageExtensions->CreateImageKHR(reinterpret_cast<EGLClientBuffer>(mConsumeSurface));
346         mEglImageExtensions->TargetTextureKHR(eglImageKHR);
347
348         mEglImages.push_back(EglImagePair(mConsumeSurface, eglImageKHR));
349       }
350     }
351   }
352 }
353
354 const char* NativeImageSourceQueueTizen::GetCustomFragmentPrefix() const
355 {
356   return FRAGMENT_PREFIX;
357 }
358
359 bool NativeImageSourceQueueTizen::ApplyNativeFragmentShader(std::string& shader)
360 {
361   return mEglGraphics->ApplyNativeFragmentShader(shader, SAMPLER_TYPE);
362 }
363
364 const char* NativeImageSourceQueueTizen::GetCustomSamplerTypename() const
365 {
366   return SAMPLER_TYPE;
367 }
368
369 int NativeImageSourceQueueTizen::GetTextureTarget() const
370 {
371   return GL_TEXTURE_EXTERNAL_OES;
372 }
373
374 Any NativeImageSourceQueueTizen::GetNativeImageHandle() const
375 {
376   return nullptr;
377 }
378
379 bool NativeImageSourceQueueTizen::SourceChanged() const
380 {
381   return false;
382 }
383
384 void NativeImageSourceQueueTizen::ResetEglImageList()
385 {
386   if(mConsumeSurface)
387   {
388     if(tbm_surface_internal_is_valid(mConsumeSurface))
389     {
390       tbm_surface_queue_release(mTbmQueue, mConsumeSurface);
391     }
392     mConsumeSurface = NULL;
393   }
394
395   for(auto&& iter : mEglImages)
396   {
397     mEglImageExtensions->DestroyImageKHR(iter.second);
398
399     tbm_surface_internal_unref(iter.first);
400   }
401   mEglImages.clear();
402 }
403
404 bool NativeImageSourceQueueTizen::CheckBlending(int format)
405 {
406   for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
407   {
408     if(format == FORMATS_BLENDING_REQUIRED[i])
409     {
410       return true;
411     }
412   }
413
414   return false;
415 }
416
417 } // namespace Adaptor
418
419 } // namespace Internal
420
421 } // namespace Dali