diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 1cf01616ce76a70b923f53b6dc20e01f77b079d3..d467693bd5929783e8acbf591532207453f8db35 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -9717,6 +9717,7 @@ static void sm6_parser_emit_dcl_tessellator_domain(struct sm6_parser *sm6, ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_TESSELLATOR_DOMAIN); ins->declaration.tessellator_domain = tessellator_domain; + sm6->p.program->tess_domain = tessellator_domain; } static void sm6_parser_validate_control_point_count(struct sm6_parser *sm6, diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index b0e89bededb49d31273b2108675cccb1bf6595cf..56c98d30661fa80b5582578e22fefcd6ec8b8ef4 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -743,6 +743,7 @@ static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *pr case VKD3DSIH_DCL_GLOBAL_FLAGS: case VKD3DSIH_DCL_SAMPLER: case VKD3DSIH_DCL_TEMPS: + case VKD3DSIH_DCL_TESSELLATOR_DOMAIN: case VKD3DSIH_DCL_THREAD_GROUP: case VKD3DSIH_DCL_UAV_TYPED: vkd3d_shader_instruction_make_nop(ins); @@ -6665,6 +6666,9 @@ struct validation_context enum vkd3d_shader_opcode *blocks; size_t depth; size_t blocks_capacity; + + unsigned int outer_tess_idxs[4]; + unsigned int inner_tess_idxs[2]; }; static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *ctx, @@ -7469,9 +7473,11 @@ static void vsir_validate_signature_element(struct validation_context *ctx, const struct shader_signature *signature, enum vsir_signature_type signature_type, unsigned int idx) { + enum vkd3d_tessellator_domain expected_tess_domain = VKD3D_TESSELLATOR_DOMAIN_INVALID; const char *signature_type_name = signature_type_names[signature_type]; const struct signature_element *element = &signature->elements[idx]; - bool integer_type = false; + bool integer_type = false, is_outer = false; + unsigned int semantic_index_max = 0; if (element->register_count == 0) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, @@ -7523,12 +7529,6 @@ static void vsir_validate_signature_element(struct validation_context *ctx, case VKD3D_SHADER_SV_INSTANCE_ID: case VKD3D_SHADER_SV_IS_FRONT_FACE: case VKD3D_SHADER_SV_SAMPLE_INDEX: - case VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE: - case VKD3D_SHADER_SV_TESS_FACTOR_QUADINT: - case VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE: - case VKD3D_SHADER_SV_TESS_FACTOR_TRIINT: - case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET: - case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: case VKD3D_SHADER_SV_TARGET: case VKD3D_SHADER_SV_DEPTH: case VKD3D_SHADER_SV_COVERAGE: @@ -7537,6 +7537,37 @@ static void vsir_validate_signature_element(struct validation_context *ctx, case VKD3D_SHADER_SV_STENCIL_REF: break; + case VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE: + expected_tess_domain = VKD3D_TESSELLATOR_DOMAIN_QUAD; + semantic_index_max = 4; + is_outer = true; + break; + + case VKD3D_SHADER_SV_TESS_FACTOR_QUADINT: + expected_tess_domain = VKD3D_TESSELLATOR_DOMAIN_QUAD; + semantic_index_max = 2; + is_outer = false; + break; + + case VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE: + expected_tess_domain = VKD3D_TESSELLATOR_DOMAIN_TRIANGLE; + semantic_index_max = 3; + is_outer = true; + break; + + case VKD3D_SHADER_SV_TESS_FACTOR_TRIINT: + expected_tess_domain = VKD3D_TESSELLATOR_DOMAIN_TRIANGLE; + semantic_index_max = 1; + is_outer = false; + break; + + case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET: + case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: + expected_tess_domain = VKD3D_TESSELLATOR_DOMAIN_LINE; + semantic_index_max = 2; + is_outer = true; + break; + default: validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid system value semantic %#x.", @@ -7544,6 +7575,38 @@ static void vsir_validate_signature_element(struct validation_context *ctx, break; } + if (expected_tess_domain != VKD3D_TESSELLATOR_DOMAIN_INVALID) + { + if (signature_type != SIGNATURE_TYPE_PATCH_CONSTANT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: System value semantic %#x is only valid " + "in the patch constant signature.", + idx, signature_type_name, element->sysval_semantic); + + if (ctx->program->tess_domain != expected_tess_domain) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid system value semantic %#x for tessellator domain %#x.", + idx, signature_type_name, element->sysval_semantic, ctx->program->tess_domain); + + if (element->semantic_index >= semantic_index_max) + { + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid semantic index %u for system value semantic %#x.", + idx, signature_type_name, element->semantic_index, element->sysval_semantic); + } + else + { + unsigned int *idx_pos = &(is_outer ? ctx->outer_tess_idxs : ctx->inner_tess_idxs)[element->semantic_index]; + + if (*idx_pos != ~0u) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Duplicate semantic index %u for system value semantic %#x.", + idx, signature_type_name, element->semantic_index, element->sysval_semantic); + else + *idx_pos = idx; + } + } + if (element->sysval_semantic < ARRAY_SIZE(sysval_validation_data)) { const struct sysval_validation_data_element *data = &sysval_validation_data[element->sysval_semantic]; @@ -7801,6 +7864,11 @@ static void vsir_validate_dcl_tessellator_domain(struct validation_context *ctx, || 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); + + if (instruction->declaration.tessellator_domain != ctx->program->tess_domain) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "DCL_TESSELLATOR_DOMAIN argument %#x doesn't match the shader tessellator domain %#x.", + instruction->declaration.tessellator_domain, ctx->program->tess_domain); } static void vsir_validate_dcl_tessellator_output_primitive(struct validation_context *ctx, @@ -8177,6 +8245,12 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c .status = VKD3D_OK, .phase = VKD3DSIH_INVALID, .invalid_instruction_idx = true, + .outer_tess_idxs[0] = ~0u, + .outer_tess_idxs[1] = ~0u, + .outer_tess_idxs[2] = ~0u, + .outer_tess_idxs[3] = ~0u, + .inner_tess_idxs[0] = ~0u, + .inner_tess_idxs[1] = ~0u, }; unsigned int i; @@ -8187,12 +8261,20 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c { case VKD3D_SHADER_TYPE_HULL: case VKD3D_SHADER_TYPE_DOMAIN: + if (program->tess_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID + || program->tess_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) + validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Invalid tessellation domain %#x.", program->tess_domain); break; default: if (program->patch_constant_signature.element_count != 0) validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "Patch constant signature is only valid for hull and domain shaders."); + + if (program->tess_domain != VKD3D_TESSELLATOR_DOMAIN_INVALID) + validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Invalid tessellation domain %#x.", program->tess_domain); } switch (program->shader_version.type) diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index b9876e743a09cd5cd1a10378608076f3d28bb5c9..ef5456430c126c176fca0d2a20bf6d79072ee6f4 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -6822,15 +6822,11 @@ static void spirv_compiler_emit_dcl_gs_instances(struct spirv_compiler *compiler compiler->spirv_builder.invocation_count = instruction->declaration.count; } -static void spirv_compiler_emit_dcl_tessellator_domain(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) +static void spirv_compiler_emit_tessellator_domain(struct spirv_compiler *compiler, + enum vkd3d_tessellator_domain domain) { - enum vkd3d_tessellator_domain domain = instruction->declaration.tessellator_domain; SpvExecutionMode mode; - if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && spirv_compiler_is_opengl_target(compiler)) - return; - switch (domain) { case VKD3D_TESSELLATOR_DOMAIN_LINE: @@ -10239,9 +10235,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT: spirv_compiler_emit_output_vertex_count(compiler, instruction); break; - case VKD3DSIH_DCL_TESSELLATOR_DOMAIN: - spirv_compiler_emit_dcl_tessellator_domain(compiler, instruction); - break; case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: spirv_compiler_emit_tessellator_output_primitive(compiler, instruction->declaration.tessellator_output_primitive); @@ -10743,6 +10736,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, struct compiler->input_control_point_count = program->input_control_point_count; compiler->output_control_point_count = program->output_control_point_count; + if (program->shader_version.type == VKD3D_SHADER_TYPE_HULL && !spirv_compiler_is_opengl_target(compiler)) + spirv_compiler_emit_tessellator_domain(compiler, program->tess_domain); + if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) spirv_compiler_emit_shader_signature_outputs(compiler); diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 0c20981b4dd321c0413bfa14f15b12b73cd7c5bf..e1ca5d6f0aca095b4ba4bc8d5edf6047427cd845 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -1268,6 +1268,7 @@ static void shader_sm5_read_dcl_tessellator_domain(struct vkd3d_shader_instructi { ins->declaration.tessellator_domain = (opcode_token & VKD3D_SM5_TESSELLATOR_MASK) >> VKD3D_SM5_TESSELLATOR_SHIFT; + priv->p.program->tess_domain = ins->declaration.tessellator_domain; } static void shader_sm5_read_dcl_tessellator_partitioning(struct vkd3d_shader_instruction *ins, uint32_t opcode, diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index c3f9dc2e5a02f06c80323a07129fe874c7358440..b9f2b25c84c93aefea65b31adfed636620af919d 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1431,6 +1431,7 @@ struct vsir_program uint8_t diffuse_written_mask; enum vsir_control_flow_type cf_type; enum vsir_normalisation_level normalisation_level; + enum vkd3d_tessellator_domain tess_domain; const char **block_names; size_t block_name_count;