From: Evan Tang etang@codeweavers.com
--- include/vkd3d_shader.h | 4 ++ libs/vkd3d-shader/spirv.c | 68 ++++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_main.c | 5 +- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 4 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index ece22f2ae..214cb2a77 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -791,6 +791,8 @@ enum vkd3d_shader_spirv_extension VKD3D_SHADER_SPIRV_EXTENSION_EXT_DESCRIPTOR_INDEXING, /** \since 1.3 */ VKD3D_SHADER_SPIRV_EXTENSION_EXT_STENCIL_EXPORT, + /** \since 1.10 */ + VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SPIRV_EXTENSION), }; @@ -1344,6 +1346,8 @@ enum vkd3d_shader_descriptor_info_flag /** The descriptor is a UAV resource, which is globally coherent. * \since 1.9 */ VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_GLOBALLY_COHERENT = 0x00000020, + /** The descriptor is a rasterizer-ordered UAV resource. \since 1.10 */ + VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_RASTERIZER_ORDERED = 0x00000040,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_DESCRIPTOR_INFO_FLAG), }; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 3f96e2924..3a4ae0436 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1880,6 +1880,9 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_descriptor_indexing"); if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityStencilExportEXT)) vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_shader_stencil_export"); + if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityFragmentShaderPixelInterlockEXT) + || vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityFragmentShaderSampleInterlockEXT)) + vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_fragment_shader_interlock");
if (builder->ext_instr_set_glsl_450) vkd3d_spirv_build_op_ext_inst_import(&stream, builder->ext_instr_set_glsl_450, "GLSL.std.450"); @@ -2321,6 +2324,7 @@ struct spirv_compiler size_t spec_constants_size; enum vkd3d_shader_compile_option_formatting_flags formatting; bool write_tess_geom_point_size; + bool wrap_main_in_interlock;
struct vkd3d_string_buffer_cache string_buffers; }; @@ -5939,6 +5943,28 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp if (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_GLOBALLY_COHERENT) vkd3d_spirv_build_op_decorate(builder, var_id, SpvDecorationCoherent, NULL, 0);
+ if (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_RASTERIZER_ORDERED) + { + if (compiler->shader_type != VKD3D_SHADER_TYPE_PIXEL) + { + FIXME("ROV is not supported for shader type %d\n", compiler->shader_type); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INCOMPATIBLE_PROFILE, + "ROV used in non-pixel shader."); + } + else if (spirv_compiler_is_target_extension_supported(compiler, VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK)) + { + /* Will be later converted to SampleInterlockEXT if the shader turns out to run per-sample */ + vkd3d_spirv_enable_capability(builder, SpvCapabilityFragmentShaderPixelInterlockEXT); + compiler->wrap_main_in_interlock = true; + } + else + { + FIXME("The target environment does not support fragment shader interlock.\n"); + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_FRAGMENT_SHADER_INTERLOCK_UNSUPPORTED, + "Cannot enable fragment shader interlock."); + } + } + if (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER) { assert(structure_stride); /* counters are valid only for structured buffers */ @@ -6449,6 +6475,9 @@ static void spirv_compiler_emit_shader_epilogue_invocation(struct spirv_compiler uint32_t arguments[MAX_REG_OUTPUT]; unsigned int i, count;
+ if (compiler->wrap_main_in_interlock) + vkd3d_spirv_build_op(&builder->function_stream, SpvOpEndInvocationInterlockEXT); + if ((function_id = compiler->epilogue_function_id)) { void_id = vkd3d_spirv_get_op_type_void(builder); @@ -9150,6 +9179,21 @@ static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler) if (compiler->xfb_info && compiler->xfb_info->element_count && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY) spirv_compiler_emit_point_size(compiler); + + if (compiler->wrap_main_in_interlock) + { + if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL) + { + assert(compiler->main_block_open); + /* Maybe in the future we can try to shrink the size of the interlocked section */ + vkd3d_spirv_build_op(&compiler->spirv_builder.function_stream, SpvOpBeginInvocationInterlockEXT); + } + else + { + ERR("ROV used in non-pixel shader"); + compiler->wrap_main_in_interlock = false; + } + } }
static bool is_dcl_instruction(enum vkd3d_shader_opcode handler_idx) @@ -9540,6 +9584,28 @@ static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *c } }
+static void spirv_compiler_fix_up_fragment_shader_interlock(struct spirv_compiler *compiler) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + unsigned int i; + + /* We don't know whether to use pixel or sample interlock during initial parse, so fix that up now */ + for (i = 0; i < builder->capabilities_count; i++) + { + if (builder->capabilities[i] == SpvCapabilityFragmentShaderPixelInterlockEXT) + { + SpvExecutionMode mode = SpvExecutionModePixelInterlockOrderedEXT; + if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilitySampleRateShading)) + { + builder->capabilities[i] = SpvCapabilityFragmentShaderSampleInterlockEXT; + mode = SpvExecutionModeSampleInterlockOrderedEXT; + } + spirv_compiler_emit_execution_mode(compiler, mode, NULL, 0); + break; + } + } +} + static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *spirv) @@ -9618,6 +9684,8 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, spirv_compiler_emit_shader_epilogue_function(compiler); }
+ spirv_compiler_fix_up_fragment_shader_interlock(compiler); + if (compiler->strip_debug) vkd3d_spirv_stream_clear(&builder->debug_stream);
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 46a414a4a..d2d6d67fd 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -834,8 +834,11 @@ static void vkd3d_shader_scan_resource_declaration(struct vkd3d_shader_scan_cont { if (flags & VKD3DSUF_GLOBALLY_COHERENT) info_flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_GLOBALLY_COHERENT; + /* ROVs are implicitly globally coherent */ + if (flags & VKD3DSUF_RASTERISER_ORDERED_VIEW) + info_flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_GLOBALLY_COHERENT | VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_RASTERIZER_ORDERED; /* We don't distinguish between APPEND and COUNTER UAVs. */ - flags &= ~(VKD3DSUF_ORDER_PRESERVING_COUNTER | VKD3DSUF_GLOBALLY_COHERENT); + flags &= ~(VKD3DSUF_ORDER_PRESERVING_COUNTER | VKD3DSUF_GLOBALLY_COHERENT | VKD3DSUF_RASTERISER_ORDERED_VIEW); if (flags) FIXME("Unhandled UAV flags %#x.\n", flags); type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index ea3db0267..ee945ba04 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -92,6 +92,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING = 2002, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED = 2003, VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED = 2004, + VKD3D_SHADER_ERROR_SPV_INCOMPATIBLE_PROFILE = 2005, + VKD3D_SHADER_ERROR_SPV_FRAGMENT_SHADER_INTERLOCK_UNSUPPORTED = 2006,
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300, VKD3D_SHADER_WARNING_SPV_INVALID_UAV_FLAGS = 2301,