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