From 09226543fe22012b3aaa57f7cba0c501ff786d92 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 21 Feb 2025 23:57:50 +0100 Subject: [PATCH] vkd3d-shader/fx: Implement parsing complex value and index expressions. Signed-off-by: Nikolay Sivov --- include/private/vkd3d_common.h | 3 + libs/vkd3d-shader/fx.c | 319 ++++++++++++++++++++++++++++++++- 2 files changed, 320 insertions(+), 2 deletions(-) diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 3560c691..2e17cb96 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -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') diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c index de29cb0e..88779622 100644 --- a/libs/vkd3d-shader/fx.c +++ b/libs/vkd3d-shader/fx.c @@ -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 ""; +} + +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, "()"); + 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, "", 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: {