Stefan Dösinger : wined3d: Use a hashmap to store the ffp shaders.

Alexandre Julliard julliard at winehq.org
Thu Jul 31 07:17:49 CDT 2008


Module: wine
Branch: master
Commit: bc4435e4063c70d0ef2fcc2ab7bb6df3efcfc0e7
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=bc4435e4063c70d0ef2fcc2ab7bb6df3efcfc0e7

Author: Stefan Dösinger <stefan at 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




More information about the wine-cvs mailing list