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