d3dx9: Match native out of bounds array selector index handling.
Signed-off-by: Paul Gofman <gofmanp@gmail.com> Signed-off-by: Matteo Bruni <mbruni@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a179584844
commit
454a2c5c21
|
@ -28,6 +28,8 @@
|
||||||
#define COBJMACROS
|
#define COBJMACROS
|
||||||
#include "d3dx9.h"
|
#include "d3dx9.h"
|
||||||
|
|
||||||
|
#define ULONG64_MAX (~(ULONG64)0)
|
||||||
|
|
||||||
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
|
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
|
||||||
|
|
||||||
struct vec4
|
struct vec4
|
||||||
|
@ -269,6 +271,6 @@ HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval,
|
||||||
const struct d3dx_parameter *param, void *param_value) DECLSPEC_HIDDEN;
|
const struct d3dx_parameter *param, void *param_value) DECLSPEC_HIDDEN;
|
||||||
HRESULT d3dx_param_eval_set_shader_constants(ID3DXEffectStateManager *manager, struct IDirect3DDevice9 *device,
|
HRESULT d3dx_param_eval_set_shader_constants(ID3DXEffectStateManager *manager, struct IDirect3DDevice9 *device,
|
||||||
struct d3dx_param_eval *peval, BOOL update_all) DECLSPEC_HIDDEN;
|
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 */
|
#endif /* __WINE_D3DX9_PRIVATE_H */
|
||||||
|
|
|
@ -1051,7 +1051,9 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
|
||||||
FIXME("Preshader structure is null.\n");
|
FIXME("Preshader structure is null.\n");
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
}
|
}
|
||||||
if (update_all || is_param_eval_input_dirty(param->param_eval))
|
/* We override with the update_version of the pass because we want
|
||||||
|
* to force index recomputation and check for out of bounds. */
|
||||||
|
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)))
|
if (FAILED(hr = d3dx_evaluate_parameter(param->param_eval, &array_idx_param, &array_idx)))
|
||||||
return hr;
|
return hr;
|
||||||
|
@ -1063,6 +1065,13 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
|
||||||
ref_param = param->u.referenced_param;
|
ref_param = param->u.referenced_param;
|
||||||
TRACE("Array index %u, stored array index %u, element_count %u.\n", array_idx, state->index,
|
TRACE("Array index %u, stored array index %u, element_count %u.\n", array_idx, state->index,
|
||||||
ref_param->element_count);
|
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 == ~0u)
|
||||||
|
{
|
||||||
|
WARN("Array index is -1, setting to 0.\n");
|
||||||
|
array_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (array_idx >= ref_param->element_count)
|
if (array_idx >= ref_param->element_count)
|
||||||
{
|
{
|
||||||
|
@ -1083,7 +1092,7 @@ static HRESULT d3dx9_get_param_value_ptr(struct d3dx_pass *pass, struct d3dx_sta
|
||||||
{
|
{
|
||||||
*out_param = param;
|
*out_param = param;
|
||||||
*param_value = param->data;
|
*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, ULONG64_MAX))
|
||||||
{
|
{
|
||||||
*param_dirty = TRUE;
|
*param_dirty = TRUE;
|
||||||
return d3dx_evaluate_parameter(param->param_eval, param, *param_value);
|
return d3dx_evaluate_parameter(param->param_eval, param, *param_value);
|
||||||
|
@ -1134,7 +1143,7 @@ static HRESULT d3dx9_base_effect_get_pass_desc(struct d3dx9_base_effect *base,
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if (FAILED(hr = d3dx9_get_param_value_ptr(pass, &pass->states[i], ¶m_value, ¶m,
|
if (FAILED(hr = d3dx9_get_param_value_ptr(pass, &pass->states[i], ¶m_value, ¶m,
|
||||||
TRUE, ¶m_dirty)))
|
FALSE, ¶m_dirty)))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
if (!param->object_id)
|
if (!param->object_id)
|
||||||
|
@ -2944,13 +2953,11 @@ static HRESULT d3dx9_apply_state(struct ID3DXEffectImpl *effect, struct d3dx_pas
|
||||||
if (FAILED(hr = d3dx9_get_param_value_ptr(pass, state, ¶m_value, ¶m,
|
if (FAILED(hr = d3dx9_get_param_value_ptr(pass, state, ¶m_value, ¶m,
|
||||||
update_all, ¶m_dirty)))
|
update_all, ¶m_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 CommitChanges() involving
|
||||||
* out of bounds array access and does not touch the affected
|
* out of bounds array access and does not touch the affected
|
||||||
* state, except for BeginPass when the out of bounds array index
|
* states. */
|
||||||
* depends on dirty parameters. The latter case is supposed to
|
|
||||||
* return E_FAIL but is currently TODO. */
|
|
||||||
WARN("Returning D3D_OK on out of bounds array access.\n");
|
WARN("Returning D3D_OK on out of bounds array access.\n");
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1292,22 +1292,24 @@ static HRESULT execute_preshader(struct d3dx_preshader *pres)
|
||||||
return D3D_OK;
|
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;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (update_version == ULONG64_MAX)
|
||||||
|
update_version = ctab->update_version;
|
||||||
for (i = 0; i < ctab->const_set_count; ++i)
|
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 TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
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)
|
return is_const_tab_input_dirty(&peval->pres.inputs, update_version)
|
||||||
|| is_const_tab_input_dirty(&peval->shader_inputs);
|
|| is_const_tab_input_dirty(&peval->shader_inputs, update_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval, const struct d3dx_parameter *param,
|
HRESULT d3dx_evaluate_parameter(struct d3dx_param_eval *peval, const struct d3dx_parameter *param,
|
||||||
|
@ -1320,7 +1322,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);
|
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, ULONG64_MAX))
|
||||||
{
|
{
|
||||||
set_constants(&peval->pres.regs, &peval->pres.inputs, FALSE,
|
set_constants(&peval->pres.regs, &peval->pres.inputs, FALSE,
|
||||||
next_update_version(peval->version_counter));
|
next_update_version(peval->version_counter));
|
||||||
|
@ -1426,7 +1428,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);
|
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, ULONG64_MAX))
|
||||||
{
|
{
|
||||||
set_constants(rs, &pres->inputs, update_all, new_update_version);
|
set_constants(rs, &pres->inputs, update_all, new_update_version);
|
||||||
if (FAILED(hr = execute_preshader(pres)))
|
if (FAILED(hr = execute_preshader(pres)))
|
||||||
|
|
|
@ -4704,15 +4704,13 @@ static void test_effect_out_of_bounds_selector(IDirect3DDevice9 *device)
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
||||||
|
|
||||||
hr = effect->lpVtbl->BeginPass(effect, 1);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
todo_wine ok(hr == E_FAIL, "Got result %#x.\n", hr);
|
ok(hr == E_FAIL, "Got result %#x.\n", hr);
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
effect->lpVtbl->EndPass(effect);
|
|
||||||
|
|
||||||
/* Second try reports success and selects array element used previously.
|
/* Second try reports success and selects array element used previously.
|
||||||
* Probably array index is not recomputed and previous index value is used. */
|
* Probably array index is not recomputed and previous index value is used. */
|
||||||
hr = effect->lpVtbl->BeginPass(effect, 1);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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
|
/* Confirm that array element selected is the previous good one and does not depend
|
||||||
* on computed (out of bound) index value. */
|
* 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);
|
hr = IDirect3DDevice9_SetVertexShader(device, NULL);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
||||||
hr = effect->lpVtbl->BeginPass(effect, 1);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
todo_wine
|
|
||||||
ok(hr == E_FAIL, "Got result %#x.\n", hr);
|
ok(hr == E_FAIL, "Got result %#x.\n", hr);
|
||||||
hr = effect->lpVtbl->BeginPass(effect, 1);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
todo_wine
|
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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
|
/* End and begin effect again to ensure it will not trigger array
|
||||||
* index recompute and error return from BeginPass. */
|
* 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);
|
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
||||||
hr = effect->lpVtbl->BeginPass(effect, 1);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
hr = effect->lpVtbl->EndPass(effect);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
||||||
|
|
||||||
hr = effect->lpVtbl->BeginPass(effect, 1);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
todo_wine ok(hr == E_FAIL, "Got result %#x.\n", hr);
|
ok(hr == E_FAIL, "Got result %#x.\n", hr);
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
hr = effect->lpVtbl->EndPass(effect);
|
|
||||||
|
|
||||||
hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
|
hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
hr = effect->lpVtbl->EndPass(effect);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
hr = effect->lpVtbl->BeginPass(effect, 1);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
hr = IDirect3DDevice9_SetVertexShader(device, NULL);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
hr = effect->lpVtbl->CommitChanges(effect);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
hr = effect->lpVtbl->EndPass(effect);
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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);
|
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
||||||
|
|
||||||
hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
|
hr = effect->lpVtbl->GetPassDesc(effect, pass, &desc);
|
||||||
todo_wine
|
|
||||||
ok(hr == D3D_OK, "Got result %#x.\n", hr);
|
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;
|
fvect.z = 2.0f;
|
||||||
hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
|
hr = effect->lpVtbl->SetVector(effect, "g_iVect", &fvect);
|
||||||
|
|
Loading…
Reference in New Issue