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