Module: wine Branch: master Commit: bc4435e4063c70d0ef2fcc2ab7bb6df3efcfc0e7 URL: http://source.winehq.org/git/wine.git/?a=commit;h=bc4435e4063c70d0ef2fcc2ab7...
Author: Stefan Dösinger stefan@codeweavers.com Date: Tue Jul 29 10:51:52 2008 -0500
wined3d: Use a hashmap to store the ffp shaders.
---
dlls/wined3d/ati_fragment_shader.c | 32 +++++++++-------- dlls/wined3d/glsl_shader.c | 2 +- dlls/wined3d/utils.c | 64 ++++++++++++++++++++++++++---------- dlls/wined3d/wined3d_private.h | 9 +++-- 4 files changed, 69 insertions(+), 38 deletions(-)
diff --git a/dlls/wined3d/ati_fragment_shader.c b/dlls/wined3d/ati_fragment_shader.c index 6dc0193..54b05b1 100644 --- a/dlls/wined3d/ati_fragment_shader.c +++ b/dlls/wined3d/ati_fragment_shader.c @@ -50,7 +50,7 @@ struct atifs_ffp_desc
struct atifs_private_data { - struct list fragment_shaders; /* A linked list to track fragment pipeline replacement shaders */ + hash_table_t *fragment_shaders; /* A hashtable to track fragment pipeline replacement shaders */
};
@@ -786,7 +786,7 @@ static void set_tex_op_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, Wi unsigned int i;
gen_ffp_op(stateblock, &settings, TRUE); - desc = (struct atifs_ffp_desc *) find_ffp_shader(&priv->fragment_shaders, &settings); + desc = (struct atifs_ffp_desc *) find_ffp_shader(priv->fragment_shaders, &settings); if(!desc) { desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc)); if(!desc) { @@ -801,7 +801,7 @@ static void set_tex_op_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, Wi
memcpy(&desc->parent.settings, &settings, sizeof(settings)); desc->shader = gen_ati_shader(settings.op, &GLINFO_LOCATION); - add_ffp_shader(&priv->fragment_shaders, &desc->parent); + add_ffp_shader(priv->fragment_shaders, &desc->parent); TRACE("Allocated fixed function replacement shader descriptor %p\n", desc); }
@@ -1036,26 +1036,28 @@ static HRESULT atifs_alloc(IWineD3DDevice *iface) { return E_OUTOFMEMORY; } priv = (struct atifs_private_data *) This->fragment_priv; - list_init(&priv->fragment_shaders); + priv->fragment_shaders = hash_table_create(ffp_program_key_hash, ffp_program_key_compare); return WINED3D_OK; }
#define GLINFO_LOCATION This->adapter->gl_info +static void atifs_free_ffpshader(void *value, void *device) { + IWineD3DDeviceImpl *This = device; + struct atifs_ffp_desc *entry_ati = value; + + ENTER_GL(); + GL_EXTCALL(glDeleteFragmentShaderATI(entry_ati->shader)); + checkGLcall("glDeleteFragmentShaderATI(entry->shader)"); + HeapFree(GetProcessHeap(), 0, entry_ati); + LEAVE_GL(); +} + static void atifs_free(IWineD3DDevice *iface) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; struct atifs_private_data *priv = (struct atifs_private_data *) This->fragment_priv; - struct ffp_desc *entry, *entry2; - struct atifs_ffp_desc *entry_ati;
- ENTER_GL(); - LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &priv->fragment_shaders, struct ffp_desc, entry) { - entry_ati = (struct atifs_ffp_desc *) entry; - GL_EXTCALL(glDeleteFragmentShaderATI(entry_ati->shader)); - checkGLcall("glDeleteFragmentShaderATI(entry->shader)"); - list_remove(&entry->entry); - HeapFree(GetProcessHeap(), 0, entry); - } - LEAVE_GL(); + hash_table_destroy(priv->fragment_shaders, atifs_free_ffpshader, This); + HeapFree(GetProcessHeap(), 0, priv); This->fragment_priv = NULL; } diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index ce84ea7..80c4411 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -3527,7 +3527,7 @@ static void shader_glsl_free(IWineD3DDevice *iface) { GL_EXTCALL(glDeleteObjectARB(priv->depth_blt_glsl_program_id)); }
- hash_table_destroy(priv->glsl_program_lookup); + hash_table_destroy(priv->glsl_program_lookup, NULL, NULL);
HeapFree(GetProcessHeap(), 0, This->shader_priv); This->shader_priv = NULL; diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 4398724..a9fc780 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -1576,12 +1576,15 @@ hash_table_t *hash_table_create(hash_function_t *hash_function, compare_function return table; }
-void hash_table_destroy(hash_table_t *table) +void hash_table_destroy(hash_table_t *table, void (*free_value)(void *value, void *cb), void *cb) { unsigned int i = 0;
for (i = 0; i < table->entry_count; ++i) { + if(free_value) { + free_value(table->entries[i].value, cb); + } HeapFree(GetProcessHeap(), 0, table->entries[i].key); }
@@ -1953,26 +1956,18 @@ void gen_ffp_op(IWineD3DStateBlockImpl *stateblock, struct ffp_settings *setting } #undef GLINFO_LOCATION
-struct ffp_desc *find_ffp_shader(struct list *shaders, struct ffp_settings *settings) +struct ffp_desc *find_ffp_shader(hash_table_t *fragment_shaders, struct ffp_settings *settings) { - struct ffp_desc *entry; + return (struct ffp_desc *)hash_table_get(fragment_shaders, settings);}
- /* TODO: Optimize this. Finding the shader can be optimized by e.g. sorting the list, - * or maybe consider using hashtables +void add_ffp_shader(hash_table_t *shaders, struct ffp_desc *desc) { + struct ffp_settings *key = HeapAlloc(GetProcessHeap(), 0, sizeof(*key)); + /* Note that the key is the implementation independent part of the ffp_desc structure, + * whereas desc points to an extended structure with implementation specific parts. + * Make a copy of the key because hash_table_put takes ownership of it */ - LIST_FOR_EACH_ENTRY(entry, shaders, struct ffp_desc, entry) { - if(memcmp(settings, &entry->settings, sizeof(*settings)) == 0) { - TRACE("Found shader entry %p\n", entry); - return entry; - } - } - - TRACE("Shader not found\n"); - return NULL; -} - -void add_ffp_shader(struct list *shaders, struct ffp_desc *desc) { - list_add_head(shaders, &desc->entry); + *key = desc->settings; + hash_table_put(shaders, key, desc); }
/* Activates the texture dimension according to the bound D3D texture. @@ -2069,3 +2064,36 @@ void sampler_texdim(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont texture_activate_dimensions(sampler, stateblock, context); } #undef GLINFO_LOCATION + +unsigned int ffp_program_key_hash(void *key) { + struct ffp_settings *k = (struct ffp_settings *)key; + unsigned int hash = 0, i; + DWORD *blob; + + /* This takes the texture op settings of stage 0 and 1 into account. + * how exactly depends on the memory laybout of the compiler, but it + * should not matter too much. Stages > 1 are used rarely, so there's + * no need to process them. Even if they're used it is likely that + * the ffp setup has distinct stage 0 and 1 settings. + */ + for(i = 0; i < 2; i++) { + blob = (DWORD *) &k->op[i]; + hash ^= blob[0] ^ blob[1]; + } + + hash += ~(hash << 15); + hash ^= (hash >> 10); + hash += (hash << 3); + hash ^= (hash >> 6); + hash += ~(hash << 11); + hash ^= (hash >> 16); + + return hash; +} + +BOOL ffp_program_key_compare(void *keya, void *keyb) { + struct ffp_settings *ka = (struct ffp_settings *)keya; + struct ffp_settings *kb = (struct ffp_settings *)keyb; + + return memcmp(ka, kb, sizeof(*ka)) == 0; +} diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 66e5a32..5b19acc 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -68,7 +68,7 @@ typedef struct { } hash_table_t;
hash_table_t *hash_table_create(hash_function_t *hash_function, compare_function_t *compare_function); -void hash_table_destroy(hash_table_t *table); +void hash_table_destroy(hash_table_t *table, void (*free_value)(void *value, void *cb), void *cb); void *hash_table_get(hash_table_t *table, void *key); void hash_table_put(hash_table_t *table, void *key, void *value); void hash_table_remove(hash_table_t *table, void *key); @@ -761,12 +761,13 @@ struct ffp_settings { struct ffp_desc { struct ffp_settings settings; - struct list entry; };
void gen_ffp_op(IWineD3DStateBlockImpl *stateblock, struct ffp_settings *settings, BOOL ignore_textype); -struct ffp_desc *find_ffp_shader(struct list *shaders, struct ffp_settings *settings); -void add_ffp_shader(struct list *shaders, struct ffp_desc *desc); +struct ffp_desc *find_ffp_shader(hash_table_t *fragment_shaders, struct ffp_settings *settings); +void add_ffp_shader(hash_table_t *shaders, struct ffp_desc *desc); +BOOL ffp_program_key_compare(void *keya, void *keyb); +unsigned int ffp_program_key_hash(void *key);
/***************************************************************************** * IWineD3D implementation structure