Updated all code to new format
[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
38 {
39 const char* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
40 const char* SAMPLER_TYPE    = "samplerExternalOES";
41 } // namespace
42
43 namespace Dali
44 {
45 namespace Internal
46 {
47 namespace Adaptor
48 {
49 using Dali::Integration::PixelBuffer;
50
51 NativeImageSourceAndroid* NativeImageSourceAndroid::New(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
52 {
53   NativeImageSourceAndroid* image = new NativeImageSourceAndroid(width, height, depth, nativeImageSource);
54   DALI_ASSERT_DEBUG(image && "NativeImageSource allocation failed.");
55
56   // 2nd phase construction
57   if(image) //< Defensive in case we ever compile without exceptions.
58   {
59     image->Initialize();
60   }
61
62   return image;
63 }
64
65 NativeImageSourceAndroid::NativeImageSourceAndroid(uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource)
66 : mWidth(width),
67   mHeight(height),
68   mOwnPixmap(true),
69   mPixmap(NULL),
70   mBlendingRequired(false),
71   mColorDepth(depth),
72   mEglImageKHR(NULL),
73   mEglImageExtensions(NULL)
74 {
75   DALI_ASSERT_ALWAYS(Adaptor::IsAvailable());
76
77   GraphicsInterface* graphics    = &(Adaptor::GetImplementation(Adaptor::Get()).GetGraphicsInterface());
78   auto               eglGraphics = static_cast<EglGraphics*>(graphics);
79
80   mEglImageExtensions = eglGraphics->GetImageExtensions();
81
82   DALI_ASSERT_DEBUG(mEglImageExtensions);
83
84   // assign the pixmap
85   mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(nativeImageSource));
86   if(!mPixmap)
87   {
88     AHardwareBuffer_Desc bufferDescription;
89     memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
90     bufferDescription.width  = width;
91     bufferDescription.height = height;
92     bufferDescription.layers = 1;
93     bufferDescription.usage  = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
94     switch(mColorDepth)
95     {
96       case Dali::NativeImageSource::COLOR_DEPTH_32:
97       case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
98         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
99         break;
100       case Dali::NativeImageSource::COLOR_DEPTH_24:
101         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
102         break;
103       case Dali::NativeImageSource::COLOR_DEPTH_16:
104         bufferDescription.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
105         break;
106       case Dali::NativeImageSource::COLOR_DEPTH_8:
107         bufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB;
108         break;
109     }
110
111     int ret = AHardwareBuffer_allocate(&bufferDescription, &mPixmap);
112     if(ret)
113     {
114       DALI_LOG_ERROR("Failed to allocate AHardwareBuffer %d", ret);
115     }
116
117     mOwnPixmap = true;
118   }
119 }
120
121 void NativeImageSourceAndroid::Initialize()
122 {
123   if(mPixmap && !mOwnPixmap)
124   {
125     AHardwareBuffer_acquire(mPixmap);
126
127     // find out the pixmap width / height and color depth
128     GetPixmapDetails();
129   }
130 }
131
132 NativeImageSourceAndroid::~NativeImageSourceAndroid()
133 {
134   AHardwareBuffer_release(mPixmap);
135   mPixmap = NULL;
136 }
137
138 Any NativeImageSourceAndroid::GetNativeImageSource() const
139 {
140   return Any(mPixmap);
141 }
142
143 bool NativeImageSourceAndroid::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
144 {
145   DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
146   bool success = false;
147
148   width  = mWidth;
149   height = mHeight;
150
151   AHardwareBuffer_Desc bufferDescription;
152   memset(&bufferDescription, 0, sizeof(AHardwareBuffer_Desc));
153   AHardwareBuffer_describe(mPixmap, &bufferDescription);
154   switch(bufferDescription.format)
155   {
156     case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
157       pixelFormat = Pixel::Format::RGBA8888;
158       break;
159     case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
160       pixelFormat = Pixel::Format::RGB8888;
161       break;
162     case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
163       pixelFormat = Pixel::Format::RGB888;
164       break;
165     case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
166       pixelFormat = Pixel::Format::RGB565;
167       break;
168     case AHARDWAREBUFFER_FORMAT_BLOB:
169     default:
170       pixelFormat = Pixel::Format::A8;
171       break;
172   }
173
174   void* buffer = NULL;
175   int   ret    = AHardwareBuffer_lock(mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer);
176   if(ret != 0)
177   {
178     DALI_LOG_ERROR("Failed to AHardwareBuffer_lock %d", ret);
179     return success;
180   }
181
182   uint32_t pixelBytes = GetBytesPerPixel(pixelFormat);
183   if(bufferDescription.stride < (pixelBytes * bufferDescription.width))
184   {
185     //On Android device, bufferDescription.stride doesn't seem to mean (width * pixelbytes)
186     //in an actual case, (AHardwareBuffer_Desc) bufferDescription = (width = 1080, height = 1060, layers = 1, format = 1, usage = 306, stride = 1088, rfu0 = 0, rfu1 = 0)
187     //deal with situation
188     uint32_t dstStride = pixelBytes * bufferDescription.width;
189     uint32_t srcStride = pixelBytes * bufferDescription.stride;
190     uint32_t size      = dstStride * bufferDescription.height;
191     pixbuf.resize(size);
192     //copy each row over
193     const unsigned char* ptrSrc = reinterpret_cast<const unsigned char*>(buffer);
194     unsigned char*       ptrDst = pixbuf.data();
195     for(int y = 0; y < bufferDescription.height; y++, ptrSrc += srcStride, ptrDst += dstStride)
196     {
197       memcpy(ptrDst, ptrSrc, dstStride);
198     }
199   }
200   else
201   {
202     uint32_t size = bufferDescription.stride * bufferDescription.height;
203     pixbuf.resize(size);
204     memcpy(pixbuf.data(), buffer, size);
205   }
206
207   ret = AHardwareBuffer_unlock(mPixmap, NULL);
208   if(ret != 0)
209   {
210     DALI_LOG_ERROR("failed to AHardwareBuffer_unlock %d", ret);
211     return success;
212   }
213   success = true;
214
215   return success;
216 }
217
218 void NativeImageSourceAndroid::SetSource(Any source)
219 {
220   if(mPixmap)
221   {
222     mOwnPixmap = false;
223
224     AHardwareBuffer_release(mPixmap);
225     mPixmap = NULL;
226   }
227
228   mPixmap = static_cast<AHardwareBuffer*>(GetPixmapFromAny(source));
229
230   if(mPixmap)
231   {
232     // we don't own the pixmap
233     mOwnPixmap = false;
234
235     // find out the pixmap width / height and color depth
236     GetPixmapDetails();
237   }
238 }
239
240 bool NativeImageSourceAndroid::IsColorDepthSupported(Dali::NativeImageSource::ColorDepth colorDepth)
241 {
242   return true;
243 }
244
245 bool NativeImageSourceAndroid::CreateResource()
246 {
247   // if the image existed previously delete it.
248   if(mEglImageKHR != NULL)
249   {
250     DestroyResource();
251   }
252
253   DALI_ASSERT_ALWAYS(mPixmap);
254   EGLClientBuffer eglBuffer = eglGetNativeClientBufferANDROID(mPixmap);
255   switch(eglGetError())
256   {
257     case EGL_SUCCESS:
258     {
259       break;
260     }
261     case EGL_BAD_PARAMETER:
262     {
263       DALI_LOG_ERROR("EGL_BAD_PARAMETER: bad pixmap parameter\n");
264       break;
265     }
266     case EGL_BAD_ACCESS:
267     {
268       DALI_LOG_ERROR("EGL_BAD_ACCESS: bad access to pixmap\n");
269       break;
270     }
271     case EGL_BAD_ALLOC:
272     {
273       DALI_LOG_ERROR("EGL_BAD_ALLOC: Insufficient memory is available\n");
274       break;
275     }
276     default:
277     {
278       DALI_LOG_ERROR("eglGetNativeClientBufferANDROID error\n");
279       break;
280     }
281   }
282
283   DALI_ASSERT_ALWAYS(eglBuffer);
284   mEglImageKHR = mEglImageExtensions->CreateImageKHR(eglBuffer);
285
286   return mEglImageKHR != NULL;
287 }
288
289 void NativeImageSourceAndroid::DestroyResource()
290 {
291   mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
292
293   mEglImageKHR = NULL;
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 const char* NativeImageSourceAndroid::GetCustomFragmentPrefix() const
313 {
314   return nullptr;
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 } // namespace Adaptor
400
401 } // namespace Internal
402
403 } // namespace Dali