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 vkd3d_clamp(value, lower, upper) max(min(value, upper), lower)
|
||||||
|
|
||||||
#define TAG_AON9 VKD3D_MAKE_TAG('A', 'o', 'n', '9')
|
#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_DXBC VKD3D_MAKE_TAG('D', 'X', 'B', 'C')
|
||||||
#define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L')
|
#define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L')
|
||||||
#define TAG_FX10 VKD3D_MAKE_TAG('F', 'X', '1', '0')
|
#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_ISG1 VKD3D_MAKE_TAG('I', 'S', 'G', '1')
|
||||||
#define TAG_ISGN VKD3D_MAKE_TAG('I', 'S', 'G', 'N')
|
#define TAG_ISGN VKD3D_MAKE_TAG('I', 'S', 'G', 'N')
|
||||||
#define TAG_OSG1 VKD3D_MAKE_TAG('O', 'S', 'G', '1')
|
#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_VARIABLE = 0x2,
|
||||||
FX_4_ASSIGNMENT_ARRAY_CONSTANT_INDEX = 0x3,
|
FX_4_ASSIGNMENT_ARRAY_CONSTANT_INDEX = 0x3,
|
||||||
FX_4_ASSIGNMENT_ARRAY_VARIABLE_INDEX = 0x4,
|
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_4_ASSIGNMENT_INLINE_SHADER = 0x7,
|
||||||
FX_5_ASSIGNMENT_INLINE_SHADER = 0x8,
|
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[] =
|
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];
|
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;
|
const uint8_t *ptr;
|
||||||
|
|
||||||
memset(dst, 0, size);
|
memset(dst, 0, size);
|
||||||
if (!(ptr = fx_parser_get_unstructured_ptr(parser, offset, size)))
|
if (!(ptr = fx_parser_get_unstructured_ptr(parser, offset, size)))
|
||||||
return;
|
return offset;
|
||||||
|
|
||||||
memcpy(dst, ptr, size);
|
memcpy(dst, ptr, size);
|
||||||
|
return offset + size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *fx_4_get_string(struct fx_parser *parser, uint32_t offset)
|
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;
|
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,
|
static void fx_4_parse_state_object_initializer(struct fx_parser *parser, uint32_t count,
|
||||||
enum hlsl_type_class type_class)
|
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),
|
vkd3d_string_buffer_printf(&parser->buffer, "%s[%s]", fx_4_get_string(parser, index.name),
|
||||||
fx_4_get_string(parser, index.index));
|
fx_4_get_string(parser, index.index));
|
||||||
break;
|
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_4_ASSIGNMENT_INLINE_SHADER:
|
||||||
case FX_5_ASSIGNMENT_INLINE_SHADER:
|
case FX_5_ASSIGNMENT_INLINE_SHADER:
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user