bb6693f42da1becebfd8780c0af54b73aca4b649
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / android / native-image-source-impl-android.cpp
1 /*
2  * Copyright (c) 2021 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   mEglImageExtensions(NULL),
68   mResourceDestructionCallback()
69 {
70   DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
71
72   GraphicsInterface* graphics    = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
73   auto               eglGraphics = static_cast<EglGraphics*>(graphics);
74
75   mEglImageExtensions = eglGraphics->GetImageExtensions();
76
77   DALI_ASSERT_DEBUG(mEglImageExtensions);
78
79   // assign the pixmap
80   mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(nativeImageSource));
81   if(!mPixmap)
82   {
83     AHardwareBuffer_Desc bufferDescription;
84     memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
85     bufferDescription.width  = width;
86     bufferDescription.height = height;
87     bufferDescription.layers = 1;
88     bufferDescription.usage  = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
89     switch(mColorDepth)
90     {
91       case Dali::NativeImageSource::COLOR_DEPTH_32:
92       case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
93         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
94         break;
95       case Dali::NativeImageSource::COLOR_DEPTH_24:
96         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
97         break;
98       case Dali::NativeImageSource::COLOR_DEPTH_16:
99         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
100         break;
101       case Dali::NativeImageSource::COLOR_DEPTH_8:
102         bufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB;
103         break;
104     }
105
106     int ret = AHardwareBuffer_allocate(&bufferDescription, &mPixmap);
107     if(ret)
108     {
109       DALI_LOG_ERROR("Failed to allocate AHardwareBuffer %d", ret);
110     }
111
112     mOwnPixmap = true;
113   }
114 }
115
116 void NativeImageSourceAndroid::Initialize()
117 {
118   if(mPixmap && !mOwnPixmap)
119   {
120     AHardwareBuffer_acquire(mPixmap);
121
122     // find out the pixmap width / height and color depth
123     GetPixmapDetails();
124   }
125 }
126
127 NativeImageSourceAndroid::~NativeImageSourceAndroid()
128 {
129   AHardwareBuffer_release(mPixmap);
130   mPixmap = NULL;
131 }
132
133 Any NativeImageSourceAndroid::GetNativeImageSource() const
134 {
135   return Any(mPixmap);
136 }
137
138 bool NativeImageSourceAndroid::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
139 {
140   DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
141   bool success = false;
142
143   width  = mWidth;
144   height = mHeight;
145
146   AHardwareBuffer_Desc bufferDescription;
147   memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
148   AHardwareBuffer_describe(mPixmap, &bufferDescription);
149   switch(bufferDescription.format)
150   {
151     case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
152       pixelFormat = Pixel::Format::RGBA8888;
153       break;
154     case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
155       pixelFormat = Pixel::Format::RGB8888;
156       break;
157     case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
158       pixelFormat = Pixel::Format::RGB888;
159       break;
160     case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
161       pixelFormat = Pixel::Format::RGB565;
162       break;
163     case AHARDWAREBUFFER_FORMAT_BLOB:
164     default:
165       pixelFormat = Pixel::Format::A8;
166       break;
167   }
168
169   void* buffer = NULL;
170   int   ret    = AHardwareBuffer_lock(mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer);
171   if(ret != 0)
172   {
173     DALI_LOG_ERROR("Failed to AHardwareBuffer_lock %d", ret);
174     return success;
175   }
176
177   uint32_t pixelBytes = GetBytesPerPixel(pixelFormat);
178   if(bufferDescription.stride < (pixelBytes * bufferDescription.width))
179   {
180     //On Android device, bufferDescription.stride doesn't seem to mean (width * pixelbytes)
181     //in an actual case, (AHardwareBuffer_Desc) bufferDescription = (width = 1080, height = 1060, layers = 1, format = 1, usage = 306, stride = 1088, rfu0 = 0, rfu1 = 0)
182     //deal with situation
183     uint32_t dstStride = pixelBytes * bufferDescription.width;
184     uint32_t srcStride = pixelBytes * bufferDescription.stride;
185     uint32_t size      = dstStride * bufferDescription.height;
186     pixbuf.resize(size);
187     //copy each row over
188     const unsigned char* ptrSrc = reinterpret_cast<const unsigned char*>(buffer);
189     unsigned char*       ptrDst = pixbuf.data();
190     for(int y = 0; y < bufferDescription.height; y++, ptrSrc += srcStride, ptrDst += dstStride)
191     {
192       memcpy(ptrDst, ptrSrc, dstStride);
193     }
194   }
195   else
196   {
197     uint32_t size = bufferDescription.stride * bufferDescription.height;
198     pixbuf.resize(size);
199     memcpy(pixbuf.data(), buffer, size);
200   }
201
202   ret = AHardwareBuffer_unlock(mPixmap, NULL);
203   if(ret != 0)
204   {
205     DALI_LOG_ERROR("failed to AHardwareBuffer_unlock %d", ret);
206     return success;
207   }
208   success = true;
209
210   return success;
211 }
212
213 void NativeImageSourceAndroid::SetSource(Any source)
214 {
215   if(mPixmap)
216   {
217     mOwnPixmap = false;
218
219     AHardwareBuffer_release(mPixmap);
220     mPixmap = NULL;
221   }
222
223   mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(source));
224
225   if(mPixmap)
226   {
227     // we don't own the pixmap
228     mOwnPixmap = false;
229
230     // find out the pixmap width / height and color depth
231     GetPixmapDetails();
232   }
233 }
234
235 bool NativeImageSourceAndroid::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
236 {
237   return true;
238 }
239
240 bool NativeImageSourceAndroid::CreateResource()
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(uint16_t& width, uint16_t& height, uint16_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()
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 } // namespace Adaptor
405
406 } // namespace Internal
407
408 } // namespace Dali