At some point I would like to have an assembler for TPF, so that it's easier to write and modify tests. This is a first step in that direction, fixing some kind of format for serializing signatures in the comment at the beginning of the assembler code. I'm not decided yet on all details, so take this as an RFC for the moment.
-- v4: tests: Test emitting the signature. vkd3d-compiler: Add an option to emit the signature when disassembling. vkd3d-shader/d3d-asm: Support emitting the shader signature. vkd3d-shader/d3d-asm: Refactor dumping a write mask to a dedicated function. vkd3d-shader/d3d-asm: Describe the ASM dialect with a bunch of flags instead of a plain enum. vkd3d-shader/d3d-asm: Do not make a copy of the buffer before returning it.
From: Giovanni Mascellani gmascellani@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 14 +------------- libs/vkd3d-shader/vkd3d_shader_main.c | 10 ++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 412b8f29c..b551ab622 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -2030,7 +2030,6 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio struct vkd3d_string_buffer *buffer; unsigned int indent, i, j; const char *indent_str; - void *code;
static const struct vkd3d_d3d_asm_colours no_colours = { @@ -2129,18 +2128,7 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio } }
- if ((code = vkd3d_malloc(buffer->content_size))) - { - memcpy(code, buffer->buffer, buffer->content_size); - out->size = buffer->content_size; - out->code = code; - } - else - { - result = VKD3D_ERROR_OUT_OF_MEMORY; - } - - vkd3d_string_buffer_cleanup(buffer); + vkd3d_shader_code_from_string_buffer(out, buffer);
return result; } diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 31d4fc69e..1d2d4699f 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -226,6 +226,16 @@ void vkd3d_string_buffer_release(struct vkd3d_string_buffer_cache *cache, struct cache->buffers[cache->count++] = buffer; }
+void vkd3d_shader_code_from_string_buffer(struct vkd3d_shader_code *code, struct vkd3d_string_buffer *buffer) +{ + code->code = buffer->buffer; + code->size = buffer->content_size; + + buffer->buffer = NULL; + buffer->buffer_size = 0; + buffer->content_size = 0; +} + void vkd3d_shader_message_context_init(struct vkd3d_shader_message_context *context, enum vkd3d_shader_log_level log_level) { diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index c801d1187..3758535bc 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1369,6 +1369,7 @@ void vkd3d_string_buffer_release(struct vkd3d_string_buffer_cache *list, struct vkd3d_string_buffer_trace_(buffer, __FUNCTION__) void vkd3d_string_buffer_trace_(const struct vkd3d_string_buffer *buffer, const char *function); int vkd3d_string_buffer_vprintf(struct vkd3d_string_buffer *buffer, const char *format, va_list args); +void vkd3d_shader_code_from_string_buffer(struct vkd3d_shader_code *code, struct vkd3d_string_buffer *buffer);
struct vkd3d_bytecode_buffer {
From: Giovanni Mascellani gmascellani@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 10 +++++----- libs/vkd3d-shader/vkd3d_shader_main.c | 2 +- libs/vkd3d-shader/vkd3d_shader_private.h | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index b551ab622..e7df4c567 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -367,7 +367,7 @@ struct vkd3d_d3d_asm_compiler struct vkd3d_string_buffer buffer; struct vkd3d_shader_version shader_version; struct vkd3d_d3d_asm_colours colours; - enum vsir_asm_dialect dialect; + enum vsir_asm_flags flags; const struct vkd3d_shader_instruction *current; };
@@ -1355,7 +1355,7 @@ static void shader_dump_reg_type(struct vkd3d_d3d_asm_compiler *compiler, struct vkd3d_string_buffer *buffer = &compiler->buffer; const char *dimension;
- if (compiler->dialect != VSIR_ASM_VSIR) + if (!(compiler->flags & VSIR_ASM_FLAG_DUMP_TYPES)) return;
if (reg->dimension < ARRAY_SIZE(dimensions)) @@ -2019,12 +2019,12 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, enum vsir_asm_dialect dialect) + struct vkd3d_shader_code *out, enum vsir_asm_flags flags) { enum vkd3d_shader_compile_option_formatting_flags formatting; struct vkd3d_d3d_asm_compiler compiler = { - .dialect = dialect, + .flags = flags, }; enum vkd3d_result result = VKD3D_OK; struct vkd3d_string_buffer *buffer; @@ -2139,7 +2139,7 @@ void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instruction const char *p, *q, *end; struct vkd3d_shader_code code;
- if (vkd3d_dxbc_binary_to_text(instructions, shader_version, NULL, &code, VSIR_ASM_VSIR) != VKD3D_OK) + if (vkd3d_dxbc_binary_to_text(instructions, shader_version, NULL, &code, VSIR_ASM_FLAG_DUMP_TYPES) != VKD3D_OK) return;
end = (const char *)code.code + code.size; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 1d2d4699f..59cb519eb 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1595,7 +1595,7 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, switch (compile_info->target_type) { case VKD3D_SHADER_TARGET_D3D_ASM: - ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out, VSIR_ASM_D3D); + ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out, VSIR_ASM_FLAG_NONE); break;
case VKD3D_SHADER_TARGET_GLSL: diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 3758535bc..c4946f732 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1347,15 +1347,15 @@ struct vkd3d_string_buffer_cache size_t count, max_count, capacity; };
-enum vsir_asm_dialect +enum vsir_asm_flags { - VSIR_ASM_VSIR, - VSIR_ASM_D3D, + VSIR_ASM_FLAG_NONE = 0, + VSIR_ASM_FLAG_DUMP_TYPES = 0x1, };
enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, enum vsir_asm_dialect dialect); + struct vkd3d_shader_code *out, enum vsir_asm_flags flags); void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer); struct vkd3d_string_buffer *vkd3d_string_buffer_get(struct vkd3d_string_buffer_cache *list); void vkd3d_string_buffer_init(struct vkd3d_string_buffer *buffer);
From: Giovanni Mascellani gmascellani@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index e7df4c567..4053bb874 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -1368,31 +1368,40 @@ static void shader_dump_reg_type(struct vkd3d_d3d_asm_compiler *compiler, shader_addline(buffer, ">"); }
+static char *dump_write_mask(char buffer[5], uint32_t write_mask) +{ + unsigned int i = 0; + + if (write_mask & VKD3DSP_WRITEMASK_0) + buffer[i++] = 'x'; + if (write_mask & VKD3DSP_WRITEMASK_1) + buffer[i++] = 'y'; + if (write_mask & VKD3DSP_WRITEMASK_2) + buffer[i++] = 'z'; + if (write_mask & VKD3DSP_WRITEMASK_3) + buffer[i++] = 'w'; + + buffer[i++] = '\0'; + + return buffer; +} + static void shader_dump_dst_param(struct vkd3d_d3d_asm_compiler *compiler, const struct vkd3d_shader_dst_param *param, bool is_declaration) { struct vkd3d_string_buffer *buffer = &compiler->buffer; uint32_t write_mask = param->write_mask; + char tmp[5];
shader_dump_register(compiler, ¶m->reg, is_declaration);
if (write_mask && param->reg.dimension == VSIR_DIMENSION_VEC4) { - static const char write_mask_chars[] = "xyzw"; - if (param->reg.data_type == VKD3D_DATA_DOUBLE) write_mask = vsir_write_mask_32_from_64(write_mask);
- shader_addline(buffer, ".%s", compiler->colours.write_mask); - if (write_mask & VKD3DSP_WRITEMASK_0) - shader_addline(buffer, "%c", write_mask_chars[0]); - if (write_mask & VKD3DSP_WRITEMASK_1) - shader_addline(buffer, "%c", write_mask_chars[1]); - if (write_mask & VKD3DSP_WRITEMASK_2) - shader_addline(buffer, "%c", write_mask_chars[2]); - if (write_mask & VKD3DSP_WRITEMASK_3) - shader_addline(buffer, "%c", write_mask_chars[3]); - shader_addline(buffer, "%s", compiler->colours.reset); + shader_addline(buffer, ".%s%s%s", compiler->colours.write_mask, + dump_write_mask(tmp, write_mask), compiler->colours.reset); }
shader_print_precision(compiler, ¶m->reg);
From: Giovanni Mascellani gmascellani@codeweavers.com
--- include/vkd3d_shader.h | 11 +++ libs/vkd3d-shader/d3d_asm.c | 113 ++++++++++++++++++++++- libs/vkd3d-shader/vkd3d_shader_main.c | 18 +++- libs/vkd3d-shader/vkd3d_shader_private.h | 6 +- 4 files changed, 142 insertions(+), 6 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index a9c9ccc4a..ac49b013f 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -271,6 +271,17 @@ enum vkd3d_shader_compile_option_name * \since 1.11 */ VKD3D_SHADER_COMPILE_OPTION_FEATURE = 0x0000000a, + /** + * If \a value is nonzero, emit the input and output signature + * when disassembling a shader. + * + * This option is supported by vkd3d_shader_compile() when using + * D3D_BYTECODE, DXBC_TPF or DXBC_DXIL as source and D3D_ASM as + * target; it should not be enabled otherwise. + * + * \since 1.11 + */ + VKD3D_SHADER_COMPILE_OPTION_EMIT_SIGNATURE = 0x0000000b,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_NAME), }; diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 4053bb874..90ae9915a 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -2026,9 +2026,107 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler, shader_addline(buffer, "\n"); }
+static const char *get_sysval_semantic_name(enum vkd3d_shader_sysval_semantic semantic) +{ + switch (semantic) + { + case VKD3D_SHADER_SV_NONE: return NULL; + case VKD3D_SHADER_SV_POSITION: return "POS"; + case VKD3D_SHADER_SV_CLIP_DISTANCE: return "CLIPDST"; + case VKD3D_SHADER_SV_CULL_DISTANCE: return "CULLDST"; + case VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX: return "RTINDEX"; + case VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX: return "VPINDEX"; + case VKD3D_SHADER_SV_VERTEX_ID: return "VERTID"; + case VKD3D_SHADER_SV_PRIMITIVE_ID: return "PRIMID"; + case VKD3D_SHADER_SV_INSTANCE_ID: return "INSTID"; + case VKD3D_SHADER_SV_IS_FRONT_FACE: return "FFACE"; + case VKD3D_SHADER_SV_SAMPLE_INDEX: return "SAMPLE"; + case VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE: return "QUADEDGE"; + case VKD3D_SHADER_SV_TESS_FACTOR_QUADINT: return "QUADINT"; + case VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE: return "TRIEDGE"; + case VKD3D_SHADER_SV_TESS_FACTOR_TRIINT: return "TRIINT"; + case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET: return "LINEDET"; + case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: return "LINEDEN"; + case VKD3D_SHADER_SV_TARGET: return "TARGET"; + case VKD3D_SHADER_SV_DEPTH: return "DEPTH"; + case VKD3D_SHADER_SV_COVERAGE: return "COVERAGE"; + case VKD3D_SHADER_SV_DEPTH_GREATER_EQUAL: return "DEPTHGE"; + case VKD3D_SHADER_SV_DEPTH_LESS_EQUAL: return "DEPTHLE"; + case VKD3D_SHADER_SV_STENCIL_REF: return "STENCILREF"; + default: return "??"; + } +} + +static const char *get_component_type_name(enum vkd3d_shader_component_type type) +{ + switch (type) + { + case VKD3D_SHADER_COMPONENT_VOID: return "void"; + case VKD3D_SHADER_COMPONENT_UINT: return "uint"; + case VKD3D_SHADER_COMPONENT_INT: return "int"; + case VKD3D_SHADER_COMPONENT_FLOAT: return "float"; + case VKD3D_SHADER_COMPONENT_BOOL: return "bool"; + case VKD3D_SHADER_COMPONENT_DOUBLE: return "double"; + case VKD3D_SHADER_COMPONENT_UINT64: return "uint64"; + default: return "??"; + } +} + +static enum vkd3d_result dump_signature(const struct shader_signature *signature, + struct vkd3d_string_buffer *buffer) +{ + unsigned int i; + char tmp[5]; + + for (i = 0; i < signature->element_count; ++i) + { + struct signature_element *element = &signature->elements[i]; + const char *sysval_semantic = get_sysval_semantic_name(element->sysval_semantic); + + vkd3d_string_buffer_printf(buffer, ".param %s", + element->semantic_name); + + if (element->semantic_index != 0) + vkd3d_string_buffer_printf(buffer, "%u", element->semantic_index); + + vkd3d_string_buffer_printf(buffer, ".%s, v%d.%s, %s", + dump_write_mask(tmp, element->mask), + element->register_index, dump_write_mask(tmp, element->used_mask), + get_component_type_name(element->component_type)); + + if (sysval_semantic) + vkd3d_string_buffer_printf(buffer, ", %s", sysval_semantic); + + vkd3d_string_buffer_printf(buffer, "\n"); + } + + return VKD3D_OK; +} + +static enum vkd3d_result dump_signatures(const struct vkd3d_shader_desc *shader_desc, + struct vkd3d_string_buffer *buffer) +{ + enum vkd3d_result ret; + + vkd3d_string_buffer_printf(buffer, ".section ISGN\n"); + ret = dump_signature(&shader_desc->input_signature, buffer); + + if (ret >= 0) + { + vkd3d_string_buffer_printf(buffer, ".section OSGN\n"); + ret = dump_signature(&shader_desc->output_signature, buffer); + } + + if (ret >= 0) + vkd3d_string_buffer_printf(buffer, ".section SHEX\n"); + + return ret; +} + enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, - const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, enum vsir_asm_flags flags) + const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_desc *shader_desc, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, + enum vsir_asm_flags flags) { enum vkd3d_shader_compile_option_formatting_flags formatting; struct vkd3d_d3d_asm_compiler compiler = @@ -2090,6 +2188,15 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio buffer = &compiler.buffer; vkd3d_string_buffer_init(buffer);
+ if (flags & VSIR_ASM_FLAG_EMIT_SIGNATURE) + { + if ((result = dump_signatures(shader_desc, buffer)) < 0) + { + vkd3d_string_buffer_cleanup(buffer); + return result; + } + } + compiler.shader_version = *shader_version; shader_version = &compiler.shader_version; vkd3d_string_buffer_printf(buffer, "%s%s_%u_%u%s\n", compiler.colours.version, @@ -2148,7 +2255,7 @@ void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instruction const char *p, *q, *end; struct vkd3d_shader_code code;
- if (vkd3d_dxbc_binary_to_text(instructions, shader_version, NULL, &code, VSIR_ASM_FLAG_DUMP_TYPES) != VKD3D_OK) + if (vkd3d_dxbc_binary_to_text(instructions, shader_version, NULL, NULL, &code, VSIR_ASM_FLAG_DUMP_TYPES) != VKD3D_OK) return;
end = (const char *)code.code + code.size; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 59cb519eb..04abbc26a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1581,6 +1581,21 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char return ret; }
+static enum vsir_asm_flags asm_flags_from_compile_info(const struct vkd3d_shader_compile_info *compile_info) +{ + enum vsir_asm_flags ret = VSIR_ASM_FLAG_NONE; + unsigned int i; + + for (i = 0; i < compile_info->option_count; ++i) + { + if (compile_info->options[i].name == VKD3D_SHADER_COMPILE_OPTION_EMIT_SIGNATURE + && compile_info->options[i].value) + ret |= VSIR_ASM_FLAG_EMIT_SIGNATURE; + } + + return ret; +} + static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) @@ -1595,7 +1610,8 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser, switch (compile_info->target_type) { case VKD3D_SHADER_TARGET_D3D_ASM: - ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out, VSIR_ASM_FLAG_NONE); + ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, + &parser->shader_desc, compile_info, out, asm_flags_from_compile_info(compile_info)); break;
case VKD3D_SHADER_TARGET_GLSL: diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index c4946f732..3272b75ce 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1351,11 +1351,13 @@ enum vsir_asm_flags { VSIR_ASM_FLAG_NONE = 0, VSIR_ASM_FLAG_DUMP_TYPES = 0x1, + VSIR_ASM_FLAG_EMIT_SIGNATURE = 0x2, };
enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions, - const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, enum vsir_asm_flags flags); + const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_desc *shader_desc, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out, + enum vsir_asm_flags flags); void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer); struct vkd3d_string_buffer *vkd3d_string_buffer_get(struct vkd3d_string_buffer_cache *list); void vkd3d_string_buffer_init(struct vkd3d_string_buffer *buffer);
From: Giovanni Mascellani gmascellani@codeweavers.com
--- programs/vkd3d-compiler/main.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/programs/vkd3d-compiler/main.c b/programs/vkd3d-compiler/main.c index 4aa368b04..e889544ec 100644 --- a/programs/vkd3d-compiler/main.c +++ b/programs/vkd3d-compiler/main.c @@ -50,6 +50,7 @@ enum OPTION_STRIP_DEBUG, OPTION_VERSION, OPTION_TEXT_FORMATTING, + OPTION_EMIT_SIGNATURE, };
static const struct source_type_info @@ -188,6 +189,7 @@ static void print_usage(const char *program_name) " 'storage-buffer'.\n" " -e, --entry=<name> Use <name> as the entry point (default is "main").\n" " -E Preprocess the source code instead of compiling it.\n" + " --emit-signature Emit the shader signature when disassembling.\n" " --formatting=<flags> Specify the formatting options for text output.\n" " <flags> is a comma separated list of formatting flags,\n" " optionally prefixed by '+' or '-'. Valid flags are\n" @@ -488,6 +490,7 @@ static bool parse_command_line(int argc, char **argv, struct options *options) {"strip-debug", no_argument, NULL, OPTION_STRIP_DEBUG}, {"version", no_argument, NULL, OPTION_VERSION}, {"semantic-compat-map", no_argument, NULL, OPTION_SEMANTIC_COMPAT_MAP}, + {"emit-signature", no_argument, NULL, OPTION_EMIT_SIGNATURE}, {NULL, 0, NULL, 0}, };
@@ -584,6 +587,10 @@ static bool parse_command_line(int argc, char **argv, struct options *options) add_compile_option(options, VKD3D_SHADER_COMPILE_OPTION_STRIP_DEBUG, 1); break;
+ case OPTION_EMIT_SIGNATURE: + add_compile_option(options, VKD3D_SHADER_COMPILE_OPTION_EMIT_SIGNATURE, 1); + break; + case OPTION_VERSION: case 'V': options->print_version = true;
From: Giovanni Mascellani gmascellani@codeweavers.com
--- tests/vkd3d_shader_api.c | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+)
diff --git a/tests/vkd3d_shader_api.c b/tests/vkd3d_shader_api.c index 018506a45..2731bc245 100644 --- a/tests/vkd3d_shader_api.c +++ b/tests/vkd3d_shader_api.c @@ -999,6 +999,145 @@ static void test_scan_combined_resource_samplers(void) pfn_free_combined_sampler_info(&combined_sampler_info); }
+static void test_emit_signature(void) +{ + static const struct emit_signature_test + { + const char *source; + const char *signature; + bool hlsl_todo; + bool signature_todo; + } tests[] = + { + { + "void main(float4 pos : SV_Position, float3 color : COLOR2, uint2 color2 : COLOR5,\n" + " out int3 target : SV_Target1, out float target2 : SV_Target5)\n" + "{\n" + " float tmp = length(pos) + length(color) + length(color2);\n" + " target.xyz = tmp;\n" + " target2 = tmp;\n" + "}\n", + ".section ISGN\n" + ".param SV_Position.xyzw, v0.xyzw, float, POS\n" + ".param COLOR2.xyz, v1.xyz, float\n" + ".param COLOR5.xy, v2.xy, uint\n" + ".section OSGN\n" + ".param SV_Target1.xyz, v1.xyz, int, TARGET\n" + ".param SV_Target5.x, v5.x, float, TARGET\n", + false, false + }, + { + "void main(float4 pos : SV_Position, float3 color : COLOR2, uint2 color2 : COLOR5,\n" + " out int3 target : SV_Target1, out float target2 : SV_Target5)\n" + "{\n" + " float tmp = pos.x + pos.w + color.y + color.z + color2.x;\n" + " target.xz = tmp;\n" + " target2 = tmp;\n" + "}\n", + ".section ISGN\n" + ".param SV_Position.xyzw, v0.xw, float, POS\n" + ".param COLOR2.xyz, v1.yz, float\n" + ".param COLOR5.xy, v2.x, uint\n" + ".section OSGN\n" + ".param SV_Target1.xyz, v1.xz, int, TARGET\n" + ".param SV_Target5.x, v5.x, float, TARGET\n", + false, true + }, + { + "void main(float4 pos : SV_Position, float3 color : COLOR2, uint2 color2 : COLOR5,\n" + " float2 clip : SV_ClipDistance0, float3 clip2 : SV_ClipDistance1,\n" + " float1 cull : SV_CullDistance0, float cull2 : SV_CullDistance1,\n" + " uint prim : SV_PrimitiveID, uint inst : SV_InstanceID,\n" + " bool front : SV_IsFrontFace0, uint sample : SV_SampleIndex,\n" + " out int3 target : SV_Target1, out float target2 : SV_Target5,\n" + " out float depth : SV_Depth)\n" + "{\n" + " float tmp = color.y + color.z + color2 + pos.x + pos.w + clip.x + clip2.x + clip2.z\n" + " + cull.x + cull2 + prim + front + sample;\n" + " target.xz = tmp;\n" + " target2 = tmp;\n" + " depth = tmp;\n" + "}\n", + ".section ISGN\n" + ".param SV_Position.xyzw, v0.xw, float, POS\n" + ".param COLOR2.xyz, v1.yz, float\n" + ".param COLOR5.xy, v2.x, uint\n" + ".param SV_PrimitiveID.z, v2.z, uint, PRIMID\n" + ".param SV_InstanceID.w, v2.w, uint\n" + ".param SV_ClipDistance.xy, v3.x, float, CLIPDST\n" + ".param SV_CullDistance.z, v3.z, float, CULLDST\n" + ".param SV_CullDistance1.w, v3.w, float, CULLDST\n" + ".param SV_ClipDistance1.xyz, v4.xz, float, CLIPDST\n" + ".param SV_IsFrontFace.x, v5.x, uint, FFACE\n" + ".param SV_SampleIndex.y, v5.y, uint, SAMPLE\n" + ".section OSGN\n" + ".param SV_Target1.xyz, v1.xz, int, TARGET\n" + ".param SV_Target5.x, v5.x, float, TARGET\n" + ".param SV_Depth, oDepth, float, DEPTH\n", + true, true + }, + }; + + struct vkd3d_shader_hlsl_source_info hlsl_info = + { + .type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO, + .entry_point = "main", + .profile = "ps_5_0", + }; + struct vkd3d_shader_compile_info compile_info = + { + .type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO, + .next = &hlsl_info, + .source_type = VKD3D_SHADER_SOURCE_HLSL, + .target_type = VKD3D_SHADER_TARGET_DXBC_TPF, + .log_level = VKD3D_SHADER_LOG_NONE, + }; + struct vkd3d_shader_compile_option disassemble_options[] = + { + { .name = VKD3D_SHADER_COMPILE_OPTION_EMIT_SIGNATURE, .value = 1 }, + }; + struct vkd3d_shader_compile_info disassemble_info = + { + .type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO, + .source_type = VKD3D_SHADER_SOURCE_DXBC_TPF, + .target_type = VKD3D_SHADER_TARGET_D3D_ASM, + .options = disassemble_options, + .option_count = ARRAY_SIZE(disassemble_options), + .log_level = VKD3D_SHADER_LOG_NONE, + }; + struct vkd3d_shader_code dxbc, disasm; + unsigned int i; + char *ptr; + int rc; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + const struct emit_signature_test *test = &tests[i]; + + compile_info.source.code = test->source; + compile_info.source.size = strlen(test->source); + rc = vkd3d_shader_compile(&compile_info, &dxbc, NULL); + todo_if(test->hlsl_todo) + ok(rc == VKD3D_OK, "Cannot compile HLSL shader, rc %d.\n", rc); + + if (rc != VKD3D_OK) + continue; + + disassemble_info.source = dxbc; + rc = vkd3d_shader_compile(&disassemble_info, &disasm, NULL); + ok(rc == VKD3D_OK, "Cannot disassemble shader, rc %d.\n", rc); + + ptr = strstr(disasm.code, ".section SHEX\n"); + ok(ptr, "Cannot find SHEX marker in disassembled code.\n"); + *ptr = '\0'; + todo_if(test->signature_todo) + ok(strcmp(disasm.code, test->signature) == 0, "Unexpected signature description.\n"); + + vkd3d_shader_free_shader_code(&dxbc); + vkd3d_shader_free_shader_code(&disasm); + } +} + START_TEST(vkd3d_shader_api) { setlocale(LC_ALL, ""); @@ -1012,4 +1151,5 @@ START_TEST(vkd3d_shader_api) run_test(test_scan_descriptors); run_test(test_build_varying_map); run_test(test_scan_combined_resource_samplers); + run_test(test_emit_signature); }
I think I like the syntax as it is, at least I agree with the changes that have been made, but:
* Do we really want to invent a new set of names like that for sysval? Should we just clip VKD3D_SHADER_SV from the existing enum instead?
* What's the plan for GS stream index and for minimum precision?
* Any reason we're leaving out patch constant signatures from this series?
From patch 4/6:
- if (ret >= 0)
vkd3d_string_buffer_printf(buffer, ".section SHEX\n");
This feels weird, partly because it's in dump_signatures(), also because I don't see why it's SHEX and not SHDR.
Do we really want to invent a new set of names like that for sysval? Should we just clip VKD3D_SHADER_SV from the existing enum instead?
I copied them from native `/dumpbin`. We might still want to use our existing enum, sure; my personal opinion is that it's nice to have them a bit shorter.
What's the plan for GS stream index and for minimum precision?
The general idea is that unspecified fields are treated as default; so we have to dump fields until all the rightmost ones are default. I was aware of minimum precision, but not of GS stream index. I'll try to add support for both.
Any reason we're leaving out patch constant signatures from this series?
No, it's just that I still have to add support for this too. My knowledge of shader signatures is still pretty young, so I'm learning while I'm doing.
From patch 4/6:
if (ret >= 0) vkd3d_string_buffer_printf(buffer, ".section SHEX\n");
This feels weird, partly because it's in dump_signatures(), also because I don't see why it's SHEX and not SHDR.
Ok, I can move this out. WRT to using fourccs, I don't have strong opinions, but I'd like to avoid overcomplicating the matter. So, for example, I would try to avoid two different tags depending on whether we're using minimum precision or not. My idea is that the directives I'm introducing specify the logical data; it's up to the assembler to decide which tags to use depending on the data. Using this point of view it might be preferable to rather use: ``` .section input .section output .section patch_constant .section code ``` However Henri explicitly suggested using fourccs, so he might have opinions here.
Do we really want to invent a new set of names like that for sysval? Should we just clip VKD3D_SHADER_SV from the existing enum instead?
I copied them from native `/dumpbin`. We might still want to use our existing enum, sure; my personal opinion is that it's nice to have them a bit shorter.
Ah, I should have recognized that. If there's precedent I think that's fine, I just thought we were inventing names out of nowhere.
Any reason we're leaving out patch constant signatures from this series?
No, it's just that I still have to add support for this too. My knowledge of shader signatures is still pretty young, so I'm learning while I'm doing.
Fair enough.
FWIW, patch constant signatures are pretty simple: they're output for HS and input for DS. I think you can just copy any one of the tessellation shader pairs from d3d12.c for a simple example.
From patch 4/6:
if (ret >= 0) vkd3d_string_buffer_printf(buffer, ".section SHEX\n");
This feels weird, partly because it's in dump_signatures(), also because I don't see why it's SHEX and not SHDR.
Ok, I can move this out. WRT to using fourccs, I don't have strong opinions, but I'd like to avoid overcomplicating the matter. So, for example, I would try to avoid two different tags depending on whether we're using minimum precision or not. My idea is that the directives I'm introducing specify the logical data; it's up to the assembler to decide which tags to use depending on the data. Using this point of view it might be preferable to rather use:
.section input .section output .section patch_constant .section code
However Henri explicitly suggested using fourccs, so he might have opinions here.
Hrm, I see those were in the original suggestion.
What's weird about it is mostly that SHEX is the extended 5.0 version of SHDR, whereas ISGN and OSGN are the original versions. Granted, that *is* the default you get with 5.0, if you don't have minimum precision or GS stream index, but it feels like not the most obvious arbitrary choice.
The idea was mostly that you would then be able to specify the contents of arbitrary DXBC sections with things like .byte and .string. That doesn't have to be mutually exclusive with something like .input/.output/.patch_constant/.text, of course, and we could certainly start with those.