[v2 2/5] d3dx9: Match native out of bounds array selector index handling.

Paul Gofman gofmanp at gmail.com
Tue May 16 11:49:18 CDT 2017


Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
v2:
    - removed unnessary work with -1 state->index value;
    - clarified comment.
---
 dlls/d3dx9_36/d3dx9_private.h |  2 +-
 dlls/d3dx9_36/effect.c        | 21 +++++++++++++--------
 dlls/d3dx9_36/preshader.c     | 16 +++++++++-------
 dlls/d3dx9_36/tests/effect.c  | 25 +++++++++----------------
 4 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h
index 88914d8..4e06f3a 100644
--- a/dlls/d3dx9_36/d3dx9_private.h
+++ b/dlls/d3dx9_36/d3dx9_private.h
@@ -269,6 +269,6 @@ HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval,
         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;
+BOOL is_param_eval_input_dirty(struct d3dx_param_eval *peval, ULONG64 update_version) DECLSPEC_HIDDEN;
 
 #endif /* __WINE_D3DX9_PRIVATE_H */
diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c
index 3b821a4..ff29702 100644
--- a/dlls/d3dx9_36/effect.c
+++ b/dlls/d3dx9_36/effect.c
@@ -1051,7 +1051,7 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
                 FIXME("Preshader structure is null.\n");
                 return D3DERR_INVALIDCALL;
             }
-            if (update_all || is_param_eval_input_dirty(param->param_eval))
+            if (is_param_eval_input_dirty(param->param_eval, pass->update_version))
             {
                 if (FAILED(hr = d3dx_evaluate_parameter(param->param_eval, &array_idx_param, &array_idx)))
                     return hr;
@@ -1063,6 +1063,13 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
             ref_param = param->u.referenced_param;
             TRACE("Array index %u, stored array index %u, element_count %u.\n", array_idx, state->index,
                     ref_param->element_count);
+            /* According to the tests, native d3dx handles the case of array index evaluated to -1
+             * in a specific way, always selecting first array element and not returning error. */
+            if (array_idx == 0xffffffffu)
+            {
+                WARN("Array index is -1, setting to 0.\n");
+                array_idx = 0;
+            }
 
             if (array_idx >= ref_param->element_count)
             {
@@ -1083,7 +1090,7 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
             {
                 *out_param = param;
                 *param_value = param->data;
-                if (update_all || is_param_eval_input_dirty(param->param_eval))
+                if (update_all || is_param_eval_input_dirty(param->param_eval, ~0))
                 {
                     *param_dirty = TRUE;
                     return d3dx_evaluate_parameter(param->param_eval, param, *param_value);
@@ -1134,7 +1141,7 @@ static HRESULT d3dx9_base_effect_get_pass_desc(struct d3dx9_base_effect *base,
             HRESULT hr;
 
             if (FAILED(hr = d3dx9_get_param_value_ptr(pass, &pass->states[i], &param_value, &param,
-                    TRUE, &param_dirty)))
+                    FALSE, &param_dirty)))
                 return hr;
 
             if (!param->object_id)
@@ -2944,13 +2951,11 @@ static HRESULT d3dx9_apply_state(struct ID3DXEffectImpl *effect, struct d3dx_pas
     if (FAILED(hr = d3dx9_get_param_value_ptr(pass, state, &param_value, &param,
             update_all, &param_dirty)))
     {
-        if (hr == E_FAIL)
+        if (!update_all && hr == E_FAIL)
         {
-            /* Native d3dx9 returns D3D_OK from BeginPass or Commit involving
+            /* Native d3dx9 returns D3D_OK from Commit involving
              * out of bounds array access and does not touch the affected
-             * state, except for BeginPass when the out of bounds array index
-             * depends on dirty parameters. The latter case is supposed to
-             * return E_FAIL but is currently TODO. */
+             * state. */
             WARN("Returning D3D_OK on out of bounds array access.\n");
             return D3D_OK;
         }
diff --git a/dlls/d3dx9_36/preshader.c b/dlls/d3dx9_36/preshader.c
index 6f5a6f5..9dcf5af 100644
--- a/dlls/d3dx9_36/preshader.c
+++ b/dlls/d3dx9_36/preshader.c
@@ -1288,22 +1288,24 @@ static HRESULT execute_preshader(struct d3dx_preshader *pres)
     return D3D_OK;
 }
 
-static BOOL is_const_tab_input_dirty(struct d3dx_const_tab *ctab)
+static BOOL is_const_tab_input_dirty(struct d3dx_const_tab *ctab, ULONG64 update_version)
 {
     unsigned int i;
 
+    if (update_version == ~0)
+        update_version = ctab->update_version;
     for (i = 0; i < ctab->const_set_count; ++i)
     {
-        if (is_param_dirty(ctab->const_set[i].param, ctab->update_version))
+        if (is_param_dirty(ctab->const_set[i].param, update_version))
             return TRUE;
     }
     return FALSE;
 }
 
-BOOL is_param_eval_input_dirty(struct d3dx_param_eval *peval)
+BOOL is_param_eval_input_dirty(struct d3dx_param_eval *peval, ULONG64 update_version)
 {
-    return is_const_tab_input_dirty(&peval->pres.inputs)
-            || is_const_tab_input_dirty(&peval->shader_inputs);
+    return is_const_tab_input_dirty(&peval->pres.inputs, update_version)
+            || is_const_tab_input_dirty(&peval->shader_inputs, update_version);
 }
 
 HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval, const struct d3dx_parameter *param,
@@ -1316,7 +1318,7 @@ 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);
 
-    if (is_const_tab_input_dirty(&peval->pres.inputs))
+    if (is_const_tab_input_dirty(&peval->pres.inputs, ~0))
     {
         set_constants(&peval->pres.regs, &peval->pres.inputs, FALSE,
                 next_update_version(peval->version_counter));
@@ -1422,7 +1424,7 @@ HRESULT d3dx_param_eval_set_shader_constants(ID3DXEffectStateManager *manager, s
 
     TRACE("device %p, peval %p, param_type %u.\n", device, peval, peval->param_type);
 
-    if (update_all || is_const_tab_input_dirty(&pres->inputs))
+    if (update_all || is_const_tab_input_dirty(&pres->inputs, ~0))
     {
         set_constants(rs, &pres->inputs, update_all, new_update_version);
         if (FAILED(hr = execute_preshader(pres)))
diff --git a/dlls/d3dx9_36/tests/effect.c b/dlls/d3dx9_36/tests/effect.c
index 7991b80..f4a4777 100644
--- a/dlls/d3dx9_36/tests/effect.c
+++ b/dlls/d3dx9_36/tests/effect.c
@@ -4704,15 +4704,13 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     hr = effect->lpVtbl->BeginPass(effect, 1);
-    todo_wine ok(hr == E_FAIL, "Got result %#x.\n", hr);
-    if (SUCCEEDED(hr))
-        effect->lpVtbl->EndPass(effect);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
 
     /* Second try reports success and selects array element used previously.
      * Probably array index is not recomputed and previous index value is used. */
     hr = effect->lpVtbl->BeginPass(effect, 1);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
-    test_effect_preshader_compare_shader(device, 2, TRUE);
+    test_effect_preshader_compare_shader(device, 2, FALSE);
 
     /* Confirm that array element selected is the previous good one and does not depend
      * on computed (out of bound) index value. */
@@ -4732,12 +4730,10 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
     hr = IDirect3DDevice9_SetVertexShader(device, NULL);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
     hr = effect->lpVtbl->BeginPass(effect, 1);
-    todo_wine
     ok(hr == E_FAIL, "Got result %#x.\n", hr);
     hr = effect->lpVtbl->BeginPass(effect, 1);
-    todo_wine
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
-    test_effect_preshader_compare_shader(device, 1, TRUE);
+    test_effect_preshader_compare_shader(device, 1, FALSE);
 
     /* End and begin effect again to ensure it will not trigger array
      * index recompute and error return from BeginPass. */
@@ -4749,7 +4745,7 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
     hr = effect->lpVtbl->BeginPass(effect, 1);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
-    test_effect_preshader_compare_shader(device, 1, TRUE);
+    test_effect_preshader_compare_shader(device, 1, FALSE);
     hr = effect->lpVtbl->EndPass(effect);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
@@ -4762,9 +4758,7 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     hr = effect->lpVtbl->BeginPass(effect, 1);
-    todo_wine ok(hr == E_FAIL, "Got result %#x.\n", hr);
-    if (SUCCEEDED(hr))
-        hr = effect->lpVtbl->EndPass(effect);
+    ok(hr == E_FAIL, "Got result %#x.\n", hr);
 
     hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
@@ -4773,7 +4767,7 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
     hr = effect->lpVtbl->BeginPass(effect, 1);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
-    test_effect_preshader_compare_shader(device, 1, TRUE);
+    test_effect_preshader_compare_shader(device, 1, FALSE);
 
     hr = effect->lpVtbl->EndPass(effect);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
@@ -4785,7 +4779,7 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
     hr = effect->lpVtbl->BeginPass(effect, 1);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
-    test_effect_preshader_compare_shader(device, 0, TRUE);
+    test_effect_preshader_compare_shader(device, 0, FALSE);
 
     hr = IDirect3DDevice9_SetVertexShader(device, NULL);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
@@ -4816,7 +4810,7 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
     hr = effect->lpVtbl->CommitChanges(effect);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
-    test_effect_preshader_compare_shader(device, 1, TRUE);
+    test_effect_preshader_compare_shader(device, 1, FALSE);
 
     hr = effect->lpVtbl->EndPass(effect);
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
@@ -6350,10 +6344,9 @@ static void test_effect_get_pass_desc(IDirect3DDevice9 *device)
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
     hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
-    todo_wine
     ok(hr == D3D_OK, "Got result %#x.\n", hr);
 
-    test_effect_preshader_compare_shader_bytecode(desc.pVertexShaderFunction, 0, 0, TRUE);
+    test_effect_preshader_compare_shader_bytecode(desc.pVertexShaderFunction, 0, 0, FALSE);
 
     fvect.z = 2.0f;
     hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
-- 
2.9.3




More information about the wine-patches mailing list