diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index fcf5db8e..6b4d3f57 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -224,6 +224,13 @@ enum vkd3d_shader_target VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TARGET), }; +enum vkd3d_shader_target_extension +{ + VKD3D_SHADER_TARGET_EXTENSION_NONE, + + VKD3D_SHADER_TARGET_EXTENSION_SPV_EXT_DEMOTE_TO_HELPER_INVOCATION, +}; + struct vkd3d_shader_compile_arguments { enum vkd3d_shader_structure_type type; @@ -231,8 +238,11 @@ struct vkd3d_shader_compile_arguments enum vkd3d_shader_target target; + unsigned int target_extension_count; + const enum vkd3d_shader_target_extension *target_extensions; + unsigned int parameter_count; - struct vkd3d_shader_parameter *parameters; + const struct vkd3d_shader_parameter *parameters; bool dual_source_blending; const unsigned int *output_swizzles; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index f17c7fa1..0fb499e9 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -266,6 +266,7 @@ struct vkd3d_spirv_builder { uint64_t capability_mask; uint64_t capability_draw_parameters : 1; + uint64_t capability_demote_to_helper_invocation : 1; uint32_t ext_instr_set_glsl_450; SpvExecutionModel execution_model; @@ -311,6 +312,10 @@ static void vkd3d_spirv_enable_capability(struct vkd3d_spirv_builder *builder, { builder->capability_draw_parameters = 1; } + else if (cap == SpvCapabilityDemoteToHelperInvocationEXT) + { + builder->capability_demote_to_helper_invocation = 1; + } else { FIXME("Unhandled capability %#x.\n", cap); @@ -1222,6 +1227,11 @@ static void vkd3d_spirv_build_op_kill(struct vkd3d_spirv_builder *builder) vkd3d_spirv_build_op(&builder->function_stream, SpvOpKill); } +static void vkd3d_spirv_build_op_demote_to_helper_invocation(struct vkd3d_spirv_builder *builder) +{ + vkd3d_spirv_build_op(&builder->function_stream, SpvOpDemoteToHelperInvocationEXT); +} + static void vkd3d_spirv_build_op_return(struct vkd3d_spirv_builder *builder) { vkd3d_spirv_build_op(&builder->function_stream, SpvOpReturn); @@ -1703,10 +1713,14 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, } if (builder->capability_draw_parameters) vkd3d_spirv_build_op_capability(&stream, SpvCapabilityDrawParameters); + if (builder->capability_demote_to_helper_invocation) + vkd3d_spirv_build_op_capability(&stream, SpvCapabilityDemoteToHelperInvocationEXT); /* extensions */ if (builder->capability_draw_parameters) vkd3d_spirv_build_op_extension(&stream, "SPV_KHR_shader_draw_parameters"); + if (builder->capability_demote_to_helper_invocation) + vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_demote_to_helper_invocation"); if (builder->ext_instr_set_glsl_450) vkd3d_spirv_build_op_ext_inst_import(&stream, builder->ext_instr_set_glsl_450, "GLSL.std.450"); @@ -2148,6 +2162,21 @@ static bool vkd3d_dxbc_compiler_is_opengl_target(const struct vkd3d_dxbc_compile return vkd3d_dxbc_compiler_get_target(compiler) == VKD3D_SHADER_TARGET_SPIRV_OPENGL_4_5; } +static bool vkd3d_dxbc_compiler_is_target_extension_supported(const struct vkd3d_dxbc_compiler *compiler, + enum vkd3d_shader_target_extension extension) +{ + const struct vkd3d_shader_compile_arguments *args = compiler->compile_args; + unsigned int i; + + for (i = 0; args && i < args->target_extension_count; ++i) + { + if (args->target_extensions[i] == extension) + return true; + } + + return false; +} + static bool vkd3d_dxbc_compiler_check_shader_visibility(const struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_visibility visibility) { @@ -6477,7 +6506,18 @@ static void vkd3d_dxbc_compiler_emit_kill(struct vkd3d_dxbc_compiler *compiler, merge_block_id = vkd3d_dxbc_compiler_emit_conditional_branch(compiler, instruction, target_id); vkd3d_spirv_build_op_label(builder, target_id); - vkd3d_spirv_build_op_kill(builder); + + if (vkd3d_dxbc_compiler_is_target_extension_supported(compiler, + VKD3D_SHADER_TARGET_EXTENSION_SPV_EXT_DEMOTE_TO_HELPER_INVOCATION)) + { + vkd3d_spirv_build_op_demote_to_helper_invocation(builder); + vkd3d_spirv_build_op_branch(builder, merge_block_id); + } + else + { + vkd3d_spirv_build_op_kill(builder); + } + vkd3d_spirv_build_op_label(builder, merge_block_id); } diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 79466804..26d4a7aa 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -2254,6 +2254,8 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s ps_compile_args.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_ARGUMENTS; ps_compile_args.next = NULL; ps_compile_args.target = VKD3D_SHADER_TARGET_SPIRV_VULKAN_1_0; + ps_compile_args.target_extension_count = 0; + ps_compile_args.target_extensions = NULL; ps_compile_args.parameter_count = ARRAY_SIZE(ps_shader_parameters); ps_compile_args.parameters = ps_shader_parameters; ps_compile_args.dual_source_blending = is_dual_source_blending(&desc->BlendState.RenderTarget[0]);