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?
-- v2: vkd3d-shader/spirv: Add optimization pass to reduce scope of fsi begin/end in ROV translation. vkd3d: Enable EXT_fragment_shader_interlock. vkd3d-shader/spirv: Compile ROV to fragment shader interlock. vkd3d-shader/hlsl: Parse ROV types. vkd3d-shader/hlsl: Support SV_PrimitiveID in pixel shaders. tests: Add ROV test. tests: Support specifying required spirv extensions. tests: Support testing for integer pixel data. tests: Replicate init data across resources. vkd3d-shader: Add EXT_fragment_shader_interlock extension. vkd3d-shader/spirv: Handle thread group UAV barriers. vkd3d-shader/spirv: Include Uniform in the memory semantics for UAV barriers. vkd3d-shader/spirv: Handle globally coherent UAVs. vkd3d-shader: Introduce a UAV_GLOBALLY_COHERENT descriptor info flag. vkd3d-shader/d3d-asm: Trace the RASTERISER_ORDERED_VIEW UAV flag. vkd3d-shader/tpf: Fix extraction of the UAV declaration flags.
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 bf4c03c05..5686ef143 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 85041f2a5..cdfadd620 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -682,8 +682,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 5a75cf25e..197c689d4 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -478,6 +478,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 cdfadd620..b0d021a28 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -683,6 +683,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 f112e7c75..0db1ced68 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -1343,6 +1343,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 052edeb50..fc61f0481 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -849,25 +849,39 @@ static void vkd3d_shader_scan_combined_sampler_declaration( 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, @@ -926,7 +940,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, @@ -966,13 +980,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 bd9e7a336..8c2faeafc 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5990,6 +5990,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 8c2faeafc..eae75fa97 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9198,7 +9198,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 | 15 ++++++++++++--- libs/vkd3d-shader/vkd3d_shader_private.h | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 197c689d4..c7a96443c 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -434,6 +434,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 eae75fa97..08384e112 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9195,11 +9195,20 @@ static void spirv_compiler_emit_sync(struct spirv_compiler *compiler, flags &= ~VKD3DSSF_THREAD_GROUP; }
- if (flags & VKD3DSSF_GLOBAL_UAV) + if (flags & (VKD3DSSF_THREAD_GROUP_UAV | VKD3DSSF_GLOBAL_UAV)) { - memory_scope = SpvScopeDevice; + bool group_uav = flags & VKD3DSSF_THREAD_GROUP_UAV; + bool global_uav = flags & VKD3DSSF_GLOBAL_UAV; + + if (group_uav && global_uav) + { + 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 = global_uav ? SpvScopeDevice : SpvScopeWorkgroup; memory_semantics |= SpvMemorySemanticsUniformMemoryMask | SpvMemorySemanticsImageMemoryMask; - flags &= ~VKD3DSSF_GLOBAL_UAV; + flags &= ~(VKD3DSSF_THREAD_GROUP_UAV | VKD3DSSF_GLOBAL_UAV); }
if (flags) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index b0d021a28..0de814221 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -95,6 +95,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY = 2005,
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, @@ -677,6 +678,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 | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 0db1ced68..46c685449 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -793,6 +793,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), };
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 9b9d1d9e4..f6948b765 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1081,6 +1081,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 c2a6ca92e..a007d281b 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -254,11 +254,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 2c7b10f45..d65bf636e 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 }; @@ -509,12 +501,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}; @@ -522,40 +508,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 f6948b765..99f4b5c10 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -671,7 +671,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;
@@ -682,6 +691,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 99f4b5c10..5a8761395 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" #include "dxcompiler.h" @@ -189,6 +190,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); @@ -1417,6 +1439,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o } }
+ 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 3efbcf362..9ab534dfa 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -109,6 +109,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; @@ -136,6 +137,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 bd9d363ce..282f42e2c 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 8453617ef..4a3544b81 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -24,6 +24,7 @@ #include "d3d12_crosstest.h" #include "shader_runner.h" #include "dxcompiler.h" +#include "vkd3d_shader.h"
struct d3d12_resource { @@ -96,6 +97,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) @@ -567,6 +596,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 f89b4d624..2eaa3492f 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; @@ -1157,6 +1182,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, @@ -1189,6 +1215,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, @@ -1207,6 +1238,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; @@ -1237,14 +1286,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))) { @@ -1254,6 +1316,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) { @@ -1285,8 +1354,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; @@ -1302,7 +1389,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)); @@ -1310,7 +1413,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 8364aaa37..bbc144ad3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -140,6 +140,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..d40be4314 --- /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 todo] +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] +todo draw triangle list 93 +probe uav 1 all rui ( 0x7fffffff ) +probe all rui ( 0x3fffffff )
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 5686ef143..5e65f843c 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2749,6 +2749,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
--- libs/vkd3d-shader/hlsl.c | 3 +- libs/vkd3d-shader/hlsl.h | 39 +++--- libs/vkd3d-shader/hlsl.l | 5 + libs/vkd3d-shader/hlsl.y | 112 ++++++++++++------ libs/vkd3d-shader/tpf.c | 5 + .../hlsl/rasterizer-ordered-views.shader_test | 8 +- 6 files changed, 111 insertions(+), 61 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index b42e30888..af6586fe7 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -759,7 +759,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;
@@ -770,6 +770,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 9f1a3fe21..15674dbff 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -340,26 +340,29 @@ struct hlsl_attribute struct hlsl_src args[]; };
-#define HLSL_STORAGE_EXTERN 0x00000001 -#define HLSL_STORAGE_NOINTERPOLATION 0x00000002 -#define HLSL_MODIFIER_PRECISE 0x00000004 -#define HLSL_STORAGE_SHARED 0x00000008 -#define HLSL_STORAGE_GROUPSHARED 0x00000010 -#define HLSL_STORAGE_STATIC 0x00000020 -#define HLSL_STORAGE_UNIFORM 0x00000040 -#define HLSL_MODIFIER_VOLATILE 0x00000080 -#define HLSL_MODIFIER_CONST 0x00000100 -#define HLSL_MODIFIER_ROW_MAJOR 0x00000200 -#define HLSL_MODIFIER_COLUMN_MAJOR 0x00000400 -#define HLSL_STORAGE_IN 0x00000800 -#define HLSL_STORAGE_OUT 0x00001000 -#define HLSL_MODIFIER_INLINE 0x00002000 -#define HLSL_STORAGE_CENTROID 0x00004000 -#define HLSL_STORAGE_NOPERSPECTIVE 0x00008000 +#define HLSL_STORAGE_EXTERN 0x00000001 +#define HLSL_STORAGE_NOINTERPOLATION 0x00000002 +#define HLSL_MODIFIER_PRECISE 0x00000004 +#define HLSL_STORAGE_SHARED 0x00000008 +#define HLSL_STORAGE_GROUPSHARED 0x00000010 +#define HLSL_STORAGE_STATIC 0x00000020 +#define HLSL_STORAGE_UNIFORM 0x00000040 +#define HLSL_MODIFIER_VOLATILE 0x00000080 +#define HLSL_MODIFIER_CONST 0x00000100 +#define HLSL_MODIFIER_ROW_MAJOR 0x00000200 +#define HLSL_MODIFIER_COLUMN_MAJOR 0x00000400 +#define HLSL_STORAGE_IN 0x00000800 +#define HLSL_STORAGE_OUT 0x00001000 +#define HLSL_MODIFIER_INLINE 0x00002000 +#define HLSL_STORAGE_CENTROID 0x00004000 +#define HLSL_STORAGE_NOPERSPECTIVE 0x00008000 +#define HLSL_MODIFIER_GLOBALLY_COHERENT 0x00010000 +#define HLSL_MODIFIER_RASTERIZER_ORDERED 0x00020000
#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_INTERPOLATION_MODIFIERS_MASK (HLSL_STORAGE_NOINTERPOLATION | HLSL_STORAGE_CENTROID | \ HLSL_STORAGE_NOPERSPECTIVE) @@ -1203,7 +1206,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 90abd64a3..a98693f50 100644 --- a/libs/vkd3d-shader/hlsl.l +++ b/libs/vkd3d-shader/hlsl.l @@ -102,6 +102,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 ba738473f..198fc0b1c 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4641,6 +4641,45 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) return scope->upper ? get_loop_scope(scope->upper) : NULL; }
+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 @@ -4714,6 +4753,11 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) %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 @@ -4870,7 +4914,7 @@ static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) %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
@@ -5556,6 +5600,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 '>' { @@ -5684,43 +5750,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 5e65f843c..c58609472 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -4106,6 +4106,11 @@ static void write_sm4_dcl_textures(const struct tpf_writer *tpf, const struct ex instr.extra_bits |= 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); } } diff --git a/tests/hlsl/rasterizer-ordered-views.shader_test b/tests/hlsl/rasterizer-ordered-views.shader_test index d40be4314..6ab453c38 100644 --- a/tests/hlsl/rasterizer-ordered-views.shader_test +++ b/tests/hlsl/rasterizer-ordered-views.shader_test @@ -23,7 +23,7 @@ format r32g32b32a32 uint size (1, 1) 0 0 0 0
-[pixel shader todo] +[pixel shader] RasterizerOrderedTexture2D<uint4> tex : register(u1); Texture2D<uint4> spin : register(t0);
@@ -45,6 +45,6 @@ uint4 main(float4 pos : SV_Position, uint id : SV_PrimitiveID) : SV_Target return val; } [test] -todo draw triangle list 93 -probe uav 1 all rui ( 0x7fffffff ) -probe all rui ( 0x3fffffff ) +todo(sm>=6) draw triangle list 93 +todo probe uav 1 all rui ( 0x7fffffff ) +todo probe all rui ( 0x3fffffff )
From: Evan Tang etang@codeweavers.com
--- include/vkd3d_shader.h | 2 + libs/vkd3d-shader/spirv.c | 68 +++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_main.c | 5 +- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + .../hlsl/rasterizer-ordered-views.shader_test | 4 +- 5 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 46c685449..8f686cea7 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -1348,6 +1348,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 08384e112..7863b985d 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1893,6 +1893,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"); @@ -2334,6 +2337,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;
@@ -5993,6 +5997,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 */ @@ -6496,6 +6522,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); @@ -9276,6 +9305,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) @@ -9670,6 +9714,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) @@ -9750,6 +9816,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 fc61f0481..ca42b1a9d 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -864,8 +864,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 0de814221..603291808 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -93,6 +93,8 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED = 2003, VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED = 2004, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY = 2005, + VKD3D_SHADER_ERROR_SPV_INCOMPATIBLE_PROFILE = 2006, + VKD3D_SHADER_ERROR_SPV_FRAGMENT_SHADER_INTERLOCK_UNSUPPORTED = 2007,
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300, VKD3D_SHADER_WARNING_SPV_INVALID_UAV_FLAGS = 2301, diff --git a/tests/hlsl/rasterizer-ordered-views.shader_test b/tests/hlsl/rasterizer-ordered-views.shader_test index 6ab453c38..f081f956f 100644 --- a/tests/hlsl/rasterizer-ordered-views.shader_test +++ b/tests/hlsl/rasterizer-ordered-views.shader_test @@ -46,5 +46,5 @@ uint4 main(float4 pos : SV_Position, uint id : SV_PrimitiveID) : SV_Target } [test] todo(sm>=6) draw triangle list 93 -todo probe uav 1 all rui ( 0x7fffffff ) -todo probe all rui ( 0x3fffffff ) +probe uav 1 all rui ( 0x7fffffff ) +probe all rui ( 0x3fffffff )
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 2d7051f3a..213bafbe0 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -94,6 +94,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), @@ -757,6 +758,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; @@ -775,6 +777,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; @@ -791,6 +794,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; @@ -811,6 +815,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; @@ -1128,6 +1134,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"); @@ -1250,6 +1257,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); @@ -1441,6 +1454,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; @@ -1502,8 +1516,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 */ @@ -1586,6 +1598,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) @@ -1642,6 +1659,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 2e9845dfa..bd3cd1bde 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -55,7 +55,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 @@ -133,6 +133,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/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 7863b985d..07b00ee64 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2337,7 +2337,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;
@@ -4156,7 +4155,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; @@ -6009,7 +6008,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 { @@ -6522,9 +6520,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); @@ -7335,6 +7330,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); @@ -9305,21 +9303,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) @@ -9339,6 +9322,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: @@ -9667,6 +9653,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; }
@@ -9736,6 +9726,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) @@ -9761,6 +9852,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 603291808..207b241c4 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -714,6 +714,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,
On Tue Oct 31 16:07:18 2023 +0000, Giovanni Mascellani wrote:
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".
I reordered the commits.
One minus of adding tests first is in b1a7c4efc3e1428e05bc3c1d509495272a00fbdf, the todos can fail if your GPU runs everything ordered regardless of FSI (e.g. my Intel iGPU and probably llvmpipe).
Commit https://gitlab.winehq.org/wine/vkd3d/-/commit/c1de65a99ba851f97cb5f345b66a2b... should do what you want, if I interpret it well.
It does not. For an example of what I mean, check out 0605202ea21b58ee826831586f4d4e138eaecc80 and run `build/tests/shader_runner tests/hlsl/rasterizer-ordered-views.shader_test`, and compare it to the results on the final commit. The test succeeds, but doesn't run at all on vkd3d because vkd3d doesn't advertise ROV support. The only indication that the test is succeeding due to lack of support (rather than actually running the test) is the fact that there's ~50 fewer tests run than there should be. Which means that if you mess up adding the support flag (e.g. because you checked FSI status before `vkd3d_check_extensions` is run), you'll still pass the tests and might not notice that your code isn't actually being tested.