[PATCH 2/6] d3dx9: Use versioned parameter updates instead of 'dirty' flags.

Paul Gofman gofmanp at gmail.com
Fri May 12 07:24:13 CDT 2017


Looping through shared parameters in set_dirty() which is removed by this patch
has a major performance impact on parameter update for applications creating a
lot of effects and sharing parameters between them, which is a common case.
Using versioned scheme also allows for some further optimization.

Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
 dlls/d3dx9_36/d3dx9_private.h | 36 +++++++++++++++++-----
 dlls/d3dx9_36/effect.c        | 72 +++++++++++++++++++++++--------------------
 dlls/d3dx9_36/preshader.c     | 29 +++++++++++------
 3 files changed, 86 insertions(+), 51 deletions(-)

diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h
index 49c351f..587ffff 100644
--- a/dlls/d3dx9_36/d3dx9_private.h
+++ b/dlls/d3dx9_36/d3dx9_private.h
@@ -163,6 +163,7 @@ struct d3dx_const_tab
     unsigned int const_set_size;
     struct d3dx_const_param_eval_output *const_set;
     const enum pres_reg_tables *regset2table;
+    ULONG64 update_version;
 };
 
 struct d3dx_regstore
@@ -190,9 +191,9 @@ struct d3dx_param_eval
 
     struct d3dx_preshader pres;
     struct d3dx_const_tab shader_inputs;
-};
 
-#define PARAMETER_FLAG_DIRTY 0x1u
+    ULONG64 *update_version_counter;
+};
 
 struct d3dx_shared_data;
 
@@ -213,6 +214,8 @@ struct d3dx_parameter
     UINT bytes;
     DWORD runtime_flags;
     DWORD object_id;
+    ULONG64 update_version;
+    ULONG64 *update_version_counter;
 
     struct d3dx_parameter *annotations;
     struct d3dx_parameter *members;
@@ -227,13 +230,31 @@ struct d3dx_parameter
     } u;
 };
 
-static inline BOOL is_param_dirty(struct d3dx_parameter *param)
+struct d3dx_shared_data
 {
-    return param->top_level_param->runtime_flags & PARAMETER_FLAG_DIRTY;
-}
+    void *data;
+    struct d3dx_parameter **parameters;
+    unsigned int size, count;
+    ULONG64 update_version;
+};
 
 struct d3dx9_base_effect;
 
+static inline ULONG64 get_update_version_counter(ULONG64 *update_version_counter)
+{
+    return ++*update_version_counter;
+}
+
+static inline BOOL is_param_dirty(struct d3dx_parameter *param, ULONG64 update_version)
+{
+    struct d3dx_shared_data *shared_data;
+
+    if ((shared_data = param->top_level_param->u.shared_data))
+        return update_version < shared_data->update_version;
+    else
+        return update_version < param->top_level_param->update_version;
+}
+
 struct d3dx_parameter *get_parameter_by_name(struct d3dx9_base_effect *base,
         struct d3dx_parameter *parameter, const char *name) DECLSPEC_HIDDEN;
 
@@ -242,10 +263,11 @@ struct d3dx_parameter *get_parameter_by_name(struct d3dx9_base_effect *base,
 #define SET_D3D_STATE(base_effect, args...) SET_D3D_STATE_(base_effect->manager, base_effect->device, args)
 
 void d3dx_create_param_eval(struct d3dx9_base_effect *base_effect, void *byte_code,
-        unsigned int byte_code_size, D3DXPARAMETER_TYPE type, struct d3dx_param_eval **peval) DECLSPEC_HIDDEN;
+        unsigned int byte_code_size, D3DXPARAMETER_TYPE type,
+        struct d3dx_param_eval **peval, ULONG64 *update_version_counter) DECLSPEC_HIDDEN;
 void d3dx_free_param_eval(struct d3dx_param_eval *peval) DECLSPEC_HIDDEN;
 HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval,
-        const struct d3dx_parameter *param, void *param_value, BOOL update_all) DECLSPEC_HIDDEN;
+        const struct d3dx_parameter *param, void *param_value) DECLSPEC_HIDDEN;
 HRESULT d3dx_param_eval_set_shader_constants(ID3DXEffectStateManager *manager, struct IDirect3DDevice9 *device,
         struct d3dx_param_eval *peval, BOOL update_all) DECLSPEC_HIDDEN;
 BOOL is_param_eval_input_dirty(struct d3dx_param_eval *peval) DECLSPEC_HIDDEN;
diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c
index 30855a6..9c07f9c 100644
--- a/dlls/d3dx9_36/effect.c
+++ b/dlls/d3dx9_36/effect.c
@@ -127,6 +127,8 @@ struct d3dx_pass
 
     struct d3dx_state *states;
     struct d3dx_parameter *annotations;
+
+    ULONG64 update_version;
 };
 
 struct d3dx_technique
@@ -155,6 +157,8 @@ struct d3dx9_base_effect
 
     struct d3dx_effect_pool *pool;
     DWORD flags;
+
+    ULONG64 update_version_counter;
 };
 
 struct ID3DXEffectImpl
@@ -180,13 +184,6 @@ struct ID3DXEffectImpl
 
 #define INITIAL_SHARED_DATA_SIZE 4
 
-struct d3dx_shared_data
-{
-    void *data;
-    struct d3dx_parameter **parameters;
-    unsigned int size, count;
-};
-
 struct d3dx_effect_pool
 {
     ID3DXEffectPool ID3DXEffectPool_iface;
@@ -194,6 +191,8 @@ struct d3dx_effect_pool
 
     struct d3dx_shared_data *shared_data;
     unsigned int size;
+
+    ULONG64 update_version_counter;
 };
 
 struct ID3DXEffectCompilerImpl
@@ -1033,7 +1032,7 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
     {
         case ST_PARAMETER:
             param = param->u.referenced_param;
-            *param_dirty = is_param_dirty(param);
+            *param_dirty = is_param_dirty(param, pass->update_version);
             /* fallthrough */
         case ST_CONSTANT:
             *out_param = param;
@@ -1054,8 +1053,7 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
             }
             if (update_all || is_param_eval_input_dirty(param->param_eval))
             {
-                if (FAILED(hr = d3dx_evaluate_parameter(param->param_eval, &array_idx_param,
-                        &array_idx, update_all)))
+                if (FAILED(hr = d3dx_evaluate_parameter(param->param_eval, &array_idx_param, &array_idx)))
                     return hr;
             }
             else
@@ -1073,7 +1071,7 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
                 return E_FAIL;
             }
             selected_param = &ref_param->members[array_idx];
-            *param_dirty = state->index != array_idx || is_param_dirty(selected_param);
+            *param_dirty = state->index != array_idx || is_param_dirty(selected_param, pass->update_version);
             state->index = array_idx;
 
             *param_value = selected_param->data;
@@ -1088,7 +1086,7 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
                 if (update_all || is_param_eval_input_dirty(param->param_eval))
                 {
                     *param_dirty = TRUE;
-                    return d3dx_evaluate_parameter(param->param_eval, param, *param_value, update_all);
+                    return d3dx_evaluate_parameter(param->param_eval, param, *param_value);
                 }
                 else
                     return D3D_OK;
@@ -1473,28 +1471,26 @@ static BOOL walk_parameter_tree(struct d3dx_parameter *param, walk_parameter_dep
     return FALSE;
 }
 
-static void set_dirty(struct d3dx_parameter *param)
+static ULONG64 *get_update_version_counter_ptr(struct d3dx9_base_effect *base)
 {
-    struct d3dx_shared_data *shared_data;
-    unsigned int i;
+    return base->pool ? &base->pool->update_version_counter : &base->update_version_counter;
+}
 
-    if ((shared_data = param->top_level_param->u.shared_data))
-    {
-        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 ULONG64 get_effect_update_version_counter(struct d3dx9_base_effect *base)
+{
+    return get_update_version_counter(get_update_version_counter_ptr(base));
 }
 
-static void clear_dirty_params(struct d3dx9_base_effect *base)
+static void set_dirty(struct d3dx_parameter *param)
 {
-    unsigned int i;
+    struct d3dx_shared_data *shared_data;
+    struct d3dx_parameter *top_param = param->top_level_param;
+    ULONG64 new_update_version = get_update_version_counter(top_param->update_version_counter);
 
-    for (i = 0; i < base->parameter_count; ++i)
-        base->parameters[i].runtime_flags &= ~PARAMETER_FLAG_DIRTY;
+    if ((shared_data = top_param->u.shared_data))
+        shared_data->update_version = new_update_version;
+    else
+        top_param->update_version = new_update_version;
 }
 
 static HRESULT set_string(char **param_data, const char *string)
@@ -3078,6 +3074,7 @@ static HRESULT d3dx9_apply_pass_states(struct ID3DXEffectImpl *effect, struct d3
     unsigned int i;
     HRESULT ret;
     HRESULT hr;
+    ULONG64 new_update_version = get_effect_update_version_counter(&effect->base_effect);
 
     TRACE("effect %p, pass %p, state_count %u.\n", effect, pass, pass->state_count);
 
@@ -3109,7 +3106,7 @@ static HRESULT d3dx9_apply_pass_states(struct ID3DXEffectImpl *effect, struct d3
     }
     effect->material_updated = FALSE;
 
-    clear_dirty_params(&effect->base_effect);
+    pass->update_version = new_update_version;
     return ret;
 }
 
@@ -5944,7 +5941,7 @@ static HRESULT d3dx9_parse_array_selector(struct d3dx9_base_effect *base, struct
     if (string_size % sizeof(DWORD))
         FIXME("Unaligned string_size %u.\n", string_size);
     d3dx_create_param_eval(base, (DWORD *)(ptr + string_size) + 1, object->size - (string_size + sizeof(DWORD)),
-            D3DXPT_INT, &param->param_eval);
+            D3DXPT_INT, &param->param_eval, get_update_version_counter_ptr(base));
     ret = D3D_OK;
     param = param->u.referenced_param;
     if (param->type == D3DXPT_VERTEXSHADER || param->type == D3DXPT_PIXELSHADER)
@@ -5962,7 +5959,8 @@ static HRESULT d3dx9_parse_array_selector(struct d3dx9_base_effect *base, struct
             {
                 TRACE("Creating preshader for object %u.\n", param->members[i].object_id);
                 object = &base->objects[param->members[i].object_id];
-                d3dx_create_param_eval(base, object->data, object->size, param->type, &param->members[i].param_eval);
+                d3dx_create_param_eval(base, object->data, object->size, param->type,
+                        &param->members[i].param_eval, get_update_version_counter_ptr(base));
             }
         }
     }
@@ -6075,7 +6073,8 @@ static HRESULT d3dx9_parse_resource(struct d3dx9_base_effect *base, const char *
                     {
                         if (FAILED(hr = d3dx9_create_object(base, object)))
                             return hr;
-                        d3dx_create_param_eval(base, object->data, object->size, param->type, &param->param_eval);
+                        d3dx_create_param_eval(base, object->data, object->size, param->type,
+                                &param->param_eval, get_update_version_counter_ptr(base));
                     }
                     break;
 
@@ -6086,7 +6085,8 @@ static HRESULT d3dx9_parse_resource(struct d3dx9_base_effect *base, const char *
                     state->type = ST_FXLC;
                     if (FAILED(hr = d3dx9_copy_data(base, param->object_id, ptr)))
                         return hr;
-                    d3dx_create_param_eval(base, object->data, object->size, param->type, &param->param_eval);
+                    d3dx_create_param_eval(base, object->data, object->size, param->type,
+                            &param->param_eval, get_update_version_counter_ptr(base));
                     break;
 
                 default:
@@ -6113,7 +6113,7 @@ static HRESULT d3dx9_parse_resource(struct d3dx9_base_effect *base, const char *
 
                     if (!refpar->param_eval)
                         d3dx_create_param_eval(base, refobj->data, refobj->size,
-                                refpar->type, &refpar->param_eval);
+                                refpar->type, &refpar->param_eval, get_update_version_counter_ptr(base));
                 }
             }
             else
@@ -6257,6 +6257,10 @@ static HRESULT d3dx9_parse_effect(struct d3dx9_base_effect *base, const char *da
             goto err_out;
         walk_parameter_tree(&base->parameters[i], param_set_top_level_param,
                 &base->parameters[i]);
+        base->parameters[i].update_version_counter = base->pool
+                ? &base->pool->update_version_counter
+                : &base->update_version_counter;
+        set_dirty(&base->parameters[i]);
     }
     return D3D_OK;
 
diff --git a/dlls/d3dx9_36/preshader.c b/dlls/d3dx9_36/preshader.c
index fbd99ac..a35111b 100644
--- a/dlls/d3dx9_36/preshader.c
+++ b/dlls/d3dx9_36/preshader.c
@@ -809,7 +809,7 @@ static HRESULT parse_preshader(struct d3dx_preshader *pres, unsigned int *ptr, u
 }
 
 void d3dx_create_param_eval(struct d3dx9_base_effect *base_effect, void *byte_code, unsigned int byte_code_size,
-        D3DXPARAMETER_TYPE type, struct d3dx_param_eval **peval_out)
+        D3DXPARAMETER_TYPE type, struct d3dx_param_eval **peval_out, ULONG64 *update_version_counter)
 {
     struct d3dx_param_eval *peval;
     unsigned int *ptr;
@@ -832,6 +832,8 @@ void d3dx_create_param_eval(struct d3dx9_base_effect *base_effect, void *byte_co
     if (!peval)
         goto err_out;
 
+    peval->update_version_counter = update_version_counter;
+
     peval->param_type = type;
     switch (type)
     {
@@ -930,7 +932,8 @@ void d3dx_free_param_eval(struct d3dx_param_eval *peval)
     HeapFree(GetProcessHeap(), 0, peval);
 }
 
-static void set_constants(struct d3dx_regstore *rs, struct d3dx_const_tab *const_tab, BOOL update_all)
+static void set_constants(struct d3dx_regstore *rs, struct d3dx_const_tab *const_tab,
+        BOOL update_all, ULONG64 new_update_version)
 {
     unsigned int const_idx;
 
@@ -945,7 +948,7 @@ static void set_constants(struct d3dx_regstore *rs, struct d3dx_const_tab *const
         BOOL transpose;
         unsigned int count;
 
-        if (!(update_all || is_param_dirty(param)))
+        if (!(update_all || is_param_dirty(param, const_tab->update_version)))
             continue;
 
         transpose = (const_set->constant_class == D3DXPC_MATRIX_COLUMNS && param->class == D3DXPC_MATRIX_ROWS)
@@ -1016,6 +1019,7 @@ static void set_constants(struct d3dx_regstore *rs, struct d3dx_const_tab *const
             }
         }
     }
+    const_tab->update_version = new_update_version;
 }
 
 #define INITIAL_CONST_SET_SIZE 16
@@ -1290,7 +1294,7 @@ static BOOL is_const_tab_input_dirty(struct d3dx_const_tab *ctab)
 
     for (i = 0; i < ctab->const_set_count; ++i)
     {
-        if (is_param_dirty(ctab->const_set[i].param))
+        if (is_param_dirty(ctab->const_set[i].param, ctab->update_version))
             return TRUE;
     }
     return FALSE;
@@ -1303,7 +1307,7 @@ BOOL is_param_eval_input_dirty(struct d3dx_param_eval *peval)
 }
 
 HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval, const struct d3dx_parameter *param,
-        void *param_value, BOOL update_all)
+        void *param_value)
 {
     HRESULT hr;
     unsigned int i;
@@ -1312,10 +1316,14 @@ HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval, const struct d3dx
 
     TRACE("peval %p, param %p, param_value %p.\n", peval, param, param_value);
 
-    set_constants(&peval->pres.regs, &peval->pres.inputs, update_all);
+    if (is_const_tab_input_dirty(&peval->pres.inputs))
+    {
+        set_constants(&peval->pres.regs, &peval->pres.inputs, FALSE,
+                get_update_version_counter(peval->update_version_counter));
 
-    if (FAILED(hr = execute_preshader(&peval->pres)))
-        return hr;
+        if (FAILED(hr = execute_preshader(&peval->pres)))
+            return hr;
+    }
 
     elements_table = table_info[PRES_REGTAB_OCONST].reg_component_count
             * peval->pres.regs.table_sizes[PRES_REGTAB_OCONST];
@@ -1410,17 +1418,18 @@ HRESULT d3dx_param_eval_set_shader_constants(ID3DXEffectStateManager *manager, s
     struct d3dx_preshader *pres = &peval->pres;
     struct d3dx_regstore *rs = &pres->regs;
     unsigned int i;
+    ULONG64 new_update_version = get_update_version_counter(peval->update_version_counter);
 
     TRACE("device %p, peval %p, param_type %u.\n", device, peval, peval->param_type);
 
     if (update_all || is_const_tab_input_dirty(&pres->inputs))
     {
-        set_constants(rs, &pres->inputs, update_all);
+        set_constants(rs, &pres->inputs, update_all, new_update_version);
         if (FAILED(hr = execute_preshader(pres)))
             return hr;
     }
 
-    set_constants(rs, &peval->shader_inputs, update_all);
+    set_constants(rs, &peval->shader_inputs, update_all, new_update_version);
     result = D3D_OK;
     for (i = 0; i < ARRAY_SIZE(set_tables); ++i)
     {
-- 
2.9.3




More information about the wine-patches mailing list