2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "pixmap-image-impl.h"
23 #include <X11/Xutil.h>
25 #include <dali/integration-api/debug.h>
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>
42 using Dali::Integration::PixelBuffer;
44 // Pieces needed to save compressed images (temporary location while plumbing):
49 * Free an allocated XImage on destruction.
53 XImageJanitor( XImage* const pXImage ) : mXImage( pXImage )
55 DALI_ASSERT_DEBUG(pXImage != 0 && "Null pointer to XImage.");
62 if( !XDestroyImage(mXImage) )
64 DALI_ASSERT_DEBUG("XImage deallocation failure");
68 XImage* const mXImage;
70 XImageJanitor( const XImageJanitor& rhs );
71 XImageJanitor& operator = ( const XImageJanitor& rhs );
75 PixmapImage* PixmapImage::New(unsigned int width, unsigned int height, Dali::PixmapImage::ColorDepth depth, Any pixmap )
77 PixmapImage* image = new PixmapImage( width, height, depth, pixmap );
78 DALI_ASSERT_DEBUG( image && "PixmapImage allocation failed." );
80 // 2nd phase construction
81 if(image) //< Defensive in case we ever compile without exceptions.
89 PixmapImage::PixmapImage( unsigned int width, unsigned int height, Dali::PixmapImage::ColorDepth depth, Any pixmap )
94 mPixelFormat( Pixel::RGB888 ),
97 mEglImageExtensions( NULL )
99 DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
100 EglFactory& eglFactory = Adaptor::GetImplementation( Adaptor::Get() ).GetEGLFactory();
101 mEglImageExtensions = eglFactory.GetImageExtensions();
102 DALI_ASSERT_DEBUG( mEglImageExtensions );
105 mPixmap = GetPixmapFromAny(pixmap);
108 void PixmapImage::Initialize()
110 // if pixmap has been created outside of X11 Image we can return
113 // we don't own the pixmap
116 // find out the pixmap width / height and color depth
121 // get the pixel depth
122 int depth = GetPixelDepth(mColorDepth);
124 // set the pixel format
125 SetPixelFormat(depth);
127 mPixmap = ecore_x_pixmap_new( 0, mWidth, mHeight, depth );
131 PixmapImage::~PixmapImage()
133 if (mOwnPixmap && mPixmap)
135 ecore_x_pixmap_free(mPixmap);
139 bool PixmapImage::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
141 DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
142 bool success = false;
146 // Open a display connection
147 Display* displayConnection = XOpenDisplay( 0 );
149 XImageJanitor xImageJanitor( XGetImage( displayConnection,
151 0, 0, // x,y of subregion to extract.
152 width, height, // of suregion to extract.
155 XImage* const pXImage = xImageJanitor.mXImage;
156 DALI_ASSERT_DEBUG(pXImage && "XImage (from pixmap) could not be retrieved from the server");
159 DALI_LOG_ERROR("Could not retrieve Ximage.");
163 switch(pXImage->depth)
165 // Note, depth is a logical value. On target the framebuffer is still 32bpp
166 // (see pXImage->bits_per_pixel) so we go through XGetPixel() and swizzle.
167 // Note, this could be the default, fallback case for all depths if *pXImage
168 // didn't have blank RGB masks (X bug), but we have to hardcode the masks and
172 pixelFormat = Pixel::RGB888;
173 pixbuf.resize(width*height*3);
174 unsigned char* bufPtr = &pixbuf[0];
176 for(unsigned y = height-1; y < height; --y)
178 for(unsigned x = 0; x < width; ++x, bufPtr+=3)
180 const unsigned pixel = XGetPixel(pXImage,x,y);
183 const unsigned blue = pixel & 0xFFU;
184 const unsigned green = (pixel >> 8) & 0xFFU;
185 const unsigned red = (pixel >> 16) & 0xFFU;
199 // Sweep through the image, doing a vertical flip, but handling each scanline as
200 // an inlined intrinsic/builtin memcpy (should be fast):
201 pixbuf.resize(width*height*4);
202 unsigned * bufPtr = reinterpret_cast<unsigned *>(&pixbuf[0]);
203 const unsigned xDataLineSkip = pXImage->bytes_per_line;
204 const size_t copy_count = width * 4;
205 pixelFormat = Pixel::BGRA8888;
207 for(unsigned y = height-1; y < height; --y, bufPtr += width)
209 const char * const in = pXImage->data + xDataLineSkip * y;
211 // Copy a whole scanline at a time:
212 DALI_ASSERT_DEBUG( size_t( bufPtr ) >= size_t( &pixbuf[0] ));
213 DALI_ASSERT_DEBUG( reinterpret_cast<size_t>( bufPtr ) + copy_count <= reinterpret_cast<size_t>( &pixbuf[pixbuf.size()] ) );
214 DALI_ASSERT_DEBUG( in >= pXImage->data );
215 DALI_ASSERT_DEBUG( in + copy_count <= pXImage->data + xDataLineSkip * height );
216 __builtin_memcpy( bufPtr, in, copy_count );
222 DALI_LOG_ERROR("XImage has null data pointer.");
226 // Make a case for 16 bit modes especially to remember that the only reason we don't support them is a bug in X:
229 DALI_ASSERT_DEBUG(pXImage->red_mask && pXImage->green_mask && pXImage->blue_mask && "No image masks mean 16 bit modes are not possible.");
230 ///! If the above assert doesn't fail in a debug build, the X bug may have been fixed, so revisit this function.
231 ///! No break, fall through to the general unsupported format warning below.
235 DALI_LOG_WARNING("Pixmap has unsupported bit-depth for getting pixels: %u", pXImage->depth);
241 DALI_LOG_ERROR("Failed to get pixels from PixmapImage.");
247 // Close the display connection
248 XCloseDisplay( displayConnection );
253 bool PixmapImage::EncodeToFile(const std::string& filename) const
255 std::vector< unsigned char > pixbuf;
256 unsigned int width(0), height(0);
257 Pixel::Format pixelFormat;
259 if(GetPixels(pixbuf, width, height, pixelFormat))
261 return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
266 bool PixmapImage::GlExtensionCreate()
268 // if the image existed previously delete it.
269 if (mEglImageKHR != NULL)
271 GlExtensionDestroy();
274 // casting from an unsigned int to a void *, which should then be cast back
275 // to an unsigned int in the driver.
276 EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mPixmap);
278 mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
280 return mEglImageKHR != NULL;
283 void PixmapImage::GlExtensionDestroy()
285 mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
290 unsigned int PixmapImage::TargetTexture()
292 mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
297 int PixmapImage::GetPixelDepth(Dali::PixmapImage::ColorDepth depth) const
301 case Dali::PixmapImage::COLOR_DEPTH_DEFAULT:
303 // Get the default screen depth
304 return ecore_x_default_depth_get(ecore_x_display_get(), ecore_x_default_screen_get());
306 case Dali::PixmapImage::COLOR_DEPTH_8:
310 case Dali::PixmapImage::COLOR_DEPTH_16:
314 case Dali::PixmapImage::COLOR_DEPTH_24:
318 case Dali::PixmapImage::COLOR_DEPTH_32:
324 DALI_ASSERT_DEBUG(0 && "unknown color enum");
330 void PixmapImage::SetPixelFormat(int depth)
332 // store the pixel format based on the depth
337 mPixelFormat = Pixel::A8;
342 mPixelFormat = Pixel::RGB565;
347 mPixelFormat = Pixel::RGBA8888;
353 mPixelFormat = Pixel::RGB888;
359 Ecore_X_Pixmap PixmapImage::GetPixmapFromAny(Any pixmap) const
366 // see if it is of type x11 pixmap
367 if (pixmap.GetType() == typeid (Pixmap))
369 // get the x pixmap type
370 Pixmap xpixmap = AnyCast<Pixmap>(pixmap);
372 // cast it to a ecore pixmap type
373 return static_cast<Ecore_X_Pixmap>(xpixmap);
377 return AnyCast<Ecore_X_Pixmap>(pixmap);
381 void PixmapImage::GetPixmapDetails()
385 // get the width, height and depth
386 ecore_x_pixmap_geometry_get(mPixmap, &x, &y, (int*)&mWidth, (int*)&mHeight);
388 // set the pixel format
389 SetPixelFormat(ecore_x_pixmap_depth_get(mPixmap));
392 } // namespace Adaptor
394 } // namespace internal