2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/imaging/tizen/native-image-source-impl-tizen.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-defines.h>
24 #include <tbm_surface_internal.h>
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>
41 const char* SAMPLER_TYPE = "samplerExternalOES";
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
57 const int NUM_FORMATS_BLENDING_REQUIRED = 18;
61 using Dali::Integration::PixelBuffer;
63 NativeImageSourceTizen* NativeImageSourceTizen::New(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
65 NativeImageSourceTizen* image = new NativeImageSourceTizen(width, height, depth, nativeImageSource);
66 DALI_ASSERT_DEBUG(image && "NativeImageSource allocation failed.");
76 NativeImageSourceTizen::NativeImageSourceTizen(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
80 mTbmBackSurface(NULL),
86 mEglImageExtensions(NULL),
87 mResourceDestructionCallback(),
88 mOwnTbmSurface(false),
89 mBlendingRequired(false),
91 mIsBufferAcquired(false),
92 mBackBufferEnabled(false)
94 DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
96 GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
97 mEglGraphics = static_cast<EglGraphics*>(graphics);
99 mTbmSurface = GetSurfaceFromAny(nativeImageSource);
101 if(mTbmSurface != NULL)
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);
110 void NativeImageSourceTizen::Initialize()
112 if(mTbmSurface != NULL || mWidth == 0 || mHeight == 0)
117 tbm_format format = TBM_FORMAT_RGB888;
122 case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
124 format = TBM_FORMAT_ARGB8888;
128 case Dali::NativeImageSource::COLOR_DEPTH_8:
130 format = TBM_FORMAT_C8;
134 case Dali::NativeImageSource::COLOR_DEPTH_16:
136 format = TBM_FORMAT_RGB565;
140 case Dali::NativeImageSource::COLOR_DEPTH_24:
142 format = TBM_FORMAT_RGB888;
146 case Dali::NativeImageSource::COLOR_DEPTH_32:
148 format = TBM_FORMAT_ARGB8888;
154 DALI_LOG_WARNING("Wrong color depth.\n");
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);
166 mTbmSurface = tbm_surface_create(mWidth, mHeight, format);
167 mOwnTbmSurface = true;
170 tbm_surface_h NativeImageSourceTizen::GetSurfaceFromAny(Any source) const
177 if(source.GetType() == typeid(tbm_surface_h))
179 return AnyCast<tbm_surface_h>(source);
187 void NativeImageSourceTizen::DestroySurface()
191 if(mIsBufferAcquired)
193 Rect<uint32_t> emptyRect{};
194 ReleaseBuffer(emptyRect);
198 if(tbm_surface_destroy(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
200 DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
205 tbm_surface_internal_unref(mTbmSurface);
213 NativeImageSourceTizen::~NativeImageSourceTizen()
218 Any NativeImageSourceTizen::GetNativeImageSource() const
220 return Any(mTbmSurface);
223 bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
225 std::scoped_lock lock(mMutex);
226 if(mTbmSurface != NULL)
228 tbm_surface_info_s surface_info;
230 if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE)
232 DALI_LOG_ERROR("Fail to map tbm_surface\n");
240 tbm_format format = surface_info.format;
241 uint32_t stride = surface_info.planes[0].stride;
242 unsigned char* ptr = surface_info.planes[0].ptr;
252 case TBM_FORMAT_RGB888:
254 lineSize = width * 3;
255 pixelFormat = Pixel::RGB888;
256 pixbuf.resize(lineSize * height);
257 unsigned char* bufptr = &pixbuf[0];
259 for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
261 for(unsigned int c = 0; c < width; ++c)
264 offset = cOffset + r * stride;
265 *(bufptr + cOffset) = ptr[offset + 2];
266 *(bufptr + cOffset + 1) = ptr[offset + 1];
267 *(bufptr + cOffset + 2) = ptr[offset];
272 case TBM_FORMAT_RGBA8888:
274 lineSize = width * 4;
275 pixelFormat = Pixel::RGBA8888;
276 pixbuf.resize(lineSize * height);
277 unsigned char* bufptr = &pixbuf[0];
279 for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
281 for(unsigned int c = 0; c < width; ++c)
284 offset = cOffset + r * stride;
285 *(bufptr + cOffset) = ptr[offset + 3];
286 *(bufptr + cOffset + 1) = ptr[offset + 2];
287 *(bufptr + cOffset + 2) = ptr[offset + 1];
288 *(bufptr + cOffset + 3) = ptr[offset];
293 case TBM_FORMAT_ARGB8888:
295 lineSize = width * 4;
296 pixelFormat = Pixel::RGBA8888;
297 pixbuf.resize(lineSize * height);
298 unsigned char* bufptr = &pixbuf[0];
300 for(unsigned int r = 0; r < height; ++r, bufptr += lineSize)
302 for(unsigned int c = 0; c < width; ++c)
305 offset = cOffset + r * stride;
306 *(bufptr + cOffset) = ptr[offset + 2];
307 *(bufptr + cOffset + 1) = ptr[offset + 1];
308 *(bufptr + cOffset + 2) = ptr[offset];
309 *(bufptr + cOffset + 3) = ptr[offset + 3];
316 DALI_ASSERT_ALWAYS(0 && "Tbm surface has unsupported pixel format.\n");
322 if(tbm_surface_unmap(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
324 DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
330 DALI_LOG_WARNING("TBM surface does not exist.\n");
338 void NativeImageSourceTizen::SetSource(Any source)
340 std::scoped_lock lock(mMutex);
344 mOwnTbmSurface = false;
345 mTbmSurface = GetSurfaceFromAny(source);
347 if(mTbmSurface != NULL)
350 tbm_surface_internal_ref(mTbmSurface);
351 mBlendingRequired = CheckBlending(tbm_surface_get_format(mTbmSurface));
352 mWidth = tbm_surface_get_width(mTbmSurface);
353 mHeight = tbm_surface_get_height(mTbmSurface);
355 if(mBackBufferEnabled)
363 bool NativeImageSourceTizen::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
367 tbm_format format = TBM_FORMAT_RGB888;
371 case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
373 format = TBM_FORMAT_ARGB8888;
376 case Dali::NativeImageSource::COLOR_DEPTH_8:
378 format = TBM_FORMAT_C8;
381 case Dali::NativeImageSource::COLOR_DEPTH_16:
383 format = TBM_FORMAT_RGB565;
386 case Dali::NativeImageSource::COLOR_DEPTH_24:
388 format = TBM_FORMAT_RGB888;
391 case Dali::NativeImageSource::COLOR_DEPTH_32:
393 format = TBM_FORMAT_ARGB8888;
398 if(tbm_surface_query_formats(&formats, &formatNum))
400 for(unsigned int i = 0; i < formatNum; i++)
402 if(formats[i] == format)
414 bool NativeImageSourceTizen::CreateResource()
416 // If an EGL image exists, use it as it is without creating it.
417 if(mEglImageKHR != NULL)
422 // casting from an unsigned int to a void *, which should then be cast back
423 // to an unsigned int in the driver.
424 EGLClientBuffer eglBuffer = mTbmBackSurface ? reinterpret_cast<EGLClientBuffer>(mTbmBackSurface) : reinterpret_cast<EGLClientBuffer>(mTbmSurface);
425 if(!eglBuffer || !tbm_surface_internal_is_valid(mTbmSurface))
427 DALI_LOG_ERROR("Invalid surface\n");
431 mEglImageExtensions = mEglGraphics->GetImageExtensions();
432 DALI_ASSERT_DEBUG(mEglImageExtensions);
434 mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
437 DALI_LOG_ERROR("Fail to CreateImageKHR\n");
440 return mEglImageKHR != NULL;
443 void NativeImageSourceTizen::DestroyResource()
445 std::scoped_lock lock(mMutex);
448 mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
453 if(mResourceDestructionCallback)
455 mResourceDestructionCallback->Trigger();
459 uint32_t NativeImageSourceTizen::TargetTexture()
461 mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
466 void NativeImageSourceTizen::PrepareTexture()
468 std::scoped_lock lock(mMutex);
471 // Destroy previous eglImage because use for new one.
472 // if mEglImageKHR is not to be NULL here, it will not be updated with a new eglImage.
473 mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
485 bool NativeImageSourceTizen::ApplyNativeFragmentShader(std::string& shader)
487 return mEglGraphics->ApplyNativeFragmentShader(shader, SAMPLER_TYPE);
490 const char* NativeImageSourceTizen::GetCustomSamplerTypename() const
495 int NativeImageSourceTizen::GetTextureTarget() const
497 return GL_TEXTURE_EXTERNAL_OES;
500 Any NativeImageSourceTizen::GetNativeImageHandle() const
502 return GetNativeImageSource();
505 bool NativeImageSourceTizen::SourceChanged() const
509 return mUpdatedArea.IsEmpty() ? false : true;
514 Rect<uint32_t> NativeImageSourceTizen::GetUpdatedArea()
516 std::scoped_lock lock(mMutex);
517 Rect<uint32_t> updatedArea{0, 0, mWidth, mHeight};
518 if(!mUpdatedArea.IsEmpty() && mTbmSurface != NULL && mTbmBackSurface != NULL)
520 updatedArea = mUpdatedArea;
522 tbm_surface_info_s info;
523 if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
525 DALI_LOG_ERROR("Fail to map tbm_surface\n");
529 tbm_surface_info_s backBufferInfo;
530 if(tbm_surface_map(mTbmBackSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &backBufferInfo) != TBM_SURFACE_ERROR_NONE)
532 DALI_LOG_ERROR("Fail to map tbm_surface - backbuffer\n");
533 tbm_surface_unmap(mTbmSurface);
537 unsigned char* srcBuffer = info.planes[0].ptr;
538 unsigned char* dstBuffer = backBufferInfo.planes[0].ptr;
540 uint32_t stride = info.planes[0].stride;
541 uint32_t bytesPerPixel = info.bpp >> 3;
543 srcBuffer += updatedArea.y * stride + updatedArea.x * bytesPerPixel;
544 dstBuffer += updatedArea.y * stride + updatedArea.x * bytesPerPixel;
546 // Copy to back buffer
547 for(uint32_t y = 0; y < updatedArea.height; y++)
549 memcpy(dstBuffer, srcBuffer, updatedArea.width * bytesPerPixel);
554 tbm_surface_unmap(mTbmSurface);
555 tbm_surface_unmap(mTbmBackSurface);
557 // Reset the updated area
558 mUpdatedArea.Set(0u, 0u, 0u, 0u);
563 bool NativeImageSourceTizen::CheckBlending(tbm_format format)
565 if(mTbmFormat != format)
567 for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
569 if(format == FORMATS_BLENDING_REQUIRED[i])
571 mBlendingRequired = true;
578 return mBlendingRequired;
581 uint8_t* NativeImageSourceTizen::AcquireBuffer(uint32_t& width, uint32_t& height, uint32_t& stride)
583 mMutex.lock(); // We don't use std::scoped_lock here
584 if(mTbmSurface != NULL)
586 tbm_surface_info_s info;
588 if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
590 DALI_LOG_ERROR("Fail to map tbm_surface\n");
598 tbm_surface_internal_ref(mTbmSurface);
599 mIsBufferAcquired = true;
601 stride = info.planes[0].stride;
605 // The lock is held until ReleaseBuffer is called
606 return info.planes[0].ptr;
612 bool NativeImageSourceTizen::ReleaseBuffer(const Rect<uint32_t>& updatedArea)
615 if(mTbmSurface != NULL)
619 if(updatedArea.IsEmpty())
621 mUpdatedArea.Set(0, 0, mWidth, mHeight);
625 if(mUpdatedArea.IsEmpty())
627 mUpdatedArea = updatedArea;
631 mUpdatedArea.Merge(updatedArea);
636 ret = (tbm_surface_unmap(mTbmSurface) == TBM_SURFACE_ERROR_NONE);
639 DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
641 tbm_surface_internal_unref(mTbmSurface);
642 mIsBufferAcquired = false;
644 // Unlock the mutex locked by AcquireBuffer.
649 void NativeImageSourceTizen::SetResourceDestructionCallback(EventThreadCallback* callback)
651 std::scoped_lock lock(mMutex);
652 mResourceDestructionCallback = std::unique_ptr<EventThreadCallback>(callback);
655 void NativeImageSourceTizen::EnableBackBuffer(bool enable)
657 if(enable != mBackBufferEnabled)
659 mBackBufferEnabled = enable;
661 if(mBackBufferEnabled)
672 void NativeImageSourceTizen::CreateBackBuffer()
674 if(!mTbmBackSurface && mTbmSurface)
676 mTbmBackSurface = tbm_surface_create(mWidth, mHeight, tbm_surface_get_format(mTbmSurface));
680 void NativeImageSourceTizen::DestroyBackBuffer()
684 if(tbm_surface_destroy(mTbmBackSurface) != TBM_SURFACE_ERROR_NONE)
686 DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
688 mTbmBackSurface = NULL;
692 } // namespace Adaptor
694 } // namespace Internal