From c44bf575e7747f340086fa9b74543ee934b8f5f1 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 18 Sep 2024 11:57:45 +1000 Subject: [PATCH] Updated vkd3d to a1487380bb69c6ec07495c1a6eef4cfb224710cb. --- libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 6 +- libs/vkd3d/libs/vkd3d-shader/glsl.c | 360 ++++++++++++++++++++++++- libs/vkd3d/libs/vkd3d-shader/ir.c | 284 ++++++++++--------- libs/vkd3d/libs/vkd3d-shader/msl.c | 129 +++++++++ libs/vkd3d/libs/vkd3d-shader/tpf.c | 106 +++++++- 5 files changed, 743 insertions(+), 142 deletions(-) create mode 100644 libs/vkd3d/libs/vkd3d-shader/msl.c diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c index 77e9711300f..cfee053d49c 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c @@ -79,7 +79,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_DCL_INDEXABLE_TEMP ] = "dcl_indexableTemp", [VKD3DSIH_DCL_INPUT ] = "dcl_input", [VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT ] = "dcl_input_control_point_count", - [VKD3DSIH_DCL_INPUT_PRIMITIVE ] = "dcl_inputPrimitive", + [VKD3DSIH_DCL_INPUT_PRIMITIVE ] = "dcl_inputprimitive", [VKD3DSIH_DCL_INPUT_PS ] = "dcl_input_ps", [VKD3DSIH_DCL_INPUT_PS_SGV ] = "dcl_input_ps_sgv", [VKD3DSIH_DCL_INPUT_PS_SIV ] = "dcl_input_ps_siv", @@ -89,7 +89,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_DCL_OUTPUT ] = "dcl_output", [VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT ] = "dcl_output_control_point_count", [VKD3DSIH_DCL_OUTPUT_SIV ] = "dcl_output_siv", - [VKD3DSIH_DCL_OUTPUT_TOPOLOGY ] = "dcl_outputTopology", + [VKD3DSIH_DCL_OUTPUT_TOPOLOGY ] = "dcl_outputtopology", [VKD3DSIH_DCL_RESOURCE_RAW ] = "dcl_resource_raw", [VKD3DSIH_DCL_RESOURCE_STRUCTURED ] = "dcl_resource_structured", [VKD3DSIH_DCL_SAMPLER ] = "dcl_sampler", @@ -104,7 +104,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_DCL_UAV_RAW ] = "dcl_uav_raw", [VKD3DSIH_DCL_UAV_STRUCTURED ] = "dcl_uav_structured", [VKD3DSIH_DCL_UAV_TYPED ] = "dcl_uav_typed", - [VKD3DSIH_DCL_VERTICES_OUT ] = "dcl_maxOutputVertexCount", + [VKD3DSIH_DCL_VERTICES_OUT ] = "dcl_maxout", [VKD3DSIH_DDIV ] = "ddiv", [VKD3DSIH_DEF ] = "def", [VKD3DSIH_DEFAULT ] = "default", diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c index b0aacdfef65..f8fec6ac2bc 100644 --- a/libs/vkd3d/libs/vkd3d-shader/glsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c @@ -38,7 +38,16 @@ struct vkd3d_glsl_generator struct vkd3d_shader_location location; struct vkd3d_shader_message_context *message_context; unsigned int indent; + const char *prefix; bool failed; + + struct shader_limits + { + unsigned int input_count; + unsigned int output_count; + } limits; + bool interstage_input; + bool interstage_output; }; static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( @@ -53,6 +62,27 @@ static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error( generator->failed = true; } +static const char *shader_glsl_get_prefix(enum vkd3d_shader_type type) +{ + switch (type) + { + case VKD3D_SHADER_TYPE_VERTEX: + return "vs"; + case VKD3D_SHADER_TYPE_HULL: + return "hs"; + case VKD3D_SHADER_TYPE_DOMAIN: + return "ds"; + case VKD3D_SHADER_TYPE_GEOMETRY: + return "gs"; + case VKD3D_SHADER_TYPE_PIXEL: + return "ps"; + case VKD3D_SHADER_TYPE_COMPUTE: + return "cs"; + default: + return NULL; + } +} + static void shader_glsl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent) { vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); @@ -67,6 +97,42 @@ static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer, vkd3d_string_buffer_printf(buffer, "r[%u]", reg->idx[0].offset); break; + case VKD3DSPR_INPUT: + if (reg->idx_count != 1) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled input register index count %u.", reg->idx_count); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + if (reg->idx[0].rel_addr) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled input register indirect addressing."); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, reg->idx[0].offset); + break; + + case VKD3DSPR_OUTPUT: + if (reg->idx_count != 1) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled output register index count %u.", reg->idx_count); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + if (reg->idx[0].rel_addr) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled output register indirect addressing."); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + vkd3d_string_buffer_printf(buffer, "%s_out[%u]", gen->prefix, reg->idx[0].offset); + break; + default: vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, "Internal compiler error: Unhandled register type %#x.", reg->type); @@ -198,16 +264,130 @@ static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d glsl_dst_cleanup(&dst, &gen->string_buffers); } +static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, + enum vkd3d_shader_sysval_semantic sysval, unsigned int idx) +{ + switch (sysval) + { + case VKD3D_SHADER_SV_POSITION: + if (gen->program->shader_version.type == VKD3D_SHADER_TYPE_PIXEL + || gen->program->shader_version.type == VKD3D_SHADER_TYPE_COMPUTE) + { + vkd3d_string_buffer_printf(buffer, "", sysval); + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled system value %#x.", sysval); + } + else + { + vkd3d_string_buffer_printf(buffer, "gl_Position"); + if (idx) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled SV_POSITION index %u.", idx); + } + break; + + default: + vkd3d_string_buffer_printf(buffer, "", sysval); + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled system value %#x.", sysval); + break; + } +} + +static void shader_glsl_shader_prologue(struct vkd3d_glsl_generator *gen) +{ + const struct shader_signature *signature = &gen->program->input_signature; + struct vkd3d_string_buffer *buffer = gen->buffer; + const struct signature_element *e; + unsigned int i; + + for (i = 0; i < signature->element_count; ++i) + { + e = &signature->elements[i]; + + if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) + continue; + + shader_glsl_print_indent(buffer, gen->indent); + vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, e->register_index); + shader_glsl_print_write_mask(buffer, e->mask); + if (e->sysval_semantic == VKD3D_SHADER_SV_NONE) + { + if (gen->interstage_input) + { + vkd3d_string_buffer_printf(buffer, " = shader_in.reg_%u", e->target_location); + if (e->target_location >= gen->limits.input_count) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Input element %u specifies target location %u, " + "but only %u inputs are supported.", + i, e->target_location, gen->limits.input_count); + } + else + { + vkd3d_string_buffer_printf(buffer, " = shader_in_%u", i); + } + } + else + { + vkd3d_string_buffer_printf(buffer, " = "); + shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index); + } + shader_glsl_print_write_mask(buffer, e->mask); + vkd3d_string_buffer_printf(buffer, ";\n"); + } +} + +static void shader_glsl_shader_epilogue(struct vkd3d_glsl_generator *gen) +{ + const struct shader_signature *signature = &gen->program->output_signature; + struct vkd3d_string_buffer *buffer = gen->buffer; + const struct signature_element *e; + unsigned int i; + + for (i = 0; i < signature->element_count; ++i) + { + e = &signature->elements[i]; + + if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) + continue; + + shader_glsl_print_indent(buffer, gen->indent); + if (e->sysval_semantic == VKD3D_SHADER_SV_NONE) + { + if (gen->interstage_output) + { + vkd3d_string_buffer_printf(buffer, "shader_out.reg_%u", e->target_location); + if (e->target_location >= gen->limits.output_count) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Output element %u specifies target location %u, " + "but only %u outputs are supported.", + i, e->target_location, gen->limits.output_count); + } + else + { + vkd3d_string_buffer_printf(buffer, "", e->target_location); + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled output."); + } + } + else + { + shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index); + } + shader_glsl_print_write_mask(buffer, e->mask); + vkd3d_string_buffer_printf(buffer, " = %s_out[%u]", gen->prefix, e->register_index); + shader_glsl_print_write_mask(buffer, e->mask); + vkd3d_string_buffer_printf(buffer, ";\n"); + } +} + static void shader_glsl_ret(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) { const struct vkd3d_shader_version *version = &gen->program->shader_version; - /* - * TODO: Implement in_subroutine - * TODO: shader_glsl_generate_shader_epilogue(generator); - */ if (version->major >= 4) { + shader_glsl_shader_epilogue(gen); shader_glsl_print_indent(gen->buffer, gen->indent); vkd3d_string_buffer_printf(gen->buffer, "return;\n"); } @@ -237,13 +417,144 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, } } +static void shader_glsl_generate_interface_block(struct vkd3d_string_buffer *buffer, + const char *type, unsigned int count) +{ + unsigned int i; + + vkd3d_string_buffer_printf(buffer, "%s shader_in_out\n{\n", type); + for (i = 0; i < count; ++i) + { + vkd3d_string_buffer_printf(buffer, " vec4 reg_%u;\n", i); + } + vkd3d_string_buffer_printf(buffer, "} shader_%s;\n", type); +} + +static void shader_glsl_generate_input_declarations(struct vkd3d_glsl_generator *gen) +{ + const struct shader_signature *signature = &gen->program->input_signature; + struct vkd3d_string_buffer *buffer = gen->buffer; + const struct signature_element *e; + unsigned int i; + + if (!gen->interstage_input) + { + for (i = 0; i < signature->element_count; ++i) + { + e = &signature->elements[i]; + + if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) + continue; + + if (e->sysval_semantic) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled system value %#x.", e->sysval_semantic); + continue; + } + + if (e->component_type != VKD3D_SHADER_COMPONENT_FLOAT) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled component type %#x.", e->component_type); + continue; + } + + if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled minimum precision %#x.", e->min_precision); + continue; + } + + if (e->interpolation_mode != VKD3DSIM_NONE) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode); + continue; + } + + vkd3d_string_buffer_printf(buffer, + "layout(location = %u) in vec4 shader_in_%u;\n", e->target_location, i); + } + } + else if (gen->limits.input_count) + { + shader_glsl_generate_interface_block(buffer, "in", gen->limits.input_count); + } + vkd3d_string_buffer_printf(buffer, "\n"); +} + +static void shader_glsl_generate_output_declarations(struct vkd3d_glsl_generator *gen) +{ + const struct shader_signature *signature = &gen->program->output_signature; + struct vkd3d_string_buffer *buffer = gen->buffer; + const struct signature_element *e; + unsigned int i; + + if (!gen->interstage_output) + { + for (i = 0; i < signature->element_count; ++i) + { + e = &signature->elements[i]; + + if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED) + continue; + + if (e->sysval_semantic != VKD3D_SHADER_SV_TARGET) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled system value %#x.", e->sysval_semantic); + continue; + } + + if (e->component_type != VKD3D_SHADER_COMPONENT_FLOAT) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled component type %#x.", e->component_type); + continue; + } + + if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled minimum precision %#x.", e->min_precision); + continue; + } + + if (e->interpolation_mode != VKD3DSIM_NONE) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode); + continue; + } + + vkd3d_string_buffer_printf(buffer, + "layout(location = %u) out vec4 shader_out_%u;\n", e->target_location, i); + } + } + else if (gen->limits.output_count) + { + shader_glsl_generate_interface_block(buffer, "out", gen->limits.output_count); + } + vkd3d_string_buffer_printf(buffer, "\n"); +} + static void shader_glsl_generate_declarations(struct vkd3d_glsl_generator *gen) { const struct vsir_program *program = gen->program; struct vkd3d_string_buffer *buffer = gen->buffer; + shader_glsl_generate_input_declarations(gen); + shader_glsl_generate_output_declarations(gen); + + if (gen->limits.input_count) + vkd3d_string_buffer_printf(buffer, "vec4 %s_in[%u];\n", gen->prefix, gen->limits.input_count); + if (gen->limits.output_count) + vkd3d_string_buffer_printf(buffer, "vec4 %s_out[%u];\n", gen->prefix, gen->limits.output_count); if (program->temp_count) - vkd3d_string_buffer_printf(buffer, "vec4 r[%u];\n\n", program->temp_count); + vkd3d_string_buffer_printf(buffer, "vec4 r[%u];\n", program->temp_count); + vkd3d_string_buffer_printf(buffer, "\n"); } static int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *gen, struct vkd3d_shader_code *out) @@ -264,6 +575,7 @@ static int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *gen, struc vkd3d_string_buffer_printf(buffer, "void main()\n{\n"); ++gen->indent; + shader_glsl_shader_prologue(gen); for (i = 0; i < instructions->count; ++i) { vkd3d_glsl_handle_instruction(gen, &instructions->elements[i]); @@ -294,14 +606,52 @@ static void vkd3d_glsl_generator_cleanup(struct vkd3d_glsl_generator *gen) vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); } +static void shader_glsl_init_limits(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_version *version) +{ + struct shader_limits *limits = &gen->limits; + + if (version->major < 4 || version->major >= 6) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled shader version %u.%u.", version->major, version->minor); + + switch (version->type) + { + case VKD3D_SHADER_TYPE_VERTEX: + limits->input_count = 32; + limits->output_count = 32; + break; + case VKD3D_SHADER_TYPE_PIXEL: + limits->input_count = 32; + limits->output_count = 8; + break; + default: + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled shader type %#x.", version->type); + limits->input_count = 0; + limits->output_count = 0; + break; + } +} + static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen, struct vsir_program *program, struct vkd3d_shader_message_context *message_context) { + enum vkd3d_shader_type type = program->shader_version.type; + memset(gen, 0, sizeof(*gen)); gen->program = program; vkd3d_string_buffer_cache_init(&gen->string_buffers); gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers); gen->message_context = message_context; + if (!(gen->prefix = shader_glsl_get_prefix(type))) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled shader type %#x.", type); + gen->prefix = "unknown"; + } + shader_glsl_init_limits(gen, &program->shader_version); + gen->interstage_input = type != VKD3D_SHADER_TYPE_VERTEX; + gen->interstage_output = type != VKD3D_SHADER_TYPE_PIXEL; } int glsl_compile(struct vsir_program *program, uint64_t config_flags, diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index 1efb7106e71..9e06b94e2eb 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -6153,6 +6153,21 @@ static void vsir_validator_push_block(struct validation_context *ctx, enum vkd3d ctx->blocks[ctx->depth++] = opcode; } +static void vsir_validate_hull_shader_phase(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (ctx->program->shader_version.type != VKD3D_SHADER_TYPE_HULL) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, + "Phase instruction %#x is only valid in a hull shader.", + instruction->opcode); + if (ctx->depth != 0) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, + "Phase instruction %#x must appear to top level.", + instruction->opcode); + ctx->phase = instruction->opcode; + ctx->dcl_temps_found = false; +} + static void vsir_validate_branch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) { size_t i; @@ -6193,6 +6208,54 @@ static void vsir_validate_branch(struct validation_context *ctx, const struct vk instruction->src[i].reg.type); } } + + ctx->inside_block = false; +} + +static void vsir_validate_dcl_gs_instances(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (!instruction->declaration.count || instruction->declaration.count > 32) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS instance count %u is invalid.", + instruction->declaration.count); +} + +static void vsir_validate_dcl_hs_max_tessfactor(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + /* Exclude non-finite values. */ + if (!(instruction->declaration.max_tessellation_factor >= 1.0f + && instruction->declaration.max_tessellation_factor <= 64.0f)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Max tessellation factor %f is invalid.", + instruction->declaration.max_tessellation_factor); +} + +static void vsir_validate_dcl_input_primitive(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED + || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS input primitive %u is invalid.", + instruction->declaration.primitive_type.type); +} + +static void vsir_validate_dcl_output_control_point_count(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (!instruction->declaration.count || instruction->declaration.count > 32) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Output control point count %u is invalid.", + instruction->declaration.count); +} + +static void vsir_validate_dcl_output_topology(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED + || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output primitive %u is invalid.", + instruction->declaration.primitive_type.type); } static void vsir_validate_dcl_temps(struct validation_context *ctx, @@ -6208,6 +6271,45 @@ static void vsir_validate_dcl_temps(struct validation_context *ctx, ctx->dcl_temps_found = true; } +static void vsir_validate_dcl_tessellator_domain(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID + || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain); +} + +static void vsir_validate_dcl_tessellator_output_primitive(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (!instruction->declaration.tessellator_output_primitive + || instruction->declaration.tessellator_output_primitive + > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Tessellator output primitive %#x is invalid.", + instruction->declaration.tessellator_output_primitive); +} + +static void vsir_validate_dcl_tessellator_partitioning(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (!instruction->declaration.tessellator_partitioning + || instruction->declaration.tessellator_partitioning + > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Tessellator partitioning %#x is invalid.", + instruction->declaration.tessellator_partitioning); +} + +static void vsir_validate_dcl_vertices_out(struct validation_context *ctx, + const struct vkd3d_shader_instruction *instruction) +{ + if (instruction->declaration.count > 1024) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output vertex count %u is invalid.", + instruction->declaration.count); +} + static void vsir_validate_else(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) { vsir_validate_cf_type(ctx, instruction, VSIR_CF_STRUCTURED); @@ -6278,6 +6380,11 @@ static void vsir_validate_label(struct validation_context *ctx, const struct vkd validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, "Invalid register of type %#x in a LABEL instruction, expected LABEL.", instruction->src[0].reg.type); + + if (ctx->inside_block) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, + "Invalid LABEL instruction inside a block."); + ctx->inside_block = true; } static void vsir_validate_loop(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) @@ -6359,6 +6466,7 @@ static void vsir_validate_rep(struct validation_context *ctx, const struct vkd3d static void vsir_validate_ret(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) { + ctx->inside_block = false; } static void vsir_validate_switch(struct validation_context *ctx, const struct vkd3d_shader_instruction *instruction) @@ -6412,6 +6520,8 @@ static void vsir_validate_switch_monolithic(struct validation_context *ctx, "Invalid label register for case %u of type %#x in monolithic SWITCH instruction, " "expected LABEL.", i, instruction->src[value_idx].reg.type); } + + ctx->inside_block = false; } struct vsir_validator_instruction_desc @@ -6423,23 +6533,36 @@ struct vsir_validator_instruction_desc static const struct vsir_validator_instruction_desc vsir_validator_instructions[] = { - [VKD3DSIH_BRANCH] = {0, ~0u, vsir_validate_branch}, - [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, - [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, - [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, - [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, - [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, - [VKD3DSIH_ENDSWITCH] = {0, 0, vsir_validate_endswitch}, - [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, - [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, - [VKD3DSIH_LABEL] = {0, 1, vsir_validate_label}, - [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, - [VKD3DSIH_NOP] = {0, 0, vsir_validate_nop}, - [VKD3DSIH_PHI] = {1, ~0u, vsir_validate_phi}, - [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, - [VKD3DSIH_RET] = {0, 0, vsir_validate_ret}, - [VKD3DSIH_SWITCH] = {0, 1, vsir_validate_switch}, - [VKD3DSIH_SWITCH_MONOLITHIC] = {0, ~0u, vsir_validate_switch_monolithic}, + [VKD3DSIH_BRANCH] = {0, ~0u, vsir_validate_branch}, + [VKD3DSIH_HS_CONTROL_POINT_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, + [VKD3DSIH_HS_DECLS] = {0, 0, vsir_validate_hull_shader_phase}, + [VKD3DSIH_HS_FORK_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, + [VKD3DSIH_HS_JOIN_PHASE] = {0, 0, vsir_validate_hull_shader_phase}, + [VKD3DSIH_DCL_GS_INSTANCES] = {0, 0, vsir_validate_dcl_gs_instances}, + [VKD3DSIH_DCL_HS_MAX_TESSFACTOR] = {0, 0, vsir_validate_dcl_hs_max_tessfactor}, + [VKD3DSIH_DCL_INPUT_PRIMITIVE] = {0, 0, vsir_validate_dcl_input_primitive}, + [VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT] = {0, 0, vsir_validate_dcl_output_control_point_count}, + [VKD3DSIH_DCL_OUTPUT_TOPOLOGY] = {0, 0, vsir_validate_dcl_output_topology}, + [VKD3DSIH_DCL_TEMPS] = {0, 0, vsir_validate_dcl_temps}, + [VKD3DSIH_DCL_TESSELLATOR_DOMAIN] = {0, 0, vsir_validate_dcl_tessellator_domain}, + [VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE] = {0, 0, vsir_validate_dcl_tessellator_output_primitive}, + [VKD3DSIH_DCL_TESSELLATOR_PARTITIONING] = {0, 0, vsir_validate_dcl_tessellator_partitioning}, + [VKD3DSIH_DCL_VERTICES_OUT] = {0, 0, vsir_validate_dcl_vertices_out}, + [VKD3DSIH_ELSE] = {0, 0, vsir_validate_else}, + [VKD3DSIH_ENDIF] = {0, 0, vsir_validate_endif}, + [VKD3DSIH_ENDLOOP] = {0, 0, vsir_validate_endloop}, + [VKD3DSIH_ENDREP] = {0, 0, vsir_validate_endrep}, + [VKD3DSIH_ENDSWITCH] = {0, 0, vsir_validate_endswitch}, + [VKD3DSIH_IF] = {0, 1, vsir_validate_if}, + [VKD3DSIH_IFC] = {0, 2, vsir_validate_ifc}, + [VKD3DSIH_LABEL] = {0, 1, vsir_validate_label}, + [VKD3DSIH_LOOP] = {0, ~0u, vsir_validate_loop}, + [VKD3DSIH_NOP] = {0, 0, vsir_validate_nop}, + [VKD3DSIH_PHI] = {1, ~0u, vsir_validate_phi}, + [VKD3DSIH_REP] = {0, 1, vsir_validate_rep}, + [VKD3DSIH_RET] = {0, 0, vsir_validate_ret}, + [VKD3DSIH_SWITCH] = {0, 1, vsir_validate_switch}, + [VKD3DSIH_SWITCH_MONOLITHIC] = {0, ~0u, vsir_validate_switch_monolithic}, }; static void vsir_validate_instruction(struct validation_context *ctx) @@ -6462,121 +6585,40 @@ static void vsir_validate_instruction(struct validation_context *ctx) instruction->opcode); } - switch (instruction->opcode) + if (version->type == VKD3D_SHADER_TYPE_HULL && ctx->phase == VKD3DSIH_INVALID) { - case VKD3DSIH_HS_DECLS: - case VKD3DSIH_HS_CONTROL_POINT_PHASE: - case VKD3DSIH_HS_FORK_PHASE: - case VKD3DSIH_HS_JOIN_PHASE: - vsir_validate_dst_count(ctx, instruction, 0); - vsir_validate_src_count(ctx, instruction, 0); - if (version->type != VKD3D_SHADER_TYPE_HULL) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, - "Phase instruction %#x is only valid in a hull shader.", - instruction->opcode); - if (ctx->depth != 0) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, - "Phase instruction %#x must appear to top level.", - instruction->opcode); - ctx->phase = instruction->opcode; - ctx->dcl_temps_found = false; - return; - - case VKD3DSIH_DCL_HS_MAX_TESSFACTOR: - /* Exclude non-finite values. */ - if (!(instruction->declaration.max_tessellation_factor >= 1.0f - && instruction->declaration.max_tessellation_factor <= 64.0f)) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Max tessellation factor %f is invalid.", - instruction->declaration.max_tessellation_factor); - return; - - case VKD3DSIH_DCL_INPUT_PRIMITIVE: - if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED - || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS input primitive %u is invalid.", - instruction->declaration.primitive_type.type); - return; - - case VKD3DSIH_DCL_VERTICES_OUT: - if (instruction->declaration.count > 1024) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output vertex count %u is invalid.", - instruction->declaration.count); - return; - - case VKD3DSIH_DCL_OUTPUT_TOPOLOGY: - if (instruction->declaration.primitive_type.type == VKD3D_PT_UNDEFINED - || instruction->declaration.primitive_type.type >= VKD3D_PT_COUNT) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS output primitive %u is invalid.", - instruction->declaration.primitive_type.type); - return; - - case VKD3DSIH_DCL_GS_INSTANCES: - if (!instruction->declaration.count || instruction->declaration.count > 32) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_GS, "GS instance count %u is invalid.", - instruction->declaration.count); - return; - - case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT: - if (!instruction->declaration.count || instruction->declaration.count > 32) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Output control point count %u is invalid.", - instruction->declaration.count); - return; - - case VKD3DSIH_DCL_TESSELLATOR_DOMAIN: - if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID - || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, - "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain); - return; - - case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: - if (!instruction->declaration.tessellator_output_primitive - || instruction->declaration.tessellator_output_primitive > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, - "Tessellator output primitive %#x is invalid.", instruction->declaration.tessellator_output_primitive); - return; - - case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING: - if (!instruction->declaration.tessellator_partitioning - || instruction->declaration.tessellator_partitioning > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, - "Tessellator partitioning %#x is invalid.", instruction->declaration.tessellator_partitioning); - return; + switch (instruction->opcode) + { + case VKD3DSIH_NOP: + case VKD3DSIH_HS_DECLS: + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + break; - default: - break; + default: + if (!vsir_instruction_is_dcl(instruction)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, + "Instruction %#x appear before any phase instruction in a hull shader.", + instruction->opcode); + break; + } } - /* Only DCL instructions may occur outside hull shader phases. */ - if (!vsir_instruction_is_dcl(instruction) && version->type == VKD3D_SHADER_TYPE_HULL - && ctx->phase == VKD3DSIH_INVALID) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, - "Instruction %#x appear before any phase instruction in a hull shader.", - instruction->opcode); - - if (ctx->program->cf_type == VSIR_CF_BLOCKS && !vsir_instruction_is_dcl(instruction) - && instruction->opcode != VKD3DSIH_NOP) + if (ctx->program->cf_type == VSIR_CF_BLOCKS && !ctx->inside_block) { switch (instruction->opcode) { + case VKD3DSIH_NOP: case VKD3DSIH_LABEL: - if (ctx->inside_block) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid LABEL instruction inside a block."); - ctx->inside_block = true; - break; - - case VKD3DSIH_RET: - case VKD3DSIH_BRANCH: - case VKD3DSIH_SWITCH_MONOLITHIC: - if (!ctx->inside_block) - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, - "Invalid instruction %#x outside any block.", - instruction->opcode); - ctx->inside_block = false; + case VKD3DSIH_HS_DECLS: + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: break; default: - if (!ctx->inside_block) + if (!vsir_instruction_is_dcl(instruction)) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x outside any block.", instruction->opcode); diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c new file mode 100644 index 00000000000..2923494feed --- /dev/null +++ b/libs/vkd3d/libs/vkd3d-shader/msl.c @@ -0,0 +1,129 @@ +/* + * Copyright 2024 Feifan He for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "vkd3d_shader_private.h" + +struct msl_generator +{ + struct vsir_program *program; + struct vkd3d_string_buffer_cache string_buffers; + struct vkd3d_string_buffer *buffer; + struct vkd3d_shader_location location; + struct vkd3d_shader_message_context *message_context; + unsigned int indent; +}; + +static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen, + enum vkd3d_shader_error error, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vkd3d_shader_verror(gen->message_context, &gen->location, error, fmt, args); + va_end(args); +} + +static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent) +{ + vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); +} + + +static void msl_unhandled(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) +{ + msl_print_indent(gen->buffer, gen->indent); + vkd3d_string_buffer_printf(gen->buffer, "/* */\n", ins->opcode); + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled instruction %#x.", ins->opcode); +} + +static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) +{ + gen->location = ins->location; + + switch (ins->opcode) + { + case VKD3DSIH_NOP: + break; + default: + msl_unhandled(gen, ins); + break; + } +} + +static void msl_generator_generate(struct msl_generator *gen) +{ + const struct vkd3d_shader_instruction_array *instructions = &gen->program->instructions; + unsigned int i; + + MESSAGE("Generating a MSL shader. This is unsupported; you get to keep all the pieces if it breaks.\n"); + + vkd3d_string_buffer_printf(gen->buffer, "/* Generated by %s. */\n\n", vkd3d_shader_get_version(NULL, NULL)); + + vkd3d_string_buffer_printf(gen->buffer, "void shader_main()\n{\n"); + + ++gen->indent; + for (i = 0; i < instructions->count; ++i) + { + msl_handle_instruction(gen, &instructions->elements[i]); + } + + vkd3d_string_buffer_printf(gen->buffer, "}\n"); + + if (TRACE_ON()) + vkd3d_string_buffer_trace(gen->buffer); +} + +static void msl_generator_cleanup(struct msl_generator *gen) +{ + vkd3d_string_buffer_release(&gen->string_buffers, gen->buffer); + vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); +} + +static int msl_generator_init(struct msl_generator *gen, struct vsir_program *program, + struct vkd3d_shader_message_context *message_context) +{ + memset(gen, 0, sizeof(*gen)); + gen->program = program; + vkd3d_string_buffer_cache_init(&gen->string_buffers); + if (!(gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers))) + { + vkd3d_string_buffer_cache_cleanup(&gen->string_buffers); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + gen->message_context = message_context; + + return VKD3D_OK; +} + +int msl_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) +{ + struct msl_generator generator; + int ret; + + if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0) + return ret; + + if ((ret = msl_generator_init(&generator, program, message_context)) < 0) + return ret; + msl_generator_generate(&generator); + msl_generator_cleanup(&generator); + + return VKD3D_ERROR_INVALID_SHADER; +} diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index a9d6c9e7c13..48efe1e2d72 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -635,6 +635,16 @@ enum vkd3d_sm4_stat_field VKD3D_STAT_SAMPLE_BIAS, VKD3D_STAT_LOAD, VKD3D_STAT_STORE, + VKD3D_STAT_DCL_VERTICES_OUT, + VKD3D_STAT_DCL_INPUT_PRIMITIVE, + VKD3D_STAT_DCL_OUTPUT_TOPOLOGY, + VKD3D_STAT_DCL_GS_INSTANCES, + VKD3D_STAT_BITWISE, + VKD3D_STAT_ATOMIC, + VKD3D_STAT_TESS_DOMAIN, + VKD3D_STAT_TESS_PARTITIONING, + VKD3D_STAT_TESS_OUTPUT_PRIMITIVE, + VKD3D_STAT_TESS_CONTROL_POINT_COUNT, VKD3D_STAT_COUNT, }; @@ -1809,6 +1819,44 @@ static void init_sm4_lookup_tables(struct vkd3d_sm4_lookup_tables *lookup) {VKD3D_SM5_OP_STORE_UAV_TYPED, VKD3D_STAT_STORE}, {VKD3D_SM5_OP_STORE_RAW, VKD3D_STAT_STORE}, {VKD3D_SM5_OP_STORE_STRUCTURED,VKD3D_STAT_STORE}, + + {VKD3D_SM4_OP_DCL_VERTICES_OUT, VKD3D_STAT_DCL_VERTICES_OUT}, + {VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE, VKD3D_STAT_DCL_INPUT_PRIMITIVE}, + {VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY, VKD3D_STAT_DCL_OUTPUT_TOPOLOGY}, + {VKD3D_SM5_OP_DCL_GS_INSTANCES, VKD3D_STAT_DCL_GS_INSTANCES}, + + {VKD3D_SM4_OP_AND, VKD3D_STAT_BITWISE}, + {VKD3D_SM4_OP_NOT, VKD3D_STAT_BITWISE}, + {VKD3D_SM4_OP_OR, VKD3D_STAT_BITWISE}, + {VKD3D_SM4_OP_XOR, VKD3D_STAT_BITWISE}, + + {VKD3D_SM5_OP_ATOMIC_AND, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_OR, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_XOR, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_CMP_STORE, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_IADD, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_IMAX, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_IMIN, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_UMAX, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_ATOMIC_UMIN, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_ALLOC, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_CONSUME, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_IADD, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_AND, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_OR, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_XOR, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_EXCH, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_CMP_EXCH, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_IMAX, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_IMIN, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_UMAX, VKD3D_STAT_ATOMIC}, + {VKD3D_SM5_OP_IMM_ATOMIC_UMIN, VKD3D_STAT_ATOMIC}, + + {VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN, VKD3D_STAT_TESS_DOMAIN}, + {VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING, VKD3D_STAT_TESS_PARTITIONING}, + {VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE, VKD3D_STAT_TESS_OUTPUT_PRIMITIVE}, + {VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, + {VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT, VKD3D_STAT_TESS_CONTROL_POINT_COUNT}, }; memset(lookup, 0, sizeof(*lookup)); @@ -4353,8 +4401,9 @@ static void sm4_write_src_register(const struct tpf_writer *tpf, const struct vk static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4_instruction *instr) { + enum vkd3d_shader_type shader_type = tpf->ctx->profile->type; + uint32_t token = instr->opcode | instr->extra_bits, opcode; struct vkd3d_bytecode_buffer *buffer = tpf->buffer; - uint32_t token = instr->opcode | instr->extra_bits; enum vkd3d_sm4_stat_field stat_field; unsigned int size, i, j; size_t token_position; @@ -4391,8 +4440,39 @@ static void write_sm4_instruction(const struct tpf_writer *tpf, const struct sm4 ++tpf->stat->fields[VKD3D_STAT_INSTR_COUNT]; - stat_field = get_stat_field_from_sm4_opcode(&tpf->lookup, instr->opcode & VKD3D_SM4_OPCODE_MASK); - ++tpf->stat->fields[stat_field]; + opcode = instr->opcode & VKD3D_SM4_OPCODE_MASK; + stat_field = get_stat_field_from_sm4_opcode(&tpf->lookup, opcode); + + switch (opcode) + { + case VKD3D_SM4_OP_DCL_OUTPUT_TOPOLOGY: + case VKD3D_SM4_OP_DCL_INPUT_PRIMITIVE: + tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM4_PRIMITIVE_TYPE_MASK) + >> VKD3D_SM4_PRIMITIVE_TYPE_SHIFT; + break; + case VKD3D_SM4_OP_DCL_VERTICES_OUT: + case VKD3D_SM5_OP_DCL_GS_INSTANCES: + tpf->stat->fields[stat_field] = instr->idx[0]; + break; + case VKD3D_SM5_OP_DCL_TESSELLATOR_DOMAIN: + case VKD3D_SM5_OP_DCL_TESSELLATOR_PARTITIONING: + case VKD3D_SM5_OP_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: + tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM5_TESSELLATOR_MASK) >> VKD3D_SM5_TESSELLATOR_SHIFT; + break; + case VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT: + case VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT: + if ((shader_type == VKD3D_SHADER_TYPE_HULL && opcode == VKD3D_SM5_OP_DCL_OUTPUT_CONTROL_POINT_COUNT) + || (shader_type == VKD3D_SHADER_TYPE_DOMAIN + && opcode == VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT)) + { + tpf->stat->fields[stat_field] = (instr->opcode & VKD3D_SM5_CONTROL_POINT_COUNT_MASK) + >> VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT; + } + break; + default: + ++tpf->stat->fields[stat_field]; + } + } static bool encode_texel_offset_as_aoffimmi(struct sm4_instruction *instr, @@ -6349,23 +6429,23 @@ static void write_sm4_stat(struct hlsl_ctx *ctx, const struct sm4_stat *stat, st put_u32(&buffer, stat->fields[VKD3D_STAT_MOV]); put_u32(&buffer, stat->fields[VKD3D_STAT_MOVC]); put_u32(&buffer, stat->fields[VKD3D_STAT_CONV]); - put_u32(&buffer, 0); /* Bitwise instructions */ - put_u32(&buffer, 0); /* Input primitive */ - put_u32(&buffer, 0); /* GS output topology */ - put_u32(&buffer, 0); /* GS max output vertex count */ + put_u32(&buffer, stat->fields[VKD3D_STAT_BITWISE]); + put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_INPUT_PRIMITIVE]); + put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_OUTPUT_TOPOLOGY]); + put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_VERTICES_OUT]); put_u32(&buffer, 0); /* Unknown */ put_u32(&buffer, 0); /* Unknown */ put_u32(&buffer, 0); /* Sample frequency */ if (hlsl_version_ge(ctx, 5, 0)) { - put_u32(&buffer, 0); /* GS instance count */ - put_u32(&buffer, 0); /* Control point count */ - put_u32(&buffer, 0); /* HS output primitive */ - put_u32(&buffer, 0); /* HS partitioning */ - put_u32(&buffer, 0); /* Tessellator domain */ + put_u32(&buffer, stat->fields[VKD3D_STAT_DCL_GS_INSTANCES]); + put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_CONTROL_POINT_COUNT]); + put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_OUTPUT_PRIMITIVE]); + put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_PARTITIONING]); + put_u32(&buffer, stat->fields[VKD3D_STAT_TESS_DOMAIN]); put_u32(&buffer, 0); /* Barrier instructions */ - put_u32(&buffer, 0); /* Interlocked instructions */ + put_u32(&buffer, stat->fields[VKD3D_STAT_ATOMIC]); put_u32(&buffer, stat->fields[VKD3D_STAT_STORE]); } -- 2.45.2