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.
18 #define EGL_EGLEXT_PROTOTYPES
19 #if __ANDROID_API__ < 26
20 #error "Unsupported Android API version, must be >= 26"
24 #include <dali/internal/imaging/android/native-image-source-impl-android.h>
28 #include <dali/devel-api/common/stage.h>
29 #include <dali/integration-api/debug.h>
30 #include <include/EGL/eglext.h>
33 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
34 #include <dali/internal/adaptor/common/adaptor-impl.h>
35 #include <dali/internal/graphics/common/egl-image-extensions.h>
36 #include <dali/internal/graphics/gles/egl-graphics.h>
44 using Dali::Integration::PixelBuffer;
46 NativeImageSourceAndroid* NativeImageSourceAndroid::New(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
48 NativeImageSourceAndroid* image = new NativeImageSourceAndroid(width, height, depth, nativeImageSource);
49 DALI_ASSERT_DEBUG(image && "NativeImageSource allocation failed.");
51 // 2nd phase construction
52 if(image) //< Defensive in case we ever compile without exceptions.
60 NativeImageSourceAndroid::NativeImageSourceAndroid(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
65 mBlendingRequired(false),
69 mEglImageExtensions(NULL),
70 mResourceDestructionCallback()
72 DALI_ASSERT_ALWAYS(Dali::Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
74 GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
75 mEglGraphics = static_cast<EglGraphics*>(graphics);
78 mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(nativeImageSource));
81 AHardwareBuffer_Desc bufferDescription;
82 memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
83 bufferDescription.width = width;
84 bufferDescription.height = height;
85 bufferDescription.layers = 1;
86 bufferDescription.usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
89 case Dali::NativeImageSource::COLOR_DEPTH_32:
90 case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
91 bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
93 case Dali::NativeImageSource::COLOR_DEPTH_24:
94 bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
96 case Dali::NativeImageSource::COLOR_DEPTH_16:
97 bufferDescription.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
99 case Dali::NativeImageSource::COLOR_DEPTH_8:
100 bufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB;
104 int ret = AHardwareBuffer_allocate(&bufferDescription, &mPixmap);
107 DALI_LOG_ERROR("Failed to allocate AHardwareBuffer %d", ret);
114 void NativeImageSourceAndroid::Initialize()
116 if(mPixmap && !mOwnPixmap)
118 AHardwareBuffer_acquire(mPixmap);
120 // find out the pixmap width / height and color depth
125 NativeImageSourceAndroid::~NativeImageSourceAndroid()
127 AHardwareBuffer_release(mPixmap);
131 Any NativeImageSourceAndroid::GetNativeImageSource() const
136 bool NativeImageSourceAndroid::GetPixels(std::vector<uint8_t>& pixbuf, uint32_t& width, uint32_t& height, Pixel::Format& pixelFormat) const
138 DALI_ASSERT_DEBUG(sizeof(uint32_t) == 4);
139 bool success = false;
144 AHardwareBuffer_Desc bufferDescription;
145 memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
146 AHardwareBuffer_describe(mPixmap, &bufferDescription);
147 switch(bufferDescription.format)
149 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
150 pixelFormat = Pixel::Format::RGBA8888;
152 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
153 pixelFormat = Pixel::Format::RGB8888;
155 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
156 pixelFormat = Pixel::Format::RGB888;
158 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
159 pixelFormat = Pixel::Format::RGB565;
161 case AHARDWAREBUFFER_FORMAT_BLOB:
163 pixelFormat = Pixel::Format::A8;
168 int ret = AHardwareBuffer_lock(mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer);
171 DALI_LOG_ERROR("Failed to AHardwareBuffer_lock %d", ret);
175 uint32_t pixelBytes = GetBytesPerPixel(pixelFormat);
176 if(bufferDescription.stride < (pixelBytes * bufferDescription.width))
178 //On Android device, bufferDescription.stride doesn't seem to mean (width * pixelbytes)
179 //in an actual case, (AHardwareBuffer_Desc) bufferDescription = (width = 1080, height = 1060, layers = 1, format = 1, usage = 306, stride = 1088, rfu0 = 0, rfu1 = 0)
180 //deal with situation
181 uint32_t dstStride = pixelBytes * bufferDescription.width;
182 uint32_t srcStride = pixelBytes * bufferDescription.stride;
183 uint32_t size = dstStride * bufferDescription.height;
186 const uint8_t* ptrSrc = reinterpret_cast<const uint8_t*>(buffer);
187 uint8_t* ptrDst = pixbuf.data();
188 for(int y = 0; y < bufferDescription.height; y++, ptrSrc += srcStride, ptrDst += dstStride)
190 memcpy(ptrDst, ptrSrc, dstStride);
195 uint32_t size = bufferDescription.stride * bufferDescription.height;
197 memcpy(pixbuf.data(), buffer, size);
200 ret = AHardwareBuffer_unlock(mPixmap, NULL);
203 DALI_LOG_ERROR("failed to AHardwareBuffer_unlock %d", ret);
211 void NativeImageSourceAndroid::SetSource(Any source)
217 AHardwareBuffer_release(mPixmap);
221 mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(source));
225 // we don't own the pixmap
228 // find out the pixmap width / height and color depth
233 bool NativeImageSourceAndroid::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
238 bool NativeImageSourceAndroid::CreateResource()
240 mEglImageExtensions = mEglGraphics->GetImageExtensions();
241 DALI_ASSERT_DEBUG(mEglImageExtensions);
243 // if the image existed previously delete it.
244 if(mEglImageKHR != NULL)
249 DALI_ASSERT_ALWAYS(mPixmap);
250 EGLClientBuffer eglBuffer = eglGetNativeClientBufferANDROID(mPixmap);
251 switch(eglGetError())
257 case EGL_BAD_PARAMETER:
259 DALI_LOG_ERROR("EGL_BAD_PARAMETER: bad pixmap parameter\n");
264 DALI_LOG_ERROR("EGL_BAD_ACCESS: bad access to pixmap\n");
269 DALI_LOG_ERROR("EGL_BAD_ALLOC: Insufficient memory is available\n");
274 DALI_LOG_ERROR("eglGetNativeClientBufferANDROID error\n");
279 DALI_ASSERT_ALWAYS(eglBuffer);
280 mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
282 return mEglImageKHR != NULL;
285 void NativeImageSourceAndroid::DestroyResource()
287 mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
291 if(mResourceDestructionCallback)
293 mResourceDestructionCallback->Trigger();
297 uint32_t NativeImageSourceAndroid::TargetTexture()
299 mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
304 void NativeImageSourceAndroid::PrepareTexture()
308 int NativeImageSourceAndroid::GetTextureTarget() const
310 return GL_TEXTURE_2D;
313 bool NativeImageSourceAndroid::ApplyNativeFragmentShader(std::string& shader)
318 const char* NativeImageSourceAndroid::GetCustomSamplerTypename() const
323 void* NativeImageSourceAndroid::GetPixmapFromAny(Any pixmap) const
330 return AnyCast<void*>(pixmap);
333 void NativeImageSourceAndroid::GetPixmapDetails()
335 // get the width, height and depth
336 mBlendingRequired = false;
338 AHardwareBuffer_Desc bufferDescription;
339 memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
340 AHardwareBuffer_describe(mPixmap, &bufferDescription);
342 mWidth = bufferDescription.width;
343 mHeight = bufferDescription.height;
344 switch(bufferDescription.format)
346 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
347 mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_32;
349 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
350 mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_24;
352 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
353 mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_16;
355 case AHARDWAREBUFFER_FORMAT_BLOB:
357 mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_8;
361 uint8_t* NativeImageSourceAndroid::AcquireBuffer(uint32_t& width, uint32_t& height, uint32_t& stride)
365 AHardwareBuffer_Desc bufferDescription;
366 memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
367 AHardwareBuffer_describe(mPixmap, &bufferDescription);
370 if(AHardwareBuffer_lock(mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer) != 0)
372 DALI_LOG_ERROR("Failed to AHardwareBuffer_lock\n");
376 stride = bufferDescription.stride;
377 width = bufferDescription.width;
378 height = bufferDescription.height;
380 return static_cast<uint8_t*>(buffer);
386 bool NativeImageSourceAndroid::ReleaseBuffer(const Rect<uint32_t>& updatedArea)
390 if(AHardwareBuffer_unlock(mPixmap, NULL) != 0)
392 DALI_LOG_ERROR("failed to AHardwareBuffer_unlock\n");
400 void NativeImageSourceAndroid::SetResourceDestructionCallback(EventThreadCallback* callback)
402 mResourceDestructionCallback = std::unique_ptr<EventThreadCallback>(callback);
405 void NativeImageSourceAndroid::EnableBackBuffer(bool enable)
409 } // namespace Adaptor
411 } // namespace Internal