[PATCH 7/8] d3dx9: Support parameters sharing in effect.

Paul Gofman gofmanp at gmail.com
Thu Apr 20 06:26:49 CDT 2017


Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
 dlls/d3dx9_36/d3dx9_private.h |  11 ++-
 dlls/d3dx9_36/effect.c        | 197 +++++++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/tests/effect.c  |  17 ++--
 3 files changed, 211 insertions(+), 14 deletions(-)

diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h
index da4564d..d6d4280 100644
--- a/dlls/d3dx9_36/d3dx9_private.h
+++ b/dlls/d3dx9_36/d3dx9_private.h
@@ -215,15 +215,22 @@ struct d3dx_parameter
     struct d3dx_parameter *annotations;
     struct d3dx_parameter *members;
 
-    struct d3dx_parameter *referenced_param;
     struct d3dx_param_eval *param_eval;
 
     struct d3dx_parameter *top_level_param;
+    union
+    {
+        struct d3dx_parameter *referenced_param;
+        struct d3dx_parameter *shared_param;
+    };
+    LONG shared_refcount;
 };
 
 static inline BOOL is_param_dirty(struct d3dx_parameter *param)
 {
-    return param->top_level_param->runtime_flags & PARAMETER_FLAG_DIRTY;
+    return param->top_level_param->shared_param
+            ? param->top_level_param->shared_param->runtime_flags & PARAMETER_FLAG_DIRTY
+            : param->top_level_param->runtime_flags & PARAMETER_FLAG_DIRTY;
 }
 
 struct d3dx9_base_effect;
diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c
index c8e5ef0..74a3e4d 100644
--- a/dlls/d3dx9_36/effect.c
+++ b/dlls/d3dx9_36/effect.c
@@ -29,6 +29,10 @@
 
 static const char parameter_magic_string[4] = {'@', '!', '#', '\xFF'};
 
+#define PARAMETER_FLAG_SHARED 1
+
+#define INITIAL_POOL_TABLE_SIZE 16
+
 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
 
 enum STATE_CLASS
@@ -177,6 +181,10 @@ struct ID3DXEffectPoolImpl
 {
     ID3DXEffectPool ID3DXEffectPool_iface;
     LONG ref;
+
+    unsigned int parameter_count;
+    unsigned int table_size;
+    struct d3dx_parameter **parameters;
 };
 
 struct ID3DXEffectCompilerImpl
@@ -510,8 +518,12 @@ static void free_sampler(struct d3dx_sampler *sampler)
     HeapFree(GetProcessHeap(), 0, sampler->states);
 }
 
+static void d3dx_pool_release_shared_parameter(struct d3dx_parameter *param);
+
 static void free_parameter_data(struct d3dx_parameter *param, BOOL child)
 {
+    if (!param->data)
+        return;
     if (param->class == D3DXPC_OBJECT && !param->element_count)
     {
         switch (param->type)
@@ -568,6 +580,8 @@ static void free_parameter(struct d3dx_parameter *param, BOOL element, BOOL chil
         param->annotations = NULL;
     }
 
+    d3dx_pool_release_shared_parameter(param);
+
     if (param->members)
     {
         unsigned int count = param->element_count ? param->element_count : param->member_count;
@@ -588,6 +602,53 @@ static void free_parameter(struct d3dx_parameter *param, BOOL element, BOOL chil
     }
 }
 
+static HRESULT copy_parameter_structure(struct d3dx_parameter *src, struct d3dx_parameter *dest,
+        struct d3dx_parameter *dest_parent, BOOL element)
+{
+    *dest = *src;
+    if (element)
+    {
+        dest->name = dest_parent->name;
+    }
+    else
+    {
+        if (src->name)
+        {
+            dest->name = HeapAlloc(GetProcessHeap(), 0, strlen(src->name) + 1);
+            strcpy(dest->name, src->name);
+        }
+    }
+    dest->semantic = NULL;
+    dest->param_eval = NULL;
+    dest->annotations = NULL;
+    dest->data = NULL;
+    dest->referenced_param = NULL;
+    dest->shared_param = NULL;
+    dest->shared_refcount = 0;
+
+    dest->element_count = src->element_count;
+    dest->member_count = src->member_count;
+    if (src->members)
+    {
+        unsigned int i;
+        unsigned int count = src->element_count ? src->element_count : src->member_count;
+
+        dest->members = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(*dest->members));
+        if (!dest->members)
+        {
+            ERR("Out of memory.\n");
+            return E_OUTOFMEMORY;
+        }
+        for (i = 0; i < count; ++i)
+        {
+            if (FAILED(copy_parameter_structure(&src->members[i], &dest->members[i],
+                    dest, src->element_count != 0)))
+                return E_OUTOFMEMORY;
+        }
+    }
+    return D3D_OK;
+}
+
 static void free_pass(struct d3dx_pass *pass)
 {
     unsigned int i;
@@ -1342,7 +1403,10 @@ static BOOL walk_parameter_tree(struct d3dx_parameter *param, walk_parameter_dep
 
 static void set_dirty(struct d3dx_parameter *param)
 {
-    param->top_level_param->runtime_flags |= PARAMETER_FLAG_DIRTY;
+    if (param->top_level_param->shared_param)
+        param->top_level_param->shared_param->runtime_flags |= PARAMETER_FLAG_DIRTY;
+    else
+        param->top_level_param->runtime_flags |= PARAMETER_FLAG_DIRTY;
 }
 
 static void clear_dirty_params(struct d3dx9_base_effect *base)
@@ -1350,7 +1414,12 @@ static void clear_dirty_params(struct d3dx9_base_effect *base)
     unsigned int i;
 
     for (i = 0; i < base->parameter_count; ++i)
-        base->parameters[i].runtime_flags &= ~PARAMETER_FLAG_DIRTY;
+    {
+        if (base->parameters[i].shared_param)
+            base->parameters[i].shared_param->runtime_flags &= ~PARAMETER_FLAG_DIRTY;
+        else
+            base->parameters[i].runtime_flags &= ~PARAMETER_FLAG_DIRTY;
+    }
 }
 
 static HRESULT d3dx9_base_effect_set_value(struct d3dx9_base_effect *base,
@@ -3021,6 +3090,23 @@ static HRESULT d3dx9_apply_pass_states(struct ID3DXEffectImpl *effect, struct d3
     return ret;
 }
 
+static void param_set_data_pointer(struct d3dx_parameter *param, unsigned char *data, BOOL child, BOOL free_data)
+{
+    unsigned int i, count;
+    unsigned char *member_data;
+
+    count = param->element_count ? param->element_count : param->member_count;
+    member_data = data;
+    for (i = 0; i < count; ++i)
+    {
+        param_set_data_pointer(&param->members[i], member_data, TRUE, free_data);
+        member_data += param->members[i].bytes;
+    }
+    if (free_data)
+        free_parameter_data(param, child);
+    param->data = data;
+}
+
 static BOOL is_same_parameter(void *param1_, struct d3dx_parameter *param2)
 {
     struct d3dx_parameter *param1 = (struct d3dx_parameter *)param1_;
@@ -3045,6 +3131,98 @@ static BOOL is_same_parameter(void *param1_, struct d3dx_parameter *param2)
     return TRUE;
 }
 
+static void d3dx_pool_sync_shared_parameter(struct ID3DXEffectPoolImpl *pool, struct d3dx_parameter *param)
+{
+    unsigned int i, free_entry_index;
+    LONG new_refcount;
+
+    if (!(param->flags & PARAMETER_FLAG_SHARED) || !pool
+            || is_param_type_sampler(param->type))
+        return;
+
+    free_entry_index = pool->parameter_count;
+    for (i = 0; i < pool->parameter_count; ++i)
+    {
+        if (!pool->parameters[i]->shared_refcount)
+            free_entry_index = i;
+        else if (is_same_parameter(param, pool->parameters[i]))
+            break;
+    }
+    if (i == pool->parameter_count)
+    {
+        i = free_entry_index;
+        if (i >= pool->table_size)
+        {
+            struct d3dx_parameter ** new_alloc;
+            unsigned int new_size;
+
+            if (!pool->table_size)
+            {
+                new_size = INITIAL_POOL_TABLE_SIZE;
+                new_alloc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                        sizeof(*pool->parameters) * new_size);
+                if (!new_alloc)
+                {
+                    ERR("Out of memory.\n");
+                    return;
+                }
+            }
+            else
+            {
+                new_size = pool->table_size * 2;
+                new_alloc = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pool->parameters,
+                        sizeof(*pool->parameters) * new_size);
+                if (!new_alloc)
+                {
+                    ERR("Out of memory.\n");
+                    return;
+                }
+            }
+            pool->parameters = new_alloc;
+            pool->table_size = new_size;
+        }
+        pool->parameters[i] = HeapAlloc(GetProcessHeap(),
+                HEAP_ZERO_MEMORY, sizeof(*pool->parameters[i]));
+        copy_parameter_structure(param, pool->parameters[i], NULL, FALSE);
+        param_set_data_pointer(pool->parameters[i], (unsigned char *)param->data, FALSE, FALSE);
+        if (i == pool->parameter_count)
+            pool->parameter_count++;
+    }
+    else
+    {
+        param_set_data_pointer(param, (unsigned char *)pool->parameters[i]->data, FALSE, TRUE);
+    }
+    new_refcount = InterlockedIncrement(&pool->parameters[i]->shared_refcount);
+    param->shared_param = pool->parameters[i];
+
+    TRACE("name %s, parameter idx %u, new refcount %u.\n", param->name, i,
+            new_refcount);
+    return;
+}
+
+static BOOL param_zero_data_func(void *dummy, struct d3dx_parameter *param)
+{
+    param->data = NULL;
+    return FALSE;
+}
+
+static void d3dx_pool_release_shared_parameter(struct d3dx_parameter *param)
+{
+    LONG new_refcount;
+
+    if (!(param->flags & PARAMETER_FLAG_SHARED) || !param->shared_param)
+        return;
+    new_refcount = InterlockedDecrement(&param->shared_param->shared_refcount);
+
+    TRACE("param %p, param->shared_param %p, refcount %d.\n",
+            param, param->shared_param, new_refcount);
+
+    walk_parameter_tree(param, param_zero_data_func, NULL);
+
+    if (!new_refcount)
+        free_parameter(param->shared_param, FALSE, FALSE);
+}
+
 static inline struct ID3DXEffectPoolImpl *impl_from_ID3DXEffectPool(ID3DXEffectPool *iface)
 {
     return CONTAINING_RECORD(iface, struct ID3DXEffectPoolImpl, ID3DXEffectPool_iface);
@@ -6008,8 +6186,11 @@ static HRESULT d3dx9_parse_effect(struct d3dx9_base_effect *base, const char *da
     }
 
     for (i = 0; i < base->parameter_count; ++i)
+    {
+        d3dx_pool_sync_shared_parameter(base->pool, &base->parameters[i]);
         walk_parameter_tree(&base->parameters[i], param_set_top_level_param,
                 &base->parameters[i]);
+    }
     return D3D_OK;
 
 err_out:
@@ -6309,6 +6490,18 @@ static ULONG WINAPI ID3DXEffectPoolImpl_AddRef(ID3DXEffectPool *iface)
 
 static void free_effect_pool(struct ID3DXEffectPoolImpl *pool)
 {
+    unsigned int i;
+
+    for (i = 0; i < pool->parameter_count; ++i)
+    {
+        if (pool->parameters[i]->shared_refcount)
+        {
+            ERR("Releasing pool with referenced parameters.\n");
+            free_parameter(pool->parameters[i], FALSE, FALSE);
+        }
+        HeapFree(GetProcessHeap(), 0, pool->parameters[i]);
+    }
+    HeapFree(GetProcessHeap(), 0, pool->parameters);
     HeapFree(GetProcessHeap(), 0, pool);
 }
 
diff --git a/dlls/d3dx9_36/tests/effect.c b/dlls/d3dx9_36/tests/effect.c
index a4239d1..968a447 100644
--- a/dlls/d3dx9_36/tests/effect.c
+++ b/dlls/d3dx9_36/tests/effect.c
@@ -5909,7 +5909,6 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     effect1->lpVtbl->GetFloat(effect1, "arr2[0]", &fvect.x);
-    todo_wine
     ok(fvect.x == 28.0f, "Unexpected parameter value %g.\n", fvect.x);
 
     hr = D3DXCreateEffect(device, test_effect_shared_parameters_blob, sizeof(test_effect_shared_parameters_blob),
@@ -5926,10 +5925,8 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
     ok(fvect.x == 0.0f, "Unexpected parameter value %g.\n", fvect.x);
     effect4->lpVtbl->SetFloat(effect4, "arr2[0]", 28.0f);
     effect3->lpVtbl->GetFloat(effect3, "arr2[0]", &fvect.x);
-    todo_wine
     ok(fvect.x == 28.0f, "Unexpected parameter value %g.\n", fvect.x);
     effect1->lpVtbl->GetFloat(effect1, "arr2[0]", &fvect.x);
-    todo_wine
     ok(fvect.x == 3.0f, "Unexpected parameter value %g.\n", fvect.x);
 
     param = effect3->lpVtbl->GetParameterByName(effect3, NULL, "ts2[0].fv_2");
@@ -5984,6 +5981,7 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     hr = effect3->lpVtbl->BeginPass(effect3, 1);
+    todo_wine
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     hr = IDirect3DDevice9_GetVertexShaderConstantF(device, 0, &fvect.x, 1);
@@ -6007,9 +6005,9 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
         hr = effect1->lpVtbl->GetVertexShader(effect1, param_child, &vshader1);
         ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
-        test_effect_shared_vs_arr_compare_helper(effect2, param_child, vshader1, i, TRUE);
-        test_effect_shared_vs_arr_compare_helper(effect3, param_child, vshader1, i, TRUE);
-        test_effect_shared_vs_arr_compare_helper(effect4, param_child, vshader1, i, TRUE);
+        test_effect_shared_vs_arr_compare_helper(effect2, param_child, vshader1, i, FALSE);
+        test_effect_shared_vs_arr_compare_helper(effect3, param_child, vshader1, i, FALSE);
+        test_effect_shared_vs_arr_compare_helper(effect4, param_child, vshader1, i, FALSE);
         IDirect3DVertexShader9_Release(vshader1);
     }
 
@@ -6045,7 +6043,6 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
     fval[0] = 0.0f;
     hr = effect2->lpVtbl->GetFloatArray(effect2, "arr2", fval, 2);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
-    todo_wine
     ok(fval[0] == 33.0f && fval[1] == 93.0f, "Unexpected values %g, %g.\n", fval[0], fval[1]);
 
     hr = effect1->lpVtbl->Begin(effect1, &passes_count, 0);
@@ -6067,7 +6064,7 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
     fvect.x = 91.0f;
     test_effect_shared_parameters_compare_vconst(device, 32, &fvect, FALSE);
     fvect.x = 33.0f;
-    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, TRUE);
+    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, FALSE);
 
     fval[0] = 28.0f;
     fval[1] = -1.0f;
@@ -6107,9 +6104,9 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     fvect.x = -2.0f;
-    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, TRUE);
+    test_effect_shared_parameters_compare_vconst(device, 29, &fvect, FALSE);
     fvect.x = -1.0f;
-    test_effect_shared_parameters_compare_vconst(device, 30, &fvect, TRUE);
+    test_effect_shared_parameters_compare_vconst(device, 30, &fvect, FALSE);
 
     fvect.x = fvect.y = fvect.z = fvect.w = 1111.0f;
     hr = effect2->lpVtbl->SetVector(effect2, "g_Pos1", &fvect);
-- 
2.9.3




More information about the wine-patches mailing list