Based off !306, so leaving it as a draft until that's merged
We don't seem to print anything if a test is skipped due to not meeting its requirements, should we be?
From: Conor McCarthy cmccarthy@codeweavers.com
The flags start at bit 16 in the token. --- libs/vkd3d-shader/tpf.c | 4 ++-- libs/vkd3d-shader/vkd3d_shader_private.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 7949be150..9142ed989 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -95,8 +95,8 @@ STATIC_ASSERT(SM4_MAX_SRC_COUNT <= SPIRV_MAX_SRC_COUNT); #define VKD3D_SM5_FP_ARRAY_SIZE_SHIFT 16 #define VKD3D_SM5_FP_TABLE_COUNT_MASK 0xffffu
-#define VKD3D_SM5_UAV_FLAGS_SHIFT 15 -#define VKD3D_SM5_UAV_FLAGS_MASK (0x1ffu << VKD3D_SM5_UAV_FLAGS_SHIFT) +#define VKD3D_SM5_UAV_FLAGS_SHIFT 16 +#define VKD3D_SM5_UAV_FLAGS_MASK (0xffu << VKD3D_SM5_UAV_FLAGS_SHIFT)
#define VKD3D_SM5_SYNC_FLAGS_SHIFT 11 #define VKD3D_SM5_SYNC_FLAGS_MASK (0xffu << VKD3D_SM5_SYNC_FLAGS_SHIFT) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 84614a4eb..1c9b6e1eb 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -626,8 +626,8 @@ enum vkd3d_shader_sync_flags
enum vkd3d_shader_uav_flags { - VKD3DSUF_GLOBALLY_COHERENT = 0x2, - VKD3DSUF_ORDER_PRESERVING_COUNTER = 0x100, + VKD3DSUF_GLOBALLY_COHERENT = 0x1, + VKD3DSUF_ORDER_PRESERVING_COUNTER = 0x80, };
enum vkd3d_tessellator_domain
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 5 +++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 6 insertions(+)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index d72402eb2..df09445fb 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -477,6 +477,11 @@ static void shader_dump_uav_flags(struct vkd3d_d3d_asm_compiler *compiler, uint3 vkd3d_string_buffer_printf(&compiler->buffer, "_opc"); uav_flags &= ~VKD3DSUF_ORDER_PRESERVING_COUNTER; } + if (uav_flags & VKD3DSUF_RASTERISER_ORDERED_VIEW) + { + vkd3d_string_buffer_printf(&compiler->buffer, "_rov"); + uav_flags &= ~VKD3DSUF_RASTERISER_ORDERED_VIEW; + }
if (uav_flags) vkd3d_string_buffer_printf(&compiler->buffer, "_unknown_flags(%#x)", uav_flags); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 1c9b6e1eb..a5fc5f56d 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -627,6 +627,7 @@ enum vkd3d_shader_sync_flags enum vkd3d_shader_uav_flags { VKD3DSUF_GLOBALLY_COHERENT = 0x1, + VKD3DSUF_RASTERISER_ORDERED_VIEW = 0x2, VKD3DSUF_ORDER_PRESERVING_COUNTER = 0x80, };
From: Conor McCarthy cmccarthy@codeweavers.com
--- include/vkd3d_shader.h | 3 +++ libs/vkd3d-shader/vkd3d_shader_main.c | 26 ++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index cfe54dbff..ece22f2ae 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -1341,6 +1341,9 @@ enum vkd3d_shader_descriptor_info_flag VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_ATOMICS = 0x00000008, /** The descriptor is a raw (byte-addressed) buffer. \since 1.9 */ VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER = 0x00000010, + /** The descriptor is a UAV resource, which is globally coherent. + * \since 1.9 */ + VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_GLOBALLY_COHERENT = 0x00000020,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_DESCRIPTOR_INFO_FLAG), }; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 38f909667..46a414a4a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -819,25 +819,39 @@ static void vkd3d_shader_scan_sampler_declaration(struct vkd3d_shader_scan_conte static void vkd3d_shader_scan_resource_declaration(struct vkd3d_shader_scan_context *context, const struct vkd3d_shader_resource *resource, enum vkd3d_shader_resource_type resource_type, enum vkd3d_shader_resource_data_type resource_data_type, - unsigned int sample_count, unsigned int structure_stride, bool raw) + unsigned int sample_count, unsigned int structure_stride, bool raw, unsigned int flags) { struct vkd3d_shader_descriptor_info1 *d; enum vkd3d_shader_descriptor_type type; + unsigned int info_flags;
if (!context->scan_descriptor_info) return;
+ info_flags = raw ? VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER : 0; + if (resource->reg.reg.type == VKD3DSPR_UAV) + { + if (flags & VKD3DSUF_GLOBALLY_COHERENT) + info_flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_GLOBALLY_COHERENT; + /* We don't distinguish between APPEND and COUNTER UAVs. */ + flags &= ~(VKD3DSUF_ORDER_PRESERVING_COUNTER | VKD3DSUF_GLOBALLY_COHERENT); + if (flags) + FIXME("Unhandled UAV flags %#x.\n", flags); type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; + } else + { + if (flags) + FIXME("Unhandled SRV flags %#x.\n", flags); type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV; + } if (!(d = vkd3d_shader_scan_add_descriptor(context, type, &resource->reg.reg, &resource->range, resource_type, resource_data_type))) return; d->sample_count = sample_count; d->structure_stride = structure_stride; - if (raw) - d->flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER; + d->flags = info_flags; }
static void vkd3d_shader_scan_typed_resource_declaration(struct vkd3d_shader_scan_context *context, @@ -896,7 +910,7 @@ static void vkd3d_shader_scan_typed_resource_declaration(struct vkd3d_shader_sca }
vkd3d_shader_scan_resource_declaration(context, &semantic->resource, - semantic->resource_type, resource_data_type, semantic->sample_count, 0, false); + semantic->resource_type, resource_data_type, semantic->sample_count, 0, false, instruction->flags); }
static void vkd3d_shader_scan_error(struct vkd3d_shader_scan_context *context, @@ -930,13 +944,13 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_DCL_RESOURCE_RAW: case VKD3DSIH_DCL_UAV_RAW: vkd3d_shader_scan_resource_declaration(context, &instruction->declaration.raw_resource.resource, - VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0, 0, true); + VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0, 0, true, instruction->flags); break; case VKD3DSIH_DCL_RESOURCE_STRUCTURED: case VKD3DSIH_DCL_UAV_STRUCTURED: vkd3d_shader_scan_resource_declaration(context, &instruction->declaration.structured_resource.resource, VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0, - instruction->declaration.structured_resource.byte_stride, false); + instruction->declaration.structured_resource.byte_stride, false, instruction->flags); break; case VKD3DSIH_IF: cf_info = vkd3d_shader_scan_push_cf_info(context);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 9b3084538..41104012e 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5936,6 +5936,9 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp if (!(d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ)) vkd3d_spirv_build_op_decorate(builder, var_id, SpvDecorationNonReadable, NULL, 0);
+ 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_COUNTER) { assert(structure_stride); /* counters are valid only for structured buffers */
From: Conor McCarthy cmccarthy@codeweavers.com
The UniformMemory semantic applies the constraints to Uniform storage class memory, which matches how UAV variables are declared. --- libs/vkd3d-shader/spirv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 41104012e..6edcfb2b5 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9074,7 +9074,7 @@ static void spirv_compiler_emit_sync(struct spirv_compiler *compiler, if (flags & VKD3DSSF_GLOBAL_UAV) { memory_scope = SpvScopeDevice; - memory_semantics |= SpvMemorySemanticsImageMemoryMask; + memory_semantics |= SpvMemorySemanticsUniformMemoryMask | SpvMemorySemanticsImageMemoryMask; flags &= ~VKD3DSSF_GLOBAL_UAV; }
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 5 +++++ libs/vkd3d-shader/spirv.c | 13 ++++++++++--- libs/vkd3d-shader/vkd3d_shader_private.h | 2 ++ 3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index df09445fb..c5eeaa413 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -433,6 +433,11 @@ static void shader_dump_sync_flags(struct vkd3d_d3d_asm_compiler *compiler, uint vkd3d_string_buffer_printf(&compiler->buffer, "_uglobal"); sync_flags &= ~VKD3DSSF_GLOBAL_UAV; } + if (sync_flags & VKD3DSSF_THREAD_GROUP_UAV) + { + vkd3d_string_buffer_printf(&compiler->buffer, "_ugroup"); + sync_flags &= ~VKD3DSSF_THREAD_GROUP_UAV; + } if (sync_flags & VKD3DSSF_GROUP_SHARED_MEMORY) { vkd3d_string_buffer_printf(&compiler->buffer, "_g"); diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 6edcfb2b5..3f96e2924 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9053,6 +9053,7 @@ static void spirv_compiler_emit_eval_attrib(struct spirv_compiler *compiler, static void spirv_compiler_emit_sync(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { + const enum vkd3d_shader_sync_flags uav_flags = VKD3DSSF_THREAD_GROUP_UAV | VKD3DSSF_GLOBAL_UAV; unsigned int memory_semantics = SpvMemorySemanticsAcquireReleaseMask; unsigned int flags = instruction->flags; SpvScope execution_scope = SpvScopeMax; @@ -9071,11 +9072,17 @@ static void spirv_compiler_emit_sync(struct spirv_compiler *compiler, flags &= ~VKD3DSSF_THREAD_GROUP; }
- if (flags & VKD3DSSF_GLOBAL_UAV) + if (flags & uav_flags) { - memory_scope = SpvScopeDevice; + if ((flags & uav_flags) == uav_flags) + { + WARN("Invalid UAV sync flag combination; assuming global.\n"); + spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_UAV_FLAGS, + "The flags for a UAV sync instruction are contradictory; assuming global sync."); + } + memory_scope = (flags & VKD3DSSF_GLOBAL_UAV) ? SpvScopeDevice : SpvScopeWorkgroup; memory_semantics |= SpvMemorySemanticsUniformMemoryMask | SpvMemorySemanticsImageMemoryMask; - flags &= ~VKD3DSSF_GLOBAL_UAV; + flags &= ~uav_flags; }
if (flags) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index a5fc5f56d..ea3db0267 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -94,6 +94,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED = 2004,
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300, + VKD3D_SHADER_WARNING_SPV_INVALID_UAV_FLAGS = 2301,
VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY = 3000, VKD3D_SHADER_ERROR_RS_INVALID_VERSION = 3001, @@ -621,6 +622,7 @@ enum vkd3d_shader_sync_flags { VKD3DSSF_THREAD_GROUP = 0x1, VKD3DSSF_GROUP_SHARED_MEMORY = 0x2, + VKD3DSSF_THREAD_GROUP_UAV = 0x4, VKD3DSSF_GLOBAL_UAV = 0x8, };
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,
From: Evan Tang etang@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 3 +- libs/vkd3d-shader/hlsl.h | 7 ++- libs/vkd3d-shader/hlsl.l | 5 ++ libs/vkd3d-shader/hlsl.y | 112 ++++++++++++++++++++++++++------------- libs/vkd3d-shader/tpf.c | 5 ++ 5 files changed, 91 insertions(+), 41 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 8b706e1e6..aa1726cd3 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -720,7 +720,7 @@ struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_ return type; }
-struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format) +struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, unsigned int modifiers) { struct hlsl_type *type;
@@ -731,6 +731,7 @@ struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim type->dimx = format->dimx; type->dimy = 1; type->sampler_dim = dim; + type->modifiers = modifiers; type->e.resource_format = format; hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 8bc72a8a2..919f2be62 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -357,10 +357,13 @@ struct hlsl_attribute #define HLSL_STORAGE_IN 0x00000800 #define HLSL_STORAGE_OUT 0x00001000 #define HLSL_MODIFIER_INLINE 0x00002000 +#define HLSL_MODIFIER_GLOBALLY_COHERENT 0x04000 +#define HLSL_MODIFIER_RASTERIZER_ORDERED 0x8000
#define HLSL_TYPE_MODIFIERS_MASK (HLSL_MODIFIER_PRECISE | HLSL_MODIFIER_VOLATILE | \ HLSL_MODIFIER_CONST | HLSL_MODIFIER_ROW_MAJOR | \ - HLSL_MODIFIER_COLUMN_MAJOR) + HLSL_MODIFIER_COLUMN_MAJOR | HLSL_MODIFIER_GLOBALLY_COHERENT | \ + HLSL_MODIFIER_RASTERIZER_ORDERED)
#define HLSL_MODIFIERS_MAJORITY_MASK (HLSL_MODIFIER_ROW_MAJOR | HLSL_MODIFIER_COLUMN_MAJOR)
@@ -1184,7 +1187,7 @@ struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const cha struct hlsl_type *type, const struct vkd3d_shader_location *loc, bool dummy_scope); struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, unsigned int sample_count); -struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format); +struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, unsigned int modifiers); struct hlsl_ir_node *hlsl_new_uint_constant(struct hlsl_ctx *ctx, unsigned int n, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, diff --git a/libs/vkd3d-shader/hlsl.l b/libs/vkd3d-shader/hlsl.l index e9ae3ccf3..cb7d4f277 100644 --- a/libs/vkd3d-shader/hlsl.l +++ b/libs/vkd3d-shader/hlsl.l @@ -100,6 +100,11 @@ packoffset {return KW_PACKOFFSET; } pass {return KW_PASS; } PixelShader {return KW_PIXELSHADER; } precise {return KW_PRECISE; } +RasterizerOrderedBuffer {return KW_RASTERIZERORDEREDBUFFER; } +RasterizerOrderedStructuredBuffer {return KW_RASTERIZERORDEREDSTRUCTUREDBUFFER; } +RasterizerOrderedTexture1D {return KW_RASTERIZERORDEREDTEXTURE1D; } +RasterizerOrderedTexture2D {return KW_RASTERIZERORDEREDTEXTURE2D; } +RasterizerOrderedTexture3D {return KW_RASTERIZERORDEREDTEXTURE3D; } RasterizerState {return KW_RASTERIZERSTATE; } RenderTargetView {return KW_RENDERTARGETVIEW; } return {return KW_RETURN; } diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 43ea4b4d0..fceef364e 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4568,6 +4568,45 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type } }
+static void validate_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, const struct vkd3d_shader_location* loc) +{ + struct vkd3d_string_buffer *string = hlsl_type_to_string(ctx, format); + + if (!type_contains_only_numerics(format)) + { + if (string) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "UAV type %s is not numeric.", string->buffer); + } + + switch (dim) + { + case HLSL_SAMPLER_DIM_BUFFER: + case HLSL_SAMPLER_DIM_1D: + case HLSL_SAMPLER_DIM_2D: + case HLSL_SAMPLER_DIM_3D: + if (format->class == HLSL_CLASS_ARRAY) + { + if (string) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "This type of UAV does not support array type."); + } + else if (hlsl_type_component_count(format) > 4) + { + if (string) + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "UAV data type %s size exceeds maximum size.", string->buffer); + } + break; + case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER: + break; + default: + vkd3d_unreachable(); + } + + hlsl_release_string_buffer(ctx, string); +} + }
%locations @@ -4639,6 +4678,11 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %token KW_PASS %token KW_PIXELSHADER %token KW_PRECISE +%token KW_RASTERIZERORDEREDBUFFER +%token KW_RASTERIZERORDEREDSTRUCTUREDBUFFER +%token KW_RASTERIZERORDEREDTEXTURE1D +%token KW_RASTERIZERORDEREDTEXTURE2D +%token KW_RASTERIZERORDEREDTEXTURE3D %token KW_RASTERIZERSTATE %token KW_RENDERTARGETVIEW %token KW_RETURN @@ -4795,7 +4839,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %type <reg_reservation> register_opt %type <reg_reservation> packoffset_opt
-%type <sampler_dim> texture_type texture_ms_type uav_type +%type <sampler_dim> texture_type texture_ms_type uav_type rov_type
%type <semantic> semantic
@@ -5474,6 +5518,28 @@ uav_type: $$ = HLSL_SAMPLER_DIM_3D; }
+rov_type: + KW_RASTERIZERORDEREDBUFFER + { + $$ = HLSL_SAMPLER_DIM_BUFFER; + } + | KW_RASTERIZERORDEREDSTRUCTUREDBUFFER + { + $$ = HLSL_SAMPLER_DIM_STRUCTURED_BUFFER; + } + | KW_RASTERIZERORDEREDTEXTURE1D + { + $$ = HLSL_SAMPLER_DIM_1D; + } + | KW_RASTERIZERORDEREDTEXTURE2D + { + $$ = HLSL_SAMPLER_DIM_2D; + } + | KW_RASTERIZERORDEREDTEXTURE3D + { + $$ = HLSL_SAMPLER_DIM_3D; + } + type_no_void: KW_VECTOR '<' type ',' C_INTEGER '>' { @@ -5602,43 +5668,13 @@ type_no_void: } | uav_type '<' type '>' { - struct vkd3d_string_buffer *string = hlsl_type_to_string(ctx, $3); - - if (!type_contains_only_numerics($3)) - { - if (string) - hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "UAV type %s is not numeric.", string->buffer); - } - - switch ($1) - { - case HLSL_SAMPLER_DIM_BUFFER: - case HLSL_SAMPLER_DIM_1D: - case HLSL_SAMPLER_DIM_2D: - case HLSL_SAMPLER_DIM_3D: - if ($3->class == HLSL_CLASS_ARRAY) - { - if (string) - hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "This type of UAV does not support array type."); - } - else if (hlsl_type_component_count($3) > 4) - { - if (string) - hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, - "UAV data type %s size exceeds maximum size.", string->buffer); - } - break; - case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER: - break; - default: - vkd3d_unreachable(); - } - - hlsl_release_string_buffer(ctx, string); - - $$ = hlsl_new_uav_type(ctx, $1, $3); + validate_uav_type(ctx, $1, $3, &@3); + $$ = hlsl_new_uav_type(ctx, $1, $3, 0); + } + | rov_type '<' type '>' + { + validate_uav_type(ctx, $1, $3, &@3); + $$ = hlsl_new_uav_type(ctx, $1, $3, HLSL_MODIFIER_RASTERIZER_ORDERED); } | TYPE_IDENTIFIER { diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 9142ed989..d21a8fc44 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -4098,6 +4098,11 @@ static void write_sm4_dcl_textures(const struct tpf_writer *tpf, const struct ex instr.opcode |= component_type->sample_count << VKD3D_SM4_RESOURCE_SAMPLE_COUNT_SHIFT; }
+ if (resource->data_type->modifiers & HLSL_MODIFIER_RASTERIZER_ORDERED) + instr.opcode |= VKD3DSUF_RASTERISER_ORDERED_VIEW << VKD3D_SM5_UAV_FLAGS_SHIFT; + else if (resource->data_type->modifiers & HLSL_MODIFIER_GLOBALLY_COHERENT) + instr.opcode |= VKD3DSUF_GLOBALLY_COHERENT << VKD3D_SM5_UAV_FLAGS_SHIFT; + write_sm4_instruction(tpf, &instr); } }
From: Evan Tang etang@codeweavers.com
--- libs/vkd3d/device.c | 25 +++++++++++++++++++++++-- libs/vkd3d/vkd3d_private.h | 3 ++- 2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index c33061073..ff2ba9811 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -93,6 +93,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker), VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable), VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing), + VK_EXTENSION(EXT_FRAGMENT_SHADER_INTERLOCK, EXT_fragment_shader_interlock), VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2), VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation), VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export), @@ -756,6 +757,7 @@ struct vkd3d_physical_device_info VkPhysicalDeviceConditionalRenderingFeaturesEXT conditional_rendering_features; VkPhysicalDeviceDepthClipEnableFeaturesEXT depth_clip_features; VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_features; + VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock_features; VkPhysicalDeviceRobustness2FeaturesEXT robustness2_features; VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote_features; VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT texel_buffer_alignment_features; @@ -774,6 +776,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *vertex_divisor_properties; VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *buffer_alignment_properties; VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features; + VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *fragment_shader_interlock_features; VkPhysicalDeviceRobustness2FeaturesEXT *robustness2_features; VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features; VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features; @@ -790,6 +793,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i conditional_rendering_features = &info->conditional_rendering_features; depth_clip_features = &info->depth_clip_features; descriptor_indexing_features = &info->descriptor_indexing_features; + fragment_shader_interlock_features = &info->fragment_shader_interlock_features; robustness2_features = &info->robustness2_features; descriptor_indexing_properties = &info->descriptor_indexing_properties; maintenance3_properties = &info->maintenance3_properties; @@ -810,6 +814,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i vk_prepend_struct(&info->features2, depth_clip_features); descriptor_indexing_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; vk_prepend_struct(&info->features2, descriptor_indexing_features); + fragment_shader_interlock_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT; + vk_prepend_struct(&info->features2, fragment_shader_interlock_features); robustness2_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; vk_prepend_struct(&info->features2, robustness2_features); demote_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT; @@ -1127,6 +1133,7 @@ static void vkd3d_trace_physical_device_features(const struct vkd3d_physical_dev const VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing; const VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features; const VkPhysicalDeviceFeatures *features = &info->features2.features; + const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *fragment_shader_interlock_features; const VkPhysicalDeviceTransformFeedbackFeaturesEXT *xfb;
TRACE("Device features:\n"); @@ -1249,6 +1256,12 @@ static void vkd3d_trace_physical_device_features(const struct vkd3d_physical_dev TRACE(" VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT:\n"); TRACE(" texelBufferAlignment: %#x.\n", buffer_alignment_features->texelBufferAlignment);
+ fragment_shader_interlock_features = &info->fragment_shader_interlock_features; + TRACE(" VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT:\n"); + TRACE(" fragmentShaderSampleInterlock: %#x\n.", fragment_shader_interlock_features->fragmentShaderSampleInterlock); + TRACE(" fragmentShaderPixelInterlock: %#x\n.", fragment_shader_interlock_features->fragmentShaderPixelInterlock); + TRACE(" fragmentShaderShadingRateInterlock: %#x\n.", fragment_shader_interlock_features->fragmentShaderShadingRateInterlock); + xfb = &info->xfb_features; TRACE(" VkPhysicalDeviceTransformFeedbackFeaturesEXT:\n"); TRACE(" transformFeedback: %#x.\n", xfb->transformFeedback); @@ -1440,6 +1453,7 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, const struct vkd3d_vk_instance_procs *vk_procs = &device->vkd3d_instance->vk_procs; const struct vkd3d_optional_device_extensions_info *optional_extensions; VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing; + VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *fragment_shader_interlock; VkPhysicalDevice physical_device = device->vk_physical_device; struct vkd3d_vulkan_info *vulkan_info = &device->vk_info; VkExtensionProperties *vk_extensions; @@ -1501,8 +1515,6 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
device->feature_options.TypedUAVLoadAdditionalFormats = features->shaderStorageImageReadWithoutFormat && d3d12_device_supports_typed_uav_load_additional_formats(device); - /* GL_INTEL_fragment_shader_ordering, no Vulkan equivalent. */ - device->feature_options.ROVsSupported = FALSE; /* GL_INTEL_conservative_rasterization, no Vulkan equivalent. */ device->feature_options.ConservativeRasterizationTier = D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED; device->feature_options.MaxGPUVirtualAddressBitsPerResource = 40; /* FIXME */ @@ -1585,6 +1597,11 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, *user_extension_supported, vulkan_info, "device", device->vkd3d_instance->config_flags & VKD3D_CONFIG_FLAG_VULKAN_DEBUG);
+ fragment_shader_interlock = &physical_device_info->fragment_shader_interlock_features; + if (!fragment_shader_interlock->fragmentShaderSampleInterlock || !fragment_shader_interlock->fragmentShaderPixelInterlock) + vulkan_info->EXT_fragment_shader_interlock = false; + device->feature_options.ROVsSupported = vulkan_info->EXT_fragment_shader_interlock; + if (!physical_device_info->conditional_rendering_features.conditionalRendering) vulkan_info->EXT_conditional_rendering = false; if (!physical_device_info->depth_clip_features.depthClipEnable) @@ -1641,6 +1658,10 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, vulkan_info->shader_extensions[vulkan_info->shader_extension_count++] = VKD3D_SHADER_SPIRV_EXTENSION_EXT_STENCIL_EXPORT;
+ if (vulkan_info->EXT_fragment_shader_interlock) + vulkan_info->shader_extensions[vulkan_info->shader_extension_count++] + = VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK; + /* Disable unused Vulkan features. */ features->shaderTessellationAndGeometryPointSize = VK_FALSE;
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index a18287b4c..d5efd68c4 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -54,7 +54,7 @@
#define VKD3D_MAX_COMPATIBLE_FORMAT_COUNT 6u #define VKD3D_MAX_QUEUE_FAMILY_COUNT 3u -#define VKD3D_MAX_SHADER_EXTENSIONS 3u +#define VKD3D_MAX_SHADER_EXTENSIONS 4u #define VKD3D_MAX_SHADER_STAGES 5u #define VKD3D_MAX_VK_SYNC_OBJECTS 4u #define VKD3D_MAX_DEVICE_BLOCKED_QUEUES 16u @@ -131,6 +131,7 @@ struct vkd3d_vulkan_info bool EXT_debug_marker; bool EXT_depth_clip_enable; bool EXT_descriptor_indexing; + bool EXT_fragment_shader_interlock; bool EXT_robustness2; bool EXT_shader_demote_to_helper_invocation; bool EXT_shader_stencil_export;
From: Evan Tang etang@codeweavers.com
--- libs/vkd3d-shader/hlsl_constant_ops.c | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl_constant_ops.c b/libs/vkd3d-shader/hlsl_constant_ops.c index 41a72ab6c..3a4f29cf4 100644 --- a/libs/vkd3d-shader/hlsl_constant_ops.c +++ b/libs/vkd3d-shader/hlsl_constant_ops.c @@ -231,6 +231,31 @@ static bool fold_neg(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, return true; }
+static bool fold_bit_not(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, + const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src) +{ + enum hlsl_base_type type = dst_type->base_type; + unsigned int k; + + assert(type == src->node.data_type->base_type); + + for (k = 0; k < dst_type->dimx; ++k) + { + switch (type) + { + case HLSL_TYPE_INT: + case HLSL_TYPE_UINT: + dst->u[k].u = ~src->value.u[k].u; + break; + + default: + FIXME("Fold negation for type %s.\n", debug_hlsl_type(ctx, dst_type)); + return false; + } + } + return true; +} + static bool fold_rcp(struct hlsl_ctx *ctx, struct hlsl_constant_value *dst, const struct hlsl_type *dst_type, const struct hlsl_ir_constant *src, const struct vkd3d_shader_location *loc) { @@ -920,6 +945,10 @@ bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, success = fold_neg(ctx, &res, instr->data_type, arg1); break;
+ case HLSL_OP1_BIT_NOT: + success = fold_bit_not(ctx, &res, instr->data_type, arg1); + break; + case HLSL_OP1_RCP: success = fold_rcp(ctx, &res, instr->data_type, arg1, &instr->loc); break;
From: Evan Tang etang@codeweavers.com
--- libs/vkd3d-shader/tpf.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index d21a8fc44..0447818d4 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2740,6 +2740,7 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant
{"position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, {"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION}, + {"sv_primitiveid", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_PRIMITIVE_ID}, {"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_IS_FRONT_FACE},
{"color", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET},
From: Evan Tang etang@codeweavers.com
Good for clearing things to an initial color --- tests/shader_runner.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 05edf5daf..54d3c29b8 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -856,6 +856,18 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o break;
case STATE_RESOURCE: + if (current_resource.data) + { + /* Replicate data to full size of resource */ + size_t target_size = current_resource.texel_size * current_resource.width * current_resource.height; + while (current_resource.data_size < target_size) + { + size_t next_size = min(current_resource.data_size * 2, target_size); + vkd3d_array_reserve((void**)¤t_resource.data, ¤t_resource.data_capacity, next_size, 1); + memcpy(current_resource.data + current_resource.data_size, current_resource.data, next_size - current_resource.data_size); + current_resource.data_size = next_size; + } + } set_resource(runner, runner->ops->create_resource(runner, ¤t_resource)); free(current_resource.data); break;
From: Evan Tang etang@codeweavers.com
--- tests/d3d12.c | 5 --- tests/d3d12_test_utils.h | 48 ----------------------- tests/shader_runner.c | 27 ++++++++++++- tests/utils.h | 82 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 54 deletions(-)
diff --git a/tests/d3d12.c b/tests/d3d12.c index 586b82228..10381fdf0 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -240,11 +240,6 @@ static uint64_t get_readback_uint64(struct resource_readback *rb, unsigned int x return *(uint64_t *)get_readback_data(rb, x, y, 0, sizeof(uint64_t)); }
-static const struct uvec4 *get_readback_uvec4(struct resource_readback *rb, unsigned int x, unsigned int y) -{ - return get_readback_data(rb, x, y, 0, sizeof(struct uvec4)); -} - #define check_sub_resource_float(a, b, c, d, e, f) check_sub_resource_float_(__LINE__, a, b, c, d, e, f) static void check_sub_resource_float_(unsigned int line, ID3D12Resource *resource, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, diff --git a/tests/d3d12_test_utils.h b/tests/d3d12_test_utils.h index ec5ba5c57..6afccd639 100644 --- a/tests/d3d12_test_utils.h +++ b/tests/d3d12_test_utils.h @@ -74,14 +74,6 @@ static void set_viewport(D3D12_VIEWPORT *vp, float x, float y, vp->MaxDepth = max_depth; }
-static bool compare_color(DWORD c1, DWORD c2, BYTE max_diff) -{ - return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) - && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff) - && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff) - && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); -} - static D3D12_SHADER_BYTECODE shader_bytecode(const DWORD *code, size_t size) { D3D12_SHADER_BYTECODE shader_bytecode = { code, size }; @@ -504,12 +496,6 @@ static void get_resource_readback_with_command_list(ID3D12Resource *resource, un assert_that(hr == S_OK, "Failed to map readback buffer, hr %#x.\n", hr); }
-static unsigned int get_readback_uint(struct resource_readback *rb, - unsigned int x, unsigned int y, unsigned int z) -{ - return *(unsigned int *)get_readback_data(rb, x, y, z, sizeof(unsigned int)); -} - static void release_resource_readback(struct d3d12_resource_readback *rb) { D3D12_RANGE range = {0, 0}; @@ -517,40 +503,6 @@ static void release_resource_readback(struct d3d12_resource_readback *rb) ID3D12Resource_Release(rb->resource); }
-#define check_readback_data_uint(a, b, c, d) check_readback_data_uint_(__LINE__, a, b, c, d) -static void check_readback_data_uint_(unsigned int line, struct resource_readback *rb, - const D3D12_BOX *box, unsigned int expected, unsigned int max_diff) -{ - D3D12_BOX b = {0, 0, 0, rb->width, rb->height, rb->depth}; - unsigned int x = 0, y = 0, z; - bool all_match = true; - unsigned int got = 0; - - if (box) - b = *box; - - for (z = b.front; z < b.back; ++z) - { - for (y = b.top; y < b.bottom; ++y) - { - for (x = b.left; x < b.right; ++x) - { - got = get_readback_uint(rb, x, y, z); - if (!compare_color(got, expected, max_diff)) - { - all_match = false; - break; - } - } - if (!all_match) - break; - } - if (!all_match) - break; - } - ok_(line)(all_match, "Got 0x%08x, expected 0x%08x at (%u, %u, %u).\n", got, expected, x, y, z); -} - #define check_sub_resource_uint(a, b, c, d, e, f) check_sub_resource_uint_(__LINE__, a, b, c, d, e, f) static inline void check_sub_resource_uint_(unsigned int line, ID3D12Resource *texture, unsigned int sub_resource_idx, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list, diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 54d3c29b8..19453df3f 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -636,7 +636,16 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) fatal_error("Malformed probe arguments '%s'.\n", line); }
- if (match_string(line, "rgba", &line)) + if (match_string(line, "rgbaui", &line)) + { + struct uvec4 v; + + ret = sscanf(line, "( %i , %i , %i , %i )", &v.x, &v.y, &v.z, &v.w); + if (ret < 4) + fatal_error("Malformed probe arguments '%s'.\n", line); + todo_if(runner->is_todo) check_readback_data_uvec4(rb, &rect, &v); + } + else if (match_string(line, "rgba", &line)) { struct vec4 v;
@@ -647,6 +656,22 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) ulps = 0; todo_if(runner->is_todo) check_readback_data_vec4(rb, &rect, &v, ulps); } + else if (match_string(line, "rui", &line)) + { + unsigned int expect; + D3D12_BOX box; + + box.left = rect.left; + box.right = rect.right; + box.top = rect.top; + box.bottom = rect.bottom; + box.front = 0; + box.back = 1; + ret = sscanf(line, "( %i )", &expect); + if (ret < 1) + fatal_error("Malformed probe arguments '%s'.\n", line); + todo_if(runner->is_todo) check_readback_data_uint(rb, &box, expect, 0); + } else if (match_string(line, "r", &line)) { float expect; diff --git a/tests/utils.h b/tests/utils.h index 670941905..66e01c33d 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -89,6 +89,14 @@ static bool compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) return diff <= max_diff; }
+static bool compare_color(DWORD c1, DWORD c2, BYTE max_diff) +{ + return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) + && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff) + && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff) + && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); +} + static bool compare_float(float f, float g, unsigned int ulps) { int x, y; @@ -144,11 +152,21 @@ static float get_readback_float(const struct resource_readback *rb, unsigned int return *(float *)get_readback_data(rb, x, y, 0, sizeof(float)); }
+static unsigned int get_readback_uint(const struct resource_readback *rb, unsigned int x, unsigned int y, unsigned int z) +{ + return *(unsigned int*)get_readback_data(rb, x, y, z, sizeof(unsigned int)); +} + static const struct vec4 *get_readback_vec4(const struct resource_readback *rb, unsigned int x, unsigned int y) { return get_readback_data(rb, x, y, 0, sizeof(struct vec4)); }
+static const struct uvec4 *get_readback_uvec4(const struct resource_readback *rb, unsigned int x, unsigned int y) +{ + return get_readback_data(rb, x, y, 0, sizeof(struct uvec4)); +} + #define check_readback_data_float(a, b, c, d) check_readback_data_float_(__LINE__, a, b, c, d) static inline void check_readback_data_float_(unsigned int line, const struct resource_readback *rb, const RECT *rect, float expected, unsigned int max_diff) @@ -178,6 +196,40 @@ static inline void check_readback_data_float_(unsigned int line, const struct re ok_(line)(all_match, "Got %.8e, expected %.8e at (%u, %u).\n", got, expected, x, y); }
+#define check_readback_data_uint(a, b, c, d) check_readback_data_uint_(__LINE__, a, b, c, d) +static inline void check_readback_data_uint_(unsigned int line, struct resource_readback *rb, + const D3D12_BOX *box, unsigned int expected, unsigned int max_diff) +{ + D3D12_BOX b = {0, 0, 0, rb->width, rb->height, rb->depth}; + unsigned int x = 0, y = 0, z; + bool all_match = true; + unsigned int got = 0; + + if (box) + b = *box; + + for (z = b.front; z < b.back; ++z) + { + for (y = b.top; y < b.bottom; ++y) + { + for (x = b.left; x < b.right; ++x) + { + got = get_readback_uint(rb, x, y, z); + if (!compare_color(got, expected, max_diff)) + { + all_match = false; + break; + } + } + if (!all_match) + break; + } + if (!all_match) + break; + } + ok_(line)(all_match, "Got 0x%08x, expected 0x%08x at (%u, %u, %u).\n", got, expected, x, y, z); +} + #define check_readback_data_vec4(a, b, c, d) check_readback_data_vec4_(__LINE__, a, b, c, d) static inline void check_readback_data_vec4_(unsigned int line, const struct resource_readback *rb, const RECT *rect, const struct vec4 *expected, unsigned int max_diff) @@ -208,6 +260,36 @@ static inline void check_readback_data_vec4_(unsigned int line, const struct res got.x, got.y, got.z, got.w, expected->x, expected->y, expected->z, expected->w, x, y); }
+#define check_readback_data_uvec4(a, b, c) check_readback_data_uvec4_(__LINE__, a, b, c) +static inline void check_readback_data_uvec4_(unsigned int line, const struct resource_readback *rb, + const RECT *rect, const struct uvec4 *expected) +{ + RECT r = {0, 0, rb->width, rb->height}; + unsigned int x = 0, y = 0; + struct uvec4 got = {0}; + bool all_match = true; + + if (rect) + r = *rect; + + for (y = r.top; y < r.bottom; ++y) + { + for (x = r.left; x < r.right; ++x) + { + got = *get_readback_uvec4(rb, x, y); + if (!compare_uvec4(&got, expected)) + { + all_match = false; + break; + } + } + if (!all_match) + break; + } + ok_(line)(all_match, "Got {0x%08x, 0x%08x, 0x%08x, 0x%08x}, expected {0x%08x, 0x%08x, 0x%08x, 0x%08x} at (%u, %u).\n", + got.x, got.y, got.z, got.w, expected->x, expected->y, expected->z, expected->w, x, y); +} + struct test_options { bool use_warp_device;
From: Evan Tang etang@codeweavers.com
--- tests/shader_runner.c | 23 +++++++ tests/shader_runner.h | 4 ++ tests/shader_runner_d3d11.c | 29 +++++++++ tests/shader_runner_d3d12.c | 30 ++++++++++ tests/shader_runner_vulkan.c | 113 +++++++++++++++++++++++++++++++++-- tests/vulkan_procs.h | 3 +- 6 files changed, 196 insertions(+), 6 deletions(-)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 19453df3f..ade65882e 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -58,6 +58,7 @@ typedef int HRESULT; #include "vkd3d_windows.h" #include "vkd3d_d3dcommon.h" #include "vkd3d_d3dcompiler.h" +#include "vkd3d_shader.h" #include "vkd3d_test.h" #include "shader_runner.h"
@@ -158,6 +159,27 @@ static void parse_require_directive(struct shader_runner *runner, const char *li runner->compile_options |= options[i].option; } } + else if (match_string(line, "features:", &line)) + { + static const struct feature + { + enum vkd3d_shader_spirv_extension extension; + const char* name; + } + features[] = + { + { VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK, "rov" }, + }; + + for (i = 0; i < ARRAY_SIZE(features); ++i) + { + if (match_string(line, features[i].name, &line)) + { + vkd3d_array_reserve((void**)&runner->required_extensions, &runner->required_extension_capacity, runner->required_extension_count + 1, sizeof(*runner->required_extensions)); + runner->required_extensions[runner->required_extension_count++] = features[i].extension; + } + } + } else { fatal_error("Unknown require directive '%s'.\n", line); @@ -1220,6 +1242,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o }
out: + free(runner->required_extensions); for (i = 0; i < runner->input_element_count; ++i) free(runner->input_elements[i].name); free(runner->input_elements); diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 0844943da..687c59876 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -99,6 +99,7 @@ struct input_element #define MAX_RESOURCES 32 #define MAX_SAMPLERS 32
+enum vkd3d_shader_spirv_extension; struct shader_runner { const struct shader_runner_ops *ops; @@ -125,6 +126,9 @@ struct shader_runner size_t input_element_count, input_element_capacity;
unsigned int compile_options; + + enum vkd3d_shader_spirv_extension *required_extensions; + size_t required_extension_count, required_extension_capacity; };
struct shader_runner_ops diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 25b585b14..98fcae620 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -29,6 +29,7 @@ #define __vkd3d_dxgibase_h__ #define __vkd3d_dxgiformat_h__ #include "vkd3d_d3dcompiler.h" +#include "vkd3d_shader.h" #include "shader_runner.h" #include "vkd3d_test.h"
@@ -336,6 +337,33 @@ static ID3D11Buffer *create_buffer(ID3D11Device *device, unsigned int bind_flags return buffer; }
+static bool d3d11_runner_check_requirements(struct shader_runner *r) +{ + struct d3d11_shader_runner *runner = d3d11_shader_runner(r); + ID3D11Device *device = runner->device; + unsigned int i; + + D3D11_FEATURE_DATA_D3D11_OPTIONS2 options2; + + if (FAILED(ID3D11Device_CheckFeatureSupport(device, D3D11_FEATURE_D3D11_OPTIONS2, &options2, sizeof(options2)))) + memset(&options2, 0, sizeof(options2)); + + for (i = 0; i < r->required_extension_count; i++) + { + switch (r->required_extensions[i]) + { + case VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK: + if (!options2.ROVsSupported) + return false; + break; + default: + return false; + } + } + + return true; +} + static struct resource *d3d11_runner_create_resource(struct shader_runner *r, const struct resource_params *params) { struct d3d11_shader_runner *runner = d3d11_shader_runner(r); @@ -724,6 +752,7 @@ static void d3d11_runner_release_readback(struct shader_runner *r, struct resour
static const struct shader_runner_ops d3d11_runner_ops = { + .check_requirements = d3d11_runner_check_requirements, .create_resource = d3d11_runner_create_resource, .destroy_resource = d3d11_runner_destroy_resource, .dispatch = d3d11_runner_dispatch, diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index d620f1e2d..65bdb6a98 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -23,6 +23,7 @@ #define VKD3D_TEST_NO_DEFS #include "d3d12_crosstest.h" #include "shader_runner.h" +#include "vkd3d_shader.h"
struct d3d12_resource { @@ -84,6 +85,34 @@ static ID3D10Blob *compile_shader(const struct d3d12_shader_runner *runner, cons return blob; }
+static bool d3d12_runner_check_requirements(struct shader_runner *r) +{ + struct d3d12_shader_runner *runner = d3d12_shader_runner(r); + ID3D12Device *device = runner->test_context.device; + unsigned int i; + + D3D12_FEATURE_DATA_D3D12_OPTIONS options; + + if (FAILED(ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)))) + memset(&options, 0, sizeof(options)); + + for (i = 0; i < r->required_extension_count; i++) + { + switch (r->required_extensions[i]) + { + case VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK: + if (!options.ROVsSupported) + return false; + break; + default: + return false; + } + } + + return true; +} + + #define MAX_RESOURCE_DESCRIPTORS (MAX_RESOURCES * 2)
static struct resource *d3d12_runner_create_resource(struct shader_runner *r, const struct resource_params *params) @@ -542,6 +571,7 @@ static void d3d12_runner_release_readback(struct shader_runner *r, struct resour
static const struct shader_runner_ops d3d12_runner_ops = { + .check_requirements = d3d12_runner_check_requirements, .create_resource = d3d12_runner_create_resource, .destroy_resource = d3d12_runner_destroy_resource, .dispatch = d3d12_runner_dispatch, diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index a8e59eef2..6e41c31fa 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -70,6 +70,8 @@ struct vulkan_shader_runner uint32_t binding; } samplers[MAX_SAMPLERS];
+ bool EXT_fragment_shader_interlock; + DECLARE_VK_PFN(vkCreateInstance); #define VK_INSTANCE_PFN DECLARE_VK_PFN #define VK_DEVICE_PFN DECLARE_VK_PFN @@ -245,6 +247,27 @@ static VkImageView create_2d_image_view(const struct vulkan_shader_runner *runne return view; }
+static bool vulkan_runner_check_requirements(struct shader_runner *r) +{ + struct vulkan_shader_runner *runner = vulkan_shader_runner(r); + unsigned int i; + + for (i = 0; i < r->required_extension_count; i++) + { + switch (r->required_extensions[i]) + { + case VKD3D_SHADER_SPIRV_EXTENSION_EXT_FRAGMENT_SHADER_INTERLOCK: + if (!runner->EXT_fragment_shader_interlock) + return false; + break; + default: + return false; + } + } + + return true; +} + static struct resource *vulkan_runner_create_resource(struct shader_runner *r, const struct resource_params *params) { struct vulkan_shader_runner *runner = vulkan_shader_runner(r); @@ -455,6 +478,8 @@ static bool compile_shader(const struct vulkan_shader_runner *runner, const char info.target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY;
spirv_info.next = &interface_info; + spirv_info.extensions = runner->r.required_extensions; + spirv_info.extension_count = runner->r.required_extension_count; spirv_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
push_constants.register_space = 0; @@ -1153,6 +1178,7 @@ static void vulkan_runner_release_readback(struct shader_runner *r, struct resou
static const struct shader_runner_ops vulkan_runner_ops = { + .check_requirements = vulkan_runner_check_requirements, .create_resource = vulkan_runner_create_resource, .destroy_resource = vulkan_runner_destroy_resource, .dispatch = vulkan_runner_dispatch, @@ -1185,6 +1211,11 @@ static bool get_graphics_queue_index(const struct vulkan_shader_runner *runner, return false; }
+static const char *const required_instance_extensions[] = +{ + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, +}; + static const char *const required_device_extensions[] = { VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, @@ -1202,6 +1233,24 @@ static bool has_extension(const VkExtensionProperties *extensions, uint32_t coun return false; }
+static bool check_instance_extensions(struct vulkan_shader_runner *runner) +{ + VkExtensionProperties *extensions; + uint32_t i, count; + VK_CALL(vkEnumerateInstanceExtensionProperties(NULL, &count, NULL)); + extensions = calloc(count, sizeof(*extensions)); + VK_CALL(vkEnumerateInstanceExtensionProperties(NULL, &count, extensions)); + for (i = 0; i < ARRAY_SIZE(required_instance_extensions); ++i) + { + if (!has_extension(extensions, count, required_instance_extensions[i])) + { + skip("The Vulkan instance does not support %s\n", required_instance_extensions[i]); + return false; + } + } + return true; +} + static bool check_device_extensions(struct vulkan_shader_runner *runner) { VkPhysicalDevice phys_device = runner->phys_device; @@ -1232,14 +1281,27 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) VkDeviceQueueCreateInfo queue_desc = {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; VkInstanceCreateInfo instance_desc = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; VkDeviceCreateInfo device_desc = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; - VkPhysicalDeviceFeatures ret_features, features; + VkPhysicalDeviceFeatures2 ret_features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fsi_features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT}; + VkExtensionProperties *extension_properties; VkDescriptorPoolSize descriptor_pool_sizes[4]; static const float queue_priority = 1.0f; VkFormatProperties format_props; uint32_t count, graphics_index; VkDevice device; void *libvulkan; + size_t i, j; VkResult vr; + static const struct optional_extension { + const char* name; + size_t offset; + } + optional_extensions[] = + { + { VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME, offsetof(struct vulkan_shader_runner, EXT_fragment_shader_interlock) }, + }; + const char* enabled_extensions[ARRAY_SIZE(optional_extensions) + ARRAY_SIZE(required_device_extensions)];
if (!(libvulkan = vkd3d_dlopen(SONAME_LIBVULKAN))) { @@ -1249,6 +1311,13 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) vkGetInstanceProcAddr = vkd3d_dlsym(libvulkan, "vkGetInstanceProcAddr");
runner->vkCreateInstance = (void *)vkGetInstanceProcAddr(NULL, "vkCreateInstance"); + runner->vkEnumerateInstanceExtensionProperties = (void*)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); + + if (!check_instance_extensions(runner)) + return false; + + instance_desc.enabledExtensionCount = ARRAY_SIZE(required_instance_extensions); + instance_desc.ppEnabledExtensionNames = required_instance_extensions;
if ((vr = VK_CALL(vkCreateInstance(&instance_desc, NULL, &runner->instance))) < 0) { @@ -1280,8 +1349,26 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner)
device_desc.pQueueCreateInfos = &queue_desc; device_desc.queueCreateInfoCount = 1; - device_desc.enabledExtensionCount = ARRAY_SIZE(required_device_extensions); - device_desc.ppEnabledExtensionNames = required_device_extensions; + device_desc.ppEnabledExtensionNames = enabled_extensions; + for (i = 0; i < ARRAY_SIZE(required_device_extensions); i++) + enabled_extensions[device_desc.enabledExtensionCount++] = required_device_extensions[i]; + + count = 0; + VK_CALL(vkEnumerateDeviceExtensionProperties(runner->phys_device, NULL, &count, NULL)); + extension_properties = malloc(count * sizeof(*extension_properties)); + VK_CALL(vkEnumerateDeviceExtensionProperties(runner->phys_device, NULL, &count, extension_properties)); + for (i = 0; i < ARRAY_SIZE(optional_extensions); i++) + { + for (j = 0; j < count; j++) + { + if (0 == strcmp(optional_extensions[i].name, extension_properties[j].extensionName)) + { + enabled_extensions[device_desc.enabledExtensionCount++] = optional_extensions[i].name; + *(bool*)((char*)runner + optional_extensions[i].offset) = true; + } + } + } + free(extension_properties);
queue_desc.queueFamilyIndex = graphics_index; queue_desc.queueCount = 1; @@ -1297,7 +1384,23 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) goto out_destroy_instance; }
- VK_CALL(vkGetPhysicalDeviceFeatures(runner->phys_device, &ret_features)); + if (runner->EXT_fragment_shader_interlock) + { + fsi_features.pNext = ret_features.pNext; + ret_features.pNext = &fsi_features; + } + VK_CALL(vkGetPhysicalDeviceFeatures2KHR(runner->phys_device, &ret_features)); + + if (fsi_features.fragmentShaderPixelInterlock && fsi_features.fragmentShaderSampleInterlock) + { + fsi_features.fragmentShaderShadingRateInterlock = VK_FALSE; + fsi_features.pNext = (void*)device_desc.pNext; + device_desc.pNext = &fsi_features; + } + else + { + runner->EXT_fragment_shader_interlock = false; + }
device_desc.pEnabledFeatures = &features; memset(&features, 0, sizeof(features)); @@ -1305,7 +1408,7 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) /* FIXME: Probably make these optional. */
#define ENABLE_FEATURE(x) \ - if (!ret_features.x) \ + if (!ret_features.features.x) \ { \ skip("The selected Vulkan device does not support " #x ".\n"); \ goto out_destroy_instance; \ diff --git a/tests/vulkan_procs.h b/tests/vulkan_procs.h index 1829133b2..078e93d3a 100644 --- a/tests/vulkan_procs.h +++ b/tests/vulkan_procs.h @@ -36,9 +36,10 @@ VK_INSTANCE_PFN(vkDestroyInstance) /* Load vkDestroyInstance() first. */ VK_INSTANCE_PFN(vkCreateDevice) VK_INSTANCE_PFN(vkEnumerateDeviceExtensionProperties) +VK_INSTANCE_PFN(vkEnumerateInstanceExtensionProperties) VK_INSTANCE_PFN(vkEnumeratePhysicalDevices) VK_INSTANCE_PFN(vkGetDeviceProcAddr) -VK_INSTANCE_PFN(vkGetPhysicalDeviceFeatures) +VK_INSTANCE_PFN(vkGetPhysicalDeviceFeatures2KHR) VK_INSTANCE_PFN(vkGetPhysicalDeviceFormatProperties) VK_INSTANCE_PFN(vkGetPhysicalDeviceMemoryProperties) VK_INSTANCE_PFN(vkGetPhysicalDeviceQueueFamilyProperties)
From: Evan Tang etang@codeweavers.com
--- Makefile.am | 1 + .../hlsl/rasterizer-ordered-views.shader_test | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/hlsl/rasterizer-ordered-views.shader_test
diff --git a/Makefile.am b/Makefile.am index b36358b23..61777271a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -138,6 +138,7 @@ vkd3d_shader_tests = \ tests/hlsl/object-parameters.shader_test \ tests/hlsl/object-references.shader_test \ tests/hlsl/pow.shader_test \ + tests/hlsl/rasterizer-ordered-views.shader_test \ tests/hlsl/reflect.shader_test \ tests/hlsl/register-reservations.shader_test \ tests/hlsl/return-implicit-conversion.shader_test \ diff --git a/tests/hlsl/rasterizer-ordered-views.shader_test b/tests/hlsl/rasterizer-ordered-views.shader_test new file mode 100644 index 000000000..c731d22df --- /dev/null +++ b/tests/hlsl/rasterizer-ordered-views.shader_test @@ -0,0 +1,50 @@ +[require] +shader model >= 5.0 +features: rov + +[vertex shader] +float4 main(uint vid : SV_VertexID) : SV_Position +{ + uint pos = vid % 3; + return float4(pos == 1 ? 3 : -1, pos == 2 ? 3 : -1, 0, 1); +} + +[render target 0] +format r32 uint +size (640, 480) + +[uav 1] +format r32 uint +size (640, 480) +0 + +[texture 0] +format r32g32b32a32 uint +size (1, 1) +0 0 0 0 + +[pixel shader] +RasterizerOrderedTexture2D<uint4> tex : register(u1); +Texture2D<uint4> spin : register(t0); + +uint4 main(float4 pos : SV_Position, uint id : SV_PrimitiveID) : SV_Target +{ + int2 idx = int2(pos.xy); + uint val = tex[idx].x; + uint flag = 1 << (id & 31); + uint expected = flag - 1; + // Slow down shader to increase likelihood of overlap + int2 bufidx = int2(0, 0); + for (uint i = 0; i < 64; i++) { + uint4 extra = spin[bufidx]; + val |= extra; + bufidx = extra.xy; + } + bool ok = val == expected; + tex[idx] = ok ? val | flag : 0; + return val; +} +[test] +draw triangle list 93 +probe uav 1 all rui ( 0x7fffffff ) +probe all rui ( 0x3fffffff )
From: Evan Tang etang@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 136 +++++++++++++++++++---- libs/vkd3d-shader/vkd3d_shader_private.h | 4 + 2 files changed, 119 insertions(+), 21 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 3a4ae0436..482967317 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2324,7 +2324,6 @@ 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; }; @@ -4103,7 +4102,7 @@ static uint32_t spirv_compiler_emit_int_to_bool(struct spirv_compiler *compiler, uint32_t type_id; SpvOp op;
- assert(!(condition & ~(VKD3D_SHADER_CONDITIONAL_OP_NZ | VKD3D_SHADER_CONDITIONAL_OP_Z))); + assert(!(condition & ~(VKD3D_SHADER_CONDITIONAL_OP_NZ | VKD3D_SHADER_CONDITIONAL_OP_Z | VKD3DSI_ROV_MASK)));
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count); op = condition & VKD3D_SHADER_CONDITIONAL_OP_Z ? SpvOpIEqual : SpvOpINotEqual; @@ -5955,7 +5954,6 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp { /* 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 { @@ -6475,9 +6473,6 @@ 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); @@ -7211,6 +7206,9 @@ static void spirv_compiler_emit_return(struct spirv_compiler *compiler, { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ if (instruction->flags & VKD3DSI_ROV_END) + vkd3d_spirv_build_op(&compiler->spirv_builder.function_stream, SpvOpEndInvocationInterlockEXT); + if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY && (is_in_default_phase(compiler) || is_in_control_point_phase(compiler))) spirv_compiler_emit_shader_epilogue_invocation(compiler); @@ -9179,21 +9177,6 @@ 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) @@ -9213,6 +9196,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, spirv_compiler_emit_main_prolog(compiler); }
+ if (instruction->flags & VKD3DSI_ROV_BEGIN) + vkd3d_spirv_build_op(&compiler->spirv_builder.function_stream, SpvOpBeginInvocationInterlockEXT); + switch (instruction->handler_idx) { case VKD3DSIH_DCL_GLOBAL_FLAGS: @@ -9537,6 +9523,10 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, FIXME("Unhandled instruction %#x.\n", instruction->handler_idx); }
+ /* RET and RETP have special handling since they need the end interlock *before* the ret */ + if (instruction->flags & VKD3DSI_ROV_END && instruction->handler_idx != VKD3DSIH_RET && instruction->handler_idx != VKD3DSIH_RETP) + vkd3d_spirv_build_op(&compiler->spirv_builder.function_stream, SpvOpEndInvocationInterlockEXT); + return ret; }
@@ -9606,6 +9596,107 @@ static void spirv_compiler_fix_up_fragment_shader_interlock(struct spirv_compile } }
+static bool spirv_compiler_is_rov_resource(struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg) +{ + const struct vkd3d_symbol *rsrc; + const struct vkd3d_shader_descriptor_info1 *info; + if (reg->type != VKD3DSPR_UAV) + return false; + rsrc = spirv_compiler_find_resource(compiler, reg); + info = spirv_compiler_get_descriptor_info(compiler, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, &rsrc->info.resource.range); + return !!(info->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_RASTERIZER_ORDERED); +} + +static void spirv_compiler_handle_rov(struct spirv_compiler *compiler, struct vkd3d_shader_instruction_array* instructions) +{ + struct vkd3d_shader_instruction *block_begin = NULL; + struct vkd3d_shader_instruction *rov_end = NULL; + unsigned int block_depth = 0; + unsigned int i; + bool rov_access_in_current_block = false; + bool is_in_rov = false; + + /* Begin and end need to be executed once for any run through the shader. + * It's possible to follow if/elses as long as we put one on both sides of the if/else, + * but we'd have to do fun things like make sure there actually is an else, so for now we'll + * force all control flow to happen outside of any loops or if/elses. */ + for (i = 0; i < instructions->count; i++) + { + struct vkd3d_shader_instruction *instruction = &instructions->elements[i]; + bool needs_begin = false; + switch (instruction->handler_idx) + { + case VKD3DSIH_IF: + case VKD3DSIH_LOOP: + case VKD3DSIH_SWITCH: + if (block_depth == 0) + block_begin = instruction; + block_depth++; + break; + + case VKD3DSIH_ENDIF: + case VKD3DSIH_ENDLOOP: + case VKD3DSIH_ENDSWITCH: + assert(block_depth > 0); + block_depth--; + if (block_depth == 0 && rov_access_in_current_block) + { + rov_end = instruction; + rov_access_in_current_block = false; + } + break; + + case VKD3DSIH_RET: + case VKD3DSIH_RETP: + /* Ret needs to end rov, and it can't do that if it hasn't started rov. + * We could begin and end right at the ret, but then we would need to verify that no later instruction + * places a begin before the ret after we process it (via block hoisting) */ + if (!is_in_rov) + needs_begin = true; + if (block_depth != 0) + instruction->flags |= VKD3DSI_ROV_END; + break; + + case VKD3DSIH_LD_UAV_TYPED: + case VKD3DSIH_LD_STRUCTURED: + case VKD3DSIH_LD_RAW: + needs_begin = spirv_compiler_is_rov_resource(compiler, &instruction->src[instruction->src_count - 1].reg); + break; + case VKD3DSIH_STORE_UAV_TYPED: + case VKD3DSIH_STORE_STRUCTURED: + case VKD3DSIH_STORE_RAW: + needs_begin = spirv_compiler_is_rov_resource(compiler, &instruction->dst[0].reg); + break; + + default: + break; + } + + if (needs_begin) + { + struct vkd3d_shader_instruction *rov_begin; + if (block_depth == 0) + { + rov_end = instruction; + rov_begin = instruction; + } + else + { + rov_access_in_current_block = true; + rov_begin = block_begin; + } + if (!is_in_rov) + { + is_in_rov = true; + rov_begin->flags |= VKD3DSI_ROV_BEGIN; + } + } + } + assert(block_depth == 0); + if (rov_end) + rov_end->flags |= VKD3DSI_ROV_END; +} + 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) @@ -9629,6 +9720,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0) return result;
+ if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityFragmentShaderPixelInterlockEXT)) + spirv_compiler_handle_rov(compiler, &parser->instructions); + instructions = parser->instructions; memset(&parser->instructions, 0, sizeof(parser->instructions));
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index ee945ba04..d4e785647 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -658,6 +658,10 @@ enum vkd3d_tessellator_domain | VKD3DSI_PRECISE_Z | VKD3DSI_PRECISE_W) #define VKD3DSI_PRECISE_SHIFT 8
+#define VKD3DSI_ROV_BEGIN 0x1000 +#define VKD3DSI_ROV_END 0x2000 +#define VKD3DSI_ROV_MASK (VKD3DSI_ROV_BEGIN | VKD3DSI_ROV_END) + enum vkd3d_shader_rel_op { VKD3D_SHADER_REL_OP_GT = 1,
We don't seem to print anything if a test is skipped due to not meeting its requirements, should we be?
You're based on a rather old master. Commit https://gitlab.winehq.org/wine/vkd3d/-/commit/c1de65a99ba851f97cb5f345b66a2b... should do what you want, if I interpret it well. It wouldn't be bad to rebase on current master anyway, so that the pipeline is run.
I haven't read the patches yet (I will do it as soon as I can), but it's likely the commit messages might require some work.
On Tue Oct 31 16:07:18 2023 +0000, Giovanni Mascellani wrote:
We don't seem to print anything if a test is skipped due to not
meeting its requirements, should we be? You're based on a rather old master. Commit https://gitlab.winehq.org/wine/vkd3d/-/commit/c1de65a99ba851f97cb5f345b66a2b... should do what you want, if I interpret it well. It wouldn't be bad to rebase on current master anyway, so that the pipeline is run. I haven't read the patches yet (I will do it as soon as I can), but it's likely the commit messages might require some work.
Also, I would reorder the commits in roughly this way: first the tests, then the HLSL compiler, then the SPIR-V and vkd3d bits. The idea is that you implement features in the same order they appear in the pipeline, so that reviewers can follow patches in their order and build on top of earlier patches at each step.
As for commit messages, I think that in general the following features are appreciated: * Terminate each sentence, including the commit subject, with a full stop. * Avoid nominal sentences, like "ROV support", but rather describe what is actually happening with a verb. * When possible, use specific verbs. I won't say that "support" is banned, but often there are better alternatives, like: "Parse ROV types", "Enable EXT_fragment_shader_interlock", "Support SV_PrimitiveID in pixel shaders" (using "pixel shader" rather than "fragment shader" because that change is in the context of the TPF format). * This is probably my taste more than anything, but at least when a certain acronym is often associated with a specific capitalization, I'd use it. Case in point: "SPIR-V".