384844db97f6fdd03abcf0dac969324e62deb5ba
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / ubuntu-x11 / native-image-source-impl-x.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 // CLASS HEADER
19 #include <dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/internal/system/linux/dali-ecore-x.h>
23 #include <X11/Xutil.h>
24 #include <X11/Xlib.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL INCLUDES
28 #include <dali/internal/graphics/common/egl-image-extensions.h>
29 #include <dali/internal/graphics/gles/egl-graphics.h>
30 #include <dali/internal/adaptor/common/adaptor-impl.h>
31 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
32
33 namespace Dali
34 {
35
36 namespace Internal
37 {
38
39 namespace Adaptor
40 {
41 using Dali::Integration::PixelBuffer;
42
43 // Pieces needed to save compressed images (temporary location while plumbing):
44 namespace
45 {
46
47   /**
48    * Free an allocated XImage on destruction.
49    */
50   struct XImageJanitor
51   {
52     XImageJanitor( XImage* const  pXImage ) : mXImage( pXImage )
53     {
54       DALI_ASSERT_DEBUG(pXImage != 0 && "Null pointer to XImage.");
55     }
56
57     ~XImageJanitor()
58     {
59       if( mXImage )
60       {
61         if( !XDestroyImage(mXImage) )
62         {
63           DALI_LOG_ERROR("XImage deallocation failure");
64         }
65       }
66     }
67     XImage* const  mXImage;
68   private:
69     XImageJanitor( const XImageJanitor& rhs );
70     XImageJanitor& operator = ( const XImageJanitor& rhs );
71   };
72 }
73
74 NativeImageSourceX* NativeImageSourceX::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
75 {
76   NativeImageSourceX* image = new NativeImageSourceX( width, height, depth, nativeImageSource );
77   DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
78
79   // 2nd phase construction
80   if(image) //< Defensive in case we ever compile without exceptions.
81   {
82     image->Initialize();
83   }
84
85   return image;
86 }
87
88 NativeImageSourceX::NativeImageSourceX( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
89 : mWidth( width ),
90   mHeight( height ),
91   mOwnPixmap( true ),
92   mPixmap( 0 ),
93   mBlendingRequired( false ),
94   mColorDepth( depth ),
95   mEglImageKHR( NULL ),
96   mEglImageExtensions( NULL )
97 {
98   DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
99
100   GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
101   auto eglGraphics = static_cast<EglGraphics *>(graphics);
102
103   mEglImageExtensions = eglGraphics->GetImageExtensions();
104
105   DALI_ASSERT_DEBUG( mEglImageExtensions );
106
107   // assign the pixmap
108   mPixmap = GetPixmapFromAny(nativeImageSource);
109 }
110
111 void NativeImageSourceX::Initialize()
112 {
113   // if pixmap has been created outside of X11 Image we can return
114   if (mPixmap)
115   {
116     // we don't own the pixmap
117     mOwnPixmap = false;
118
119     // find out the pixmap width / height and color depth
120     GetPixmapDetails();
121     return;
122   }
123
124   // get the pixel depth
125   int depth = GetPixelDepth(mColorDepth);
126
127   // set whether blending is required according to pixel format based on the depth
128   /* default pixel format is RGB888
129      If depth = 8, Pixel::A8;
130      If depth = 16, Pixel::RGB565;
131      If depth = 32, Pixel::RGBA8888 */
132   mBlendingRequired = ( depth == 32 || depth == 8 );
133
134   mPixmap = ecore_x_pixmap_new( 0, mWidth, mHeight, depth );
135   ecore_x_sync();
136 }
137
138 NativeImageSourceX::~NativeImageSourceX()
139 {
140   if (mOwnPixmap && mPixmap)
141   {
142     ecore_x_pixmap_free(mPixmap);
143   }
144 }
145
146 Any NativeImageSourceX::GetNativeImageSource() const
147 {
148   // return ecore x11 type
149   return Any(mPixmap);
150 }
151
152 bool NativeImageSourceX::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
153 {
154   DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
155   bool success = false;
156   width  = mWidth;
157   height = mHeight;
158
159   // Open a display connection
160   Display* displayConnection = XOpenDisplay( 0 );
161
162   XImageJanitor xImageJanitor( XGetImage( displayConnection,
163                                           mPixmap,
164                                           0, 0, // x,y of subregion to extract.
165                                           width, height, // of subregion to extract.
166                                           0xFFFFFFFF,
167                                           ZPixmap ) );
168   XImage* const  pXImage = xImageJanitor.mXImage;
169   DALI_ASSERT_DEBUG(pXImage && "XImage (from pixmap) could not be retrieved from the server");
170   if(!pXImage)
171   {
172     DALI_LOG_ERROR("Could not retrieve Ximage.\n");
173   }
174   else
175   {
176     switch(pXImage->depth)
177     {
178       // Note, depth is a logical value. On target the framebuffer is still 32bpp
179       // (see pXImage->bits_per_pixel) so we go through XGetPixel() and swizzle.
180       // Note, this could be the default, fallback case for all depths if *pXImage
181       // didn't have blank RGB masks (X bug), but we have to hardcode the masks and
182       // shifts instead.
183       case 24:
184       {
185         pixelFormat = Pixel::RGB888;
186         pixbuf.resize(width*height*3);
187         unsigned char* bufPtr = &pixbuf[0];
188
189         for(unsigned y = height-1; y < height; --y)
190         {
191           for(unsigned x = 0; x < width; ++x, bufPtr+=3)
192           {
193             const unsigned pixel = XGetPixel(pXImage,x,y);
194
195             // store as RGB
196             const unsigned blue  =  pixel & 0xFFU;
197             const unsigned green = (pixel >> 8)  & 0xFFU;
198             const unsigned red   = (pixel >> 16) & 0xFFU;
199
200             *bufPtr = red;
201             *(bufPtr+1) = green;
202             *(bufPtr+2) = blue;
203           }
204         }
205         success = true;
206         break;
207       }
208       case 32:
209       {
210         if(pXImage->data)
211         {
212           // Sweep through the image, doing a vertical flip, but handling each scanline as
213           // an inlined intrinsic/builtin memcpy (should be fast):
214           pixbuf.resize(width*height*4);
215           unsigned * bufPtr = reinterpret_cast<unsigned *>(&pixbuf[0]);
216           const unsigned xDataLineSkip = pXImage->bytes_per_line;
217           const size_t copy_count = static_cast< size_t >( width ) * 4;
218           pixelFormat = Pixel::BGRA8888;
219
220           for(unsigned y = height-1; y < height; --y, bufPtr += width)
221           {
222             const char * const in = pXImage->data + xDataLineSkip * y;
223
224             // Copy a whole scanline at a time:
225             DALI_ASSERT_DEBUG( size_t( bufPtr ) >= size_t( &pixbuf[0] ));
226             DALI_ASSERT_DEBUG( reinterpret_cast<size_t>( bufPtr ) + copy_count <= reinterpret_cast<size_t>( &pixbuf[pixbuf.size()] ) );
227             DALI_ASSERT_DEBUG( in >= pXImage->data );
228             DALI_ASSERT_DEBUG( in + copy_count <= pXImage->data + xDataLineSkip * height );
229             __builtin_memcpy( bufPtr, in, copy_count );
230           }
231           success = true;
232         }
233         else
234         {
235           DALI_LOG_ERROR("XImage has null data pointer.\n");
236         }
237         break;
238       }
239       // Make a case for 16 bit modes especially to remember that the only reason we don't support them is a bug in X:
240       case 16:
241       {
242         DALI_ASSERT_DEBUG(pXImage->red_mask && pXImage->green_mask && pXImage->blue_mask && "No image masks mean 16 bit modes are not possible.");
243         ///! If the above assert doesn't fail in a debug build, the X bug may have been fixed, so revisit this function.
244         ///! No break, fall through to the general unsupported format warning below.
245       }
246       default:
247       {
248         DALI_LOG_WARNING("Pixmap has unsupported bit-depth for getting pixels: %u\n", pXImage->depth);
249       }
250     }
251   }
252   if(!success)
253   {
254     DALI_LOG_ERROR("Failed to get pixels from NativeImageSource.\n");
255     pixbuf.resize(0);
256     width = 0;
257     height = 0;
258   }
259
260   // Close the display connection
261   XCloseDisplay( displayConnection );
262
263   return success;
264 }
265
266 void NativeImageSourceX::SetSource( Any source )
267 {
268   mPixmap = GetPixmapFromAny( source );
269
270   if (mPixmap)
271   {
272     // we don't own the pixmap
273     mOwnPixmap = false;
274
275     // find out the pixmap width / height and color depth
276     GetPixmapDetails();
277   }
278 }
279
280 bool NativeImageSourceX::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
281 {
282   return true;
283 }
284
285 bool NativeImageSourceX::CreateResource()
286 {
287   // if the image existed previously delete it.
288   if (mEglImageKHR != NULL)
289   {
290     DestroyResource();
291   }
292
293   // casting from an unsigned int to a void *, which should then be cast back
294   // to an unsigned int in the driver.
295   EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mPixmap);
296
297   mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
298
299   return mEglImageKHR != NULL;
300 }
301
302 void NativeImageSourceX::DestroyResource()
303 {
304   mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
305
306   mEglImageKHR = NULL;
307 }
308
309 uint32_t NativeImageSourceX::TargetTexture()
310 {
311   mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
312
313   return 0;
314 }
315
316 void NativeImageSourceX::PrepareTexture()
317 {
318 }
319
320 int NativeImageSourceX::GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const
321 {
322   switch (depth)
323   {
324     case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
325     {
326       // Get the default screen depth
327       return ecore_x_default_depth_get(ecore_x_display_get(), ecore_x_default_screen_get());
328     }
329     case Dali::NativeImageSource::COLOR_DEPTH_8:
330     {
331       return 8;
332     }
333     case Dali::NativeImageSource::COLOR_DEPTH_16:
334     {
335       return 16;
336     }
337     case Dali::NativeImageSource::COLOR_DEPTH_24:
338     {
339       return 24;
340     }
341     case Dali::NativeImageSource::COLOR_DEPTH_32:
342     {
343       return 32;
344     }
345     default:
346     {
347       DALI_ASSERT_DEBUG(0 && "unknown color enum");
348       return 0;
349     }
350   }
351 }
352
353 int NativeImageSourceX::GetTextureTarget() const
354 {
355   return GL_TEXTURE_2D;
356 }
357
358 const char* NativeImageSourceX::GetCustomFragmentPrefix() const
359 {
360   return nullptr;
361 }
362
363 const char* NativeImageSourceX::GetCustomSamplerTypename() const
364 {
365   return nullptr;
366 }
367
368 Any NativeImageSourceX::GetNativeImageHandle() const
369 {
370   return Any(mPixmap);
371 }
372
373 bool NativeImageSourceX::SourceChanged() const
374 {
375   return false;
376 }
377
378 Ecore_X_Pixmap NativeImageSourceX::GetPixmapFromAny(Any pixmap) const
379 {
380   if (pixmap.Empty())
381   {
382     return 0;
383   }
384
385   // see if it is of type x11 pixmap
386   if (pixmap.GetType() == typeid (Pixmap))
387   {
388     // get the x pixmap type
389     Pixmap xpixmap = AnyCast<Pixmap>(pixmap);
390
391     // cast it to a ecore pixmap type
392     return static_cast<Ecore_X_Pixmap>(xpixmap);
393   }
394   else
395   {
396     return AnyCast<Ecore_X_Pixmap>(pixmap);
397   }
398 }
399
400 void NativeImageSourceX::GetPixmapDetails()
401 {
402   int x, y;
403
404   // get the width, height and depth
405   ecore_x_pixmap_geometry_get( mPixmap, &x, &y, reinterpret_cast< int* >( &mWidth ), reinterpret_cast< int* >( &mHeight ) );
406
407   // set whether blending is required according to pixel format based on the depth
408   /* default pixel format is RGB888
409      If depth = 8, Pixel::A8;
410      If depth = 16, Pixel::RGB565;
411      If depth = 32, Pixel::RGBA8888 */
412   int depth = ecore_x_pixmap_depth_get(mPixmap);
413   mBlendingRequired = ( depth == 32 || depth == 8 );
414 }
415
416 uint8_t* NativeImageSourceX::AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride )
417 {
418   return NULL;
419 }
420
421
422 bool NativeImageSourceX::ReleaseBuffer()
423 {
424   return false;
425 }
426
427 } // namespace Adaptor
428
429 } // namespace internal
430
431 } // namespace Dali