-- v2: vkd3d-shader/disasm: Initial support for disassembling TX binaries.
From: Nikolay Sivov nsivov@codeweavers.com
--- include/vkd3d_shader.h | 2 + libs/vkd3d-shader/d3d_asm.c | 78 ++-- libs/vkd3d-shader/d3dbc.c | 459 +++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_main.c | 38 ++ libs/vkd3d-shader/vkd3d_shader_private.h | 15 + programs/vkd3d-compiler/main.c | 5 + 6 files changed, 568 insertions(+), 29 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index f112e7c75..fc8e793bb 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -672,6 +672,8 @@ enum vkd3d_shader_source_type */ VKD3D_SHADER_SOURCE_DXBC_DXIL,
+ VKD3D_SHADER_SOURCE_TX_BYTECODE, + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SOURCE_TYPE), };
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 566680be7..69c70f16a 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -30,8 +30,12 @@ static const char * const shader_opcode_names[] = { [VKD3DSIH_ABS ] = "abs", + [VKD3DSIH_ACOS ] = "acos", [VKD3DSIH_ADD ] = "add", [VKD3DSIH_AND ] = "and", + [VKD3DSIH_ASIN ] = "asin", + [VKD3DSIH_ATAN ] = "atan", + [VKD3DSIH_ATAN2 ] = "atan2", [VKD3DSIH_ATOMIC_AND ] = "atomic_and", [VKD3DSIH_ATOMIC_CMP_STORE ] = "atomic_cmp_store", [VKD3DSIH_ATOMIC_IADD ] = "atomic_iadd", @@ -56,6 +60,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_CND ] = "cnd", [VKD3DSIH_CONTINUE ] = "continue", [VKD3DSIH_CONTINUEP ] = "continuec", + [VKD3DSIH_COS ] = "cos", [VKD3DSIH_COUNTBITS ] = "countbits", [VKD3DSIH_CRS ] = "crs", [VKD3DSIH_CUT ] = "cut", @@ -118,6 +123,8 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_DMOVC ] = "dmovc", [VKD3DSIH_DMUL ] = "dmul", [VKD3DSIH_DNE ] = "dne", + [VKD3DSIH_DOT ] = "dot", + [VKD3DSIH_DOT_SWIZ ] = "d3ds_dotswiz", [VKD3DSIH_DP2 ] = "dp2", [VKD3DSIH_DP2ADD ] = "dp2add", [VKD3DSIH_DP3 ] = "dp3", @@ -229,6 +236,9 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_MSAD ] = "msad", [VKD3DSIH_MUL ] = "mul", [VKD3DSIH_NE ] = "ne", + [VKD3DSIH_NEG ] = "neg", + [VKD3DSIH_NOISE ] = "noise", + [VKD3DSIH_NOISE_SWIZ ] = "d3ds_noiseswiz", [VKD3DSIH_NOP ] = "nop", [VKD3DSIH_NOT ] = "not", [VKD3DSIH_NRM ] = "nrm", @@ -262,6 +272,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_SETP ] = "setp", [VKD3DSIH_SGE ] = "sge", [VKD3DSIH_SGN ] = "sgn", + [VKD3DSIH_SIN ] = "sin", [VKD3DSIH_SINCOS ] = "sincos", [VKD3DSIH_SLT ] = "slt", [VKD3DSIH_SQRT ] = "sqrt", @@ -753,7 +764,7 @@ static void shader_dump_decl_usage(struct vkd3d_d3d_asm_compiler *compiler, }
static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler, - const struct vkd3d_shader_src_param *param); + unsigned int component_count, const struct vkd3d_shader_src_param *param);
static void shader_print_float_literal(struct vkd3d_d3d_asm_compiler *compiler, const char *prefix, float f, const char *suffix) @@ -825,7 +836,7 @@ static void shader_print_subscript(struct vkd3d_d3d_asm_compiler *compiler, vkd3d_string_buffer_printf(&compiler->buffer, "["); if (rel_addr) { - shader_dump_src_param(compiler, rel_addr); + shader_dump_src_param(compiler, 4, rel_addr); vkd3d_string_buffer_printf(&compiler->buffer, " + "); } shader_print_uint_literal(compiler, "", offset, "]"); @@ -842,10 +853,10 @@ static void shader_print_subscript_range(struct vkd3d_d3d_asm_compiler *compiler }
static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_register *reg, - bool is_declaration) + unsigned int component_count, bool is_declaration) { struct vkd3d_string_buffer *buffer = &compiler->buffer; - unsigned int offset = reg->idx[0].offset; + unsigned int i, offset = reg->idx[0].offset; bool is_descriptor = false;
static const char * const rastout_reg_names[] = {"oPos", "oFog", "oPts"}; @@ -1108,9 +1119,8 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const { case VKD3D_DATA_FLOAT: shader_print_float_literal(compiler, "", reg->u.immconst_float[0], ""); - shader_print_float_literal(compiler, ", ", reg->u.immconst_float[1], ""); - shader_print_float_literal(compiler, ", ", reg->u.immconst_float[2], ""); - shader_print_float_literal(compiler, ", ", reg->u.immconst_float[3], ""); + for (i = 1; i < component_count; ++i) + shader_print_float_literal(compiler, ", ", reg->u.immconst_float[i], ""); break; case VKD3D_DATA_INT: shader_print_int_literal(compiler, "", reg->u.immconst_uint[0], ""); @@ -1262,7 +1272,7 @@ static void shader_dump_dst_param(struct vkd3d_d3d_asm_compiler *compiler, struct vkd3d_string_buffer *buffer = &compiler->buffer; uint32_t write_mask = param->write_mask;
- shader_dump_register(compiler, ¶m->reg, is_declaration); + shader_dump_register(compiler, ¶m->reg, 4, is_declaration);
if (write_mask && param->reg.dimension == VSIR_DIMENSION_VEC4) { @@ -1288,7 +1298,7 @@ static void shader_dump_dst_param(struct vkd3d_d3d_asm_compiler *compiler, }
static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler, - const struct vkd3d_shader_src_param *param) + unsigned int component_count, const struct vkd3d_shader_src_param *param) { enum vkd3d_shader_src_modifier src_modifier = param->modifiers; struct vkd3d_string_buffer *buffer = &compiler->buffer; @@ -1308,7 +1318,7 @@ static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler, if (src_modifier == VKD3DSPSM_ABS || src_modifier == VKD3DSPSM_ABSNEG) shader_addline(buffer, "|");
- shader_dump_register(compiler, ¶m->reg, false); + shader_dump_register(compiler, ¶m->reg, component_count, false);
switch (src_modifier) { @@ -1332,26 +1342,27 @@ static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler, if (param->reg.type != VKD3DSPR_IMMCONST && param->reg.type != VKD3DSPR_IMMCONST64 && param->reg.dimension == VSIR_DIMENSION_VEC4) { - unsigned int swizzle_x = vkd3d_swizzle_get_component(swizzle, 0); - unsigned int swizzle_y = vkd3d_swizzle_get_component(swizzle, 1); - unsigned int swizzle_z = vkd3d_swizzle_get_component(swizzle, 2); - unsigned int swizzle_w = vkd3d_swizzle_get_component(swizzle, 3); + unsigned int i, components[4]; + char swizzle_str[5];
static const char swizzle_chars[] = "xyzw";
- if (swizzle_x == swizzle_y - && swizzle_x == swizzle_z - && swizzle_x == swizzle_w) + for (i = 0; i < 4; ++i) { - shader_addline(buffer, ".%s%c%s", compiler->colours.swizzle, - swizzle_chars[swizzle_x], compiler->colours.reset); + components[i] = vkd3d_swizzle_get_component(swizzle, i); + swizzle_str[i] = swizzle_chars[components[i]]; } - else + swizzle_str[4] = 0; + + if (components[0] == components[1] + && components[0] == components[2] + && components[0] == components[3]) { - shader_addline(buffer, ".%s%c%c%c%c%s", compiler->colours.swizzle, - swizzle_chars[swizzle_x], swizzle_chars[swizzle_y], - swizzle_chars[swizzle_z], swizzle_chars[swizzle_w], compiler->colours.reset); + component_count = 1; } + swizzle_str[component_count] = 0; + + shader_addline(buffer, ".%s%s%s", compiler->colours.swizzle, swizzle_str, compiler->colours.reset); } if (src_modifier == VKD3DSPSM_ABS || src_modifier == VKD3DSPSM_ABSNEG) shader_addline(buffer, "|"); @@ -1586,16 +1597,24 @@ static void shader_print_opcode(struct vkd3d_d3d_asm_compiler *compiler, enum vk shader_opcode_names[opcode], compiler->colours.reset); }
+static unsigned int shader_get_src_component_count(const struct vkd3d_d3d_asm_compiler *compiler, + const struct vkd3d_shader_instruction *ins) +{ + if (compiler->shader_version.type != VKD3D_SHADER_TYPE_TEXTURE) + return 4; + return vkd3d_popcount(ins->dst[0].write_mask); +} + static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_instruction *ins) { struct vkd3d_string_buffer *buffer = &compiler->buffer; - unsigned int i; + unsigned int i, component_count;
if (ins->predicate) { vkd3d_string_buffer_printf(buffer, "("); - shader_dump_src_param(compiler, ins->predicate); + shader_dump_src_param(compiler, 4, ins->predicate); vkd3d_string_buffer_printf(buffer, ") "); }
@@ -1613,13 +1632,13 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, shader_dump_decl_usage(compiler, &ins->declaration.semantic, ins->flags); shader_dump_ins_modifiers(compiler, &ins->declaration.semantic.resource.reg); vkd3d_string_buffer_printf(buffer, "%s ", compiler->colours.reset); - shader_dump_register(compiler, &ins->declaration.semantic.resource.reg.reg, true); + shader_dump_register(compiler, &ins->declaration.semantic.resource.reg.reg, 4, true); shader_dump_register_space(compiler, ins->declaration.semantic.resource.range.space); break;
case VKD3DSIH_DCL_CONSTANT_BUFFER: vkd3d_string_buffer_printf(buffer, " "); - shader_dump_register(compiler, &ins->declaration.cb.src.reg, true); + shader_dump_register(compiler, &ins->declaration.cb.src.reg, 4, true); if (shader_ver_ge(&compiler->shader_version, 5, 1)) shader_print_subscript(compiler, ins->declaration.cb.size, NULL); shader_addline(buffer, ", %s", @@ -1730,7 +1749,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
case VKD3DSIH_DCL_SAMPLER: vkd3d_string_buffer_printf(buffer, " "); - shader_dump_register(compiler, &ins->declaration.sampler.src.reg, true); + shader_dump_register(compiler, &ins->declaration.sampler.src.reg, 4, true); if (ins->flags == VKD3DSI_SAMPLER_COMPARISON_MODE) shader_addline(buffer, ", comparisonMode"); shader_dump_register_space(compiler, ins->declaration.sampler.range.space); @@ -1855,12 +1874,13 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, shader_addline(buffer, !i ? " " : ", "); shader_dump_dst_param(compiler, &ins->dst[i], false); } + component_count = shader_get_src_component_count(compiler, ins);
/* Other source tokens */ for (i = ins->dst_count; i < (ins->dst_count + ins->src_count); ++i) { shader_addline(buffer, !i ? " " : ", "); - shader_dump_src_param(compiler, &ins->src[i - ins->dst_count]); + shader_dump_src_param(compiler, component_count, &ins->src[i - ins->dst_count]); } break; } diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 67fa32710..1f00c6f01 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -29,6 +29,7 @@
#define VKD3D_SM1_VS 0xfffeu #define VKD3D_SM1_PS 0xffffu +#define VKD3D_SM1_TX 0x5458u
#define VKD3D_SM1_DCL_USAGE_SHIFT 0u #define VKD3D_SM1_DCL_USAGE_MASK (0xfu << VKD3D_SM1_DCL_USAGE_SHIFT) @@ -219,6 +220,94 @@ struct vkd3d_shader_sm1_parser uint32_t constant_def_mask[3][MAX_CONSTANT_COUNT / 32]; };
+enum vkd3d_fxlc_opcode +{ + VKD3D_FXLC_OP_NOP = 0x000, + VKD3D_FXLC_OP_MOV = 0x100, + VKD3D_FXLC_OP_NEG = 0x101, + VKD3D_FXLC_OP_RCP = 0x103, + VKD3D_FXLC_OP_FRC = 0x104, + VKD3D_FXLC_OP_EXP = 0x105, + VKD3D_FXLC_OP_LOG = 0x106, + VKD3D_FXLC_OP_RSQ = 0x107, + VKD3D_FXLC_OP_SIN = 0x108, + VKD3D_FXLC_OP_COS = 0x109, + VKD3D_FXLC_OP_ASIN = 0x10a, + VKD3D_FXLC_OP_ACOS = 0x10b, + VKD3D_FXLC_OP_ATAN = 0x10c, + VKD3D_FXLC_OP_MIN = 0x200, + VKD3D_FXLC_OP_MAX = 0x201, + VKD3D_FXLC_OP_LT = 0x202, + VKD3D_FXLC_OP_GE = 0x203, + VKD3D_FXLC_OP_ADD = 0x204, + VKD3D_FXLC_OP_MUL = 0x205, + VKD3D_FXLC_OP_ATAN2 = 0x206, + VKD3D_FXLC_OP_DIV = 0x208, + VKD3D_FXLC_OP_CMP = 0x300, + VKD3D_FXLC_OP_DOT = 0x500, + VKD3D_FXLC_OP_NOISE = 0x502, + VKD3D_FXLC_OP_DOT_SWIZ = 0x70e, + VKD3D_FXLC_OP_NOISE_SWIZ = 0x711, +}; + +struct vkd3d_fxlc_opcode_info +{ + enum vkd3d_fxlc_opcode fxlc_opcode; + enum vkd3d_shader_opcode vkd3d_opcode; +}; + +static const struct vkd3d_fxlc_opcode_info tx_opcode_table[] = +{ + {VKD3D_FXLC_OP_NOP, VKD3DSIH_NOP}, + {VKD3D_FXLC_OP_MOV, VKD3DSIH_MOV}, + {VKD3D_FXLC_OP_NEG, VKD3DSIH_NEG}, + {VKD3D_FXLC_OP_RCP, VKD3DSIH_RCP}, + {VKD3D_FXLC_OP_FRC, VKD3DSIH_FRC}, + {VKD3D_FXLC_OP_EXP, VKD3DSIH_EXP}, + {VKD3D_FXLC_OP_LOG, VKD3DSIH_LOG}, + {VKD3D_FXLC_OP_RSQ, VKD3DSIH_RSQ}, + {VKD3D_FXLC_OP_SIN, VKD3DSIH_SIN}, + {VKD3D_FXLC_OP_COS, VKD3DSIH_COS}, + {VKD3D_FXLC_OP_ASIN, VKD3DSIH_ASIN}, + {VKD3D_FXLC_OP_ACOS, VKD3DSIH_ACOS}, + {VKD3D_FXLC_OP_ATAN, VKD3DSIH_ATAN}, + {VKD3D_FXLC_OP_MIN, VKD3DSIH_MIN}, + {VKD3D_FXLC_OP_MAX, VKD3DSIH_MAX}, + {VKD3D_FXLC_OP_LT, VKD3DSIH_LT}, + {VKD3D_FXLC_OP_GE, VKD3DSIH_GE}, + {VKD3D_FXLC_OP_ADD, VKD3DSIH_ADD}, + {VKD3D_FXLC_OP_MUL, VKD3DSIH_MUL}, + {VKD3D_FXLC_OP_ATAN2, VKD3DSIH_ATAN2}, + {VKD3D_FXLC_OP_DIV, VKD3DSIH_DIV}, + {VKD3D_FXLC_OP_CMP, VKD3DSIH_CMP}, + {VKD3D_FXLC_OP_DOT, VKD3DSIH_DOT}, + {VKD3D_FXLC_OP_NOISE, VKD3DSIH_NOISE}, + {VKD3D_FXLC_OP_DOT_SWIZ, VKD3DSIH_DOT_SWIZ}, + {VKD3D_FXLC_OP_NOISE_SWIZ, VKD3DSIH_NOISE_SWIZ}, + {0, VKD3DSIH_INVALID}, +}; + +struct vkd3d_shader_tx_parser +{ + const struct vkd3d_fxlc_opcode_info *opcode_table; + const uint32_t *start, *end, *ptr; + struct + { + const uint32_t *start, *end; + } fxlc; + struct + { + const double *table; + unsigned int size; + } clit; + struct vkd3d_shader_parser p; +}; + +static struct vkd3d_shader_tx_parser *vkd3d_shader_tx_parser(struct vkd3d_shader_parser *parser) +{ + return CONTAINING_RECORD(parser, struct vkd3d_shader_tx_parser, p); +} + /* This table is not order or position dependent. */ static const struct vkd3d_sm1_opcode_info vs_opcode_table[] = { @@ -1284,6 +1373,135 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, return VKD3D_OK; }
+static void shader_tx_read_sections(struct vkd3d_shader_tx_parser *tx) +{ + const uint32_t **ptr = &tx->ptr, *section; + unsigned int size; + size_t remaining; + uint32_t token; + + if (*ptr >= tx->end) + return; + + remaining = tx->end - *ptr; + + token = **ptr; + + while ((token & VKD3D_SM1_OPCODE_MASK) == VKD3D_SM1_OP_COMMENT) + { + size = (token & VKD3D_SM1_COMMENT_SIZE_MASK) >> VKD3D_SM1_COMMENT_SIZE_SHIFT; + + if (size > --remaining) + { + vkd3d_shader_parser_error(&tx->p, VKD3D_SHADER_ERROR_D3DBC_UNEXPECTED_EOF, + "Encountered a %u token comment, but only %zu token(s) is/are remaining.", + size, remaining); + return; + } + + section = ++(*ptr); + remaining -= size; + *ptr += size; + + if (*section == TAG_FXLC) + { + tx->fxlc.start = section + 1; + tx->fxlc.end = section + size; + } + else if (*section == TAG_CLIT) + { + ++section; + + tx->clit.size = *section++; + tx->clit.table = (double *)section; + } + + if (!remaining) + break; + token = **ptr; + } +} + +static void shader_tx_destroy(struct vkd3d_shader_parser *parser) +{ + struct vkd3d_shader_tx_parser *tx = vkd3d_shader_tx_parser(parser); + + shader_instruction_array_destroy(&parser->instructions); + vkd3d_free(tx); +} + +const struct vkd3d_shader_parser_ops shader_tx_parser_ops = +{ + .parser_destroy = shader_tx_destroy, +}; + +static enum vkd3d_result shader_tx_init(struct vkd3d_shader_tx_parser *tx, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) +{ + const struct vkd3d_shader_location location = {.source_name = compile_info->source_name}; + const uint32_t *code = compile_info->source.code; + size_t code_size = compile_info->source.size; + struct vkd3d_shader_desc *shader_desc; + struct vkd3d_shader_version version; + size_t token_count; + uint16_t magic; + + token_count = code_size / sizeof(*tx->start); + + if (token_count < 1) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_D3DBC_UNEXPECTED_EOF, + "Invalid shader size %zu (token count %zu). At least 2 tokens are required.", + code_size, token_count); + return VKD3D_ERROR_INVALID_SHADER; + } + + TRACE("Version: 0x%08x.\n", code[0]); + + magic = code[0] >> 16; + version.type = VKD3D_SHADER_TYPE_TEXTURE; + version.major = VKD3D_SM1_VERSION_MAJOR(code[0]); + version.minor = VKD3D_SM1_VERSION_MINOR(code[0]); + + if (magic != VKD3D_SM1_TX) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_D3DBC_INVALID_VERSION_TOKEN, + "Invalid shader magic %#x (token 0x%08x).", magic, code[0]); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (version.major != 1 || version.minor != 0) + { + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_D3DBC_INVALID_VERSION_TOKEN, + "Invalid shader version %u.%u (token 0x%08x).", version.major, version.minor, code[0]); + return VKD3D_ERROR_INVALID_SHADER; + } + + tx->start = &code[1]; + tx->end = &code[token_count]; + tx->ptr = tx->start; + + shader_tx_read_sections(tx); + + tx->opcode_table = tx_opcode_table; + /* FXLC section */ + tx->start = tx->fxlc.start; + tx->end = tx->fxlc.end; + + token_count = tx->end - tx->start; + + /* Estimate instruction count to avoid reallocation in most shaders. */ + if (!vkd3d_shader_parser_init(&tx->p, message_context, compile_info->source_name, &version, &shader_tx_parser_ops, + code_size != ~(size_t)0 ? token_count / 4u + 4 : 16)) + return VKD3D_ERROR_OUT_OF_MEMORY; + shader_desc = &tx->p.shader_desc; + shader_desc->byte_code = code; + shader_desc->byte_code_size = code_size; + tx->ptr = tx->start; + + return VKD3D_OK; +} + static uint32_t get_external_constant_count(struct vkd3d_shader_sm1_parser *sm1, enum vkd3d_shader_d3dbc_constant_register set) { @@ -1363,6 +1581,247 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi return VKD3D_OK; }
+struct fxlc_instruction +{ + uint32_t num_comp : 16; + uint32_t unused : 4; + uint32_t opcode : 11; + uint32_t scalar : 1; +}; + +static const struct vkd3d_fxlc_opcode_info *shader_tx_get_opcode_info( + const struct vkd3d_shader_tx_parser *tx, enum vkd3d_fxlc_opcode opcode) +{ + const struct vkd3d_fxlc_opcode_info *info; + unsigned int i = 0; + + for (;;) + { + info = &tx->opcode_table[i++]; + if (info->vkd3d_opcode == VKD3DSIH_INVALID) + return NULL; + + if (opcode == info->fxlc_opcode) + return info; + } +} + +enum fxlc_register_type +{ + VKD3DSPR_FXLC_IMMCONST = 1, + VKD3DSPR_FXLC_INPUT = 3, + VKD3DSPR_FXLC_RESULT = 4, + VKD3DSPR_FXLC_TEMP = 7, +}; + +static enum vkd3d_shader_register_type fxlc_get_register_type(uint32_t fxlc_regtable) +{ + static const enum vkd3d_shader_register_type map[] = + { + [VKD3DSPR_FXLC_INPUT ] = VKD3DSPR_INPUT, + [VKD3DSPR_FXLC_TEMP ] = VKD3DSPR_TEMP, + [VKD3DSPR_FXLC_RESULT ] = VKD3DSPR_COLOROUT, + [VKD3DSPR_FXLC_IMMCONST] = VKD3DSPR_IMMCONST, + }; + if (fxlc_regtable < ARRAY_SIZE(map)) return map[fxlc_regtable]; + FIXME("Unrecognized register table %u.\n", fxlc_regtable); + return VKD3DSPR_TEMP; +} + +static void shader_fxlc_read_src_param(struct vkd3d_shader_tx_parser *tx, + const struct fxlc_instruction *fxlc_ins, bool first_source, struct vkd3d_shader_src_param *src) +{ + bool scalar = first_source && fxlc_ins->scalar; + enum vkd3d_shader_register_type reg_type; + uint32_t flags, table, offset, swizzle; + const uint32_t **ptr = &tx->ptr; + unsigned int i; + + flags = read_u32(ptr); + if (flags) + { + vkd3d_shader_parser_error(&tx->p, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_INDEX, + "Relative addressing is not implemented for FXLC."); + return; + } + + table = read_u32(ptr); + offset = read_u32(ptr); + + reg_type = fxlc_get_register_type(table); + + vsir_register_init(&src->reg, reg_type, VKD3D_DATA_FLOAT, 1); + src->reg.idx[0].offset = offset / 4; + + if (src->reg.type == VKD3DSPR_IMMCONST) + { + for (i = 0; i < fxlc_ins->num_comp; ++i) + src->reg.u.immconst_float[i] = tx->clit.table[offset + (scalar ? 0 : i)]; + } + src->reg.dimension = VSIR_DIMENSION_VEC4; + + /* Components could only be specified consecutively. */ + swizzle = VKD3D_SHADER_NO_SWIZZLE; + swizzle >>= 8 * (offset % 4); + swizzle &= ~0u >> (8 * (4 - (scalar ? 1 : fxlc_ins->num_comp))); + + src->swizzle = swizzle; + src->modifiers = 0; +} + +static void shader_fxlc_read_dst_param(struct vkd3d_shader_tx_parser *tx, const struct fxlc_instruction *fxlc_ins, + struct vkd3d_shader_dst_param *dst) +{ + enum vkd3d_shader_register_type reg_type; + const uint32_t **ptr = &tx->ptr; + uint32_t flags, table, offset; + + flags = read_u32(ptr); + if (flags) + { + vkd3d_shader_parser_error(&tx->p, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_INDEX, + "Relative addressing is not implemented for FXLC."); + return; + } + table = read_u32(ptr); + offset = read_u32(ptr); + + reg_type = fxlc_get_register_type(table); + + vsir_register_init(&dst->reg, reg_type, VKD3D_DATA_FLOAT, 1); + dst->reg.idx[0].offset = offset / 4; + dst->reg.dimension = VSIR_DIMENSION_VEC4; + + dst->write_mask = ~0u >> (32 - fxlc_ins->num_comp); + dst->write_mask <<= offset % 4; + dst->modifiers = 0; + dst->shift = 0; +} + +static void shader_tx_read_instruction(struct vkd3d_shader_tx_parser *tx, struct vkd3d_shader_instruction *ins) +{ + const struct vkd3d_fxlc_opcode_info *opcode_info; + struct vkd3d_shader_src_param *src_params; + struct vkd3d_shader_dst_param *dst_param; + struct fxlc_instruction fxlc_ins; + const uint32_t **ptr = &tx->ptr; + uint32_t opcode_token; + unsigned int i; + + if (*ptr >= tx->end) + { + WARN("End of byte-code, failed to read opcode.\n"); + goto fail; + } + + ++tx->p.location.line; + opcode_token = read_u32(ptr); + memcpy(&fxlc_ins, &opcode_token, sizeof(opcode_token)); + + if (!(opcode_info = shader_tx_get_opcode_info(tx, fxlc_ins.opcode))) + { + vkd3d_shader_parser_error(&tx->p, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE, + "Invalid opcode %#x (token 0x%08x).", fxlc_ins.opcode, opcode_token); + goto fail; + } + + if (fxlc_ins.num_comp < 1 || fxlc_ins.num_comp > 4) + { + vkd3d_shader_parser_error(&tx->p, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE, + "Invalid component count %u (token 0x%08x).", fxlc_ins.num_comp, opcode_token); + goto fail; + } + + vsir_instruction_init(ins, &tx->p.location, opcode_info->vkd3d_opcode); + + ins->dst_count = 1; + ins->dst = dst_param = shader_parser_get_dst_params(&tx->p, ins->dst_count); + + ins->src_count = read_u32(ptr); + ins->src = src_params = shader_parser_get_src_params(&tx->p, ins->src_count); + + for (i = 0; i < ins->src_count; ++i) + shader_fxlc_read_src_param(tx, &fxlc_ins, i == 0, &src_params[i]); + + ins->dst_count = 1; + shader_fxlc_read_dst_param(tx, &fxlc_ins, dst_param); + + if (*ptr > tx->end) + { + vkd3d_shader_parser_error(&tx->p, VKD3D_SHADER_ERROR_D3DBC_UNEXPECTED_EOF, + "The current instruction ends %zu token(s) past the end of the shader.", + *ptr - tx->end); + goto fail; + } + + return; + +fail: + ins->handler_idx = VKD3DSIH_INVALID; + *ptr = tx->end; +} + +int vkd3d_shader_tx_parser_create(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser) +{ + struct vkd3d_shader_instruction_array *instructions; + struct vkd3d_shader_instruction *ins; + struct vkd3d_shader_tx_parser *tx; + uint32_t count; + unsigned int i; + int ret; + + if (!(tx = vkd3d_calloc(1, sizeof(*tx)))) + { + ERR("Failed to allocate parser.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + if ((ret = shader_tx_init(tx, compile_info, message_context)) < 0) + { + WARN("Failed to initialise shader parser, ret %d.\n", ret); + vkd3d_free(tx); + return ret; + } + + count = read_u32(&tx->ptr); + + instructions = &tx->p.instructions; + + if (!shader_instruction_array_reserve(instructions, count)) + { + ERR("Failed to allocate instructions.\n"); + vkd3d_shader_parser_error(&tx->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Out of memory."); + shader_tx_destroy(&tx->p); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < count; ++i) + { + ins = &instructions->elements[instructions->count]; + shader_tx_read_instruction(tx, ins); + + if (ins->handler_idx == VKD3DSIH_INVALID) + { + WARN("Encountered unrecognized or invalid instruction.\n"); + shader_tx_destroy(&tx->p); + return VKD3D_ERROR_INVALID_SHADER; + } + ++instructions->count; + } + + if (tx->p.failed) + { + WARN("Failed to parse shader.\n"); + shader_tx_destroy(&tx->p); + return VKD3D_ERROR_INVALID_SHADER; + } + + *parser = &tx->p; + + return VKD3D_OK; +} + bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, bool output, D3DSHADER_PARAM_REGISTER_TYPE *type, unsigned int *reg) { diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 052edeb50..894d5bd17 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1451,6 +1451,30 @@ static int compile_d3d_bytecode(const struct vkd3d_shader_compile_info *compile_ return VKD3D_ERROR; }
+static int compile_tx_bytecode(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) +{ + struct vkd3d_shader_parser *parser; + int ret; + + if ((ret = vkd3d_shader_tx_parser_create(compile_info, message_context, &parser)) < 0) + { + WARN("Failed to initialise shader parser.\n"); + return ret; + } + + vkd3d_shader_dump_shader(compile_info->source_type, parser->shader_version.type, &compile_info->source); + + if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_ASM) + { + ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out); + vkd3d_shader_parser_destroy(parser); + return ret; + } + + return VKD3D_ERROR; +} + static int compile_dxbc_dxil(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) { @@ -1501,6 +1525,10 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, ret = compile_d3d_bytecode(compile_info, out, &message_context); break;
+ case VKD3D_SHADER_SOURCE_TX_BYTECODE: + ret = compile_tx_bytecode(compile_info, out, &message_context); + break; + case VKD3D_SHADER_SOURCE_DXBC_DXIL: ret = compile_dxbc_dxil(compile_info, out, &message_context); break; @@ -1685,6 +1713,7 @@ const enum vkd3d_shader_source_type *vkd3d_shader_get_supported_source_types(uns #ifdef VKD3D_SHADER_UNSUPPORTED_DXIL VKD3D_SHADER_SOURCE_DXBC_DXIL, #endif + VKD3D_SHADER_SOURCE_TX_BYTECODE, };
TRACE("count %p.\n", count); @@ -1719,6 +1748,11 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( VKD3D_SHADER_TARGET_D3D_ASM, };
+ static const enum vkd3d_shader_target_type tx_types[] = + { + VKD3D_SHADER_TARGET_D3D_ASM, + }; + TRACE("source_type %#x, count %p.\n", source_type, count);
switch (source_type) @@ -1738,6 +1772,10 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( *count = ARRAY_SIZE(d3dbc_types); return d3dbc_types;
+ case VKD3D_SHADER_SOURCE_TX_BYTECODE: + *count = ARRAY_SIZE(tx_types); + return tx_types; + default: *count = 0; return NULL; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 2c84cb104..6627994b3 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -201,8 +201,12 @@ enum vkd3d_shader_error enum vkd3d_shader_opcode { VKD3DSIH_ABS, + VKD3DSIH_ACOS, VKD3DSIH_ADD, VKD3DSIH_AND, + VKD3DSIH_ASIN, + VKD3DSIH_ATAN, + VKD3DSIH_ATAN2, VKD3DSIH_ATOMIC_AND, VKD3DSIH_ATOMIC_CMP_STORE, VKD3DSIH_ATOMIC_IADD, @@ -227,6 +231,7 @@ enum vkd3d_shader_opcode VKD3DSIH_CND, VKD3DSIH_CONTINUE, VKD3DSIH_CONTINUEP, + VKD3DSIH_COS, VKD3DSIH_COUNTBITS, VKD3DSIH_CRS, VKD3DSIH_CUT, @@ -289,6 +294,8 @@ enum vkd3d_shader_opcode VKD3DSIH_DMOVC, VKD3DSIH_DMUL, VKD3DSIH_DNE, + VKD3DSIH_DOT, + VKD3DSIH_DOT_SWIZ, VKD3DSIH_DP2, VKD3DSIH_DP2ADD, VKD3DSIH_DP3, @@ -400,6 +407,9 @@ enum vkd3d_shader_opcode VKD3DSIH_MSAD, VKD3DSIH_MUL, VKD3DSIH_NE, + VKD3DSIH_NEG, + VKD3DSIH_NOISE, + VKD3DSIH_NOISE_SWIZ, VKD3DSIH_NOP, VKD3DSIH_NOT, VKD3DSIH_NRM, @@ -433,6 +443,7 @@ enum vkd3d_shader_opcode VKD3DSIH_SETP, VKD3DSIH_SGE, VKD3DSIH_SGN, + VKD3DSIH_SIN, VKD3DSIH_SINCOS, VKD3DSIH_SLT, VKD3DSIH_SQRT, @@ -1288,6 +1299,8 @@ void vkd3d_shader_trace_text_(const char *text, size_t size, const char *functio #define vkd3d_shader_trace_text(text, size) \ vkd3d_shader_trace_text_(text, size, __FUNCTION__)
+int vkd3d_shader_tx_parser_create(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser); int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser); int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compile_info, @@ -1495,8 +1508,10 @@ static inline void *vkd3d_find_struct_(const struct vkd3d_struct *chain, #define VKD3D_DXBC_CHUNK_ALIGNMENT sizeof(uint32_t)
#define TAG_AON9 VKD3D_MAKE_TAG('A', 'o', 'n', '9') +#define TAG_CLIT VKD3D_MAKE_TAG('C', 'L', 'I', 'T') #define TAG_DXBC VKD3D_MAKE_TAG('D', 'X', 'B', 'C') #define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L') +#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/programs/vkd3d-compiler/main.c b/programs/vkd3d-compiler/main.c index 61e8d48a2..3df4f5be5 100644 --- a/programs/vkd3d-compiler/main.c +++ b/programs/vkd3d-compiler/main.c @@ -75,6 +75,9 @@ source_type_info[] = "d3dbc", "Legacy Direct3D byte-code.\n" " This is the format used for Direct3D shader model 1, 2, and 3 shaders.\n", true, VKD3D_SHADER_TARGET_SPIRV_BINARY}, + {VKD3D_SHADER_SOURCE_TX_BYTECODE, + "tx", "Texture shader byte-code.\n", + true, VKD3D_SHADER_TARGET_D3D_ASM}, {VKD3D_SHADER_SOURCE_DXBC_DXIL, "dxbc-dxil", "A 'DirectX Intermediate Language' shader embedded in a DXBC container.\n" " This is the format used for Direct3D shader model 6 shaders.\n", @@ -730,6 +733,8 @@ int main(int argc, char **argv) } else if ((token & 0xfffe0000) == 0xfffe0000) options.source_type = VKD3D_SHADER_SOURCE_D3D_BYTECODE; + else if (token == 0x54580100) + options.source_type = VKD3D_SHADER_SOURCE_TX_BYTECODE; else options.source_type = VKD3D_SHADER_SOURCE_HLSL; }
Source width is not derived from a write mask, so additional types were removed.
If you're implementing these soon, the [sm6_rebase branch](https://gitlab.winehq.org/cmccarthy/vkd3d/-/tree/sm6_rebase) has `ACOS`, `ASIN` and `ATAN` (which only require table additions in `spirv_compiler_map_ext_glsl_instruction()`), but not `SIN` and `COS` since it uses the existing `SINCOS` for those. I expect it won't be long before these are upstream.
On Tue Oct 17 10:26:45 2023 +0000, Conor McCarthy wrote:
If you're implementing these soon, the [sm6_rebase branch](https://gitlab.winehq.org/cmccarthy/vkd3d/-/tree/sm6_rebase) has `ACOS`, `ASIN` and `ATAN` (which only require table additions in `spirv_compiler_map_ext_glsl_instruction()`), but not `SIN` and `COS` since it uses the existing `SINCOS` for those. I expect it won't be long before these are upstream.
I only need them to display names, and will rebase if you get them in first, it's not a problem.
Source width is now derived from a write mask, so additional types were removed.
Makes sense to me like this.
There's perhaps an open question about how something like "mov r0.zw, r1.zw" should be represented on the IR level. I think the current MR effectively stores that as "mov r0.zw, r1.zwxx", but there's something to be said for storing it as "mov r0.zw, r1.xyzw" or "mov r0.zw, r1.xxzw" instead, which would preserve how write masks and swizzles currently work on the IR level. That's a bit moot as long as d3d-asm is the only possible target, but might become a bit more relevant if we want to start actually executing these.
On Wed Oct 18 20:59:26 2023 +0000, Henri Verbeet wrote:
Source width is now derived from a write mask, so additional types
were removed. Makes sense to me like this. There's perhaps an open question about how something like "mov r0.zw, r1.zw" should be represented on the IR level. I think the current MR effectively stores that as "mov r0.zw, r1.zwxx", but there's something to be said for storing it as "mov r0.zw, r1.xyzw" or "mov r0.zw, r1.xxzw" instead, which would preserve how write masks and swizzles currently work on the IR level. That's a bit moot as long as d3d-asm is the only possible target, but might become a bit more relevant if we want to start actually executing these.
I haven't checked how bad it is, but my concern for compiling to tx_1_0 is to handled exactly this mismatch of destination sizes. I'm assuming currently it's determined by return types, so e.g. dot() will use a single component. Maybe it's easy to tweak at allocation phase. My concern specifically is to awareness of such destination size behavior must come in at some point, without us having to conditionally change types everywhere.