From: Nikolay Sivov nsivov@codeweavers.com
--- include/vkd3d_shader.h | 2 + libs/vkd3d-shader/d3d_asm.c | 39 +- libs/vkd3d-shader/d3dbc.c | 477 +++++++++++++++++++++++ libs/vkd3d-shader/tpf.c | 4 + libs/vkd3d-shader/vkd3d_shader_main.c | 38 ++ libs/vkd3d-shader/vkd3d_shader_private.h | 18 + programs/vkd3d-compiler/main.c | 5 + 7 files changed, 582 insertions(+), 1 deletion(-)
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..c8b04941f 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", @@ -1103,13 +1114,19 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const } break;
+ case VSIR_DIMENSION_VEC1: + case VSIR_DIMENSION_VEC2: + case VSIR_DIMENSION_VEC3: case VSIR_DIMENSION_VEC4: switch (reg->data_type) { case VKD3D_DATA_FLOAT: shader_print_float_literal(compiler, "", reg->u.immconst_float[0], ""); + if (reg->dimension == VSIR_DIMENSION_VEC1) break; shader_print_float_literal(compiler, ", ", reg->u.immconst_float[1], ""); + if (reg->dimension == VSIR_DIMENSION_VEC2) break; shader_print_float_literal(compiler, ", ", reg->u.immconst_float[2], ""); + if (reg->dimension == VSIR_DIMENSION_VEC3) break; shader_print_float_literal(compiler, ", ", reg->u.immconst_float[3], ""); break; case VKD3D_DATA_INT: @@ -1330,7 +1347,10 @@ 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) + && (param->reg.dimension == VSIR_DIMENSION_VEC1 + || param->reg.dimension == VSIR_DIMENSION_VEC2 + || param->reg.dimension == VSIR_DIMENSION_VEC3 + || 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); @@ -1346,6 +1366,23 @@ static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler, shader_addline(buffer, ".%s%c%s", compiler->colours.swizzle, swizzle_chars[swizzle_x], compiler->colours.reset); } + else if (param->reg.dimension == VSIR_DIMENSION_VEC1) + { + shader_addline(buffer, ".%s%c%s", compiler->colours.swizzle, + swizzle_chars[swizzle_x], compiler->colours.reset); + } + else if (param->reg.dimension == VSIR_DIMENSION_VEC2) + { + shader_addline(buffer, ".%s%c%c%s", compiler->colours.swizzle, + swizzle_chars[swizzle_x], swizzle_chars[swizzle_y], + compiler->colours.reset); + } + else if (param->reg.dimension == VSIR_DIMENSION_VEC3) + { + shader_addline(buffer, ".%s%c%c%c%s", compiler->colours.swizzle, + swizzle_chars[swizzle_x], swizzle_chars[swizzle_y], + swizzle_chars[swizzle_z], compiler->colours.reset); + } else { shader_addline(buffer, ".%s%c%c%c%c%s", compiler->colours.swizzle, diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 67fa32710..620ffa4c7 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,265 @@ 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; + static const enum vsir_dimension dimension[] = + { + [1] = VSIR_DIMENSION_VEC1, + [2] = VSIR_DIMENSION_VEC2, + [3] = VSIR_DIMENSION_VEC3, + [4] = VSIR_DIMENSION_VEC4, + }; + static const enum vsir_dimension const_dimension[] = + { + [1] = VSIR_DIMENSION_SCALAR, + [2] = VSIR_DIMENSION_VEC2, + [3] = VSIR_DIMENSION_VEC3, + [4] = VSIR_DIMENSION_VEC4, + }; + 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 = const_dimension[fxlc_ins->num_comp]; + } + else + { + src->reg.dimension = dimension[fxlc_ins->num_comp]; + } + + /* 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/tpf.c b/libs/vkd3d-shader/tpf.c index 5c42a5886..2ec677e42 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -547,6 +547,10 @@ static enum vkd3d_sm4_dimension sm4_dimension_from_vsir_dimension(enum vsir_dime return VKD3D_SM4_DIMENSION_NONE; case VSIR_DIMENSION_SCALAR: return VKD3D_SM4_DIMENSION_SCALAR; + case VSIR_DIMENSION_VEC1: + case VSIR_DIMENSION_VEC2: + case VSIR_DIMENSION_VEC3: + break; case VSIR_DIMENSION_VEC4: return VKD3D_SM4_DIMENSION_VEC4; } 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 060647a68..9aab0fcdd 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -197,8 +197,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, @@ -223,6 +227,7 @@ enum vkd3d_shader_opcode VKD3DSIH_CND, VKD3DSIH_CONTINUE, VKD3DSIH_CONTINUEP, + VKD3DSIH_COS, VKD3DSIH_COUNTBITS, VKD3DSIH_CRS, VKD3DSIH_CUT, @@ -285,6 +290,8 @@ enum vkd3d_shader_opcode VKD3DSIH_DMOVC, VKD3DSIH_DMUL, VKD3DSIH_DNE, + VKD3DSIH_DOT, + VKD3DSIH_DOT_SWIZ, VKD3DSIH_DP2, VKD3DSIH_DP2ADD, VKD3DSIH_DP3, @@ -396,6 +403,9 @@ enum vkd3d_shader_opcode VKD3DSIH_MSAD, VKD3DSIH_MUL, VKD3DSIH_NE, + VKD3DSIH_NEG, + VKD3DSIH_NOISE, + VKD3DSIH_NOISE_SWIZ, VKD3DSIH_NOP, VKD3DSIH_NOT, VKD3DSIH_NRM, @@ -429,6 +439,7 @@ enum vkd3d_shader_opcode VKD3DSIH_SETP, VKD3DSIH_SGE, VKD3DSIH_SGN, + VKD3DSIH_SIN, VKD3DSIH_SINCOS, VKD3DSIH_SLT, VKD3DSIH_SQRT, @@ -578,6 +589,9 @@ enum vsir_dimension { VSIR_DIMENSION_NONE, VSIR_DIMENSION_SCALAR, + VSIR_DIMENSION_VEC1, + VSIR_DIMENSION_VEC2, + VSIR_DIMENSION_VEC3, VSIR_DIMENSION_VEC4, };
@@ -1281,6 +1295,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, @@ -1488,8 +1504,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; }
I'd like to get some feedback first on changes for shared vsir part, specifically for additional vector types. It's necessary to get correct output, because showing ".xyxx" is meaningless for this particular case. Source and destination width is specified by a separate field of each instruction.
Another thing, literal constants are using doubles for storage. I don't think it makes sense to introduce VEC4 double type just for this obscure case, and I don't think you can use doubles in expression for fx_2_0. Newer effects are using floats for constants.
The vsir changes don't seem too bad at first sight. Is that the extent of them though, or is there much more to come?
You could probably avoid VSIR_DIMENSION_VEC1/2/3 though; I think in most cases the size of source vectors is implied either by the destination mask, or by the instruction itself. Specifically, instructions like "mov r0.xy, r1.xyzw" are effectively "mov r0.xy, r1.xy", and instructions like "dp3 r0.x, r1.xyzw, r2.xyzw" are effectively "dp3 r0.x, r1.xyz, r2.xyz". I.e., we could conceivably handle this entirely on the output side, much like we do for GLSL output in wined3d.
The vsir changes don't seem too bad at first sight. Is that the extent of them though, or is there much more to come?
It's pretty much it. There is a dozen more instructions for fx_4/fx_5 targets, but that will only extend our internal instruction set, to print correct names.
I see for fx_2 expressions we have some support for non-float constants too, but that probably works through CTAB and not the immediates table.
One minor tweak would be to omit l() prefix from immediate constants, and then use predefined names for outputs, and inputs instead of indices. I haven't looked at that, and it only matters if it's possible to assemble this output back on Windows at all, or if we care about matching textual output completely.
You could probably avoid VSIR_DIMENSION_VEC1/2/3 though; I think in most cases the size of source vectors is implied either by the destination mask, or by the instruction itself. Specifically, instructions like "mov r0.xy, r1.xyzw" are effectively "mov r0.xy, r1.xy", and instructions like "dp3 r0.x, r1.xyzw, r2.xyzw" are effectively "dp3 r0.x, r1.xyz, r2.xyz". I.e., we could conceivably handle this entirely on the output side, much like we do for GLSL output in wined3d.
I think writemask width in this type of assembly always matches number of source components, for all instructions. There is no such thing as vector sources giving scalar result, 'dot' always writes same number of components as sources have, with the same value presumably. It's not easy to check. It's not possible to tell by instruction opcode itself, there is an additional field for number of components instead.
It would be great to avoid additional vector types, it seems more simple the better in this case though - having all information in sources with new data types, instead of coupling that with per-instruction data or destination mask. I was considering also simply adding additional cases for VEC1-VEC3 and not to touch VEC4, to make it more readable.
Could you point me where this part of "output side" is, or that flexibility does not exist yet in vkd3d and wined3d was used as an example to grab the idea from?
Could you point me where this part of "output side" is, or that flexibility does not exist yet in vkd3d and wined3d was used as an example to grab the idea from?
spirv_compiler_emit_load_reg() (and spirv_compiler_emit_swizzle() in particular) does this, but SPIR-V is perhaps a bit tedious in general. The Wine GLSL code does this in shader_glsl_add_src_param_ext() -> shader_glsl_get_swizzle() -> shader_glsl_swizzle_to_str(), and that's perhaps more straightforward to follow.