Added UIThreadLoader to GLIB framework
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / android / native-image-source-impl-android.cpp
1 /*
2  * Copyright (c) 2023 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 #define EGL_EGLEXT_PROTOTYPES
19 #if __ANDROID_API__ < 26
20 #error "Unsupported Android API version, must be >= 26"
21 #endif
22
23 // CLASS HEADER
24 #include <dali/internal/imaging/android/native-image-source-impl-android.h>
25
26 // EXTERNAL INCLUDES
27 #include <EGL/egl.h>
28 #include <dali/integration-api/debug.h>
29 #include <include/EGL/eglext.h>
30
31 // INTERNAL INCLUDES
32 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
33 #include <dali/internal/adaptor/common/adaptor-impl.h>
34 #include <dali/internal/graphics/common/egl-image-extensions.h>
35 #include <dali/internal/graphics/gles/egl-graphics.h>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace Adaptor
42 {
43 using Dali::Integration::PixelBuffer;
44
45 NativeImageSourceAndroid* NativeImageSourceAndroid::New(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
46 {
47   NativeImageSourceAndroid* image = new NativeImageSourceAndroid(width, height, depth, nativeImageSource);
48   DALI_ASSERT_DEBUG(image && "NativeImageSource allocation failed.");
49
50   // 2nd phase construction
51   if(image) //< Defensive in case we ever compile without exceptions.
52   {
53     image->Initialize();
54   }
55
56   return image;
57 }
58
59 NativeImageSourceAndroid::NativeImageSourceAndroid(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
60 : mWidth(width),
61   mHeight(height),
62   mOwnPixmap(true),
63   mPixmap(NULL),
64   mBlendingRequired(false),
65   mColorDepth(depth),
66   mEglImageKHR(NULL),
67   mEglGraphics(NULL),
68   mEglImageExtensions(NULL),
69   mResourceDestructionCallback()
70 {
71   DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
72
73   GraphicsInterface* graphics = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
74   mEglGraphics                = static_cast<EglGraphics*>(graphics);
75
76   // assign the pixmap
77   mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(nativeImageSource));
78   if(!mPixmap)
79   {
80     AHardwareBuffer_Desc bufferDescription;
81     memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
82     bufferDescription.width  = width;
83     bufferDescription.height = height;
84     bufferDescription.layers = 1;
85     bufferDescription.usage  = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
86     switch(mColorDepth)
87     {
88       case Dali::NativeImageSource::COLOR_DEPTH_32:
89       case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
90         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
91         break;
92       case Dali::NativeImageSource::COLOR_DEPTH_24:
93         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
94         break;
95       case Dali::NativeImageSource::COLOR_DEPTH_16:
96         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
97         break;
98       case Dali::NativeImageSource::COLOR_DEPTH_8:
99         bufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB;
100         break;
101     }
102
103     int ret = AHardwareBuffer_allocate(&bufferDescription, &mPixmap);
104     if(ret)
105     {
106       DALI_LOG_ERROR("Failed to allocate AHardwareBuffer %d", ret);
107     }
108
109     mOwnPixmap = true;
110   }
111 }
112
113 void NativeImageSourceAndroid::Initialize()
114 {
115   if(mPixmap && !mOwnPixmap)
116   {
117     AHardwareBuffer_acquire(mPixmap);
118
119     // find out the pixmap width / height and color depth
120     GetPixmapDetails();
121   }
122 }
123
124 NativeImageSourceAndroid::~NativeImageSourceAndroid()
125 {
126   AHardwareBuffer_release(mPixmap);
127   mPixmap = NULL;
128 }
129
130 Any NativeImageSourceAndroid::GetNativeImageSource() const
131 {
132   return Any(mPixmap);
133 }
134
135 bool NativeImageSourceAndroid::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
136 {
137   DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
138   bool success = false;
139
140   width  = mWidth;
141   height = mHeight;
142
143   AHardwareBuffer_Desc bufferDescription;
144   memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
145   AHardwareBuffer_describe(mPixmap, &bufferDescription);
146   switch(bufferDescription.format)
147   {
148     case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
149       pixelFormat = Pixel::Format::RGBA8888;
150       break;
151     case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
152       pixelFormat = Pixel::Format::RGB8888;
153       break;
154     case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
155       pixelFormat = Pixel::Format::RGB888;
156       break;
157     case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
158       pixelFormat = Pixel::Format::RGB565;
159       break;
160     case AHARDWAREBUFFER_FORMAT_BLOB:
161     default:
162       pixelFormat = Pixel::Format::A8;
163       break;
164   }
165
166   void* buffer = NULL;
167   int   ret    = AHardwareBuffer_lock(mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer);
168   if(ret != 0)
169   {
170     DALI_LOG_ERROR("Failed to AHardwareBuffer_lock %d", ret);
171     return success;
172   }
173
174   uint32_t pixelBytes = GetBytesPerPixel(pixelFormat);
175   if(bufferDescription.stride < (pixelBytes * bufferDescription.width))
176   {
177     //On Android device, bufferDescription.stride doesn't seem to mean (width * pixelbytes)
178     //in an actual case, (AHardwareBuffer_Desc) bufferDescription = (width = 1080, height = 1060, layers = 1, format = 1, usage = 306, stride = 1088, rfu0 = 0, rfu1 = 0)
179     //deal with situation
180     uint32_t dstStride = pixelBytes * bufferDescription.width;
181     uint32_t srcStride = pixelBytes * bufferDescription.stride;
182     uint32_t size      = dstStride * bufferDescription.height;
183     pixbuf.resize(size);
184     //copy each row over
185     const unsigned char* ptrSrc = reinterpret_cast<const unsigned char*>(buffer);
186     unsigned char*       ptrDst = pixbuf.data();
187     for(int y = 0; y < bufferDescription.height; y++, ptrSrc += srcStride, ptrDst += dstStride)
188     {
189       memcpy(ptrDst, ptrSrc, dstStride);
190     }
191   }
192   else
193   {
194     uint32_t size = bufferDescription.stride * bufferDescription.height;
195     pixbuf.resize(size);
196     memcpy(pixbuf.data(), buffer, size);
197   }
198
199   ret = AHardwareBuffer_unlock(mPixmap, NULL);
200   if(ret != 0)
201   {
202     DALI_LOG_ERROR("failed to AHardwareBuffer_unlock %d", ret);
203     return success;
204   }
205   success = true;
206
207   return success;
208 }
209
210 void NativeImageSourceAndroid::SetSource(Any source)
211 {
212   if(mPixmap)
213   {
214     mOwnPixmap = false;
215
216     AHardwareBuffer_release(mPixmap);
217     mPixmap = NULL;
218   }
219
220   mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(source));
221
222   if(mPixmap)
223   {
224     // we don't own the pixmap
225     mOwnPixmap = false;
226
227     // find out the pixmap width / height and color depth
228     GetPixmapDetails();
229   }
230 }
231
232 bool NativeImageSourceAndroid::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
233 {
234   return true;
235 }
236
237 bool NativeImageSourceAndroid::CreateResource()
238 {
239   mEglImageExtensions = mEglGraphics->GetImageExtensions();
240   DALI_ASSERT_DEBUG(mEglImageExtensions);
241
242   // if the image existed previously delete it.
243   if(mEglImageKHR != NULL)
244   {
245     DestroyResource();
246   }
247
248   DALI_ASSERT_ALWAYS(mPixmap);
249   EGLClientBuffer eglBuffer = eglGetNativeClientBufferANDROID(mPixmap);
250   switch(eglGetError())
251   {
252     case EGL_SUCCESS:
253     {
254       break;
255     }
256     case EGL_BAD_PARAMETER:
257     {
258       DALI_LOG_ERROR("EGL_BAD_PARAMETER: bad pixmap parameter\n");
259       break;
260     }
261     case EGL_BAD_ACCESS:
262     {
263       DALI_LOG_ERROR("EGL_BAD_ACCESS: bad access to pixmap\n");
264       break;
265     }
266     case EGL_BAD_ALLOC:
267     {
268       DALI_LOG_ERROR("EGL_BAD_ALLOC: Insufficient memory is available\n");
269       break;
270     }
271     default:
272     {
273       DALI_LOG_ERROR("eglGetNativeClientBufferANDROID error\n");
274       break;
275     }
276   }
277
278   DALI_ASSERT_ALWAYS(eglBuffer);
279   mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
280
281   return mEglImageKHR != NULL;
282 }
283
284 void NativeImageSourceAndroid::DestroyResource()
285 {
286   mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
287
288   mEglImageKHR = NULL;
289
290   if(mResourceDestructionCallback)
291   {
292     mResourceDestructionCallback->Trigger();
293   }
294 }
295
296 uint32_t NativeImageSourceAndroid::TargetTexture()
297 {
298   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
299
300   return 0;
301 }
302
303 void NativeImageSourceAndroid::PrepareTexture()
304 {
305 }
306
307 int NativeImageSourceAndroid::GetTextureTarget() const
308 {
309   return GL_TEXTURE_2D;
310 }
311
312 bool NativeImageSourceAndroid::ApplyNativeFragmentShader(std::string& shader)
313 {
314   return false;
315 }
316
317 const char* NativeImageSourceAndroid::GetCustomSamplerTypename() const
318 {
319   return nullptr;
320 }
321
322 void* NativeImageSourceAndroid::GetPixmapFromAny(Any pixmap) const
323 {
324   if(pixmap.Empty())
325   {
326     return 0;
327   }
328
329   return AnyCast<void*>(pixmap);
330 }
331
332 void NativeImageSourceAndroid::GetPixmapDetails()
333 {
334   // get the width, height and depth
335   mBlendingRequired = false;
336
337   AHardwareBuffer_Desc bufferDescription;
338   memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
339   AHardwareBuffer_describe(mPixmap, &bufferDescription);
340
341   mWidth  = bufferDescription.width;
342   mHeight = bufferDescription.height;
343   switch(bufferDescription.format)
344   {
345     case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
346       mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_32;
347       break;
348     case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
349       mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_24;
350       break;
351     case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
352       mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_16;
353       break;
354     case AHARDWAREBUFFER_FORMAT_BLOB:
355     default:
356       mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_8;
357   }
358 }
359
360 uint8_t* NativeImageSourceAndroid::AcquireBuffer(uint32_t& width, uint32_t& height, uint32_t& stride)
361 {
362   if(mPixmap)
363   {
364     AHardwareBuffer_Desc bufferDescription;
365     memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
366     AHardwareBuffer_describe(mPixmap, &bufferDescription);
367
368     void* buffer = NULL;
369     if(AHardwareBuffer_lock(mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer) != 0)
370     {
371       DALI_LOG_ERROR("Failed to AHardwareBuffer_lock\n");
372       return NULL;
373     }
374
375     stride = bufferDescription.stride;
376     width  = bufferDescription.width;
377     height = bufferDescription.height;
378
379     return static_cast<uint8_t*>(buffer);
380   }
381
382   return NULL;
383 }
384
385 bool NativeImageSourceAndroid::ReleaseBuffer(const Rect<uint32_t>& updatedArea)
386 {
387   if(mPixmap)
388   {
389     if(AHardwareBuffer_unlock(mPixmap, NULL) != 0)
390     {
391       DALI_LOG_ERROR("failed to AHardwareBuffer_unlock\n");
392       return false;
393     }
394     return true;
395   }
396   return false;
397 }
398
399 void NativeImageSourceAndroid::SetResourceDestructionCallback(EventThreadCallback* callback)
400 {
401   mResourceDestructionCallback = std::unique_ptr<EventThreadCallback>(callback);
402 }
403
404 void NativeImageSourceAndroid::EnableBackBuffer(bool enable)
405 {
406 }
407
408 } // namespace Adaptor
409
410 } // namespace Internal
411
412 } // namespace Dali