2 * Copyright (c) 2024 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/devel-api/common/stage.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/integration-api/gl-defines.h>
25 #include <tbm_surface_internal.h>
29 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
30 #include <dali/internal/adaptor/common/adaptor-impl.h>
31 #include <dali/internal/graphics/common/egl-image-extensions.h>
32 #include <dali/internal/graphics/gles/egl-graphics.h>
42 const char* SAMPLER_TYPE = "samplerExternalOES";
45 tbm_format 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
58 const int NUM_FORMATS_BLENDING_REQUIRED = 18;
62 using Dali::Integration::PixelBuffer;
64 NativeImageSourceTizen* NativeImageSourceTizen::New(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
66 NativeImageSourceTizen* image = new NativeImageSourceTizen(width, height, depth, nativeImageSource);
67 DALI_ASSERT_DEBUG(image && "NativeImageSource allocation failed.");
77 NativeImageSourceTizen::NativeImageSourceTizen(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
81 mTbmBackSurface(NULL),
87 mEglImageExtensions(NULL),
88 mResourceDestructionCallback(),
89 mOwnTbmSurface(false),
90 mBlendingRequired(false),
92 mIsBufferAcquired(false),
93 mBackBufferEnabled(false)
95 DALI_ASSERT_ALWAYS(Dali::Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
97 GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
98 mEglGraphics = static_cast<EglGraphics*>(graphics);
100 mTbmSurface = GetSurfaceFromAny(nativeImageSource);
102 if(mTbmSurface != NULL)
104 tbm_surface_internal_ref(mTbmSurface);
105 mBlendingRequired = CheckBlending(tbm_surface_get_format(mTbmSurface));
106 mWidth = tbm_surface_get_width(mTbmSurface);
107 mHeight = tbm_surface_get_height(mTbmSurface);
111 void NativeImageSourceTizen::Initialize()
113 if(mTbmSurface != NULL || mWidth == 0 || mHeight == 0)
118 tbm_format format = TBM_FORMAT_RGB888;
123 case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
125 format = TBM_FORMAT_ARGB8888;
129 case Dali::NativeImageSource::COLOR_DEPTH_8:
131 format = TBM_FORMAT_C8;
135 case Dali::NativeImageSource::COLOR_DEPTH_16:
137 format = TBM_FORMAT_RGB565;
141 case Dali::NativeImageSource::COLOR_DEPTH_24:
143 format = TBM_FORMAT_RGB888;
147 case Dali::NativeImageSource::COLOR_DEPTH_32:
149 format = TBM_FORMAT_ARGB8888;
155 DALI_LOG_WARNING("Wrong color depth.\n");
160 // set whether blending is required according to pixel format based on the depth
161 /* default pixel format is RGB888
162 If depth = 8, Pixel::A8;
163 If depth = 16, Pixel::RGB565;
164 If depth = 32, Pixel::RGBA8888 */
165 mBlendingRequired = (depth == 32 || depth == 8);
167 mTbmSurface = tbm_surface_create(mWidth, mHeight, format);
168 mOwnTbmSurface = true;
171 tbm_surface_h NativeImageSourceTizen::GetSurfaceFromAny(Any source) const
178 if(source.GetType() == typeid(tbm_surface_h))
180 return AnyCast<tbm_surface_h>(source);
188 void NativeImageSourceTizen::DestroySurface()
192 if(mIsBufferAcquired)
194 Rect<uint32_t> emptyRect{};
195 ReleaseBuffer(emptyRect);
199 if(tbm_surface_destroy(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
201 DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
206 tbm_surface_internal_unref(mTbmSurface);
214 NativeImageSourceTizen::~NativeImageSourceTizen()
219 Any NativeImageSourceTizen::GetNativeImageSource() const
221 return Any(mTbmSurface);
224 bool NativeImageSourceTizen::GetPixels(std::vector<uint8_t>& pixbuf, uint32_t& width, uint32_t& height, Pixel::Format& pixelFormat) const
226 std::scoped_lock lock(mMutex);
227 if(mTbmSurface != NULL)
229 tbm_surface_info_s surface_info;
231 if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE)
233 DALI_LOG_ERROR("Fail to map tbm_surface\n");
241 tbm_format format = surface_info.format;
242 uint32_t stride = surface_info.planes[0].stride;
243 uint8_t* ptr = surface_info.planes[0].ptr;
253 case TBM_FORMAT_RGB888:
255 lineSize = width * 3;
256 pixelFormat = Pixel::RGB888;
257 pixbuf.resize(lineSize * height);
258 uint8_t* bufptr = &pixbuf[0];
260 for(uint32_t r = 0; r < height; ++r, bufptr += lineSize)
262 for(uint32_t c = 0; c < width; ++c)
265 offset = cOffset + r * stride;
266 *(bufptr + cOffset) = ptr[offset + 2];
267 *(bufptr + cOffset + 1) = ptr[offset + 1];
268 *(bufptr + cOffset + 2) = ptr[offset];
273 case TBM_FORMAT_RGBA8888:
275 lineSize = width * 4;
276 pixelFormat = Pixel::RGBA8888;
277 pixbuf.resize(lineSize * height);
278 uint8_t* bufptr = &pixbuf[0];
280 for(uint32_t r = 0; r < height; ++r, bufptr += lineSize)
282 for(uint32_t c = 0; c < width; ++c)
285 offset = cOffset + r * stride;
286 *(bufptr + cOffset) = ptr[offset + 3];
287 *(bufptr + cOffset + 1) = ptr[offset + 2];
288 *(bufptr + cOffset + 2) = ptr[offset + 1];
289 *(bufptr + cOffset + 3) = ptr[offset];
294 case TBM_FORMAT_ARGB8888:
296 lineSize = width * 4;
297 pixelFormat = Pixel::RGBA8888;
298 pixbuf.resize(lineSize * height);
299 uint8_t* bufptr = &pixbuf[0];
301 for(uint32_t r = 0; r < height; ++r, bufptr += lineSize)
303 for(uint32_t c = 0; c < width; ++c)
306 offset = cOffset + r * stride;
307 *(bufptr + cOffset) = ptr[offset + 2];
308 *(bufptr + cOffset + 1) = ptr[offset + 1];
309 *(bufptr + cOffset + 2) = ptr[offset];
310 *(bufptr + cOffset + 3) = ptr[offset + 3];
317 DALI_ASSERT_ALWAYS(0 && "Tbm surface has unsupported pixel format.\n");
323 if(tbm_surface_unmap(mTbmSurface) != TBM_SURFACE_ERROR_NONE)
325 DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
331 DALI_LOG_WARNING("TBM surface does not exist.\n");
339 void NativeImageSourceTizen::SetSource(Any source)
341 std::scoped_lock lock(mMutex);
345 mOwnTbmSurface = false;
346 mTbmSurface = GetSurfaceFromAny(source);
348 if(mTbmSurface != NULL)
351 tbm_surface_internal_ref(mTbmSurface);
352 mBlendingRequired = CheckBlending(tbm_surface_get_format(mTbmSurface));
353 mWidth = tbm_surface_get_width(mTbmSurface);
354 mHeight = tbm_surface_get_height(mTbmSurface);
356 if(mBackBufferEnabled)
364 bool NativeImageSourceTizen::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
368 tbm_format format = TBM_FORMAT_RGB888;
372 case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
374 format = TBM_FORMAT_ARGB8888;
377 case Dali::NativeImageSource::COLOR_DEPTH_8:
379 format = TBM_FORMAT_C8;
382 case Dali::NativeImageSource::COLOR_DEPTH_16:
384 format = TBM_FORMAT_RGB565;
387 case Dali::NativeImageSource::COLOR_DEPTH_24:
389 format = TBM_FORMAT_RGB888;
392 case Dali::NativeImageSource::COLOR_DEPTH_32:
394 format = TBM_FORMAT_ARGB8888;
399 if(tbm_surface_query_formats(&formats, &formatNum))
401 for(uint32_t i = 0; i < formatNum; i++)
403 if(formats[i] == format)
415 bool NativeImageSourceTizen::CreateResource()
417 // If an EGL image exists, use it as it is without creating it.
418 if(mEglImageKHR != NULL)
423 // casting from an unsigned int to a void *, which should then be cast back
424 // to an unsigned int in the driver.
425 EGLClientBuffer eglBuffer = mTbmBackSurface ? reinterpret_cast<EGLClientBuffer>(mTbmBackSurface) : reinterpret_cast<EGLClientBuffer>(mTbmSurface);
426 if(!eglBuffer || !tbm_surface_internal_is_valid(mTbmSurface))
428 DALI_LOG_ERROR("Invalid surface\n");
432 mEglImageExtensions = mEglGraphics->GetImageExtensions();
433 DALI_ASSERT_DEBUG(mEglImageExtensions);
435 mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
438 DALI_LOG_ERROR("Fail to CreateImageKHR\n");
441 return mEglImageKHR != NULL;
444 void NativeImageSourceTizen::DestroyResource()
446 std::scoped_lock lock(mMutex);
449 mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
454 if(mResourceDestructionCallback)
456 mResourceDestructionCallback->Trigger();
460 uint32_t NativeImageSourceTizen::TargetTexture()
462 mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
467 void NativeImageSourceTizen::PrepareTexture()
469 std::scoped_lock lock(mMutex);
472 // Destroy previous eglImage because use for new one.
473 // if mEglImageKHR is not to be NULL here, it will not be updated with a new eglImage.
474 mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
486 bool NativeImageSourceTizen::ApplyNativeFragmentShader(std::string& shader)
488 return mEglGraphics->ApplyNativeFragmentShader(shader, SAMPLER_TYPE);
491 const char* NativeImageSourceTizen::GetCustomSamplerTypename() const
496 int NativeImageSourceTizen::GetTextureTarget() const
498 return GL_TEXTURE_EXTERNAL_OES;
501 Any NativeImageSourceTizen::GetNativeImageHandle() const
503 return GetNativeImageSource();
506 bool NativeImageSourceTizen::SourceChanged() const
510 return mUpdatedArea.IsEmpty() ? false : true;
515 Rect<uint32_t> NativeImageSourceTizen::GetUpdatedArea()
517 std::scoped_lock lock(mMutex);
518 Rect<uint32_t> updatedArea{0, 0, mWidth, mHeight};
519 if(!mUpdatedArea.IsEmpty() && mTbmSurface != NULL && mTbmBackSurface != NULL)
521 updatedArea = mUpdatedArea;
523 tbm_surface_info_s info;
524 if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
526 DALI_LOG_ERROR("Fail to map tbm_surface\n");
530 tbm_surface_info_s backBufferInfo;
531 if(tbm_surface_map(mTbmBackSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &backBufferInfo) != TBM_SURFACE_ERROR_NONE)
533 DALI_LOG_ERROR("Fail to map tbm_surface - backbuffer\n");
534 tbm_surface_unmap(mTbmSurface);
538 uint8_t* srcBuffer = info.planes[0].ptr;
539 uint8_t* dstBuffer = backBufferInfo.planes[0].ptr;
541 uint32_t stride = info.planes[0].stride;
542 uint32_t bytesPerPixel = info.bpp >> 3;
544 srcBuffer += updatedArea.y * stride + updatedArea.x * bytesPerPixel;
545 dstBuffer += updatedArea.y * stride + updatedArea.x * bytesPerPixel;
547 // Copy to back buffer
548 for(uint32_t y = 0; y < updatedArea.height; y++)
550 memcpy(dstBuffer, srcBuffer, updatedArea.width * bytesPerPixel);
555 tbm_surface_unmap(mTbmSurface);
556 tbm_surface_unmap(mTbmBackSurface);
558 // Reset the updated area
559 mUpdatedArea.Set(0u, 0u, 0u, 0u);
564 bool NativeImageSourceTizen::CheckBlending(tbm_format format)
566 if(mTbmFormat != format)
568 for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
570 if(format == FORMATS_BLENDING_REQUIRED[i])
572 mBlendingRequired = true;
579 return mBlendingRequired;
582 uint8_t* NativeImageSourceTizen::AcquireBuffer(uint32_t& width, uint32_t& height, uint32_t& stride)
584 mMutex.lock(); // We don't use std::scoped_lock here
585 if(mTbmSurface != NULL)
587 tbm_surface_info_s info;
589 if(tbm_surface_map(mTbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info) != TBM_SURFACE_ERROR_NONE)
591 DALI_LOG_ERROR("Fail to map tbm_surface\n");
599 tbm_surface_internal_ref(mTbmSurface);
600 mIsBufferAcquired = true;
602 stride = info.planes[0].stride;
606 // The lock is held until ReleaseBuffer is called
607 return info.planes[0].ptr;
613 bool NativeImageSourceTizen::ReleaseBuffer(const Rect<uint32_t>& updatedArea)
616 if(mTbmSurface != NULL)
620 if(updatedArea.IsEmpty())
622 mUpdatedArea.Set(0, 0, mWidth, mHeight);
626 if(mUpdatedArea.IsEmpty())
628 mUpdatedArea = updatedArea;
632 mUpdatedArea.Merge(updatedArea);
637 ret = (tbm_surface_unmap(mTbmSurface) == TBM_SURFACE_ERROR_NONE);
640 DALI_LOG_ERROR("Fail to unmap tbm_surface\n");
642 tbm_surface_internal_unref(mTbmSurface);
643 mIsBufferAcquired = false;
645 // Unlock the mutex locked by AcquireBuffer.
650 void NativeImageSourceTizen::SetResourceDestructionCallback(EventThreadCallback* callback)
652 std::scoped_lock lock(mMutex);
653 mResourceDestructionCallback = std::unique_ptr<EventThreadCallback>(callback);
656 void NativeImageSourceTizen::EnableBackBuffer(bool enable)
658 if(enable != mBackBufferEnabled)
660 mBackBufferEnabled = enable;
662 if(mBackBufferEnabled)
673 void NativeImageSourceTizen::CreateBackBuffer()
675 if(!mTbmBackSurface && mTbmSurface)
677 mTbmBackSurface = tbm_surface_create(mWidth, mHeight, tbm_surface_get_format(mTbmSurface));
681 void NativeImageSourceTizen::DestroyBackBuffer()
685 if(tbm_surface_destroy(mTbmBackSurface) != TBM_SURFACE_ERROR_NONE)
687 DALI_LOG_ERROR("Failed to destroy tbm_surface\n");
689 mTbmBackSurface = NULL;
693 } // namespace Adaptor
695 } // namespace Internal