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