[v3 3/3] d3dx9: Support parameters sharing in effect.

Paul Gofman gofmanp at gmail.com
Wed Apr 26 04:21:04 CDT 2017


Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
v2:
    - merged with the last patch;
    - used a separate shared data structure, got rid of copying parameter structure;
    - removed freeing shared_data in free_effect_pool() (leaving just ERR() in this case). Free the data referenced by
    the effect parameter does not seem to make much sense, as well as freeing the parameter within the effect still referencing
    shared data.
v3:
    - renamed table_size to size, refcount to count in d3dx_shared_data;
    - removed pointless interlocked access to count in d3dx_shared_data;
    - removed unnecessary return in d3dx_pool_sync_shared_parameter();
    - changed ERR to WARN when freeing pool with referenced shared data;
    - do not increment data pointer if it is NULL in param_set_data_pointer();
    - free shared data structure when freeing pool with referenced shared data;
    - removed 'param->data = param->shared_data->data' in d3dx_pool_release_shared_parameter(),
        as it was redundant and confusing (for not setting child data pointers).
---
 dlls/d3dx9_36/d3dx9_private.h |   8 +-
 dlls/d3dx9_36/effect.c        | 211 +++++++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/tests/effect.c  |  21 ++---
 3 files changed, 226 insertions(+), 14 deletions(-)

diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h
index da4564d..e28798a 100644
--- a/dlls/d3dx9_36/d3dx9_private.h
+++ b/dlls/d3dx9_36/d3dx9_private.h
@@ -194,6 +194,8 @@ struct d3dx_param_eval
 
 #define PARAMETER_FLAG_DIRTY 0x1u
 
+struct d3dx_shared_data;
+
 struct d3dx_parameter
 {
     char magic_string[4];
@@ -215,10 +217,14 @@ 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_shared_data *shared_data;
+    };
 };
 
 static inline BOOL is_param_dirty(struct d3dx_parameter *param)
diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c
index b732c67..e256e89 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
@@ -173,10 +177,23 @@ struct ID3DXEffectImpl
     BOOL material_updated;
 };
 
+#define INITIAL_SHARED_DATA_TABLE_SIZE 4
+
+struct d3dx_shared_data
+{
+    void *data;
+    unsigned int count;
+    struct d3dx_parameter **parameters;
+    unsigned int size;
+};
+
 struct d3dx_effect_pool
 {
     ID3DXEffectPool ID3DXEffectPool_iface;
     LONG refcount;
+
+    unsigned int table_size;
+    struct d3dx_shared_data *shared_data;
 };
 
 struct ID3DXEffectCompilerImpl
@@ -510,8 +527,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)
@@ -564,6 +585,8 @@ static void free_parameter(struct d3dx_parameter *param, BOOL element, BOOL chil
         HeapFree(GetProcessHeap(), 0, param->annotations);
     }
 
+    d3dx_pool_release_shared_parameter(param);
+
     if (param->members)
     {
         unsigned int count = param->element_count ? param->element_count : param->member_count;
@@ -1337,7 +1360,18 @@ 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_data)
+    {
+        struct d3dx_shared_data *shared_data = param->top_level_param->shared_data;
+        unsigned int i;
+
+        for (i = 0; i < shared_data->count; ++i)
+            shared_data->parameters[i]->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)
@@ -3016,6 +3050,24 @@ 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);
+        if (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_;
@@ -3040,6 +3092,138 @@ static BOOL is_same_parameter(void *param1_, struct d3dx_parameter *param2)
     return TRUE;
 }
 
+static void d3dx_pool_sync_shared_parameter(struct d3dx_effect_pool *pool, struct d3dx_parameter *param)
+{
+    unsigned int i, free_entry_index;
+    LONG new_refcount;
+    unsigned int new_size;
+
+    if (!(param->flags & PARAMETER_FLAG_SHARED) || !pool
+            || is_param_type_sampler(param->type))
+        return;
+
+    free_entry_index = pool->table_size;
+    for (i = 0; i < pool->table_size; ++i)
+    {
+        if (!pool->shared_data[i].count)
+            free_entry_index = i;
+        else if (is_same_parameter(param, pool->shared_data[i].parameters[0]))
+            break;
+    }
+    if (i == pool->table_size)
+    {
+        i = free_entry_index;
+        if (i == pool->table_size)
+        {
+            struct d3dx_shared_data *new_alloc;
+
+            if (!pool->table_size)
+            {
+                new_size = INITIAL_POOL_TABLE_SIZE;
+                new_alloc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                        sizeof(*pool->shared_data) * 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->shared_data,
+                        sizeof(*pool->shared_data) * new_size);
+                if (!new_alloc)
+                {
+                    ERR("Out of memory.\n");
+                    return;
+                }
+                if (new_alloc != pool->shared_data)
+                {
+                    unsigned int j, k;
+
+                    for (j = 0; j < pool->table_size; ++j)
+                        for (k = 0; k < new_alloc[j].count; ++k)
+                            new_alloc[j].parameters[k]->shared_data = &new_alloc[j];
+                }
+            }
+            pool->shared_data = new_alloc;
+            pool->table_size = new_size;
+        }
+        pool->shared_data[i].data = param->data;
+    }
+    else
+    {
+        param_set_data_pointer(param, pool->shared_data[i].data, FALSE, TRUE);
+    }
+    new_refcount = ++pool->shared_data[i].count;
+    if (new_refcount >= pool->shared_data[i].size)
+    {
+        if (!pool->shared_data[i].size)
+        {
+            new_size = INITIAL_SHARED_DATA_TABLE_SIZE;
+            pool->shared_data[i].parameters = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                    sizeof(*pool->shared_data[i].parameters) * INITIAL_SHARED_DATA_TABLE_SIZE);
+        }
+        else
+        {
+            new_size = pool->shared_data[i].size * 2;
+            pool->shared_data[i].parameters = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                    pool->shared_data[i].parameters,
+                    sizeof(*pool->shared_data[i].parameters) * new_size);
+        }
+        pool->shared_data[i].size = new_size;
+    }
+
+    param->shared_data = &pool->shared_data[i];
+    pool->shared_data[i].parameters[new_refcount - 1] = param;
+
+    TRACE("name %s, parameter idx %u, new refcount %u.\n", param->name, i,
+            new_refcount);
+}
+
+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_data)
+        return;
+    new_refcount = --param->shared_data->count;
+
+    TRACE("param %p, param->shared_param %p, refcount %d.\n",
+            param, param->shared_data, new_refcount);
+
+    if (new_refcount)
+    {
+        unsigned int i;
+
+        for (i = 0; i < new_refcount; ++i)
+        {
+            if (param->shared_data->parameters[i] == param)
+            {
+                memmove(&param->shared_data->parameters[i],
+                        &param->shared_data->parameters[i + 1],
+                        sizeof(param->shared_data->parameters[i]) * (new_refcount - i));
+                break;
+            }
+        }
+        walk_parameter_tree(param, param_zero_data_func, NULL);
+    }
+    else
+    {
+        HeapFree(GetProcessHeap(), 0, param->shared_data->parameters);
+        /* Zeroing table size is required as the entry in pool parameters table can be reused. */
+        param->shared_data->size = 0;
+        param->shared_data = NULL;
+    }
+}
+
 static inline struct d3dx_effect_pool *impl_from_ID3DXEffectPool(ID3DXEffectPool *iface)
 {
     return CONTAINING_RECORD(iface, struct d3dx_effect_pool, ID3DXEffectPool_iface);
@@ -6003,8 +6187,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:
@@ -6305,6 +6492,28 @@ static ULONG WINAPI d3dx_effect_pool_AddRef(ID3DXEffectPool *iface)
 
 static void free_effect_pool(struct d3dx_effect_pool *pool)
 {
+    unsigned int i;
+
+    for (i = 0; i < pool->table_size; ++i)
+    {
+        if (pool->shared_data[i].count)
+        {
+            unsigned int j;
+
+            WARN("Releasing pool with referenced parameters.\n");
+
+            param_set_data_pointer(pool->shared_data[i].parameters[0], NULL, FALSE, TRUE);
+            pool->shared_data[i].parameters[0]->shared_data = NULL;
+
+            for (j = 1; j < pool->shared_data[i].count; ++j)
+            {
+                walk_parameter_tree(pool->shared_data[i].parameters[j], param_zero_data_func, NULL);
+                pool->shared_data[i].parameters[j]->shared_data = NULL;
+            }
+            HeapFree(GetProcessHeap(), 0, pool->shared_data[i].parameters);
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, pool->shared_data);
     HeapFree(GetProcessHeap(), 0, pool);
 }
 
diff --git a/dlls/d3dx9_36/tests/effect.c b/dlls/d3dx9_36/tests/effect.c
index dbf91c4..f7d7ba8 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");
@@ -5985,6 +5982,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);
@@ -6008,9 +6006,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);
     }
 
@@ -6046,7 +6044,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);
@@ -6068,7 +6065,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;
@@ -6097,9 +6094,9 @@ static void test_effect_shared_parameters(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     fvect.x = 28.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);
 
     fval[0] = -2.0f;
     hr = effect2->lpVtbl->SetFloat(effect2, "arr2[0]", fval[0]);
@@ -6108,9 +6105,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