d3dx9: Support relative addressing in preshaders.

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:
Paul Gofman 2017-04-03 19:51:22 +02:00 committed by Alexandre Julliard
parent 83bc9c85e4
commit 42cbd578f7
2 changed files with 157 additions and 57 deletions

View File

@ -185,7 +185,7 @@ static const enum pres_reg_tables shad_regset2table[] =
PRES_REGTAB_COUNT, /* D3DXRS_SAMPLER */
};
struct d3dx_pres_operand
struct d3dx_pres_reg
{
enum pres_reg_tables table;
/* offset is component index, not register index, e. g.
@ -193,6 +193,12 @@ struct d3dx_pres_operand
unsigned int offset;
};
struct d3dx_pres_operand
{
struct d3dx_pres_reg reg;
struct d3dx_pres_reg index_reg;
};
#define MAX_INPUTS_COUNT 8
struct d3dx_pres_ins
@ -368,7 +374,7 @@ static unsigned int *find_bytecode_comment(unsigned int *ptr, unsigned int count
return NULL;
}
static unsigned int *parse_pres_arg(unsigned int *ptr, unsigned int count, struct d3dx_pres_operand *opr)
static unsigned int *parse_pres_reg(unsigned int *ptr, struct d3dx_pres_reg *reg)
{
static const enum pres_reg_tables reg_table[8] =
{
@ -376,29 +382,46 @@ static unsigned int *parse_pres_arg(unsigned int *ptr, unsigned int count, struc
PRES_REGTAB_OCONST, PRES_REGTAB_OBCONST, PRES_REGTAB_OICONST, PRES_REGTAB_TEMP
};
if (count < 3)
{
WARN("Byte code buffer ends unexpectedly.\n");
return NULL;
}
if (*ptr)
{
FIXME("Relative addressing not supported yet, word %#x.\n", *ptr);
return NULL;
}
++ptr;
if (*ptr >= ARRAY_SIZE(reg_table) || reg_table[*ptr] == PRES_REGTAB_COUNT)
{
FIXME("Unsupported register table %#x.\n", *ptr);
return NULL;
}
opr->table = reg_table[*ptr++];
opr->offset = *ptr++;
if (opr->table == PRES_REGTAB_OBCONST)
opr->offset /= 4;
reg->table = reg_table[*ptr++];
reg->offset = *ptr++;
return ptr;
}
static unsigned int *parse_pres_arg(unsigned int *ptr, unsigned int count, struct d3dx_pres_operand *opr)
{
if (count < 3 || (*ptr && count < 5))
{
WARN("Byte code buffer ends unexpectedly, count %u.\n", count);
return NULL;
}
if (*ptr)
{
if (*ptr != 1)
{
FIXME("Unknown relative addressing flag, word %#x.\n", *ptr);
return NULL;
}
ptr = parse_pres_reg(ptr + 1, &opr->index_reg);
if (!ptr)
return NULL;
}
else
{
opr->index_reg.table = PRES_REGTAB_COUNT;
++ptr;
}
ptr = parse_pres_reg(ptr, &opr->reg);
if (opr->reg.table == PRES_REGTAB_OBCONST)
opr->reg.offset /= 4;
return ptr;
}
@ -452,6 +475,12 @@ static unsigned int *parse_pres_ins(unsigned int *ptr, unsigned int count, struc
ptr = p;
}
ptr = parse_pres_arg(ptr, count, &ins->output);
if (ins->output.index_reg.table != PRES_REGTAB_COUNT)
{
FIXME("Relative addressing in output register not supported.\n");
return NULL;
}
return ptr;
}
@ -566,20 +595,33 @@ static void dump_arg(struct d3dx_regstore *rs, const struct d3dx_pres_operand *a
static const char *xyzw_str = "xyzw";
unsigned int i, table;
table = arg->table;
if (table == PRES_REGTAB_IMMED)
table = arg->reg.table;
if (table == PRES_REGTAB_IMMED && arg->index_reg.table == PRES_REGTAB_COUNT)
{
TRACE("(");
for (i = 0; i < component_count; ++i)
TRACE(i < component_count - 1 ? "%.16e, " : "%.16e",
((double *)rs->tables[PRES_REGTAB_IMMED])[arg->offset + i]);
((double *)rs->tables[PRES_REGTAB_IMMED])[arg->reg.offset + i]);
TRACE(")");
}
else
{
TRACE("%s%u.", table_symbol[table], get_reg_offset(table, arg->offset));
if (arg->index_reg.table == PRES_REGTAB_COUNT)
{
TRACE("%s%u.", table_symbol[table], get_reg_offset(table, arg->reg.offset));
}
else
{
unsigned int index_reg;
index_reg = get_reg_offset(arg->index_reg.table, arg->index_reg.offset);
TRACE("%s[%u + %s%u.%c].", table_symbol[table], get_reg_offset(table, arg->reg.offset),
table_symbol[arg->index_reg.table], index_reg,
xyzw_str[arg->index_reg.offset
- index_reg * table_info[arg->index_reg.table].reg_component_count]);
}
for (i = 0; i < component_count; ++i)
TRACE("%c", xyzw_str[(arg->offset + i) % 4]);
TRACE("%c", xyzw_str[(arg->reg.offset + i) % 4]);
}
}
@ -710,13 +752,26 @@ static HRESULT parse_preshader(struct d3dx_preshader *pres, unsigned int *ptr, u
for (i = 0; i < pres->ins_count; ++i)
{
for (j = 0; j < pres_op_info[pres->ins[i].op].input_count; ++j)
update_table_size(pres->regs.table_sizes, pres->ins[i].inputs[j].table,
get_reg_offset(pres->ins[i].inputs[j].table,
pres->ins[i].inputs[j].offset + pres->ins[i].component_count - 1));
{
enum pres_reg_tables table;
unsigned int reg_idx;
update_table_size(pres->regs.table_sizes, pres->ins[i].output.table,
get_reg_offset(pres->ins[i].output.table,
pres->ins[i].output.offset + pres->ins[i].component_count - 1));
if (pres->ins[i].inputs[j].index_reg.table == PRES_REGTAB_COUNT)
{
table = pres->ins[i].inputs[j].reg.table;
reg_idx = get_reg_offset(table, pres->ins[i].inputs[j].reg.offset
+ pres->ins[i].component_count - 1);
}
else
{
table = pres->ins[i].inputs[j].index_reg.table;
reg_idx = get_reg_offset(table, pres->ins[i].inputs[j].index_reg.offset);
}
update_table_size(pres->regs.table_sizes, table, reg_idx);
}
update_table_size(pres->regs.table_sizes, pres->ins[i].output.reg.table,
get_reg_offset(pres->ins[i].output.reg.table,
pres->ins[i].output.reg.offset + pres->ins[i].component_count - 1));
}
update_table_sizes_consts(pres->regs.table_sizes, &pres->inputs);
if (FAILED(regstore_alloc_table(&pres->regs, PRES_REGTAB_IMMED)))
@ -1101,18 +1156,63 @@ static HRESULT init_set_constants(struct d3dx_const_tab *const_tab, ID3DXConstan
return ret;
}
static double exec_get_arg(struct d3dx_regstore *rs, const struct d3dx_pres_operand *opr, unsigned int comp)
static double exec_get_reg_value(struct d3dx_regstore *rs, enum pres_reg_tables table, unsigned int offset)
{
if (!regstore_is_val_set_reg(rs, opr->table, (opr->offset + comp) / table_info[opr->table].reg_component_count))
WARN("Using uninitialized input, table %u, offset %u.\n", opr->table, opr->offset + comp);
if (!regstore_is_val_set_reg(rs, table, offset / table_info[table].reg_component_count))
WARN("Using uninitialized input, table %u, offset %u.\n", table, offset);
return regstore_get_double(rs, opr->table, opr->offset + comp);
return regstore_get_double(rs, table, offset);
}
static void exec_set_arg(struct d3dx_regstore *rs, const struct d3dx_pres_operand *opr,
static double exec_get_arg(struct d3dx_regstore *rs, const struct d3dx_pres_operand *opr, unsigned int comp)
{
unsigned int offset, base_index, reg_index, table;
table = opr->reg.table;
if (opr->index_reg.table == PRES_REGTAB_COUNT)
base_index = 0;
else
base_index = lrint(exec_get_reg_value(rs, opr->index_reg.table, opr->index_reg.offset));
/* '4' is used instead of reg_component_count, as immediate constants (which have
* reg_component_count of 1) are still indexed as 4 values according to the tests. */
offset = base_index * 4 + opr->reg.offset + comp;
reg_index = offset / table_info[table].reg_component_count;
if (reg_index >= rs->table_sizes[table])
{
unsigned int wrap_size;
if (table == PRES_REGTAB_CONST)
{
/* As it can be guessed from tests, offset into floating constant table is wrapped
* to the nearest power of 2 and not to the actual table size. */
for (wrap_size = 1; wrap_size < rs->table_sizes[table]; wrap_size <<= 1)
;
}
else
{
wrap_size = rs->table_sizes[table];
}
WARN("Wrapping register index %u, table %u, wrap_size %u, table size %u.\n",
reg_index, table, wrap_size, rs->table_sizes[table]);
reg_index %= wrap_size;
if (reg_index >= rs->table_sizes[table])
return 0.0;
offset = reg_index * table_info[table].reg_component_count
+ offset % table_info[table].reg_component_count;
}
return exec_get_reg_value(rs, table, offset);
}
static void exec_set_arg(struct d3dx_regstore *rs, const struct d3dx_pres_reg *reg,
unsigned int comp, double res)
{
regstore_set_double(rs, opr->table, opr->offset + comp, res);
regstore_set_double(rs, reg->table, reg->offset + comp, res);
}
#define ARGS_ARRAY_SIZE 8
@ -1143,7 +1243,7 @@ static HRESULT execute_preshader(struct d3dx_preshader *pres)
res = oi->func(args, ins->component_count);
/* only 'dot' instruction currently falls here */
exec_set_arg(&pres->regs, &ins->output, 0, res);
exec_set_arg(&pres->regs, &ins->output.reg, 0, res);
}
else
{
@ -1152,7 +1252,7 @@ static HRESULT execute_preshader(struct d3dx_preshader *pres)
for (k = 0; k < oi->input_count; ++k)
args[k] = exec_get_arg(&pres->regs, &ins->inputs[k], ins->scalar_op && !k ? 0 : j);
res = oi->func(args, ins->component_count);
exec_set_arg(&pres->regs, &ins->output, j, res);
exec_set_arg(&pres->regs, &ins->output.reg, j, res);
}
}
}

View File

@ -3971,7 +3971,7 @@ test_effect_preshader_op_expected[] =
{"prec", {FALSE, FALSE, TRUE, FALSE}, {0x2b8cbccc, 0x2c0cbccc, 0xac531800, 0x00000000}},
{"dotswiz", {FALSE, FALSE, FALSE, FALSE}, {0xc00ccccd, 0xc0d33334, 0xc10ccccd, 0}},
{"reladdr", { TRUE, TRUE, TRUE, TRUE}, {0xc00ccccd, 0x40000000, 0x41a00000, 0x41500000}},
{"reladdr", {FALSE, FALSE, FALSE, FALSE}, {0xc00ccccd, 0x40000000, 0x41a00000, 0x41500000}},
};
enum expected_state_update
@ -4207,7 +4207,7 @@ static void test_effect_preshader(IDirect3DDevice9 *device)
ok(hr == D3D_OK, "SetVector failed, hr %#x.\n", hr);
hr = effect->lpVtbl->BeginPass(effect, 0);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->BeginPass(effect, 0);
ok(hr == D3DERR_INVALIDCALL, "Got result %#x.\n", hr);
@ -4375,7 +4375,7 @@ static void test_preshader_op(IDirect3DDevice9 *device, const DWORD *sample_effe
}
hr = effect->lpVtbl->BeginPass(effect, 0);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = IDirect3DDevice9_GetLight(device, blob_position[test->args_count].result_index, &light);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
@ -4674,7 +4674,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->BeginPass(effect, 0);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
for (i = 0; i < ARRAY_SIZE(check_op_parameters); ++i)
{
@ -4692,7 +4692,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, &fvect, sizeof(fvect));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_op_results(device, check_op_parameters[i].state_updated,
check_op_parameters[i].param_name);
@ -4710,7 +4710,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, buffer, sizeof(buffer));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[i].const_updated_mask,
check_vconsts_parameters[i].param_name);
@ -4723,7 +4723,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetVectorArray(effect, param, &fvect, 1);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[0].const_updated_mask,
check_vconsts_parameters[0].param_name);
@ -4735,7 +4735,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetFloat(effect, param, 92.0f);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, const_no_update_mask,
check_vconsts_parameters[10].param_name);
@ -4748,7 +4748,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, &fvect.x, sizeof(fvect.x));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[10].const_updated_mask,
check_vconsts_parameters[10].param_name);
@ -4759,7 +4759,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetFloatArray(effect, param, &fvect.x, 1);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[10].const_updated_mask,
check_vconsts_parameters[10].param_name);
@ -4771,7 +4771,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetInt(effect, param, 93);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, const_no_update_mask,
check_vconsts_parameters[10].param_name);
@ -4782,7 +4782,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetVector(effect, param, &fvect);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[1].const_updated_mask,
check_vconsts_parameters[1].param_name);
@ -4797,7 +4797,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, &fvect.x, sizeof(float));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, check_vconsts_parameters[7].const_updated_mask,
check_vconsts_parameters[7].param_name);
@ -4822,7 +4822,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, &fvect, sizeof(float) * 3);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGDENSITY, &value);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(value == 0, "Unexpected fog density %g.\n", *(float *)&value);
@ -4861,7 +4861,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, &fvect.x, sizeof(float));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = IDirect3DDevice9_GetRenderState(device, D3DRS_FOGDENSITY, &value);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(*(float *)&value == 9999.0f, "Unexpected fog density %g.\n", *(float *)&value);
@ -4897,7 +4897,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
test_effect_preshader_clear_vconsts(device);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
@ -4918,7 +4918,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(!vshader, "Got non NULL vshader.\n");
@ -4928,7 +4928,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = IDirect3DDevice9_GetVertexShader(device, &vshader);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(!!vshader, "Got NULL vshader.\n");
@ -4945,7 +4945,7 @@ static void test_effect_commitchanges(IDirect3DDevice9 *device)
hr = effect->lpVtbl->SetValue(effect, param, ivect, sizeof(ivect));
ok(hr == D3D_OK, "Got result %#x.\n", hr);
hr = effect->lpVtbl->CommitChanges(effect);
todo_wine ok(hr == D3D_OK, "Got result %#x.\n", hr);
ok(hr == D3D_OK, "Got result %#x.\n", hr);
test_effect_preshader_compare_vconsts(device, NULL, NULL);
hr = effect->lpVtbl->EndPass(effect);