示例#1
0
static DFBResult
x11DeallocateBuffer( CoreSurfacePool       *pool,
                     void                  *pool_data,
                     void                  *pool_local,
                     CoreSurfaceBuffer     *buffer,
                     CoreSurfaceAllocation *allocation,
                     void                  *alloc_data )
{
     x11AllocationData *alloc  = alloc_data;
     x11PoolLocalData  *local  = pool_local;
     DFBX11            *x11    = local->x11;
     DFBX11Shared      *shared = x11->shared;

     D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );
     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );

     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     if (alloc->ptr)
          SHFREE( shared->data_shmpool, alloc->ptr );

     return DFB_OK;
}
示例#2
0
static DFBResult
allocate_transfer( CoreSurfacePoolBridge    *bridge,
                   CoreSurfaceBuffer        *buffer,
                   CoreSurfaceAllocation    *from,
                   CoreSurfaceAllocation    *to,
                   const DFBRectangle       *rects,
                   unsigned int              num_rects,
                   CoreSurfacePoolTransfer **ret_transfer )
{
     CoreSurfacePoolTransfer *transfer;
     unsigned int             alloc_size;

     D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge );
     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
     CORE_SURFACE_ALLOCATION_ASSERT( from );
     CORE_SURFACE_ALLOCATION_ASSERT( to );
     D_ASSERT( rects != NULL );
     D_ASSERT( num_rects > 0 );
     D_ASSERT( ret_transfer != NULL );

     alloc_size = sizeof(CoreSurfacePoolTransfer) + num_rects * sizeof(DFBRectangle) + bridge->transfer_data_size;

     transfer = SHCALLOC( bridge->shmpool, 1, alloc_size );
     if (!transfer)
          return D_OOSHM();
          
     transfer->bridge = bridge;
     transfer->buffer = buffer;
     transfer->from   = from;
     transfer->to     = to;

     transfer->rects  = (DFBRectangle*)(transfer + 1);

     if (bridge->transfer_data_size)
          transfer->data = transfer->rects + num_rects;

     transfer->num_rects = num_rects;

     direct_memcpy( transfer->rects, rects, num_rects * sizeof(DFBRectangle) );

     D_MAGIC_SET( transfer, CoreSurfacePoolTransfer );

     *ret_transfer = transfer;

     return DFB_OK;
}
示例#3
0
static DFBResult
x11DeallocateBuffer( CoreSurfacePool       *pool,
                     void                  *pool_data,
                     void                  *pool_local,
                     CoreSurfaceBuffer     *buffer,
                     CoreSurfaceAllocation *allocation,
                     void                  *alloc_data )
{
     x11AllocationData *alloc  = alloc_data;
     x11PoolLocalData  *local  = pool_local;
     DFBX11            *x11    = local->x11;
     DFBX11Shared      *shared = x11->shared;
     void              *addr;

     D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );

     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     switch (alloc->type) {
          case X11_ALLOC_PIXMAP:
          case X11_ALLOC_WINDOW:
               if (allocation->type & CSTF_PREALLOCATED) {
                    // don't delete
               }
               else
                    XFreePixmap( x11->display, alloc->xid );
               break;

          case X11_ALLOC_IMAGE:
               x11ImageDestroy( x11, &alloc->image );

               // FIXME: also detach in other processes! (e.g. via reactor)
               addr = direct_hash_lookup( local->hash, alloc->image.seginfo.shmid );
               if (addr) {
                    x11ImageDetach( &alloc->image, addr );

                    direct_hash_remove( local->hash, alloc->image.seginfo.shmid );
               }
               break;

          case X11_ALLOC_SHM:
               if (alloc->ptr)
                    SHFREE( shared->data_shmpool, alloc->ptr );
               break;

          default:
               D_BUG( "unexpected allocation type %d\n", alloc->type );
               return DFB_BUG;
     }

     return DFB_OK;
}
static DFBResult
x11DeallocateBuffer( CoreSurfacePool       *pool,
                     void                  *pool_data,
                     void                  *pool_local,
                     CoreSurfaceBuffer     *buffer,
                     CoreSurfaceAllocation *allocation,
                     void                  *alloc_data )
{
     x11AllocationData *alloc  = alloc_data;
     x11PoolLocalData  *local  = pool_local;
     DFBX11            *x11    = local->x11;
     DFBX11Shared      *shared = x11->shared;
     void              *addr;

     D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );

     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     // FIXME: also detach in other processes! (e.g. via reactor)
     addr = direct_hash_lookup( local->hash, alloc->image.seginfo.shmid );
     if (addr) {
          x11ImageDetach( &alloc->image, addr );

          direct_hash_remove( local->hash, alloc->image.seginfo.shmid );
     }

     if (alloc->real)
          return x11ImageDestroy( x11, &alloc->image );

     if (alloc->ptr)
          SHFREE( shared->data_shmpool, alloc->ptr );

     return DFB_OK;
}
static DFBResult
prealloc_transfer_readwrite( CoreSurface             *surface,
                             CoreSurfacePoolTransfer *transfer,
                             CoreSurfaceAllocation   *alloc,
                             CoreSurfaceAccessFlags   flags,
                             CoreSlave               *slave )
{
     DFBResult ret = DFB_OK;
     int       index;
     int       i, y;

     D_MAGIC_ASSERT( surface, CoreSurface );
     D_ASSERT( transfer != NULL );
     CORE_SURFACE_ALLOCATION_ASSERT( alloc );

     index = dfb_surface_buffer_index( alloc->buffer );

     D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ );

     D_DEBUG_AT( PreAlloc_Bridge, "  ->Transfer read/write %s Fusion ID %lu (index %d)\n",
                 (flags & CSAF_WRITE) ? "from" : "to", surface->object.identity, index );


     for (i=0; i<transfer->num_rects; i++) {
          const DFBRectangle *rect   = &transfer->rects[i];
          int                 offset = DFB_BYTES_PER_LINE( surface->config.format, rect->x );
          int                 length = DFB_BYTES_PER_LINE( surface->config.format, rect->w );
          u8                 *temp   = alloca( length );    // FIXME

          for (y=0; y<rect->h; y++) {
               DFBRectangle lrect = { rect->x, rect->y + y, rect->w, 1 };

               if (flags & CSAF_WRITE) {
                    ret = CoreSlave_GetData( slave,
                                             surface->config.preallocated[index].addr +
                                             (rect->y + y) * surface->config.preallocated[index].pitch + offset,
                                             length,
                                             temp );
                    if (ret)
                         break;

                    ret = dfb_surface_pool_write( alloc->pool, alloc, temp, length, &lrect );
               }
               else {
                    ret = dfb_surface_pool_read( alloc->pool, alloc, temp, length, &lrect );
                    if (ret)
                         break;

                    ret = CoreSlave_PutData( slave,
                                             surface->config.preallocated[index].addr +
                                             (rect->y + y) * surface->config.preallocated[index].pitch + offset,
                                             length,
                                             temp );
               }
               if (ret)
                    break;
          }
          if (ret)
               break;
     }


     return ret;
}
static DFBResult
prealloc_transfer_locked( CoreSurface             *surface,
                          CoreSurfacePoolTransfer *transfer,
                          CoreSurfaceAllocation   *locked,
                          CoreSurfaceAccessFlags   flags,
                          CoreSlave               *slave )
{
     DFBResult             ret;
     CoreSurfaceBufferLock lock;
     int                   index;
     int                   i, y;

     D_MAGIC_ASSERT( surface, CoreSurface );
     D_ASSERT( transfer != NULL );
     CORE_SURFACE_ALLOCATION_ASSERT( locked );

     index = dfb_surface_buffer_index( locked->buffer );

     D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ );

     D_DEBUG_AT( PreAlloc_Bridge, "  -> Transfer locked %s Fusion ID %lu (index %d)\n",
                 (flags & CSAF_WRITE) ? "from" : "to", surface->object.identity, index );


     dfb_surface_buffer_lock_init( &lock, CSAID_CPU, flags );

     ret = dfb_surface_pool_lock( locked->pool, locked, &lock );
     if (ret) {
          dfb_surface_buffer_lock_deinit( &lock );
          return ret;
     }


     for (i=0; i<transfer->num_rects; i++) {
          const DFBRectangle *rect   = &transfer->rects[i];
          int                 offset = DFB_BYTES_PER_LINE( surface->config.format, rect->x );
          int                 length = DFB_BYTES_PER_LINE( surface->config.format, rect->w );

          for (y=0; y<rect->h; y++) {
               if (flags & CSAF_WRITE)
                    ret = CoreSlave_GetData( slave,
                                             surface->config.preallocated[index].addr +
                                             (rect->y + y) * surface->config.preallocated[index].pitch + offset,
                                             length,
                                             lock.addr + (rect->y + y) * lock.pitch + offset );
               else
                    ret = CoreSlave_PutData( slave,
                                             surface->config.preallocated[index].addr +
                                             (rect->y + y) * surface->config.preallocated[index].pitch + offset,
                                             length,
                                             lock.addr + (rect->y + y) * lock.pitch + offset );
               if (ret)
                    break;
          }
          if (ret)
               break;
     }


     dfb_surface_pool_unlock( locked->pool, locked, &lock );

     dfb_surface_buffer_lock_deinit( &lock );

     return ret;
}
示例#7
0
DFBResult
dfb_surface_pool_bridges_transfer( CoreSurfaceBuffer     *buffer,
                                   CoreSurfaceAllocation *from,
                                   CoreSurfaceAllocation *to,
                                   const DFBRectangle    *rects,
                                   unsigned int           num_rects )
{
     DFBResult                     ret;
     int                           i;
     DFBRectangle                  rect;
     CoreSurfacePoolBridge        *bridge = NULL;
     const SurfacePoolBridgeFuncs *funcs;
     CoreSurfacePoolTransfer      *transfer;

     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
     CORE_SURFACE_ALLOCATION_ASSERT( from );
     CORE_SURFACE_ALLOCATION_ASSERT( to );
     D_ASSERT( rects != NULL || num_rects == 0 );
     D_ASSERT( num_rects > 0 || rects == NULL );

     D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p [%dx%d %s], %p -> %p, %d rects )\n", __FUNCTION__,
                 buffer, buffer->config.size.w, buffer->config.size.h,
                 dfb_pixelformat_name( buffer->format ), from, to, num_rects );

     if (!rects) {
          rect.x = rect.y = 0;
          rect.w = buffer->config.size.w;
          rect.h = buffer->config.size.h;

          rects = &rect;
          num_rects = 1;
     }

     for (i=0; i<bridge_count; i++) {
          D_ASSERT( bridge_order[i] >= 0 );
          D_ASSERT( bridge_order[i] < bridge_count );

          bridge = bridge_array[bridge_order[i]];
          D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge );

          funcs = get_funcs( bridge );
          D_ASSERT( funcs->CheckTransfer != NULL );

          ret = funcs->CheckTransfer( bridge, bridge->data, get_local(bridge), buffer, from, to );
          if (ret)
               bridge = NULL;
          else
               break;
     }

     if (!bridge)
          return DFB_UNSUPPORTED;
          
     D_DEBUG_AT( Core_SurfPoolBridge, "  -> using '%s'\n", bridge->desc.name );

     ret = allocate_transfer( bridge, buffer, from, to, rects, num_rects, &transfer );
     if (ret)
          return ret;

     D_ASSERT( funcs->StartTransfer != NULL );
          
     D_DEBUG_AT( Core_SurfPoolBridge, "  -> start...\n" );

     ret = funcs->StartTransfer( bridge, bridge->data, get_local(bridge), transfer, transfer->data );
     if (ret)
          D_DERROR( ret, "Core/SurfacePoolBridge: Starting transfer via '%s' failed!\n", bridge->desc.name );
     else if (funcs->FinishTransfer) {
          D_DEBUG_AT( Core_SurfPoolBridge, "  -> finish...\n" );

          ret = funcs->FinishTransfer( bridge, bridge->data, get_local(bridge), transfer, transfer->data );
          if (ret)
               D_DERROR( ret, "Core/SurfacePoolBridge: Finishing transfer via '%s' failed!\n", bridge->desc.name );
     }

     D_DEBUG_AT( Core_SurfPoolBridge, "  => %s\n", DirectResultString(ret) );

     deallocate_transfer( transfer );

     return ret;
}
示例#8
0
static DFBResult
x11DeallocateBuffer( CoreSurfacePool       *pool,
                     void                  *pool_data,
                     void                  *pool_local,
                     CoreSurfaceBuffer     *buffer,
                     CoreSurfaceAllocation *allocation,
                     void                  *alloc_data )
{
     DFBResult          ret   = DFB_OK;
     x11AllocationData *alloc = alloc_data;
     x11PoolLocalData  *local = pool_local;
     DFBX11            *x11   = local->x11;

     D_DEBUG_AT( X11_Surfaces, "%s()\n", __FUNCTION__ );

     D_MAGIC_ASSERT( pool, CoreSurfacePool );

     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     XLockDisplay( x11->display );

     if (alloc->gc)
          XFreeGC( x11->display, alloc->gc );

     switch (alloc->type) {
          case X11_ALLOC_WINDOW:
               D_ASSUME( x11->showing != alloc->window );

               if (x11->showing == alloc->window) {
                    D_LOG( X11_Surfaces, VERBOSE, "  -> Hiding window 0x%08lx that is to be destroyed!!!\n", x11->showing );
                    XUnmapWindow( x11->display, x11->showing );

                    x11->showing = 0;
               }

          case X11_ALLOC_PIXMAP:
               if (allocation->type & CSTF_PREALLOCATED) {
                    // don't delete
               }
               else if (alloc->created) {
                    if (alloc->xid != alloc->window) {
                         D_INFO( "X11/Windows: Free Pixmap 0x%08lx\n", alloc->xid );
                         XFreePixmap( x11->display, alloc->xid );
                    }

                    if (alloc->window) {
                         D_INFO( "X11/Windows: Destroy Window 0x%08lx\n", alloc->window );
                         XDestroyWindow( x11->display, alloc->window );
                    }
               }
               break;

          default:
               D_BUG( "unexpected allocation type %d\n", alloc->type );
               ret = DFB_BUG;
     }

     XUnlockDisplay( x11->display );

     return ret;
}
示例#9
0
文件: primary.c 项目: canalplus/r7oss
static DFBResult
update_screen( DFBX11 *x11, const DFBRectangle *clip, CoreSurfaceBufferLock *lock, XWindow *xw )
{
     void                  *dst;
     void                  *src;
     unsigned int           offset = 0;
     XImage                *ximage;
     CoreSurface           *surface;
     CoreSurfaceAllocation *allocation;
     DFBX11Shared          *shared;
     DFBRectangle           rect;
     bool                   direct = false;

     D_ASSERT( x11 != NULL );
     DFB_RECTANGLE_ASSERT( clip );

     D_DEBUG_AT( X11_Update, "%s( %4d,%4d-%4dx%4d )\n", __FUNCTION__, DFB_RECTANGLE_VALS( clip ) );

     CORE_SURFACE_BUFFER_LOCK_ASSERT( lock );

     shared = x11->shared;
     D_ASSERT( shared != NULL );

     XLockDisplay( x11->display );

     if (!xw) {
          XUnlockDisplay( x11->display );
          return DFB_OK;
     }

     allocation = lock->allocation;
     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     surface = allocation->surface;
     D_ASSERT( surface != NULL );


     rect.x = rect.y = 0;
     rect.w = xw->width;
     rect.h = xw->height;

     if (!dfb_rectangle_intersect( &rect, clip )) {
          XUnlockDisplay( x11->display );
          return DFB_OK;
     }

     D_DEBUG_AT( X11_Update, "  -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &rect ) );

#ifdef USE_GLX
     /* Check for GLX allocation... */
     if (allocation->pool == shared->glx_pool && lock->handle) {
          LocalPixmap *pixmap = lock->handle;

          D_MAGIC_ASSERT( pixmap, LocalPixmap );

          /* ...and just call SwapBuffers... */
          //D_DEBUG_AT( X11_Update, "  -> Calling glXSwapBuffers( 0x%lx )...\n", alloc->drawable );
          //glXSwapBuffers( x11->display, alloc->drawable );


          D_DEBUG_AT( X11_Update, "  -> Copying from GLXPixmap...\n" );

          glXWaitGL();

          XCopyArea( x11->display, pixmap->pixmap, xw->window, xw->gc,
                     rect.x, rect.y, rect.w, rect.h, rect.x, rect.y );

          glXWaitX();

          XUnlockDisplay( x11->display );

          return DFB_OK;
     }
#endif

     /* Check for our special native allocation... */
     if (allocation->pool == shared->x11image_pool && lock->handle) {
          x11Image *image = lock->handle;

          D_MAGIC_ASSERT( image, x11Image );

          /* ...and directly XShmPutImage from that. */
          ximage = image->ximage;

          direct = true;
     }
     else {
          /* ...or copy or convert into XShmImage or XImage allocated with the XWindow. */
          ximage = xw->ximage;
          offset = xw->ximage_offset;

          xw->ximage_offset = (offset ? 0 : ximage->height / 2);

          /* make sure the 16-bit input formats are properly 2-pixel-clipped */
          switch (surface->config.format) {
               case DSPF_I420:
               case DSPF_YV12:
               case DSPF_NV12:
               case DSPF_NV21:
                    if (rect.y & 1) {
                         rect.y--;
                         rect.h++;
                    }
                    /* fall through */
               case DSPF_YUY2:
               case DSPF_UYVY:
               case DSPF_NV16:
                    if (rect.x & 1) {
                         rect.x--;
                         rect.w++;
                    }
               default: /* no action */
                    break;
          }

          dst = xw->virtualscreen + rect.x * xw->bpp + (rect.y + offset) * ximage->bytes_per_line;
          src = lock->addr + DFB_BYTES_PER_LINE( surface->config.format, rect.x ) + rect.y * lock->pitch;

          switch (xw->depth) {
               case 32:
                    dfb_convert_to_argb( surface->config.format, src, lock->pitch,
                                         surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h );
                    break;

               case 24:
                    dfb_convert_to_rgb32( surface->config.format, src, lock->pitch,
                                          surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h );
                    break;

               case 16:
                    if (surface->config.format == DSPF_LUT8) {
                         int width = rect.w; int height = rect.h;
                         const u8    *src8    = src;
                         u16         *dst16   = dst;
                         CorePalette *palette = surface->palette;
                         int          x;
                         while (height--) {

                              for (x=0; x<width; x++) {
                                   DFBColor color = palette->entries[src8[x]];
                                   dst16[x] = PIXEL_RGB16( color.r, color.g, color.b );
                              }

                              src8  += lock->pitch;
                              dst16 += ximage->bytes_per_line / 2;
                         }
                    }
                    else {
                    dfb_convert_to_rgb16( surface->config.format, src, lock->pitch,
                                          surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h );
                    }
                    break;

               case 15:
                    dfb_convert_to_rgb555( surface->config.format, src, lock->pitch,
                                           surface->config.size.h, dst, ximage->bytes_per_line, rect.w, rect.h );
                    break;

               default:
                    D_ONCE( "unsupported depth %d", xw->depth );
          }
     }

     D_ASSERT( ximage != NULL );


     /* Wait for previous data to be processed... */
     XSync( x11->display, False );

     /* ...and immediately queue or send the next! */
     if (x11->use_shm) {
          /* Just queue the command, it's XShm :) */
          XShmPutImage( xw->display, xw->window, xw->gc, ximage,
                        rect.x, rect.y + offset, rect.x, rect.y, rect.w, rect.h, False );

          /* Make sure the queue has really happened! */
          XFlush( x11->display );
     }
     else
          /* Initiate transfer of buffer... */
          XPutImage( xw->display, xw->window, xw->gc, ximage,
                     rect.x, rect.y + offset, rect.x, rect.y, rect.w, rect.h );

     /* Wait for display if single buffered and not converted... */
     if (direct && !(surface->config.caps & DSCAPS_FLIPPING))
          XSync( x11->display, False );

     XUnlockDisplay( x11->display );

     return DFB_OK;
}
DFBResult
ISurface_Real__PreWriteBuffer(
                         CoreSurface                               *obj,
                         CoreSurfaceBuffer                         *buffer,
                         const DFBRectangle                        *rect,
                         CoreSurfaceAllocation                    **ret_allocation
                         )
{
     DFBResult              ret;
     CoreSurfaceAllocation *allocation;
     CoreSurface           *surface    = obj;
     bool                   allocated  = false;

     D_DEBUG_AT( DirectFB_CoreSurface, "%s()\n", __FUNCTION__ );

     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );

     dfb_surface_lock( surface );

     if (!buffer->surface) {
          dfb_surface_unlock( surface );
          return DFB_BUFFEREMPTY;
     }

     /* Use last read allocation if it's up to date... */
     if (buffer->read && direct_serial_check( &buffer->read->serial, &buffer->serial ))
          allocation = buffer->read;
     else {
          /* ...otherwise look for allocation with CPU access. */
          allocation = dfb_surface_buffer_find_allocation( buffer, CSAID_CPU, CSAF_WRITE, false );
          if (!allocation) {
               /* If no allocation exists, create one. */
               ret = dfb_surface_pools_allocate( buffer, CSAID_CPU, CSAF_WRITE, &allocation );
               if (ret) {
                    D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" );
                    goto out;
               }

               allocated = true;
          }
     }

     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     /* Synchronize with other allocations. */
     ret = dfb_surface_allocation_update( allocation, CSAF_WRITE );
     if (ret) {
          /* Destroy if newly created. */
          if (allocated)
               dfb_surface_allocation_decouple( allocation );
          goto out;
     }

     if (!(allocation->pool->desc.caps & CSPCAPS_WRITE)) {
          ret = dfb_surface_pool_prelock( allocation->pool, allocation, CSAID_CPU, CSAF_WRITE );
          if (ret) {
               /* Destroy if newly created. */
               if (allocated)
                    dfb_surface_allocation_decouple( allocation );
               goto out;
          }

          manage_interlocks( allocation, CSAID_CPU, CSAF_WRITE );
     }

     dfb_surface_allocation_ref( allocation );

     *ret_allocation = allocation;

out:
     dfb_surface_unlock( surface );

     return ret;
}
DFBResult
ISurface_Real__PreLockBuffer2(
                         CoreSurface                               *obj,
                         CoreSurfaceBufferRole                      role,
                         CoreSurfaceAccessorID                      accessor,
                         CoreSurfaceAccessFlags                     access,
                         bool                                       lock,
                         CoreSurfaceAllocation                    **ret_allocation
                         )
{
     DFBResult              ret;
     CoreSurfaceBuffer     *buffer;
     CoreSurfaceAllocation *allocation;
     CoreSurface           *surface    = obj;
     bool                   allocated  = false;

     D_DEBUG_AT( DirectFB_CoreSurface, "%s( surface %p, role %d, accessor 0x%02x, access 0x%02x, %slock )\n",
                 __FUNCTION__, surface, role, accessor, access, lock ? "" : "no " );

     ret = (DFBResult) dfb_surface_lock( surface );
     if (ret)
          return ret;

     if (surface->num_buffers < 1) {
          dfb_surface_unlock( surface );
          return DFB_BUFFEREMPTY;
     }

     buffer = dfb_surface_get_buffer( surface, role );
     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );

     D_DEBUG_AT( DirectFB_CoreSurface, "  -> buffer %p\n", buffer );

     if (!lock && access & CSAF_READ) {
          if (fusion_vector_is_empty( &buffer->allocs )) {
               dfb_surface_unlock( surface );
               return DFB_NOALLOCATION;
          }
     }

     /* Look for allocation with proper access. */
     allocation = dfb_surface_buffer_find_allocation( buffer, accessor, access, lock );
     if (!allocation) {
          /* If no allocation exists, create one. */
          ret = dfb_surface_pools_allocate( buffer, accessor, access, &allocation );
          if (ret) {
               if (ret != DFB_NOVIDEOMEMORY && ret != DFB_UNSUPPORTED)
                    D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" );

               goto out;
          }

          allocated = true;
     }

     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     /* Synchronize with other allocations. */
     ret = dfb_surface_allocation_update( allocation, access );
     if (ret) {
          /* Destroy if newly created. */
          if (allocated)
               dfb_surface_allocation_decouple( allocation );
          goto out;
     }

     if (!lock) {
          if (access & CSAF_WRITE) {
               if (!(allocation->pool->desc.caps & CSPCAPS_WRITE))
                    lock = true;
          }
          else if (access & CSAF_READ) {
               if (!(allocation->pool->desc.caps & CSPCAPS_READ))
                    lock = true;
          }
     }

     if (lock) {
          ret = dfb_surface_pool_prelock( allocation->pool, allocation, accessor, access );
          if (ret) {
               /* Destroy if newly created. */
               if (allocated)
                    dfb_surface_allocation_decouple( allocation );
               goto out;
          }

          manage_interlocks( allocation, accessor, access );
     }

     dfb_surface_allocation_ref( allocation );

     *ret_allocation = allocation;

out:
     dfb_surface_unlock( surface );

     return ret;
}
DFBResult
ISurface_Real__PreLockBuffer(
                         CoreSurface                               *obj,
                         CoreSurfaceBuffer                         *buffer,
                         CoreSurfaceAccessorID                      accessor,
                         CoreSurfaceAccessFlags                     access,
                         CoreSurfaceAllocation                    **ret_allocation
                         )
{
     DFBResult              ret;
     CoreSurfaceAllocation *allocation;
     CoreSurface           *surface    = obj;
     bool                   allocated  = false;

     D_DEBUG_AT( DirectFB_CoreSurface, "%s()\n", __FUNCTION__ );

     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );

     dfb_surface_lock( surface );

     if (!buffer->surface) {
          dfb_surface_unlock( surface );
          return DFB_BUFFEREMPTY;
     }

     /* Look for allocation with proper access. */
     allocation = dfb_surface_buffer_find_allocation( buffer, accessor, access, true );
     if (!allocation) {
          /* If no allocation exists, create one. */
          ret = dfb_surface_pools_allocate( buffer, accessor, access, &allocation );
          if (ret) {
               if (ret != DFB_NOVIDEOMEMORY && ret != DFB_UNSUPPORTED)
                    D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" );

               goto out;
          }

          allocated = true;
     }

     CORE_SURFACE_ALLOCATION_ASSERT( allocation );

     /* Synchronize with other allocations. */
     ret = dfb_surface_allocation_update( allocation, access );
     if (ret) {
          /* Destroy if newly created. */
          if (allocated)
               dfb_surface_allocation_decouple( allocation );
          goto out;
     }

     ret = dfb_surface_pool_prelock( allocation->pool, allocation, accessor, access );
     if (ret) {
          /* Destroy if newly created. */
          if (allocated)
               dfb_surface_allocation_decouple( allocation );
          goto out;
     }

     manage_interlocks( allocation, accessor, access );

     dfb_surface_allocation_ref( allocation );

     *ret_allocation = allocation;

out:
     dfb_surface_unlock( surface );

     return ret;
}