summaryrefslogtreecommitdiff
path: root/Source/DirectFB/src/core/surface_pool.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/src/core/surface_pool.c')
-rwxr-xr-xSource/DirectFB/src/core/surface_pool.c1263
1 files changed, 1263 insertions, 0 deletions
diff --git a/Source/DirectFB/src/core/surface_pool.c b/Source/DirectFB/src/core/surface_pool.c
new file mode 100755
index 0000000..0518df2
--- /dev/null
+++ b/Source/DirectFB/src/core/surface_pool.c
@@ -0,0 +1,1263 @@
+/*
+ (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 <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ 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.
+*/
+
+#include <directfb.h>
+#include <directfb_util.h>
+
+#include <direct/debug.h>
+#include <direct/mem.h>
+
+#include <fusion/shmalloc.h>
+
+#include <core/core.h>
+#include <core/coredefs.h>
+
+#include <core/surface_buffer.h>
+#include <core/surface_pool.h>
+#include <core/system.h>
+
+#include <gfx/convert.h>
+
+#include <misc/conf.h>
+
+
+D_DEBUG_DOMAIN( Core_SurfacePool, "Core/SurfacePool", "DirectFB Core Surface Pool" );
+D_DEBUG_DOMAIN( Core_SurfPoolLock, "Core/SurfPoolLock", "DirectFB Core Surface Pool Lock" );
+
+/**********************************************************************************************************************/
+
+static const SurfacePoolFuncs *pool_funcs[MAX_SURFACE_POOLS];
+static void *pool_locals[MAX_SURFACE_POOLS];
+static int pool_count;
+static CoreSurfacePool *pool_array[MAX_SURFACE_POOLS];
+static unsigned int pool_order[MAX_SURFACE_POOLS];
+
+/**********************************************************************************************************************/
+
+static inline const SurfacePoolFuncs *
+get_funcs( const CoreSurfacePool *pool )
+{
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ D_ASSERT( pool->pool_id >= 0 );
+ D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS );
+ D_ASSERT( pool_funcs[pool->pool_id] != NULL );
+
+ /* Return function table of the pool. */
+ return pool_funcs[pool->pool_id];
+}
+
+static inline void *
+get_local( const CoreSurfacePool *pool )
+{
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ D_ASSERT( pool->pool_id >= 0 );
+ D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS );
+
+ /* Return local data of the pool. */
+ return pool_locals[pool->pool_id];
+}
+
+/**********************************************************************************************************************/
+
+static DFBResult init_pool( CoreDFB *core,
+ CoreSurfacePool *pool,
+ const SurfacePoolFuncs *funcs );
+
+/**********************************************************************************************************************/
+
+static void insert_pool_local( CoreSurfacePool *pool );
+static void remove_pool_local( CoreSurfacePoolID pool_id );
+
+/**********************************************************************************************************************/
+
+static void remove_allocation( CoreSurfacePool *pool,
+ CoreSurfaceBuffer *buffer,
+ CoreSurfaceAllocation *allocation );
+
+static DFBResult backup_allocation( CoreSurfacePool *pool,
+ CoreSurfaceBuffer *buffer,
+ CoreSurfaceAllocation *allocation );
+
+/**********************************************************************************************************************/
+
+DFBResult
+dfb_surface_pool_initialize( CoreDFB *core,
+ const SurfacePoolFuncs *funcs,
+ CoreSurfacePool **ret_pool )
+{
+ DFBResult ret;
+ CoreSurfacePool *pool;
+ FusionSHMPoolShared *shmpool;
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p )\n", __FUNCTION__, funcs );
+
+ D_ASSERT( core != NULL );
+ D_ASSERT( funcs != NULL );
+ D_ASSERT( ret_pool != NULL );
+
+ /* Check against pool limit. */
+ if (pool_count == MAX_SURFACE_POOLS) {
+ D_ERROR( "Core/SurfacePool: Maximum number of pools (%d) reached!\n", MAX_SURFACE_POOLS );
+ return DFB_LIMITEXCEEDED;
+ }
+
+ D_ASSERT( pool_funcs[pool_count] == NULL );
+
+ shmpool = dfb_core_shmpool( core );
+
+ /* Allocate pool structure. */
+ pool = SHCALLOC( shmpool, 1, sizeof(CoreSurfacePool) );
+ if (!pool)
+ return D_OOSHM();
+
+ /* Assign a pool ID. */
+ pool->pool_id = pool_count++;
+
+ /* Remember shared memory pool. */
+ pool->shmpool = shmpool;
+
+ /* Set function table of the pool. */
+ pool_funcs[pool->pool_id] = funcs;
+
+ /* Add to global pool list. */
+ pool_array[pool->pool_id] = pool;
+
+ D_MAGIC_SET( pool, CoreSurfacePool );
+
+ ret = init_pool( core, pool, funcs );
+ if (ret) {
+ pool_funcs[pool->pool_id] = NULL;
+ pool_array[pool->pool_id] = NULL;
+ pool_count--;
+ D_MAGIC_CLEAR( pool );
+ SHFREE( shmpool, pool );
+ return ret;
+ }
+
+ /* Set default backup pool being the shared memory surface pool */
+ if (!pool->backup && pool_count > 1)
+ pool->backup = pool_array[0];
+
+ /* Insert new pool into priority order */
+ insert_pool_local( pool );
+
+ /* Return the new pool. */
+ *ret_pool = pool;
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_surface_pool_join( CoreDFB *core,
+ CoreSurfacePool *pool,
+ const SurfacePoolFuncs *funcs )
+{
+ DFBResult ret;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, funcs );
+
+ D_ASSERT( core != NULL );
+ D_ASSERT( funcs != NULL );
+
+ D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS );
+ D_ASSERT( pool->pool_id == pool_count );
+ D_ASSERT( pool_funcs[pool->pool_id] == NULL );
+
+ /* Enforce same order as initialization to be used during join. */
+ if (pool->pool_id != pool_count) {
+ D_ERROR( "Core/SurfacePool: Wrong order of joining pools, got %d, should be %d!\n",
+ pool->pool_id, pool_count );
+ return DFB_BUG;
+ }
+
+ /* Allocate local pool data. */
+ if (pool->pool_local_data_size &&
+ !(pool_locals[pool->pool_id] = D_CALLOC( 1, pool->pool_local_data_size )))
+ return D_OOM();
+
+ /* Set function table of the pool. */
+ pool_funcs[pool->pool_id] = funcs;
+
+ /* Add to global pool list. */
+ pool_array[pool->pool_id] = pool;
+
+ /* Adjust pool count. */
+ if (pool_count < pool->pool_id + 1)
+ pool_count = pool->pool_id + 1;
+
+ funcs = get_funcs( pool );
+
+ if (funcs->JoinPool) {
+ ret = funcs->JoinPool( core, pool, pool->data, get_local(pool), dfb_system_data() );
+ if (ret) {
+ D_DERROR( ret, "Core/SurfacePool: Joining '%s' failed!\n", pool->desc.name );
+
+ if (pool_locals[pool->pool_id]) {
+ D_FREE( pool_locals[pool->pool_id] );
+ pool_locals[pool->pool_id] = NULL;
+ }
+
+ pool_count--;
+
+ return ret;
+ }
+ }
+
+ /* Insert new pool into priority order */
+ insert_pool_local( pool );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_surface_pool_destroy( CoreSurfacePool *pool )
+{
+ CoreSurfacePoolID pool_id;
+ const SurfacePoolFuncs *funcs;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ pool_id = pool->pool_id;
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p, '%s' [%d] )\n", __FUNCTION__, pool, pool->desc.name, pool_id );
+
+ D_ASSERT( pool->pool_id >= 0 );
+ D_ASSERT( pool_id < MAX_SURFACE_POOLS );
+ D_ASSERT( pool_array[pool_id] == pool );
+
+ funcs = get_funcs( pool );
+
+ if (funcs->DestroyPool)
+ funcs->DestroyPool( pool, pool->data, get_local(pool) );
+
+ /* Free shared pool data. */
+ if (pool->data)
+ SHFREE( pool->shmpool, pool->data );
+
+ /* Free local pool data and remove from lists */
+ remove_pool_local( pool_id );
+
+ fusion_skirmish_destroy( &pool->lock );
+
+ fusion_vector_destroy( &pool->allocs );
+
+ D_MAGIC_CLEAR( pool );
+
+ SHFREE( pool->shmpool, pool );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_surface_pool_leave( CoreSurfacePool *pool )
+{
+ CoreSurfacePoolID pool_id;
+ const SurfacePoolFuncs *funcs;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ pool_id = pool->pool_id;
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p, '%s' [%d] )\n", __FUNCTION__, pool, pool->desc.name, pool_id );
+
+ D_ASSERT( pool->pool_id >= 0 );
+ D_ASSERT( pool_id < MAX_SURFACE_POOLS );
+ D_ASSERT( pool_array[pool_id] == pool );
+
+ funcs = get_funcs( pool );
+
+ if (funcs->LeavePool)
+ funcs->LeavePool( pool, pool->data, get_local(pool) );
+
+ /* Free local pool data and remove from lists */
+ remove_pool_local( pool_id );
+
+ return DFB_OK;
+}
+
+/**********************************************************************************************************************/
+
+DFBResult
+dfb_surface_pools_negotiate( CoreSurfaceBuffer *buffer,
+ CoreSurfaceAccessorID accessor,
+ CoreSurfaceAccessFlags access,
+ CoreSurfacePool **ret_pools,
+ unsigned int max_pools,
+ unsigned int *ret_num )
+{
+ DFBResult ret;
+ int i;
+ unsigned int num = 0;
+ CoreSurface *surface;
+ CoreSurfaceTypeFlags type;
+ unsigned int free_count = 0;
+ CoreSurfacePool *free_pools[pool_count];
+ unsigned int oom_count = 0;
+ CoreSurfacePool *oom_pools[pool_count];
+
+ D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p [%s], 0x%02x, 0x%02x, max %d )\n", __FUNCTION__,
+ buffer, dfb_pixelformat_name( buffer->format ), accessor, access, max_pools );
+
+ D_ASSERT( ret_pools != NULL );
+ D_ASSERT( max_pools > 0 );
+ D_ASSERT( ret_num != NULL );
+
+ surface = buffer->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+ FUSION_SKIRMISH_ASSERT( &surface->lock );
+
+ D_ASSERT( accessor >= CSAID_CPU );
+ D_ASSUME( accessor < _CSAID_NUM );
+ if (accessor >= CSAID_ANY) {
+ D_UNIMPLEMENTED();
+ return DFB_UNIMPLEMENTED;
+ }
+
+ if (accessor < 0 || accessor >= _CSAID_NUM)
+ return DFB_INVARG;
+
+ type = surface->type & ~(CSTF_INTERNAL | CSTF_EXTERNAL);
+
+ switch (buffer->policy) {
+ case CSP_SYSTEMONLY:
+ type |= CSTF_INTERNAL;
+ break;
+
+ case CSP_VIDEOONLY:
+ type |= CSTF_EXTERNAL;
+ break;
+
+ default:
+ break;
+ }
+
+ D_DEBUG_AT( Core_SurfacePool, " -> 0x%02x 0x%03x required\n", access, type );
+
+ for (i=0; i<pool_count; i++) {
+ CoreSurfacePool *pool;
+
+ D_ASSERT( pool_order[i] >= 0 );
+ D_ASSERT( pool_order[i] < pool_count );
+
+ pool = pool_array[pool_order[i]];
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ if (D_FLAGS_ARE_SET( pool->desc.access[accessor], access ) &&
+ D_FLAGS_ARE_SET( pool->desc.types, type ))
+ {
+ const SurfacePoolFuncs *funcs;
+
+ D_DEBUG_AT( Core_SurfacePool, " -> [%d] 0x%02x 0x%03x (%d) [%s]\n", pool->pool_id,
+ pool->desc.caps, pool->desc.types, pool->desc.priority, pool->desc.name );
+
+ funcs = get_funcs( pool );
+
+ ret = funcs->TestConfig ? funcs->TestConfig( pool, pool->data, get_local(pool),
+ buffer, &surface->config ) : DFB_OK;
+ switch (ret) {
+ case DFB_OK:
+ D_DEBUG_AT( Core_SurfacePool, " => OK\n" );
+ free_pools[free_count++] = pool;
+ break;
+
+ case DFB_NOVIDEOMEMORY:
+ D_DEBUG_AT( Core_SurfacePool, " => OUT OF MEMORY\n" );
+ oom_pools[oom_count++] = pool;
+ break;
+
+ default:
+ continue;
+ }
+ }
+ }
+
+ D_DEBUG_AT( Core_SurfacePool, " => %d pools available\n", free_count );
+ D_DEBUG_AT( Core_SurfacePool, " => %d pools out of memory\n", oom_count );
+
+ for (i=0; i<free_count && num<max_pools; i++)
+ ret_pools[num++] = free_pools[i];
+
+ for (i=0; i<oom_count && num<max_pools; i++)
+ ret_pools[num++] = oom_pools[i];
+
+ *ret_num = num;
+
+ return free_count ? DFB_OK : oom_count ? DFB_NOVIDEOMEMORY : DFB_UNSUPPORTED;
+}
+
+DFBResult
+dfb_surface_pools_enumerate( CoreSurfacePoolCallback callback,
+ void *ctx )
+{
+ int i;
+
+ D_ASSERT( callback != NULL );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, callback, ctx );
+
+ for (i=0; i<pool_count; i++) {
+ CoreSurfacePool *pool = pool_array[i];
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ if (callback( pool, ctx ) == DFENUM_CANCEL)
+ break;
+ }
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_surface_pools_allocate( CoreSurfaceBuffer *buffer,
+ CoreSurfaceAccessorID accessor,
+ CoreSurfaceAccessFlags access,
+ CoreSurfaceAllocation **ret_allocation )
+{
+ DFBResult ret;
+ int i;
+ CoreSurface *surface;
+ CoreSurfaceAllocation *allocation = NULL;
+ CoreSurfacePool *pools[pool_count];
+ unsigned int num_pools;
+
+ D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
+ D_FLAGS_ASSERT( access, CSAF_ALL );
+ D_ASSERT( ret_allocation != NULL );
+
+ surface = buffer->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+ FUSION_SKIRMISH_ASSERT( &surface->lock );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p, 0x%x )\n", __FUNCTION__, buffer, access );
+
+ D_DEBUG_AT( Core_SurfacePool, " -> %dx%d %s - %s%s%s%s%s%s%s%s\n",
+ surface->config.size.w, surface->config.size.h,
+ dfb_pixelformat_name( surface->config.format ),
+ (surface->type & CSTF_SHARED) ? "SHARED" : "PRIVATE",
+ (surface->type & CSTF_LAYER) ? " LAYER" : "",
+ (surface->type & CSTF_WINDOW) ? " WINDOW" : "",
+ (surface->type & CSTF_CURSOR) ? " CURSOR" : "",
+ (surface->type & CSTF_FONT) ? " FONT" : "",
+ (surface->type & CSTF_INTERNAL) ? " INTERNAL" : "",
+ (surface->type & CSTF_EXTERNAL) ? " EXTERNAL" : "",
+ (surface->type & CSTF_PREALLOCATED) ? " PREALLOCATED" : "" );
+
+ D_ASSERT( accessor >= CSAID_CPU );
+ D_ASSUME( accessor < _CSAID_NUM );
+ if (accessor >= CSAID_ANY) {
+ D_UNIMPLEMENTED();
+ return DFB_UNIMPLEMENTED;
+ }
+
+ if (accessor < 0 || accessor >= _CSAID_NUM)
+ return DFB_INVARG;
+
+ /* Build a list of possible pools being free or out of memory */
+ ret = dfb_surface_pools_negotiate( buffer, accessor, access, pools, pool_count, &num_pools );
+ if (ret && ret != DFB_NOVIDEOMEMORY) {
+ D_DEBUG_AT( Core_SurfacePool, " -> NEGOTIATION FAILED! (%s)\n", DirectFBErrorString( ret ) );
+ return ret;
+ }
+
+ /* Try to do the allocation in one of the pools */
+ for (i=0; i<num_pools; i++) {
+ CoreSurfacePool *pool = pools[i];
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ ret = dfb_surface_pool_allocate( pool, buffer, &allocation );
+
+ if (ret == DFB_OK)
+ break;
+
+ /* When an error other than out of memory happens... */
+ if (ret != DFB_NOVIDEOMEMORY) {
+ D_DEBUG_AT( Core_SurfacePool, " -> Allocation in '%s' failed!\n", pool->desc.name );
+
+ /* ...forget about the pool for now */
+ pools[i] = NULL;
+ }
+ }
+
+ /* Check if none of the pools could do the allocation */
+ if (!allocation) {
+ /* Try to find a pool with "older" allocations to muck out */
+ for (i=0; i<num_pools; i++) {
+ CoreSurfacePool *pool = pools[i];
+
+ /* Pools with non-oom errors were sorted out above */
+ if (!pool)
+ continue;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ ret = dfb_surface_pool_displace( pool, buffer, &allocation );
+
+ if (ret == DFB_OK)
+ break;
+ }
+ }
+
+ /* Still no luck? */
+ if (!allocation) {
+ D_DEBUG_AT( Core_SurfacePool, " -> FAILED!\n" );
+ return DFB_FAILURE;
+ }
+
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+
+ D_DEBUG_AT( Core_SurfacePool, " -> %p\n", allocation );
+
+ *ret_allocation = allocation;
+
+ return DFB_OK;
+}
+
+/**********************************************************************************************************************/
+
+DFBResult
+dfb_surface_pool_allocate( CoreSurfacePool *pool,
+ CoreSurfaceBuffer *buffer,
+ CoreSurfaceAllocation **ret_allocation )
+{
+ DFBResult ret;
+ int i;
+ CoreSurface *surface;
+ CoreSurfaceAllocation *allocation = NULL;
+ const SurfacePoolFuncs *funcs;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+ D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, buffer );
+
+ D_ASSERT( ret_allocation != NULL );
+
+ surface = buffer->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+ FUSION_SKIRMISH_ASSERT( &surface->lock );
+
+ funcs = get_funcs( pool );
+
+ D_ASSERT( funcs->AllocateBuffer != NULL );
+
+ allocation = SHCALLOC( pool->shmpool, 1, sizeof(CoreSurfaceAllocation) );
+ if (!allocation)
+ return D_OOSHM();
+
+ allocation->buffer = buffer;
+ allocation->surface = surface;
+ allocation->pool = pool;
+ allocation->access = pool->desc.access;
+
+ if (pool->alloc_data_size) {
+ allocation->data = SHCALLOC( pool->shmpool, 1, pool->alloc_data_size );
+ if (!allocation->data) {
+ ret = D_OOSHM();
+ goto error;
+ }
+ }
+
+ D_MAGIC_SET( allocation, CoreSurfaceAllocation );
+
+ if (fusion_skirmish_prevail( &pool->lock )) {
+ ret = DFB_FUSION;
+ goto error;
+ }
+
+ if (dfb_config->warn.flags & DCWF_ALLOCATE_BUFFER &&
+ dfb_config->warn.allocate_buffer.min_size.w <= surface->config.size.w &&
+ dfb_config->warn.allocate_buffer.min_size.h <= surface->config.size.h)
+ D_WARN( "allocate-buffer %4dx%4d %6s, surface-caps 0x%08x",
+ surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(buffer->format),
+ surface->config.caps );
+
+ ret = funcs->AllocateBuffer( pool, pool->data, get_local(pool), buffer, allocation, allocation->data );
+ if (ret) {
+ D_DEBUG_AT( Core_SurfacePool, " -> %s\n", DirectFBErrorString( ret ) );
+ D_MAGIC_CLEAR( allocation );
+ fusion_skirmish_dismiss( &pool->lock );
+ goto error;
+ }
+
+ D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation );
+
+ if (allocation->flags & CSALF_ONEFORALL) {
+ for (i=0; i<surface->num_buffers; i++) {
+ buffer = surface->buffers[i];
+
+ D_ASSUME( fusion_vector_is_empty( &buffer->allocs ) );
+
+ D_DEBUG_AT( Core_SurfacePool, " -> %p (%d)\n", allocation, i );
+ fusion_vector_add( &buffer->allocs, allocation );
+ fusion_vector_add( &pool->allocs, allocation );
+ }
+ }
+ else {
+ D_DEBUG_AT( Core_SurfacePool, " -> %p\n", allocation );
+ fusion_vector_add( &buffer->allocs, allocation );
+ fusion_vector_add( &pool->allocs, allocation );
+ }
+
+ direct_serial_init( &allocation->serial );
+
+ fusion_skirmish_dismiss( &pool->lock );
+
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+
+ *ret_allocation = allocation;
+
+ return DFB_OK;
+
+error:
+ if (allocation->data)
+ SHFREE( pool->shmpool, allocation->data );
+
+ SHFREE( pool->shmpool, allocation );
+
+ return ret;
+}
+
+DFBResult
+dfb_surface_pool_deallocate( CoreSurfacePool *pool,
+ CoreSurfaceAllocation *allocation )
+{
+ DFBResult ret;
+ int i;
+ const SurfacePoolFuncs *funcs;
+ CoreSurfaceBuffer *buffer;
+ CoreSurface *surface;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation );
+
+ D_ASSERT( pool == allocation->pool );
+
+ buffer = allocation->buffer;
+ D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
+
+ surface = buffer->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+ FUSION_SKIRMISH_ASSERT( &surface->lock );
+
+ funcs = get_funcs( pool );
+
+ D_ASSERT( funcs->DeallocateBuffer != NULL );
+
+ if (fusion_skirmish_prevail( &pool->lock ))
+ return DFB_FUSION;
+
+ ret = funcs->DeallocateBuffer( pool, pool->data, get_local(pool), allocation->buffer, allocation, allocation->data );
+ if (ret) {
+ D_DERROR( ret, "Core/SurfacePool: Could not deallocate buffer!\n" );
+ fusion_skirmish_dismiss( &pool->lock );
+ return ret;
+ }
+
+ if (allocation->flags & CSALF_ONEFORALL) {
+ for (i=0; i<surface->num_buffers; i++)
+ remove_allocation( pool, surface->buffers[i], allocation );
+ }
+ else
+ remove_allocation( pool, buffer, allocation );
+
+ fusion_skirmish_dismiss( &pool->lock );
+
+ if (allocation->data)
+ SHFREE( pool->shmpool, allocation->data );
+
+ direct_serial_deinit( &allocation->serial );
+
+ D_MAGIC_CLEAR( allocation );
+
+ SHFREE( pool->shmpool, allocation );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_surface_pool_displace( CoreSurfacePool *pool,
+ CoreSurfaceBuffer *buffer,
+ CoreSurfaceAllocation **ret_allocation )
+{
+ DFBResult ret, ret_lock = DFB_OK;
+ int i, retries = 3;
+ CoreSurface *surface;
+ CoreSurfaceAllocation *allocation;
+ const SurfacePoolFuncs *funcs;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+ D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, buffer );
+
+ D_ASSERT( ret_allocation != NULL );
+
+ surface = buffer->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+ FUSION_SKIRMISH_ASSERT( &surface->lock );
+
+ funcs = get_funcs( pool );
+
+ if (fusion_skirmish_prevail( &pool->lock ))
+ return DFB_FUSION;
+
+ /* Check for integrated method to muck out "older" allocations for a new one */
+ if (funcs->MuckOut) {
+ ret = funcs->MuckOut( pool, pool->data, get_local(pool), buffer );
+ if (ret) {
+ fusion_skirmish_dismiss( &pool->lock );
+ return ret;
+ }
+ }
+ else {
+ /* Or take the generic approach via allocation list */
+ D_UNIMPLEMENTED();
+ }
+
+ /* FIXME: Solve potential dead lock, until then do a few retries... */
+fixme_retry:
+ fusion_vector_foreach (allocation, i, pool->allocs) {
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+
+ if (allocation->flags & CSALF_MUCKOUT) {
+ CoreSurface *alloc_surface;
+ CoreSurfaceBuffer *alloc_buffer;
+
+ alloc_buffer = allocation->buffer;
+ D_MAGIC_ASSERT( alloc_buffer, CoreSurfaceBuffer );
+
+ alloc_surface = alloc_buffer->surface;
+ D_MAGIC_ASSERT( alloc_surface, CoreSurface );
+
+ D_DEBUG_AT( Core_SurfacePool, " <= %p %5dk, %lu\n",
+ allocation, allocation->size / 1024, allocation->offset );
+
+ /* FIXME: Solve potential dead lock, until then only try to lock... */
+ ret = dfb_surface_trylock( alloc_surface );
+ if (ret) {
+ D_WARN( "could not lock surface (%s)", DirectFBErrorString(ret) );
+ ret_lock = ret;
+ continue;
+ }
+
+ /* Ensure mucked out allocation is backed up in another pool */
+ ret = backup_allocation( pool, buffer, allocation );
+ if (ret) {
+ D_WARN( "could not backup allocation (%s)", DirectFBErrorString(ret) );
+ dfb_surface_unlock( alloc_surface );
+ goto error_cleanup;
+ }
+
+ /* Deallocate mucked out allocation */
+ dfb_surface_pool_deallocate( pool, allocation );
+ i--;
+
+ dfb_surface_unlock( alloc_surface );
+ }
+ }
+
+ /* FIXME: Solve potential dead lock, until then do a few retries... */
+ if (ret_lock) {
+ if (retries--)
+ goto fixme_retry;
+
+ ret = DFB_LOCKED;
+
+ goto error_cleanup;
+ }
+ else
+ ret = dfb_surface_pool_allocate( pool, buffer, ret_allocation );
+
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return ret;
+
+
+error_cleanup:
+ fusion_vector_foreach (allocation, i, pool->allocs) {
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+
+ if (allocation->flags & CSALF_MUCKOUT)
+ allocation->flags &= ~CSALF_MUCKOUT;
+ }
+
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return ret;
+}
+
+DFBResult
+dfb_surface_pool_lock( CoreSurfacePool *pool,
+ CoreSurfaceAllocation *allocation,
+ CoreSurfaceBufferLock *lock )
+{
+ DFBResult ret;
+ const SurfacePoolFuncs *funcs;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation );
+
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+ CORE_SURFACE_BUFFER_LOCK_ASSERT( lock );
+ D_ASSERT( lock->buffer == NULL );
+
+ D_ASSERT( pool == allocation->pool );
+
+ funcs = get_funcs( pool );
+
+ D_ASSERT( funcs->Lock != NULL );
+
+ lock->allocation = allocation;
+ lock->buffer = allocation->buffer;
+
+ ret = funcs->Lock( pool, pool->data, get_local(pool), allocation, allocation->data, lock );
+ if (ret) {
+ D_DERROR( ret, "Core/SurfacePool: Could not lock allocation!\n" );
+ dfb_surface_buffer_lock_reset( lock );
+ return ret;
+ }
+
+ CORE_SURFACE_BUFFER_LOCK_ASSERT( lock );
+ D_ASSERT( lock->buffer != NULL );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_surface_pool_unlock( CoreSurfacePool *pool,
+ CoreSurfaceAllocation *allocation,
+ CoreSurfaceBufferLock *lock )
+{
+ DFBResult ret;
+ const SurfacePoolFuncs *funcs;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation );
+
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+ CORE_SURFACE_BUFFER_LOCK_ASSERT( lock );
+ D_ASSERT( lock->buffer != NULL );
+
+ D_ASSERT( pool == allocation->pool );
+
+ funcs = get_funcs( pool );
+
+ D_ASSERT( funcs->Unlock != NULL );
+
+ ret = funcs->Unlock( pool, pool->data, get_local(pool), allocation, allocation->data, lock );
+ if (ret) {
+ D_DERROR( ret, "Core/SurfacePool: Could not unlock allocation!\n" );
+ return ret;
+ }
+
+ CORE_SURFACE_BUFFER_LOCK_ASSERT( lock );
+ D_ASSERT( lock->buffer != NULL );
+
+ dfb_surface_buffer_lock_reset( lock );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_surface_pool_read( CoreSurfacePool *pool,
+ CoreSurfaceAllocation *allocation,
+ void *data,
+ int pitch,
+ const DFBRectangle *rect )
+{
+ DFBResult ret;
+ const SurfacePoolFuncs *funcs;
+ CoreSurface *surface;
+ DFBRectangle area;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation );
+
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+ D_ASSERT( data != NULL );
+ D_ASSERT( pitch >= 0 );
+ DFB_RECTANGLE_ASSERT_IF( rect );
+
+ D_ASSERT( pool == allocation->pool );
+
+ funcs = get_funcs( pool );
+ D_ASSERT( funcs != NULL );
+
+ if (!funcs->Read)
+ return DFB_UNSUPPORTED;
+
+ surface = allocation->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+
+ area.x = 0;
+ area.y = 0;
+ area.w = surface->config.size.w;
+ area.h = surface->config.size.h;
+
+ if (rect && !dfb_rectangle_intersect( &area, rect ))
+ return DFB_INVAREA;
+
+ ret = funcs->Read( pool, pool->data, get_local(pool), allocation, allocation->data, data, pitch, &area );
+ if (ret)
+ D_DERROR( ret, "Core/SurfacePool: Could not read from allocation!\n" );
+
+ return ret;
+}
+
+DFBResult
+dfb_surface_pool_write( CoreSurfacePool *pool,
+ CoreSurfaceAllocation *allocation,
+ const void *data,
+ int pitch,
+ const DFBRectangle *rect )
+{
+ DFBResult ret;
+ const SurfacePoolFuncs *funcs;
+ CoreSurface *surface;
+ DFBRectangle area;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+
+ D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation );
+
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+ D_ASSERT( data != NULL );
+ D_ASSERT( pitch >= 0 );
+ DFB_RECTANGLE_ASSERT_IF( rect );
+
+ D_ASSERT( pool == allocation->pool );
+
+ funcs = get_funcs( pool );
+ D_ASSERT( funcs != NULL );
+
+ if (!funcs->Write)
+ return DFB_UNSUPPORTED;
+
+ surface = allocation->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+
+ area.x = 0;
+ area.y = 0;
+ area.w = surface->config.size.w;
+ area.h = surface->config.size.h;
+
+ if (rect && !dfb_rectangle_intersect( &area, rect ))
+ return DFB_INVAREA;
+
+ ret = funcs->Write( pool, pool->data, get_local(pool), allocation, allocation->data, data, pitch, &area );
+ if (ret)
+ D_DERROR( ret, "Core/SurfacePool: Could not write to allocation!\n" );
+
+ return ret;
+}
+
+DFBResult
+dfb_surface_pool_enumerate ( CoreSurfacePool *pool,
+ CoreSurfaceAllocCallback callback,
+ void *ctx )
+{
+ int i;
+ CoreSurfaceAllocation *allocation;
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p, %p )\n", __FUNCTION__, pool, callback, ctx );
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+ D_ASSERT( callback != NULL );
+
+ fusion_vector_foreach (allocation, i, pool->allocs) {
+ if (callback( allocation, ctx ) == DFENUM_CANCEL)
+ break;
+ }
+
+ return DFB_OK;
+}
+
+/**********************************************************************************************************************/
+
+static DFBResult
+init_pool( CoreDFB *core,
+ CoreSurfacePool *pool,
+ const SurfacePoolFuncs *funcs )
+{
+ DFBResult ret;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+ D_ASSERT( funcs != NULL );
+ D_ASSERT( funcs->InitPool != NULL );
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, pool, funcs );
+
+ if (funcs->PoolDataSize)
+ pool->pool_data_size = funcs->PoolDataSize();
+
+ if (funcs->PoolLocalDataSize)
+ pool->pool_local_data_size = funcs->PoolLocalDataSize();
+
+ if (funcs->AllocationDataSize)
+ pool->alloc_data_size = funcs->AllocationDataSize();
+
+ /* Allocate shared pool data. */
+ if (pool->pool_data_size) {
+ pool->data = SHCALLOC( pool->shmpool, 1, pool->pool_data_size );
+ if (!pool->data)
+ return D_OOSHM();
+ }
+
+ /* Allocate local pool data. */
+ if (pool->pool_local_data_size &&
+ !(pool_locals[pool->pool_id] = D_CALLOC( 1, pool->pool_local_data_size )))
+ {
+ SHFREE( pool->shmpool, pool->data );
+ return D_OOM();
+ }
+
+ fusion_vector_init( &pool->allocs, 4, pool->shmpool );
+
+ ret = funcs->InitPool( core, pool, pool->data, get_local(pool), dfb_system_data(), &pool->desc );
+ if (ret) {
+ D_DERROR( ret, "Core/SurfacePool: Initializing '%s' failed!\n", pool->desc.name );
+
+ if (pool_locals[pool->pool_id]) {
+ D_FREE( pool_locals[pool->pool_id] );
+ pool_locals[pool->pool_id] = NULL;
+ }
+ if (pool->data) {
+ SHFREE( pool->shmpool, pool->data );
+ pool->data = NULL;
+ }
+ return ret;
+ }
+
+ fusion_skirmish_init( &pool->lock, pool->desc.name, dfb_core_world(core) );
+
+ return DFB_OK;
+}
+
+static void
+insert_pool_local( CoreSurfacePool *pool )
+{
+ int i, n;
+
+ for (i=0; i<pool_count-1; i++) {
+ D_ASSERT( pool_order[i] >= 0 );
+ D_ASSERT( pool_order[i] < pool_count-1 );
+
+ D_MAGIC_ASSERT( pool_array[pool_order[i]], CoreSurfacePool );
+
+ if (pool_array[pool_order[i]]->desc.priority < pool->desc.priority)
+ break;
+ }
+
+ for (n=pool_count-1; n>i; n--) {
+ D_ASSERT( pool_order[n-1] >= 0 );
+ D_ASSERT( pool_order[n-1] < pool_count-1 );
+
+ D_MAGIC_ASSERT( pool_array[pool_order[n-1]], CoreSurfacePool );
+
+ pool_order[n] = pool_order[n-1];
+ }
+
+ pool_order[n] = pool_count - 1;
+
+#if D_DEBUG_ENABLED
+ for (i=0; i<pool_count; i++) {
+ D_DEBUG_AT( Core_SurfacePool, " %c> [%d] %p - '%s' [%d] (%d), %p\n",
+ (i == n) ? '=' : '-', i, pool_array[pool_order[i]], pool_array[pool_order[i]]->desc.name,
+ pool_array[pool_order[i]]->pool_id, pool_array[pool_order[i]]->desc.priority,
+ pool_funcs[pool_order[i]] );
+ D_ASSERT( pool_order[i] == pool_array[pool_order[i]]->pool_id );
+ }
+#endif
+}
+
+static void
+remove_pool_local( CoreSurfacePoolID pool_id )
+{
+ int i;
+
+ /* Free local pool data. */
+ if (pool_locals[pool_id]) {
+ D_FREE( pool_locals[pool_id] );
+ pool_locals[pool_id] = NULL;
+ }
+
+ /* Erase entries of the pool. */
+ pool_array[pool_id] = NULL;
+ pool_funcs[pool_id] = NULL;
+
+ while (pool_count > 0 && !pool_array[pool_count-1]) {
+ pool_count--;
+
+ for (i=0; i<pool_count; i++) {
+ if (pool_order[i] == pool_count) {
+ direct_memmove( &pool_order[i], &pool_order[i+1], sizeof(pool_order[0]) * (pool_count - i) );
+ break;
+ }
+ }
+ }
+}
+
+/**********************************************************************************************************************/
+
+static void
+remove_allocation( CoreSurfacePool *pool,
+ CoreSurfaceBuffer *buffer,
+ CoreSurfaceAllocation *allocation )
+{
+ int index_buffer;
+ int index_pool;
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+ D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+ D_MAGIC_ASSERT( buffer->surface, CoreSurface );
+ FUSION_SKIRMISH_ASSERT( &buffer->surface->lock );
+ FUSION_SKIRMISH_ASSERT( &pool->lock );
+ D_ASSERT( pool == allocation->pool );
+
+ /* Lookup indices within vectors */
+ index_buffer = fusion_vector_index_of( &buffer->allocs, allocation );
+ index_pool = fusion_vector_index_of( &pool->allocs, allocation );
+
+ D_ASSERT( index_buffer >= 0 );
+ D_ASSERT( index_pool >= 0 );
+
+ /* Remove allocation from buffer and pool */
+ fusion_vector_remove( &buffer->allocs, index_buffer );
+ fusion_vector_remove( &pool->allocs, index_pool );
+
+ /* Update 'written' allocation pointer of buffer */
+ if (buffer->written == allocation) {
+ /* Reset pointer first */
+ buffer->written = NULL;
+
+ /* Iterate through remaining allocations */
+ fusion_vector_foreach (allocation, index_buffer, buffer->allocs) {
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+
+ /* Check if allocation is up to date and set it as 'written' allocation */
+ if (direct_serial_check( &allocation->serial, &buffer->serial )) {
+ buffer->written = allocation;
+ break;
+ }
+ }
+ }
+
+ /* Reset 'read' allocation pointer of buffer */
+ if (buffer->read == allocation)
+ buffer->read = NULL;
+}
+
+static DFBResult
+backup_allocation( CoreSurfacePool *pool,
+ CoreSurfaceBuffer *buffer,
+ CoreSurfaceAllocation *allocation )
+{
+ DFBResult ret = DFB_OK;
+ int i;
+ CoreSurfaceAllocation *backup = NULL;
+
+ D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, pool, allocation );
+
+ D_MAGIC_ASSERT( pool, CoreSurfacePool );
+ D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );
+ CORE_SURFACE_ALLOCATION_ASSERT( allocation );
+ D_MAGIC_ASSERT( buffer->surface, CoreSurface );
+ FUSION_SKIRMISH_ASSERT( &buffer->surface->lock );
+ FUSION_SKIRMISH_ASSERT( &pool->lock );
+ D_ASSERT( pool == allocation->pool );
+
+ /* Check if allocation is the only up to date (requiring a backup) */
+ if (direct_serial_check( &allocation->serial, &buffer->serial )) {
+ CoreSurfacePool *backup_pool = pool->backup;
+
+ /* First check if any of the existing allocations is up to date */
+ fusion_vector_foreach (backup, i, buffer->allocs) {
+ D_MAGIC_ASSERT( backup, CoreSurfaceAllocation );
+ D_MAGIC_ASSERT( backup->pool, CoreSurfacePool );
+
+ if (backup->pool != pool && direct_serial_check( &backup->serial, &buffer->serial )) {
+ D_DEBUG_AT( Core_SurfacePool, " -> up to date in '%s'\n", backup->pool->desc.name );
+ return DFB_OK;
+ }
+ }
+
+ /* Try to update one of the existing allocations */
+ fusion_vector_foreach (backup, i, buffer->allocs) {
+ D_MAGIC_ASSERT( backup, CoreSurfaceAllocation );
+ D_MAGIC_ASSERT( backup->pool, CoreSurfacePool );
+
+ if (backup->pool != pool && dfb_surface_allocation_update( backup, CSAF_NONE ) == DFB_OK) {
+ D_DEBUG_AT( Core_SurfacePool, " -> updated in '%s'\n", backup->pool->desc.name );
+ return DFB_OK;
+ }
+ }
+
+ /* Try the designated backup pool and theirs if failing */
+ while (backup_pool) {
+ D_MAGIC_ASSERT( backup_pool, CoreSurfacePool );
+
+ D_DEBUG_AT( Core_SurfacePool, " -> allocating in '%s'\n", backup_pool->desc.name );
+
+ /* Allocate in backup pool */
+ ret = dfb_surface_pool_allocate( backup_pool, buffer, &backup );
+ if (ret == DFB_OK) {
+ /* Update new allocation */
+ ret = dfb_surface_allocation_update( backup, CSAF_NONE );
+ if (ret) {
+ D_DEBUG_AT( Core_SurfacePool, " -> update failed! (%s)\n", DirectFBErrorString(ret) );
+ dfb_surface_pool_deallocate( backup_pool, backup );
+ backup = NULL;
+ }
+ else
+ return DFB_OK;
+ }
+ else
+ D_DEBUG_AT( Core_SurfacePool, " -> allocation failed! (%s)\n", DirectFBErrorString(ret) );
+
+ backup_pool = backup_pool->backup;
+ }
+ }
+ else
+ D_DEBUG_AT( Core_SurfacePool, " -> not up to date anyhow\n" );
+
+ return ret;
+}
+