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