Commit bc4435e4 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Use a hashmap to store the ffp shaders.

parent d4d133f0
...@@ -50,7 +50,7 @@ struct atifs_ffp_desc ...@@ -50,7 +50,7 @@ struct atifs_ffp_desc
struct atifs_private_data 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 ...@@ -786,7 +786,7 @@ static void set_tex_op_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, Wi
unsigned int i; unsigned int i;
gen_ffp_op(stateblock, &settings, TRUE); 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) { if(!desc) {
desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc)); desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc));
if(!desc) { if(!desc) {
...@@ -801,7 +801,7 @@ static void set_tex_op_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, Wi ...@@ -801,7 +801,7 @@ static void set_tex_op_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, Wi
memcpy(&desc->parent.settings, &settings, sizeof(settings)); memcpy(&desc->parent.settings, &settings, sizeof(settings));
desc->shader = gen_ati_shader(settings.op, &GLINFO_LOCATION); 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); TRACE("Allocated fixed function replacement shader descriptor %p\n", desc);
} }
...@@ -1036,26 +1036,28 @@ static HRESULT atifs_alloc(IWineD3DDevice *iface) { ...@@ -1036,26 +1036,28 @@ static HRESULT atifs_alloc(IWineD3DDevice *iface) {
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
priv = (struct atifs_private_data *) This->fragment_priv; 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; return WINED3D_OK;
} }
#define GLINFO_LOCATION This->adapter->gl_info #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) { static void atifs_free(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
struct atifs_private_data *priv = (struct atifs_private_data *) This->fragment_priv; 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(); hash_table_destroy(priv->fragment_shaders, atifs_free_ffpshader, This);
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();
HeapFree(GetProcessHeap(), 0, priv); HeapFree(GetProcessHeap(), 0, priv);
This->fragment_priv = NULL; This->fragment_priv = NULL;
} }
......
...@@ -3527,7 +3527,7 @@ static void shader_glsl_free(IWineD3DDevice *iface) { ...@@ -3527,7 +3527,7 @@ static void shader_glsl_free(IWineD3DDevice *iface) {
GL_EXTCALL(glDeleteObjectARB(priv->depth_blt_glsl_program_id)); 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); HeapFree(GetProcessHeap(), 0, This->shader_priv);
This->shader_priv = NULL; This->shader_priv = NULL;
......
...@@ -1576,12 +1576,15 @@ hash_table_t *hash_table_create(hash_function_t *hash_function, compare_function ...@@ -1576,12 +1576,15 @@ hash_table_t *hash_table_create(hash_function_t *hash_function, compare_function
return table; 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; unsigned int i = 0;
for (i = 0; i < table->entry_count; ++i) 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); HeapFree(GetProcessHeap(), 0, table->entries[i].key);
} }
...@@ -1953,26 +1956,18 @@ void gen_ffp_op(IWineD3DStateBlockImpl *stateblock, struct ffp_settings *setting ...@@ -1953,26 +1956,18 @@ void gen_ffp_op(IWineD3DStateBlockImpl *stateblock, struct ffp_settings *setting
} }
#undef GLINFO_LOCATION #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, void add_ffp_shader(hash_table_t *shaders, struct ffp_desc *desc) {
* or maybe consider using hashtables 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) { *key = desc->settings;
if(memcmp(settings, &entry->settings, sizeof(*settings)) == 0) { hash_table_put(shaders, key, desc);
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);
} }
/* Activates the texture dimension according to the bound D3D texture. /* Activates the texture dimension according to the bound D3D texture.
...@@ -2069,3 +2064,36 @@ void sampler_texdim(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont ...@@ -2069,3 +2064,36 @@ void sampler_texdim(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont
texture_activate_dimensions(sampler, stateblock, context); texture_activate_dimensions(sampler, stateblock, context);
} }
#undef GLINFO_LOCATION #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;
}
...@@ -68,7 +68,7 @@ typedef struct { ...@@ -68,7 +68,7 @@ typedef struct {
} hash_table_t; } hash_table_t;
hash_table_t *hash_table_create(hash_function_t *hash_function, compare_function_t *compare_function); 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_get(hash_table_t *table, void *key);
void hash_table_put(hash_table_t *table, void *key, void *value); void hash_table_put(hash_table_t *table, void *key, void *value);
void hash_table_remove(hash_table_t *table, void *key); void hash_table_remove(hash_table_t *table, void *key);
...@@ -761,12 +761,13 @@ struct ffp_settings { ...@@ -761,12 +761,13 @@ struct ffp_settings {
struct ffp_desc struct ffp_desc
{ {
struct ffp_settings settings; struct ffp_settings settings;
struct list entry;
}; };
void gen_ffp_op(IWineD3DStateBlockImpl *stateblock, struct ffp_settings *settings, BOOL ignore_textype); 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); struct ffp_desc *find_ffp_shader(hash_table_t *fragment_shaders, struct ffp_settings *settings);
void add_ffp_shader(struct list *shaders, struct ffp_desc *desc); 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 * IWineD3D implementation structure
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment