Revert "[Tizen] Revert "Make to use right egl image extension name in the glsl 3.x""
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / tizen / native-image-source-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-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 : mCustomFragmentPrefix(),
78   mWidth(width),
79   mHeight(height),
80   mOwnTbmSurface(false),
81   mTbmSurface(NULL),
82   mTbmFormat(0),
83   mBlendingRequired(false),
84   mColorDepth(depth),
85   mEglImageKHR(NULL),
86   mEglGraphics(NULL),
87   mEglImageExtensions(NULL),
88   mSetSource(false),
89   mMutex(),
90   mIsBufferAcquired(false)
91 {
92   DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
93
94   GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
95   mEglGraphics                = static_cast<EglGraphics*>(graphics);
96
97   mCustomFragmentPrefix = mEglGraphics->GetEglImageExtensionString();
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       ReleaseBuffer();
194     }
195     if(mOwnTbmSurface)
196     {
197       if(tbm_surface_destroy(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
198       {
199         DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
200       }
201     }
202     else
203     {
204       tbm_surface_internal_unref(mTbmSurface);
205     }
206   }
207 }
208
209 NativeImageSourceTizen::~NativeImageSourceTizen()
210 {
211   DestroySurface();
212 }
213
214 Any NativeImageSourceTizen::GetNativeImageSource() const
215 {
216   return Any(mTbmSurface);
217 }
218
219 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
220 {
221   Dali::Mutex::ScopedLock lock(mMutex);
222   if(mTbmSurface != NULL)
223   {
224     tbm_surface_info_s surface_info;
225
226     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE)
227     {
228       DALI_LOG_ERROR("Fail to map tbm_surface\n");
229
230       width  = 0;
231       height = 0;
232
233       return false;
234     }
235
236     tbm_format     format = surface_info.format;
237     uint32_t       stride = surface_info.planes[0].stride;
238     unsigned char* ptr    = surface_info.planes[0].ptr;
239
240     width  = mWidth;
241     height = mHeight;
242     size_t lineSize;
243     size_t offset;
244     size_t cOffset;
245
246     switch(format)
247     {
248       case TBM_FORMAT_RGB888:
249       {
250         lineSize    = width * 3;
251         pixelFormat = Pixel::RGB888;
252         pixbuf.resize(lineSize * height);
253         unsigned char* bufptr = &pixbuf[0];
254
255         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
256         {
257           for(unsigned int c = 0; c < width; ++c)
258           {
259             cOffset                 = c * 3;
260             offset                  = cOffset + r * stride;
261             *(bufptr + cOffset)     = ptr[offset + 2];
262             *(bufptr + cOffset + 1) = ptr[offset + 1];
263             *(bufptr + cOffset + 2) = ptr[offset];
264           }
265         }
266         break;
267       }
268       case TBM_FORMAT_RGBA8888:
269       {
270         lineSize    = width * 4;
271         pixelFormat = Pixel::RGBA8888;
272         pixbuf.resize(lineSize * height);
273         unsigned char* bufptr = &pixbuf[0];
274
275         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
276         {
277           for(unsigned int c = 0; c < width; ++c)
278           {
279             cOffset                 = c * 4;
280             offset                  = cOffset + r * stride;
281             *(bufptr + cOffset)     = ptr[offset + 3];
282             *(bufptr + cOffset + 1) = ptr[offset + 2];
283             *(bufptr + cOffset + 2) = ptr[offset + 1];
284             *(bufptr + cOffset + 3) = ptr[offset];
285           }
286         }
287         break;
288       }
289       case TBM_FORMAT_ARGB8888:
290       {
291         lineSize    = width * 4;
292         pixelFormat = Pixel::RGBA8888;
293         pixbuf.resize(lineSize * height);
294         unsigned char* bufptr = &pixbuf[0];
295
296         for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
297         {
298           for(unsigned int c = 0; c < width; ++c)
299           {
300             cOffset                 = c * 4;
301             offset                  = cOffset + r * stride;
302             *(bufptr + cOffset)     = ptr[offset + 2];
303             *(bufptr + cOffset + 1) = ptr[offset + 1];
304             *(bufptr + cOffset + 2) = ptr[offset];
305             *(bufptr + cOffset + 3) = ptr[offset + 3];
306           }
307         }
308         break;
309       }
310       default:
311       {
312         DALI_ASSERT_ALWAYS(0 && "Tbm surface has unsupported pixel format.\n");
313
314         return false;
315       }
316     }
317
318     if(tbm_surface_unmap(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
319     {
320       DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
321     }
322
323     return true;
324   }
325
326   DALI_LOG_WARNING("TBM surface does not exist.\n");
327
328   width  = 0;
329   height = 0;
330
331   return false;
332 }
333
334 void NativeImageSourceTizen::SetSource(Any source)
335 {
336   Dali::Mutex::ScopedLock lock(mMutex);
337
338   DestroySurface();
339
340   mOwnTbmSurface = false;
341   mTbmSurface    = GetSurfaceFromAny(source);
342
343   if(mTbmSurface != NULL)
344   {
345     mSetSource = true;
346     tbm_surface_internal_ref(mTbmSurface);
347     mBlendingRequired = CheckBlending(tbm_surface_get_format(mTbmSurface));
348     mWidth            = tbm_surface_get_width(mTbmSurface);
349     mHeight           = tbm_surface_get_height(mTbmSurface);
350   }
351 }
352
353 bool NativeImageSourceTizen::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
354 {
355   uint32_t*  formats;
356   uint32_t   formatNum;
357   tbm_format format = TBM_FORMAT_RGB888;
358
359   switch(colorDepth)
360   {
361     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
362     {
363       format = TBM_FORMAT_ARGB8888;
364       break;
365     }
366     case Dali::NativeImageSource::COLOR_DEPTH_8:
367     {
368       format = TBM_FORMAT_C8;
369       break;
370     }
371     case Dali::NativeImageSource::COLOR_DEPTH_16:
372     {
373       format = TBM_FORMAT_RGB565;
374       break;
375     }
376     case Dali::NativeImageSource::COLOR_DEPTH_24:
377     {
378       format = TBM_FORMAT_RGB888;
379       break;
380     }
381     case Dali::NativeImageSource::COLOR_DEPTH_32:
382     {
383       format = TBM_FORMAT_ARGB8888;
384       break;
385     }
386   }
387
388   if(tbm_surface_query_formats(&formats, &formatNum))
389   {
390     for(unsigned int i = 0; i < formatNum; i++)
391     {
392       if(formats[i] == format)
393       {
394         free(formats);
395         return true;
396       }
397     }
398   }
399
400   free(formats);
401   return false;
402 }
403
404 bool NativeImageSourceTizen::CreateResource()
405 {
406   // If an EGL image exists, use it as it is without creating it.
407   if(mEglImageKHR != NULL)
408   {
409     return true;
410   }
411
412   // casting from an unsigned int to a void *, which should then be cast back
413   // to an unsigned int in the driver.
414   EGLClientBuffer eglBuffer = reinterpret_cast<EGLClientBuffer>(mTbmSurface);
415   if(!eglBuffer || !tbm_surface_internal_is_valid(mTbmSurface))
416   {
417     return false;
418   }
419
420   mEglImageExtensions = mEglGraphics->GetImageExtensions();
421   DALI_ASSERT_DEBUG(mEglImageExtensions);
422
423   // if resource of egl was not destroyed, destroy it first
424   DestroyResource();
425
426   mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
427
428   return mEglImageKHR != NULL;
429 }
430
431 void NativeImageSourceTizen::DestroyResource()
432 {
433   Dali::Mutex::ScopedLock lock(mMutex);
434   if(mEglImageKHR)
435   {
436     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
437
438     mEglImageKHR = NULL;
439   }
440 }
441
442 uint32_t NativeImageSourceTizen::TargetTexture()
443 {
444   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
445
446   return 0;
447 }
448
449 void NativeImageSourceTizen::PrepareTexture()
450 {
451   Dali::Mutex::ScopedLock lock(mMutex);
452   if(mSetSource)
453   {
454     // Destroy previous eglImage because use for new one.
455     // if mEglImageKHR is not to be NULL here, it will not be updated with a new eglImage.
456     mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
457     mEglImageKHR = NULL;
458
459     if(CreateResource())
460     {
461       TargetTexture();
462     }
463
464     mSetSource = false;
465   }
466 }
467
468 const char* NativeImageSourceTizen::GetCustomFragmentPrefix() const
469 {
470   return mCustomFragmentPrefix;
471 }
472
473 const char* NativeImageSourceTizen::GetCustomSamplerTypename() const
474 {
475   return SAMPLER_TYPE;
476 }
477
478 int NativeImageSourceTizen::GetTextureTarget() const
479 {
480   return GL_TEXTURE_EXTERNAL_OES;
481 }
482
483 Any NativeImageSourceTizen::GetNativeImageHandle() const
484 {
485   return GetNativeImageSource();
486 }
487
488 bool NativeImageSourceTizen::SourceChanged() const
489 {
490   return false;
491 }
492
493 bool NativeImageSourceTizen::CheckBlending(tbm_format format)
494 {
495   if(mTbmFormat != format)
496   {
497     for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
498     {
499       if(format == FORMATS_BLENDING_REQUIRED[i])
500       {
501         mBlendingRequired = true;
502         break;
503       }
504     }
505     mTbmFormat = format;
506   }
507
508   return mBlendingRequired;
509 }
510
511 uint8_t* NativeImageSourceTizen::AcquireBuffer(uint16_t& width, uint16_t& height, uint16_t& stride)
512 {
513   Dali::Mutex::ScopedLock lock(mMutex);
514   if(mTbmSurface != NULL)
515   {
516     tbm_surface_info_s info;
517
518     if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
519     {
520       DALI_LOG_ERROR("Fail to map tbm_surface\n");
521
522       width  = 0;
523       height = 0;
524
525       return NULL;
526     }
527     tbm_surface_internal_ref(mTbmSurface);
528     mIsBufferAcquired = true;
529
530     stride = info.planes[0].stride;
531     width  = mWidth;
532     height = mHeight;
533
534     return info.planes[0].ptr;
535   }
536   return NULL;
537 }
538
539 bool NativeImageSourceTizen::ReleaseBuffer()
540 {
541   Dali::Mutex::ScopedLock lock(mMutex);
542   bool                    ret = false;
543   if(mTbmSurface != NULL)
544   {
545     ret = (tbm_surface_unmap(mTbmSurface) == TBM_SURFACE_ERROR_NONE);
546     if(!ret)
547     {
548       DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
549     }
550     tbm_surface_internal_unref(mTbmSurface);
551     mIsBufferAcquired = false;
552   }
553   return ret;
554 }
555
556 } // namespace Adaptor
557
558 } // namespace Internal
559
560 } // namespace Dali