mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-04-13 05:43:18 -07:00
vkd3d-shader/fx: Implement parsing complex value and index expressions.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
committed by
Henri Verbeet
parent
58aed8fd0d
commit
09226543fe
Notes:
Henri Verbeet
2025-02-24 16:28:00 +01:00
Approved-by: Henri Verbeet (@hverbeet) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1392
@ -65,9 +65,12 @@
|
||||
#define vkd3d_clamp(value, lower, upper) max(min(value, upper), lower)
|
||||
|
||||
#define TAG_AON9 VKD3D_MAKE_TAG('A', 'o', 'n', '9')
|
||||
#define TAG_CLI4 VKD3D_MAKE_TAG('C', 'L', 'I', '4')
|
||||
#define TAG_CTAB VKD3D_MAKE_TAG('C', 'T', 'A', 'B')
|
||||
#define TAG_DXBC VKD3D_MAKE_TAG('D', 'X', 'B', 'C')
|
||||
#define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L')
|
||||
#define TAG_FX10 VKD3D_MAKE_TAG('F', 'X', '1', '0')
|
||||
#define TAG_FXLC VKD3D_MAKE_TAG('F', 'X', 'L', 'C')
|
||||
#define TAG_ISG1 VKD3D_MAKE_TAG('I', 'S', 'G', '1')
|
||||
#define TAG_ISGN VKD3D_MAKE_TAG('I', 'S', 'G', 'N')
|
||||
#define TAG_OSG1 VKD3D_MAKE_TAG('O', 'S', 'G', '1')
|
||||
|
@ -560,8 +560,21 @@ enum fx_4_type_constants
|
||||
FX_4_ASSIGNMENT_VARIABLE = 0x2,
|
||||
FX_4_ASSIGNMENT_ARRAY_CONSTANT_INDEX = 0x3,
|
||||
FX_4_ASSIGNMENT_ARRAY_VARIABLE_INDEX = 0x4,
|
||||
FX_4_ASSIGNMENT_INDEX_EXPRESSION = 0x5,
|
||||
FX_4_ASSIGNMENT_VALUE_EXPRESSION = 0x6,
|
||||
FX_4_ASSIGNMENT_INLINE_SHADER = 0x7,
|
||||
FX_5_ASSIGNMENT_INLINE_SHADER = 0x8,
|
||||
|
||||
/* FXLVM constants */
|
||||
FX_4_FXLC_COMP_COUNT_MASK = 0xffff,
|
||||
FX_4_FXLC_OPCODE_MASK = 0x7ff,
|
||||
FX_4_FXLC_OPCODE_SHIFT = 20,
|
||||
FX_4_FXLC_IS_SCALAR_MASK = 0x80000000,
|
||||
|
||||
FX_4_FXLC_REG_LITERAL = 1,
|
||||
FX_4_FXLC_REG_CB = 2,
|
||||
FX_4_FXLC_REG_OUTPUT = 4,
|
||||
FX_4_FXLC_REG_TEMP = 7,
|
||||
};
|
||||
|
||||
static const uint32_t fx_4_numeric_base_types[] =
|
||||
@ -2986,15 +2999,16 @@ static const void *fx_parser_get_unstructured_ptr(struct fx_parser *parser, uint
|
||||
return &ptr[offset];
|
||||
}
|
||||
|
||||
static void fx_parser_read_unstructured(struct fx_parser *parser, void *dst, uint32_t offset, size_t size)
|
||||
static uint32_t fx_parser_read_unstructured(struct fx_parser *parser, void *dst, uint32_t offset, size_t size)
|
||||
{
|
||||
const uint8_t *ptr;
|
||||
|
||||
memset(dst, 0, size);
|
||||
if (!(ptr = fx_parser_get_unstructured_ptr(parser, offset, size)))
|
||||
return;
|
||||
return offset;
|
||||
|
||||
memcpy(dst, ptr, size);
|
||||
return offset + size;
|
||||
}
|
||||
|
||||
static const char *fx_4_get_string(struct fx_parser *parser, uint32_t offset)
|
||||
@ -3366,6 +3380,294 @@ static int fx_4_state_id_compare(const void *a, const void *b)
|
||||
return id - state->id;
|
||||
}
|
||||
|
||||
static const struct
|
||||
{
|
||||
uint32_t opcode;
|
||||
const char *name;
|
||||
}
|
||||
fx_4_fxlc_opcodes[] =
|
||||
{
|
||||
{ 0x100, "mov" },
|
||||
{ 0x101, "neg" },
|
||||
{ 0x103, "rcp" },
|
||||
{ 0x104, "frc" },
|
||||
{ 0x105, "exp" },
|
||||
{ 0x106, "log" },
|
||||
{ 0x107, "rsq" },
|
||||
{ 0x108, "sin" },
|
||||
{ 0x109, "cos" },
|
||||
{ 0x10a, "asin" },
|
||||
{ 0x10b, "acos" },
|
||||
{ 0x10c, "atan" },
|
||||
{ 0x112, "sqrt" },
|
||||
{ 0x120, "ineg" },
|
||||
{ 0x121, "not" },
|
||||
{ 0x130, "itof" },
|
||||
{ 0x131, "utof" },
|
||||
{ 0x133, "ftou" },
|
||||
{ 0x137, "ftob" },
|
||||
{ 0x139, "floor" },
|
||||
{ 0x13a, "ceil" },
|
||||
{ 0x200, "min" },
|
||||
{ 0x201, "max" },
|
||||
{ 0x204, "add" },
|
||||
{ 0x205, "mul" },
|
||||
{ 0x206, "atan2" },
|
||||
{ 0x208, "div" },
|
||||
{ 0x210, "bilt" },
|
||||
{ 0x211, "bige" },
|
||||
{ 0x212, "bieq" },
|
||||
{ 0x213, "bine" },
|
||||
{ 0x214, "buge" },
|
||||
{ 0x215, "bult" },
|
||||
{ 0x216, "iadd" },
|
||||
{ 0x219, "imul" },
|
||||
{ 0x21a, "udiv" },
|
||||
{ 0x21d, "imin" },
|
||||
{ 0x21e, "imax" },
|
||||
{ 0x21f, "umin" },
|
||||
{ 0x220, "umax" },
|
||||
{ 0x230, "and" },
|
||||
{ 0x231, "or" },
|
||||
{ 0x233, "xor" },
|
||||
{ 0x234, "ishl" },
|
||||
{ 0x235, "ishr" },
|
||||
{ 0x236, "ushr" },
|
||||
{ 0x301, "movc" },
|
||||
{ 0x500, "dot" },
|
||||
{ 0x70e, "d3ds_dotswiz" },
|
||||
};
|
||||
|
||||
static const char *fx_4_get_fxlc_opcode_name(uint32_t opcode)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fx_4_fxlc_opcodes); ++i)
|
||||
{
|
||||
if (fx_4_fxlc_opcodes[i].opcode == opcode)
|
||||
return fx_4_fxlc_opcodes[i].name;
|
||||
}
|
||||
|
||||
return "<unrecognized>";
|
||||
}
|
||||
|
||||
struct fx_4_fxlc_argument
|
||||
{
|
||||
uint32_t flags;
|
||||
uint32_t reg_type;
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
struct fx_4_ctab_entry
|
||||
{
|
||||
uint32_t name;
|
||||
uint16_t register_set;
|
||||
uint16_t register_index;
|
||||
uint16_t register_count;
|
||||
uint16_t reserved;
|
||||
uint32_t typeinfo;
|
||||
uint32_t default_value;
|
||||
};
|
||||
|
||||
struct fxlvm_code
|
||||
{
|
||||
const float *cli4;
|
||||
uint32_t cli4_count;
|
||||
|
||||
const struct fx_4_ctab_entry *constants;
|
||||
uint32_t ctab_offset;
|
||||
uint32_t ctab_count;
|
||||
const char *ctab;
|
||||
|
||||
unsigned int comp_count;
|
||||
bool scalar;
|
||||
};
|
||||
|
||||
static void fx_4_parse_print_swizzle(struct fx_parser *parser, const struct fxlvm_code *code, unsigned int addr)
|
||||
{
|
||||
unsigned int comp_count = code->scalar ? 1 : code->comp_count;
|
||||
static const char comp[] = "xyzw";
|
||||
|
||||
if (comp_count < 4)
|
||||
vkd3d_string_buffer_printf(&parser->buffer, ".%.*s", comp_count, &comp[addr % 4]);
|
||||
}
|
||||
|
||||
static void fx_4_parse_fxlc_constant_argument(struct fx_parser *parser,
|
||||
const struct fx_4_fxlc_argument *arg, const struct fxlvm_code *code)
|
||||
{
|
||||
uint32_t i, offset, register_index = arg->address / 4; /* Address counts in components. */
|
||||
|
||||
for (i = 0; i < code->ctab_count; ++i)
|
||||
{
|
||||
const struct fx_4_ctab_entry *c = &code->constants[i];
|
||||
|
||||
if (register_index < c->register_index || register_index - c->register_index >= c->register_count)
|
||||
continue;
|
||||
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "%s", &code->ctab[c->name]);
|
||||
|
||||
/* Register offset within variable */
|
||||
offset = arg->address - c->register_index * 4;
|
||||
|
||||
if (offset / 4)
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "[%u]", offset / 4);
|
||||
fx_4_parse_print_swizzle(parser, code, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "(var-not-found)");
|
||||
}
|
||||
|
||||
static void fx_4_parse_fxlc_argument(struct fx_parser *parser, uint32_t offset, const struct fxlvm_code *code)
|
||||
{
|
||||
struct fx_4_fxlc_argument arg;
|
||||
uint32_t count;
|
||||
|
||||
fx_parser_read_unstructured(parser, &arg, offset, sizeof(arg));
|
||||
|
||||
switch (arg.reg_type)
|
||||
{
|
||||
case FX_4_FXLC_REG_LITERAL:
|
||||
count = code->scalar ? 1 : code->comp_count;
|
||||
if (arg.address >= code->cli4_count || count > code->cli4_count - arg.address)
|
||||
{
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "(<out-of-bounds>)");
|
||||
parser->failed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "(");
|
||||
vkd3d_string_buffer_print_f32(&parser->buffer, code->cli4[arg.address]);
|
||||
for (unsigned int i = 1; i < code->comp_count; ++i)
|
||||
{
|
||||
vkd3d_string_buffer_printf(&parser->buffer, ", ");
|
||||
vkd3d_string_buffer_print_f32(&parser->buffer, code->cli4[arg.address + code->scalar ? 0 : i]);
|
||||
}
|
||||
vkd3d_string_buffer_printf(&parser->buffer, ")");
|
||||
break;
|
||||
|
||||
case FX_4_FXLC_REG_CB:
|
||||
fx_4_parse_fxlc_constant_argument(parser, &arg, code);
|
||||
break;
|
||||
|
||||
case FX_4_FXLC_REG_OUTPUT:
|
||||
case FX_4_FXLC_REG_TEMP:
|
||||
if (arg.reg_type == FX_4_FXLC_REG_OUTPUT)
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "expr");
|
||||
else
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "r%u", arg.address / 4);
|
||||
fx_4_parse_print_swizzle(parser, code, arg.address);
|
||||
break;
|
||||
|
||||
default:
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "<unknown register %u>", arg.reg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fx_4_parse_fxlvm_expression(struct fx_parser *parser, uint32_t offset)
|
||||
{
|
||||
struct vkd3d_shader_dxbc_section_desc *section, fxlc, cli4, ctab;
|
||||
struct vkd3d_shader_dxbc_desc dxbc_desc;
|
||||
struct vkd3d_shader_code dxbc;
|
||||
uint32_t size, ins_count;
|
||||
struct fxlvm_code code;
|
||||
size_t i, j;
|
||||
|
||||
offset = fx_parser_read_unstructured(parser, &size, offset, sizeof(size));
|
||||
|
||||
dxbc.size = size;
|
||||
dxbc.code = fx_parser_get_unstructured_ptr(parser, offset, size);
|
||||
if (!dxbc.code)
|
||||
return;
|
||||
|
||||
if (vkd3d_shader_parse_dxbc(&dxbc, 0, &dxbc_desc, NULL) < 0)
|
||||
{
|
||||
parser->failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&fxlc, 0, sizeof(fxlc));
|
||||
memset(&cli4, 0, sizeof(cli4));
|
||||
memset(&ctab, 0, sizeof(ctab));
|
||||
for (i = 0; i < dxbc_desc.section_count; ++i)
|
||||
{
|
||||
section = &dxbc_desc.sections[i];
|
||||
|
||||
if (section->tag == TAG_FXLC)
|
||||
fxlc = *section;
|
||||
else if (section->tag == TAG_CLI4)
|
||||
cli4 = *section;
|
||||
else if (section->tag == TAG_CTAB)
|
||||
ctab = *section;
|
||||
}
|
||||
|
||||
vkd3d_shader_free_dxbc(&dxbc_desc);
|
||||
|
||||
if (cli4.data.code)
|
||||
{
|
||||
uint32_t cli4_offset = offset + (size_t)cli4.data.code - (size_t)dxbc.code;
|
||||
|
||||
fx_parser_read_unstructured(parser, &code.cli4_count, cli4_offset, sizeof(code.cli4_count));
|
||||
code.cli4 = fx_parser_get_unstructured_ptr(parser, cli4_offset + 4, code.cli4_count * sizeof(float));
|
||||
}
|
||||
|
||||
if (ctab.data.code)
|
||||
{
|
||||
uint32_t ctab_offset = offset + (size_t)ctab.data.code - (size_t)dxbc.code;
|
||||
uint32_t consts_offset;
|
||||
|
||||
fx_parser_read_unstructured(parser, &code.ctab_count, ctab_offset + 12, sizeof(code.ctab_count));
|
||||
fx_parser_read_unstructured(parser, &consts_offset, ctab_offset + 16, sizeof(consts_offset));
|
||||
|
||||
code.ctab = ctab.data.code;
|
||||
code.constants = fx_parser_get_unstructured_ptr(parser,
|
||||
ctab_offset + consts_offset, code.ctab_count * sizeof(*code.constants));
|
||||
}
|
||||
|
||||
offset += (size_t)fxlc.data.code - (size_t)dxbc.code;
|
||||
offset = fx_parser_read_unstructured(parser, &ins_count, offset, sizeof(ins_count));
|
||||
|
||||
parse_fx_start_indent(parser);
|
||||
|
||||
for (i = 0; i < ins_count; ++i)
|
||||
{
|
||||
uint32_t instr, opcode, src_count;
|
||||
struct fx_4_fxlc_argument arg;
|
||||
|
||||
offset = fx_parser_read_unstructured(parser, &instr, offset, sizeof(instr));
|
||||
offset = fx_parser_read_unstructured(parser, &src_count, offset, sizeof(src_count));
|
||||
|
||||
opcode = (instr >> FX_4_FXLC_OPCODE_SHIFT) & FX_4_FXLC_OPCODE_MASK;
|
||||
code.comp_count = instr & FX_4_FXLC_COMP_COUNT_MASK;
|
||||
code.scalar = false;
|
||||
|
||||
parse_fx_print_indent(parser);
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "%s ", fx_4_get_fxlc_opcode_name(opcode));
|
||||
|
||||
/* Destination first. */
|
||||
fx_4_parse_fxlc_argument(parser, offset + sizeof(arg) * src_count, &code);
|
||||
|
||||
for (j = 0; j < src_count; ++j)
|
||||
{
|
||||
vkd3d_string_buffer_printf(&parser->buffer, ", ");
|
||||
|
||||
/* Scalar modifier applies only to first source. */
|
||||
code.scalar = j == 0 && !!(instr & FX_4_FXLC_IS_SCALAR_MASK);
|
||||
fx_4_parse_fxlc_argument(parser, offset, &code);
|
||||
|
||||
offset += sizeof(arg);
|
||||
}
|
||||
|
||||
/* Destination */
|
||||
offset += sizeof(arg);
|
||||
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "\n");
|
||||
}
|
||||
|
||||
parse_fx_end_indent(parser);
|
||||
}
|
||||
|
||||
static void fx_4_parse_state_object_initializer(struct fx_parser *parser, uint32_t count,
|
||||
enum hlsl_type_class type_class)
|
||||
{
|
||||
@ -3496,6 +3798,19 @@ static void fx_4_parse_state_object_initializer(struct fx_parser *parser, uint32
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "%s[%s]", fx_4_get_string(parser, index.name),
|
||||
fx_4_get_string(parser, index.index));
|
||||
break;
|
||||
case FX_4_ASSIGNMENT_INDEX_EXPRESSION:
|
||||
fx_parser_read_unstructured(parser, &index, entry.value, sizeof(index));
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "%s[eval(\n", fx_4_get_string(parser, index.name));
|
||||
fx_4_parse_fxlvm_expression(parser, index.index);
|
||||
parse_fx_print_indent(parser);
|
||||
vkd3d_string_buffer_printf(&parser->buffer, ")]");
|
||||
break;
|
||||
case FX_4_ASSIGNMENT_VALUE_EXPRESSION:
|
||||
vkd3d_string_buffer_printf(&parser->buffer, "eval(\n");
|
||||
fx_4_parse_fxlvm_expression(parser, entry.value);
|
||||
parse_fx_print_indent(parser);
|
||||
vkd3d_string_buffer_printf(&parser->buffer, ")");
|
||||
break;
|
||||
case FX_4_ASSIGNMENT_INLINE_SHADER:
|
||||
case FX_5_ASSIGNMENT_INLINE_SHADER:
|
||||
{
|
||||
|
Reference in New Issue
Block a user