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 "native-image-source-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 NativeImageSource* NativeImageSource::New(unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
77 NativeImageSource* image = new NativeImageSource( width, height, depth, nativeImageSource );
78 DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
80 // 2nd phase construction
81 if(image) //< Defensive in case we ever compile without exceptions.
89 NativeImageSource::NativeImageSource( unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
94 mBlendingRequired( false ),
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(nativeImageSource);
108 void NativeImageSource::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 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 );
131 mPixmap = ecore_x_pixmap_new( 0, mWidth, mHeight, depth );
135 NativeImageSource::~NativeImageSource()
137 if (mOwnPixmap && mPixmap)
139 ecore_x_pixmap_free(mPixmap);
143 Any NativeImageSource::GetNativeImageSource() const
145 // return ecore x11 type
149 bool NativeImageSource::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
151 DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
152 bool success = false;
156 // Open a display connection
157 Display* displayConnection = XOpenDisplay( 0 );
159 XImageJanitor xImageJanitor( XGetImage( displayConnection,
161 0, 0, // x,y of subregion to extract.
162 width, height, // of suregion to extract.
165 XImage* const pXImage = xImageJanitor.mXImage;
166 DALI_ASSERT_DEBUG(pXImage && "XImage (from pixmap) could not be retrieved from the server");
169 DALI_LOG_ERROR("Could not retrieve Ximage.");
173 switch(pXImage->depth)
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
182 pixelFormat = Pixel::RGB888;
183 pixbuf.resize(width*height*3);
184 unsigned char* bufPtr = &pixbuf[0];
186 for(unsigned y = height-1; y < height; --y)
188 for(unsigned x = 0; x < width; ++x, bufPtr+=3)
190 const unsigned pixel = XGetPixel(pXImage,x,y);
193 const unsigned blue = pixel & 0xFFU;
194 const unsigned green = (pixel >> 8) & 0xFFU;
195 const unsigned red = (pixel >> 16) & 0xFFU;
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 = width * 4;
215 pixelFormat = Pixel::BGRA8888;
217 for(unsigned y = height-1; y < height; --y, bufPtr += width)
219 const char * const in = pXImage->data + xDataLineSkip * y;
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 );
232 DALI_LOG_ERROR("XImage has null data pointer.");
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:
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.
245 DALI_LOG_WARNING("Pixmap has unsupported bit-depth for getting pixels: %u", pXImage->depth);
251 DALI_LOG_ERROR("Failed to get pixels from NativeImageSource.");
257 // Close the display connection
258 XCloseDisplay( displayConnection );
263 bool NativeImageSource::EncodeToFile(const std::string& filename) const
265 std::vector< unsigned char > pixbuf;
266 unsigned int width(0), height(0);
267 Pixel::Format pixelFormat;
269 if(GetPixels(pixbuf, width, height, pixelFormat))
271 return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
276 void NativeImageSource::SetSource( Any source )
278 mPixmap = GetPixmapFromAny( source );
282 // we don't own the pixmap
285 // find out the pixmap width / height and color depth
290 bool NativeImageSource::GlExtensionCreate()
292 // if the image existed previously delete it.
293 if (mEglImageKHR != NULL)
295 GlExtensionDestroy();
298 // casting from an unsigned int to a void *, which should then be cast back
299 // to an unsigned int in the driver.
300 EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mPixmap);
302 mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
304 return mEglImageKHR != NULL;
307 void NativeImageSource::GlExtensionDestroy()
309 mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
314 unsigned int NativeImageSource::TargetTexture()
316 mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
321 int NativeImageSource::GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const
325 case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
327 // Get the default screen depth
328 return ecore_x_default_depth_get(ecore_x_display_get(), ecore_x_default_screen_get());
330 case Dali::NativeImageSource::COLOR_DEPTH_8:
334 case Dali::NativeImageSource::COLOR_DEPTH_16:
338 case Dali::NativeImageSource::COLOR_DEPTH_24:
342 case Dali::NativeImageSource::COLOR_DEPTH_32:
348 DALI_ASSERT_DEBUG(0 && "unknown color enum");
354 Ecore_X_Pixmap NativeImageSource::GetPixmapFromAny(Any pixmap) const
361 // see if it is of type x11 pixmap
362 if (pixmap.GetType() == typeid (Pixmap))
364 // get the x pixmap type
365 Pixmap xpixmap = AnyCast<Pixmap>(pixmap);
367 // cast it to a ecore pixmap type
368 return static_cast<Ecore_X_Pixmap>(xpixmap);
372 return AnyCast<Ecore_X_Pixmap>(pixmap);
376 void NativeImageSource::GetPixmapDetails()
380 // get the width, height and depth
381 ecore_x_pixmap_geometry_get(mPixmap, &x, &y, (int*)&mWidth, (int*)&mHeight);
383 // set whether blending is required according to pixel format based on the depth
384 /* default pixel format is RGB888
385 If depth = 8, Pixel::A8;
386 If depth = 16, Pixel::RGB565;
387 If depth = 32, Pixel::RGBA8888 */
388 int depth = ecore_x_pixmap_depth_get(mPixmap);
389 mBlendingRequired = ( depth == 32 || depth == 8 );
392 } // namespace Adaptor
394 } // namespace internal