/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_ColorHash, "Core/ColorHash", "DirectFB ColorHash Core" ); #define HASH_SIZE 823 typedef struct { unsigned int pixel; unsigned int index; CorePalette *palette; } Colorhash; /**********************************************************************************************************************/ typedef struct { int magic; Colorhash *hash; unsigned int hash_users; FusionSkirmish hash_lock; FusionSHMPoolShared *shmpool; } DFBColorHashCoreShared; struct __DFB_DFBColorHashCore { int magic; CoreDFB *core; DFBColorHashCoreShared *shared; }; DFB_CORE_PART( colorhash_core, ColorHashCore ); /**********************************************************************************************************************/ static DFBColorHashCore *core_colorhash; /* FIXME */ static DFBResult dfb_colorhash_core_initialize( CoreDFB *core, DFBColorHashCore *data, DFBColorHashCoreShared *shared ) { D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_initialize( %p, %p, %p )\n", core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); core_colorhash = data; /* FIXME */ data->core = core; data->shared = shared; shared->shmpool = dfb_core_shmpool( core ); fusion_skirmish_init( &shared->hash_lock, "Colorhash Core", dfb_core_world(core) ); D_MAGIC_SET( data, DFBColorHashCore ); D_MAGIC_SET( shared, DFBColorHashCoreShared ); return DFB_OK; } static DFBResult dfb_colorhash_core_join( CoreDFB *core, DFBColorHashCore *data, DFBColorHashCoreShared *shared ) { D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_join( %p, %p, %p )\n", core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBColorHashCoreShared ); core_colorhash = data; /* FIXME */ data->core = core; data->shared = shared; D_MAGIC_SET( data, DFBColorHashCore ); return DFB_OK; } static DFBResult dfb_colorhash_core_shutdown( DFBColorHashCore *data, bool emergency ) { DFBColorHashCoreShared *shared; D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); shared = data->shared; fusion_skirmish_destroy( &shared->hash_lock ); D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult dfb_colorhash_core_leave( DFBColorHashCore *data, bool emergency ) { DFBColorHashCoreShared *shared; D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); shared = data->shared; D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_colorhash_core_suspend( DFBColorHashCore *data ) { DFBColorHashCoreShared *shared; D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_suspend( %p )\n", data ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); shared = data->shared; return DFB_OK; } static DFBResult dfb_colorhash_core_resume( DFBColorHashCore *data ) { DFBColorHashCoreShared *shared; D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_resume( %p )\n", data ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); shared = data->shared; return DFB_OK; } /**********************************************************************************************************************/ void dfb_colorhash_attach( DFBColorHashCore *core, CorePalette *palette ) { DFBColorHashCoreShared *shared; D_ASSUME( core != NULL ); if (core) { D_MAGIC_ASSERT( core, DFBColorHashCore ); D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); } else core = core_colorhash; shared = core->shared; fusion_skirmish_prevail( &shared->hash_lock ); if (!shared->hash) { D_ASSERT( shared->hash_users == 0 ); shared->hash = SHCALLOC( shared->shmpool, HASH_SIZE, sizeof (Colorhash) ); } shared->hash_users++; fusion_skirmish_dismiss( &shared->hash_lock ); } void dfb_colorhash_detach( DFBColorHashCore *core, CorePalette *palette ) { DFBColorHashCoreShared *shared; D_ASSUME( core != NULL ); if (core) { D_MAGIC_ASSERT( core, DFBColorHashCore ); D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); } else core = core_colorhash; shared = core->shared; D_ASSERT( shared->hash_users > 0 ); D_ASSERT( shared->hash != NULL ); fusion_skirmish_prevail( &shared->hash_lock ); shared->hash_users--; if (!shared->hash_users) { /* no more users, free allocated resources */ SHFREE( shared->shmpool, shared->hash ); shared->hash = NULL; } fusion_skirmish_dismiss( &shared->hash_lock ); } unsigned int dfb_colorhash_lookup( DFBColorHashCore *core, CorePalette *palette, u8 r, u8 g, u8 b, u8 a ) { unsigned int pixel = PIXEL_ARGB(a, r, g, b); unsigned int index = (pixel ^ (unsigned long) palette) % HASH_SIZE; DFBColorHashCoreShared *shared; // D_ASSUME( core != NULL ); if (core) { D_MAGIC_ASSERT( core, DFBColorHashCore ); D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); } else core = core_colorhash; shared = core->shared; D_ASSERT( shared->hash != NULL ); fusion_skirmish_prevail( &shared->hash_lock ); /* try a lookup in the hash table */ if (shared->hash[index].palette == palette && shared->hash[index].pixel == pixel) { /* set the return value */ index = shared->hash[index].index; } else { /* look for the closest match */ DFBColor *entries = palette->entries; int min_diff = 0; unsigned int i, min_index = 0; for (i = 0; i < palette->num_entries; i++) { int diff; int r_diff = (int) entries[i].r - (int) r; int g_diff = (int) entries[i].g - (int) g; int b_diff = (int) entries[i].b - (int) b; int a_diff = (int) entries[i].a - (int) a; if (a) diff = (r_diff * r_diff + g_diff * g_diff + b_diff * b_diff + ((a_diff * a_diff) >> 6)); else diff = (r_diff + g_diff + b_diff + (a_diff * a_diff)); if (i == 0 || diff < min_diff) { min_diff = diff; min_index = i; } if (!diff) break; } /* store the matching entry in the hash table */ shared->hash[index].pixel = pixel; shared->hash[index].index = min_index; shared->hash[index].palette = palette; /* set the return value */ index = min_index; } fusion_skirmish_dismiss( &shared->hash_lock ); return index; } void dfb_colorhash_invalidate( DFBColorHashCore *core, CorePalette *palette ) { unsigned int index = HASH_SIZE - 1; DFBColorHashCoreShared *shared; D_ASSUME( core != NULL ); if (core) { D_MAGIC_ASSERT( core, DFBColorHashCore ); D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); } else core = core_colorhash; shared = core->shared; D_ASSERT( shared->hash != NULL ); fusion_skirmish_prevail( &shared->hash_lock ); /* invalidate all entries owned by this palette */ do { if (shared->hash[index].palette == palette) shared->hash[index].palette = NULL; } while (index--); fusion_skirmish_dismiss( &shared->hash_lock ); }