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