<commit_before>/*
   (c) Copyright 2001-2012  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>> and
              <NAME> <<EMAIL>>.

   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/conf.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,
                            void                   *ctx );

/**********************************************************************************************************************/

static void insert_pool_local( CoreSurfacePool   *pool );
static void remove_pool_local( CoreSurfacePoolID  pool_id );

/**********************************************************************************************************************/

static void      remove_allocation( CoreSurfacePool       *pool,
                                    CoreSurfaceAllocation *allocation );

static DFBResult backup_allocation( CoreSurfaceAllocation *allocation );

/**********************************************************************************************************************/

/*
 * Enable a surface pool to obtain its own local data without having to
 * explicitly store a static local pointer to it during init/join.
 */
void *
dfb_surface_pool_get_local( const CoreSurfacePool *pool )
{
     return get_local( pool );
}

DFBResult
dfb_surface_pool_initialize( CoreDFB                 *core,
                             const SurfacePoolFuncs  *funcs,
                             CoreSurfacePool        **ret_pool )
{
     return dfb_surface_pool_initialize2( core, funcs, dfb_system_data(), ret_pool );
}

DFBResult
dfb_surface_pool_initialize2( CoreDFB                 *core,
                              const SurfacePoolFuncs  *funcs,
                              void                    *ctx,
                              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, ctx );
     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 )
{
     return dfb_surface_pool_join2( core, pool, funcs, dfb_system_data() );
}

DFBResult
dfb_surface_pool_join2( CoreDFB                *core,
                        CoreSurfacePool        *pool,
                        const SurfacePoolFuncs *funcs,
                        void                   *ctx )
{
     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), ctx );
          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_prealloc( const DFBSurfaceDescription *description,
                            CoreSurfaceConfig           *config )
{
     DFBResult            ret;
     int                  i;
     CoreSurfaceTypeFlags type;

     D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, description, config );

     D_ASSERT( description != NULL );
     D_ASSERT( config != NULL );

     type = CSTF_PREALLOCATED;

     if (description->flags & DSDESC_CAPS) {
          if (description->caps & DSCAPS_SYSTEMONLY)
               type |= CSTF_INTERNAL;

          if (description->caps & DSCAPS_VIDEOONLY)
               type |= CSTF_EXTERNAL;
     }

     D_DEBUG_AT( Core_SurfacePool, "  ->     type 0x%03x required\n", 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.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 );

               if (funcs->PreAlloc) {
                    ret = funcs->PreAlloc( pool, pool->data, get_local(pool), description, config );
                    if (ret == DFB_OK) {
                         config->preallocated_pool_id = pool->pool_id;
                         return DFB_OK;
                    }
               }
          }
     }

     return DFB_UNSUPPORTED;
}

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;
     }

#if D_DEBUG_ENABLED
     D_DEBUG_AT( Core_SurfacePool, "  ->     0x%02x 0x%03x required\n", access, type );

     if (access & CSAF_READ)
          D_DEBUG_AT( Core_SurfacePool, "  ->     READ\n" );

     if (access & CSAF_WRITE)
          D_DEBUG_AT( Core_SurfacePool, "  ->     WRITE\n" );

     if (access & CSAF_SHARED)
          D_DEBUG_AT( Core_SurfacePool, "  ->     SHARED\n" );

     if (type & CSTF_LAYER)
          D_DEBUG_AT( Core_SurfacePool, "  ->     LAYER\n" );

     if (type & CSTF_WINDOW)
          D_DEBUG_AT( Core_SurfacePool, "  ->     WINDOW\n" );

     if (type & CSTF_CURSOR)
          D_DEBUG_AT( Core_SurfacePool, "  ->     CURSOR\n" );

     if (type & CSTF_FONT)
          D_DEBUG_AT( Core_SurfacePool, "  ->     FONT\n" );

     if (type & CSTF_SHARED)
          D_DEBUG_AT( Core_SurfacePool, "  ->     SHARED\n" );

     if (type & CSTF_INTERNAL)
          D_DEBUG_AT( Core_SurfacePool, "  ->     INTERNAL\n" );

     if (type & CSTF_EXTERNAL)
          D_DEBUG_AT( Core_SurfacePool, "  ->     EXTERNAL\n" );

     if (type & CSTF_PREALLOCATED)
          D_DEBUG_AT( Core_SurfacePool, "  ->     PREALLOCATED\n" );
#endif

     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 & ~CSTF_PREALLOCATED ))
          {
               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;<commit_msg>debug: Print each pools access/types in dfb_surface_pools_negotiate().<commit_after>/*
   (c) Copyright 2001-2012  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>> and
              <NAME> <<EMAIL>>.

   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/conf.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,
                            void                   *ctx );

/**********************************************************************************************************************/

static void insert_pool_local( CoreSurfacePool   *pool );
static void remove_pool_local( CoreSurfacePoolID  pool_id );

/**********************************************************************************************************************/

static void      remove_allocation( CoreSurfacePool       *pool,
                                    CoreSurfaceAllocation *allocation );

static DFBResult backup_allocation( CoreSurfaceAllocation *allocation );

/**********************************************************************************************************************/

/*
 * Enable a surface pool to obtain its own local data without having to
 * explicitly store a static local pointer to it during init/join.
 */
void *
dfb_surface_pool_get_local( const CoreSurfacePool *pool )
{
     return get_local( pool );
}

DFBResult
dfb_surface_pool_initialize( CoreDFB                 *core,
                             const SurfacePoolFuncs  *funcs,
                             CoreSurfacePool        **ret_pool )
{
     return dfb_surface_pool_initialize2( core, funcs, dfb_system_data(), ret_pool );
}

DFBResult
dfb_surface_pool_initialize2( CoreDFB                 *core,
                              const SurfacePoolFuncs  *funcs,
                              void                    *ctx,
                              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, ctx );
     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 )
{
     return dfb_surface_pool_join2( core, pool, funcs, dfb_system_data() );
}

DFBResult
dfb_surface_pool_join2( CoreDFB                *core,
                        CoreSurfacePool        *pool,
                        const SurfacePoolFuncs *funcs,
                        void                   *ctx )
{
     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), ctx );
          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_prealloc( const DFBSurfaceDescription *description,
                            CoreSurfaceConfig           *config )
{
     DFBResult            ret;
     int                  i;
     CoreSurfaceTypeFlags type;

     D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, description, config );

     D_ASSERT( description != NULL );
     D_ASSERT( config != NULL );

     type = CSTF_PREALLOCATED;

     if (description->flags & DSDESC_CAPS) {
          if (description->caps & DSCAPS_SYSTEMONLY)
               type |= CSTF_INTERNAL;

          if (description->caps & DSCAPS_VIDEOONLY)
               type |= CSTF_EXTERNAL;
     }

     D_DEBUG_AT( Core_SurfacePool, "  ->     type 0x%03x required\n", 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.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 );

               if (funcs->PreAlloc) {
                    ret = funcs->PreAlloc( pool, pool->data, get_local(pool), description, config );
                    if (ret == DFB_OK) {
                         config->preallocated_pool_id = pool->pool_id;
                         return DFB_OK;
                    }
               }
          }
     }

     return DFB_UNSUPPORTED;
}

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;
     }

#if D_DEBUG_ENABLED
     D_DEBUG_AT( Core_SurfacePool, "  ->     0x%02x 0x%03x required\n", access, type );

     if (access & CSAF_READ)
          D_DEBUG_AT( Core_SurfacePool, "  ->     READ\n" );

     if (access & CSAF_WRITE)
          D_DEBUG_AT( Core_SurfacePool, "  ->     WRITE\n" );

     if (access & CSAF_SHARED)
          D_DEBUG_AT( Core_SurfacePool, "  ->     SHARED\n" );

     if (type & CSTF_LAYER)
          D_DEBUG_AT( Core_SurfacePool, "  ->     LAYER\n" );

     if (type & CSTF_WINDOW)
          D_DEBUG_AT( Core_SurfacePool, "  ->     WINDOW\n" );

     if (type & CSTF_CURSOR)
          D_DEBUG_AT( Core_SurfacePool, "  ->     CURSOR\n" );

     if (type & CSTF_FONT)
          D_DEBUG_AT( Core_SurfacePool, "  ->     FONT\n" );

     if (type & CSTF_SHARED)
          D_DEBUG_AT( Core_SurfacePool, "  ->     SHARED\n" );

     if (type & CSTF_INTERNAL)
          D_DEBUG_AT( Core_SurfacePool, "  ->     INTERNAL\n" );

     if (type & CSTF_EXTERNAL)
          D_DEBUG_AT( Core_SurfacePool, "  ->     EXTERNAL\n" );

     if (type & CSTF_PREALLOCATED)
          D_DEBUG_AT( Core_SurfacePool, "  ->     PREALLOCATED\n" );
#endif

     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 );

          D_DEBUG_AT( Core_SurfacePool, "  ->     0x%02x 0x%03x (%s)\n", pool->desc.access[accessor], pool->desc.types, pool->desc.name );

          if (D_FLAGS_ARE_SET( pool->desc.access[accessor], access ) &&
              D_FLAGS_ARE_SET( pool->desc.types, type & ~CSTF_PREALLOCATED ))
          {
               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;
{'fraction_non_alphanumeric': 0.1517063552252389, 'fraction_numerical': 0.005096314272713484, 'mean_word_length': 2.1396190476190475, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 285, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5158177', 'n_tokens_mistral': 10367, 'n_tokens_neox': 9855, 'n_words': 2313}