/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //#define DIRECT_ENABLE_DEBUG #include #include #include #include #include #include #include #include #include #include "x11.h" #include "glx_surface_pool.h" #include "x11_surface_pool.h" D_DEBUG_DOMAIN( GLX_Surfaces, "GLX/Surfaces", "GLX Surface Pool" ); D_DEBUG_DOMAIN( GLX_Pixmaps, "GLX/Pixmaps", "GLX Surface Pool Pixmaps" ); /**********************************************************************************************************************/ typedef void (*GLXBindTexImageEXTProc) ( Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list ); typedef void (*GLXReleaseTexImageEXTProc)( Display *dpy, GLXDrawable drawable, int buffer ); typedef struct { int magic; Display *display; GLXFBConfig *configs; int num_configs; GLXFBConfig config24; Visual *visual24; GLXFBConfig config32; Visual *visual32; GLXBindTexImageEXTProc BindTexImageEXT; GLXReleaseTexImageEXTProc ReleaseTexImageEXT; DirectHash *pixmaps; /* Every thread needs its own context! */ pthread_key_t context_key; pthread_key_t context_key2; } glxPoolLocalData; typedef struct { } glxPoolData; /**********************************************************************************************************************/ static void destroy_context( void *arg ) { ThreadContext *ctx = arg; XLockDisplay( ctx->display ); glXDestroyContext( ctx->display, ctx->context ); XUnlockDisplay( ctx->display ); D_FREE( ctx ); } /**********************************************************************************************************************/ static DFBResult InitLocal( glxPoolLocalData *local, DFBX11 *x11 ) { DFBResult ret; int i; int attribs[] = { GLX_DOUBLEBUFFER, False, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_X_RENDERABLE, True, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 8, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, None }; local->display = x11->display; local->BindTexImageEXT = (GLXBindTexImageEXTProc) glXGetProcAddress( (unsigned char*) "glXBindTexImageEXT" ); if (!local->BindTexImageEXT) { D_ERROR( "glXGetProcAddress( 'glXBindTexImageEXT' ) failed!\n" ); return DFB_UNSUPPORTED; } local->ReleaseTexImageEXT = (GLXReleaseTexImageEXTProc) glXGetProcAddress( (unsigned char*) "glXReleaseTexImageEXT" ); if (!local->ReleaseTexImageEXT) { D_ERROR( "glXGetProcAddress( 'glXReleaseTexImageEXT' ) failed!\n" ); return DFB_UNSUPPORTED; } ret = direct_hash_create( 7, &local->pixmaps ); if (ret) return ret; XLockDisplay( local->display ); local->configs = glXChooseFBConfig( local->display, DefaultScreen(local->display), attribs, &local->num_configs ); D_DEBUG_AT( GLX_Surfaces, " -> found %d configs\n", local->num_configs ); for (i=0; inum_configs; i++) { int depth; XVisualInfo *info = glXGetVisualFromFBConfig( local->display, local->configs[i] ); glXGetFBConfigAttrib( local->display, local->configs[i], GLX_DEPTH_SIZE, &depth ); D_DEBUG_AT( GLX_Surfaces, " [%2d] ID 0x%02lx, depth %d, RGB 0x%06lx/0x%06lx/0x%06lx {%d}, class %d, z %d\n", i, info->visualid, info->depth, info->red_mask, info->green_mask, info->blue_mask, info->bits_per_rgb, info->class, depth ); if (depth >= 8 && info->class == TrueColor) { switch (info->depth) { case 32: local->config32 = local->configs[i]; local->visual32 = info->visual; break; case 24: local->config24 = local->configs[i]; local->visual24 = info->visual; break; } } } if (!local->config24 || !local->config32) { D_ERROR( "GLX/Surfaces: Could not find useful visuals!\n" ); direct_hash_destroy( local->pixmaps ); XUnlockDisplay( local->display ); return DFB_UNSUPPORTED; } XVisualInfo *info24 = glXGetVisualFromFBConfig( local->display, local->config24 ); XVisualInfo *info32 = glXGetVisualFromFBConfig( local->display, local->config32 ); D_INFO( "GLX/Surfaces: Using visual 0x%02lx (24bit) and 0x%02lx (32bit)\n", info24->visualid, info32->visualid ); XUnlockDisplay( local->display ); pthread_key_create( &local->context_key, destroy_context ); pthread_key_create( &local->context_key2, destroy_context ); D_MAGIC_SET( local, glxPoolLocalData ); return DFB_OK; } static DFBResult GetLocalPixmap( glxPoolLocalData *local, glxAllocationData *alloc, CoreSurfaceAllocation *allocation, LocalPixmap **ret_pixmap ) { LocalPixmap *pixmap; CoreSurface *surface; CoreSurfaceBuffer *buffer; surface = allocation->surface; D_MAGIC_ASSERT( surface, CoreSurface ); buffer = allocation->buffer; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); pixmap = direct_hash_lookup( local->pixmaps, alloc->pixmap ); if (!pixmap) { pixmap = D_CALLOC( 1, sizeof(LocalPixmap) ); if (!pixmap) return D_OOM(); pixmap->pixmap = alloc->pixmap; pixmap->config = (alloc->depth == 24) ? local->config24 : local->config32; /* * Create a GLXPixmap */ int attribs[] = { GLX_TEXTURE_FORMAT_EXT, (alloc->depth == 24) ? GLX_TEXTURE_FORMAT_RGB_EXT : GLX_TEXTURE_FORMAT_RGBA_EXT, GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_RECTANGLE_EXT, None }; XLockDisplay( local->display ); pixmap->drawable = glXCreatePixmap( local->display, pixmap->config, alloc->pixmap, attribs ); if (!pixmap->drawable) { D_ERROR( "GLX/Surfaces: Could not create %dx%d (depth %d) GLXPixmap!\n", surface->config.size.w, surface->config.size.h, alloc->depth ); XUnlockDisplay( local->display ); D_FREE( pixmap ); return DFB_FAILURE; } D_DEBUG_AT( GLX_Surfaces, " -> drawable 0x%lx\n", pixmap->drawable ); /* * Create a GC (for writing to pixmap) */ pixmap->gc = XCreateGC( local->display, alloc->pixmap, 0, NULL ); D_DEBUG_AT( GLX_Surfaces, " -> gc 0x%lx\n", pixmap->drawable ); XUnlockDisplay( local->display ); /* * Create a texture object */ glGenTextures( 1, &pixmap->buffer.texture ); D_DEBUG_AT( GLX_Pixmaps, " NEW GLXPixmap 0x%lx for 0x%lx [%4dx%4d] %-10s\n", pixmap->drawable, alloc->pixmap, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(buffer->format) ); D_DEBUG_AT( GLX_Surfaces, " -> GLXPixmap 0x%lx [%4dx%4d] %-10s (%u)\n", pixmap->drawable, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(buffer->format), pixmap->buffer.texture ); D_MAGIC_SET( pixmap, LocalPixmap ); D_MAGIC_SET( &pixmap->buffer, GLBufferData ); direct_hash_insert( local->pixmaps, alloc->pixmap, pixmap ); } else D_MAGIC_ASSERT( pixmap, LocalPixmap ); *ret_pixmap = pixmap; return DFB_OK; } static void ReleasePixmap( glxPoolLocalData *local, LocalPixmap *pixmap ) { D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( pixmap, LocalPixmap ); if (pixmap->bound) { D_DEBUG_AT( GLX_Pixmaps, " RELEASE 0x%08lx from %p\n", pixmap->drawable, pixmap->bound ); local->ReleaseTexImageEXT( local->display, pixmap->drawable, GLX_FRONT_EXT ); pixmap->bound = NULL; } } static void DestroyPixmap( glxPoolLocalData *local, LocalPixmap *pixmap ) { D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( pixmap, LocalPixmap ); D_DEBUG_AT( GLX_Pixmaps, " DESTROY 0x%08lx (%d)\n", pixmap->drawable, pixmap->buffer.texture ); glXWaitGL(); ReleasePixmap( local, pixmap ); glXWaitX(); glDeleteTextures( 1, &pixmap->buffer.texture ); XFreeGC( local->display, pixmap->gc ); glXDestroyPixmap( local->display, pixmap->drawable ); direct_hash_remove( local->pixmaps, pixmap->pixmap ); D_MAGIC_CLEAR( pixmap ); D_MAGIC_CLEAR( &pixmap->buffer ); D_FREE( pixmap ); } /**********************************************************************************************************************/ static int glxPoolDataSize( void ) { return sizeof(glxPoolData); } static int glxPoolLocalDataSize( void ) { return sizeof(glxPoolLocalData); } static int glxAllocationDataSize( void ) { return sizeof(glxAllocationData); } static DFBResult glxInitPool( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data, CoreSurfacePoolDescription *ret_desc ) { glxPoolLocalData *local = pool_local; DFBX11 *x11 = system_data; D_DEBUG_AT( GLX_Surfaces, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( ret_desc != NULL ); ret_desc->caps = CSPCAPS_NONE; ret_desc->access[CSAID_GPU] = CSAF_READ | CSAF_WRITE; ret_desc->types = CSTF_LAYER | CSTF_WINDOW | CSTF_CURSOR | CSTF_FONT | CSTF_SHARED | CSTF_EXTERNAL; ret_desc->priority = CSPP_DEFAULT; /* For showing our X11 window */ ret_desc->access[CSAID_LAYER0] = CSAF_READ; /* For user contexts via DirectFBGL */ ret_desc->access[CSAID_ACCEL1] = CSAF_READ | CSAF_WRITE; snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "GLX Drawables" ); return InitLocal( local, x11 ); } static DFBResult glxJoinPool( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data ) { glxPoolLocalData *local = pool_local; DFBX11 *x11 = system_data; D_DEBUG_AT( GLX_Surfaces, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); return InitLocal( local, x11 ); } static DFBResult glxDestroyPool( CoreSurfacePool *pool, void *pool_data, void *pool_local ) { D_DEBUG_AT( GLX_Surfaces, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); return DFB_OK; } static DFBResult glxLeavePool( CoreSurfacePool *pool, void *pool_data, void *pool_local ) { D_DEBUG_AT( GLX_Surfaces, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); return DFB_OK; } static DFBResult glxTestConfig( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, const CoreSurfaceConfig *config ) { glxPoolLocalData *local = pool_local; D_MAGIC_ASSERT( local, glxPoolLocalData ); if (!local->configs) return DFB_UNSUPPORTED; return DFB_OK; } static DFBResult glxAllocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { CoreSurface *surface; glxPoolLocalData *local = pool_local; glxAllocationData *alloc = alloc_data; D_DEBUG_AT( GLX_Surfaces, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); surface = buffer->surface; D_MAGIC_ASSERT( surface, CoreSurface ); XLockDisplay( local->display ); alloc->depth = DFB_COLOR_BITS_PER_PIXEL( buffer->format ) + DFB_ALPHA_BITS_PER_PIXEL( buffer->format ); /* * Create a pixmap */ alloc->pixmap = XCreatePixmap( local->display, DefaultRootWindow( local->display ), surface->config.size.w, surface->config.size.h, alloc->depth ); if (!alloc->pixmap) { D_ERROR( "GLX/Surfaces: Could not create %dx%d (depth %d) pixmap!\n", surface->config.size.w, surface->config.size.h, alloc->depth ); XUnlockDisplay( local->display ); return DFB_FAILURE; } D_DEBUG_AT( GLX_Surfaces, " -> pixmap 0x%lx\n", alloc->pixmap ); D_DEBUG_AT( GLX_Pixmaps, " NEW Pixmap 0x%lx [%4dx%4d] %-10s\n", alloc->pixmap, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(buffer->format) ); XUnlockDisplay( local->display ); /* Pseudo calculation */ dfb_surface_calc_buffer_size( surface, 8, 2, NULL, &allocation->size ); D_MAGIC_SET( alloc, glxAllocationData ); return DFB_OK; } static DFBResult glxDeallocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { LocalPixmap *pixmap; glxPoolLocalData *local = pool_local; glxAllocationData *alloc = alloc_data; D_DEBUG_AT( GLX_Surfaces, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( alloc, glxAllocationData ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); XLockDisplay( local->display ); pixmap = direct_hash_lookup( local->pixmaps, alloc->pixmap ); if (pixmap) DestroyPixmap( local, pixmap ); XFreePixmap( local->display, alloc->pixmap ); XUnlockDisplay( local->display ); D_MAGIC_CLEAR( alloc ); return DFB_OK; } static DFBResult glxLock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { DFBResult ret; LocalPixmap *pixmap; glxPoolLocalData *local = pool_local; glxAllocationData *alloc = alloc_data; D_DEBUG_AT( GLX_Surfaces, "%s( %p )\n", __FUNCTION__, allocation ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( alloc, glxAllocationData ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); ret = GetLocalPixmap( local, alloc, allocation, &pixmap ); if (ret) return ret; if (lock->accessor == CSAID_GPU || lock->accessor == CSAID_ACCEL1) { ThreadContext *ctx; ctx = pthread_getspecific( (lock->accessor == CSAID_GPU) ? local->context_key : local->context_key2 ); if (!ctx) { ctx = D_CALLOC( 1, sizeof(ThreadContext) ); if (!ctx) return D_OOM(); ctx->display = local->display; XLockDisplay( local->display ); ctx->context = glXCreateNewContext( local->display, pixmap->config, GLX_RGBA_TYPE, NULL, GL_TRUE ); if (!ctx->context) { D_ERROR( "GLX: Could not create GLXContext!\n" ); XUnlockDisplay( local->display ); D_FREE( ctx ); return DFB_FAILURE; } XUnlockDisplay( local->display ); pthread_setspecific( (lock->accessor == CSAID_GPU) ? local->context_key : local->context_key2, ctx ); D_DEBUG_AT( GLX_Surfaces, " -> NEW CONTEXT %p\n", ctx->context ); } if (lock->access & CSAF_WRITE) { if (ctx->context != glXGetCurrentContext() || ctx->drawable != pixmap->drawable) { D_DEBUG_AT( GLX_Surfaces, " -> MAKE CURRENT 0x%08lx <- 0x%08lx\n", pixmap->drawable, glXGetCurrentDrawable() ); if (ctx->drawable != pixmap->drawable) { ctx->drawable = pixmap->drawable; pixmap->buffer.flags |= GLBF_UPDATE_TARGET; } XLockDisplay( local->display ); glXMakeContextCurrent( local->display, pixmap->drawable, pixmap->drawable, ctx->context ); pixmap->current = ctx->context; ReleasePixmap( local, pixmap ); XUnlockDisplay( local->display ); } } else { if (pixmap->bound != ctx->context) { D_DEBUG_AT( GLX_Surfaces, " -> BIND TEXTURE 0x%08lx (%d)\n", pixmap->drawable, pixmap->buffer.texture ); XLockDisplay( local->display ); ReleasePixmap( local, pixmap ); glEnable( GL_TEXTURE_RECTANGLE_ARB ); glBindTexture( GL_TEXTURE_RECTANGLE_ARB, pixmap->buffer.texture ); local->BindTexImageEXT( local->display, pixmap->drawable, GLX_FRONT_EXT, NULL ); pixmap->bound = ctx->context; XUnlockDisplay( local->display ); pixmap->buffer.flags |= GLBF_UPDATE_TEXTURE; } } lock->handle = &pixmap->buffer; } else lock->handle = pixmap; return DFB_OK; } static DFBResult glxUnlock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { #if 0 DFBResult ret; LocalPixmap *pixmap; glxPoolLocalData *local = pool_local; glxAllocationData *alloc = alloc_data; D_DEBUG_AT( GLX_Surfaces, "%s( %p )\n", __FUNCTION__, allocation ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( alloc, glxAllocationData ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); ret = GetLocalPixmap( local, alloc, allocation, &pixmap ); if (ret) return ret; if (lock->accessor == CSAID_GPU) { XLockDisplay( local->display ); if (lock->access & CSAF_WRITE) { // D_DEBUG_AT( GLX_Surfaces, " -> UNMAKE CURRENT 0x%08lx <- 0x%08lx\n", pixmap->drawable, glXGetCurrentDrawable() ); // glXMakeContextCurrent( local->display, None, None, NULL ); // pixmap->current = NULL; } else { D_DEBUG_AT( GLX_Surfaces, " -> UNBIND TEXTURE 0x%08lx (%d)\n", pixmap->drawable, pixmap->buffer.texture ); ReleasePixmap( local, pixmap ); } XUnlockDisplay( local->display ); } #endif return DFB_OK; } static DFBResult glxRead( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, void *destination, int pitch, const DFBRectangle *rect ) { XImage *image; XImage *sub; glxPoolLocalData *local = pool_local; glxAllocationData *alloc = alloc_data; D_DEBUG_AT( GLX_Surfaces, "%s( %p )\n", __FUNCTION__, allocation ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( alloc, glxAllocationData ); D_ASSERT( destination != NULL ); D_ASSERT( pitch >= 0 ); DFB_RECTANGLE_ASSERT( rect ); D_DEBUG_AT( GLX_Surfaces, " => %p 0x%08lx [%4d,%4d-%4dx%4d]\n", alloc, alloc->pixmap, DFB_RECTANGLE_VALS(rect) ); XLockDisplay( local->display ); image = XCreateImage( local->display, (alloc->depth == 24) ? local->visual24 : local->visual32, alloc->depth, ZPixmap, 0, destination, rect->w, rect->h, 32, pitch ); if (!image) { D_ERROR( "GLX/Surfaces: XCreateImage( %dx%d, depth %d ) failed!\n", rect->w, rect->h, alloc->depth ); XUnlockDisplay( local->display ); return DFB_FAILURE; } glXWaitGL(); sub = XGetSubImage( local->display, alloc->pixmap, rect->x, rect->y, rect->w, rect->h, ~0, ZPixmap, image, 0, 0 ); glXWaitX(); /* FIXME: Why the X-hell is XDestroyImage() freeing *MY* data? */ image->data = NULL; XDestroyImage( image ); XUnlockDisplay( local->display ); if (!sub) { D_ERROR( "GLX/Surfaces: XGetSubImage( %d,%d-%dx%d ) failed!\n", DFB_RECTANGLE_VALS(rect) ); return DFB_FAILURE; } return DFB_OK; } static DFBResult glxWrite( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, const void *source, int pitch, const DFBRectangle *rect ) { DFBResult ret; LocalPixmap *pixmap; CoreSurface *surface; XImage *image; glxPoolLocalData *local = pool_local; glxAllocationData *alloc = alloc_data; D_DEBUG_AT( GLX_Surfaces, "%s( %p )\n", __FUNCTION__, allocation ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( local, glxPoolLocalData ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( alloc, glxAllocationData ); D_ASSERT( source != NULL ); D_ASSERT( pitch >= 0 ); DFB_RECTANGLE_ASSERT( rect ); D_DEBUG_AT( GLX_Surfaces, " <= %p 0x%08lx [%4d,%4d-%4dx%4d]\n", alloc, alloc->pixmap, DFB_RECTANGLE_VALS(rect) ); surface = allocation->surface; D_MAGIC_ASSERT( surface, CoreSurface ); ret = GetLocalPixmap( local, alloc, allocation, &pixmap ); if (ret) return ret; XLockDisplay( local->display ); image = XCreateImage( local->display, (alloc->depth == 24) ? local->visual24 : local->visual32, alloc->depth, ZPixmap, 0, (void*) source, rect->w, rect->h, 32, pitch ); if (!image) { D_ERROR( "GLX/Surfaces: XCreateImage( %dx%d, depth %d ) failed!\n", rect->w, rect->h, alloc->depth ); XUnlockDisplay( local->display ); return DFB_FAILURE; } glXWaitGL(); XPutImage( local->display, alloc->pixmap, pixmap->gc, image, 0, 0, rect->x, rect->y, rect->w, rect->h ); glXWaitX(); /* FIXME: Why the X-hell is XDestroyImage() freeing *MY* data? */ image->data = NULL; XDestroyImage( image ); XUnlockDisplay( local->display ); return DFB_OK; } const SurfacePoolFuncs glxSurfacePoolFuncs = { .PoolDataSize = glxPoolDataSize, .PoolLocalDataSize = glxPoolLocalDataSize, .AllocationDataSize = glxAllocationDataSize, .InitPool = glxInitPool, .JoinPool = glxJoinPool, .DestroyPool = glxDestroyPool, .LeavePool = glxLeavePool, .TestConfig = glxTestConfig, .AllocateBuffer = glxAllocateBuffer, .DeallocateBuffer = glxDeallocateBuffer, .Lock = glxLock, .Unlock = glxUnlock, .Read = glxRead, .Write = glxWrite, };