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