From aeae8322da7065c2968f5b88ff1e7e0a05e62a67 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Mon, 21 Oct 2024 00:21:00 +0200 Subject: [PATCH] tests: Add a test for actual multisample loads. The existing test loads from a single sample texture. --- tests/hlsl/texture-load.shader_test | 53 ++++++++++++++++++++++ tests/shader_runner.c | 44 ++++++++++++++++++ tests/shader_runner.h | 1 + tests/shader_runner_d3d11.c | 12 +++++ tests/shader_runner_d3d12.c | 28 ++++++++++++ tests/shader_runner_d3d9.c | 6 +++ tests/shader_runner_gl.c | 24 ++++++++++ tests/shader_runner_vulkan.c | 70 ++++++++++++++++++++++++++--- tests/vulkan_procs.h | 1 + 9 files changed, 232 insertions(+), 7 deletions(-) diff --git a/tests/hlsl/texture-load.shader_test b/tests/hlsl/texture-load.shader_test index b1b3d852..759e9342 100644 --- a/tests/hlsl/texture-load.shader_test +++ b/tests/hlsl/texture-load.shader_test @@ -145,3 +145,56 @@ probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) probe (1, 0) rgba (0.5, 0.7, 0.6, 0.8) probe (0, 1) rgba (0.6, 0.5, 0.2, 0.1) probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0) + +% Test an actual multisample load + +[require] +shader model >= 4.1 + +[rtv 0] +format r32g32b32a32-float +size (2dms, 4, 64, 64) + +[srv 0] +format r32g32b32a32-float +size (2dms, 4, 64, 64) + +[pixel shader] +float4 main(uint id : sv_sampleindex) : sv_target +{ + return float4(1u << id, 0.25f, 0.5f, 1.0f); +} + +[test] +clear rtv 0 0.0 0.0 0.0 0.0 +todo(glsl | sm>=6) draw quad +probe (32, 32) rgba(3.75, 0.25, 0.5, 1.0) +copy rtv 0 srv 0 + +[rtv 0] +format r32g32b32a32-float +size (2d, 64, 64) + +[pixel shader] +Texture2DMS t; +uint sample; + +float4 main(float4 position : sv_position) : sv_target +{ + float2 p = position.xy / 64.0f; + return t.Load(p, sample); +} + +[test] +uniform 0 uint 0 +todo(glsl) draw quad +todo(sm>=6) probe (32, 32) rgba(1.0, 0.25, 0.5, 1.0) +uniform 0 uint 1 +todo(glsl) draw quad +todo(sm>=6) probe (32, 32) rgba(2.0, 0.25, 0.5, 1.0) +uniform 0 uint 2 +todo(glsl) draw quad +todo(sm>=6) probe (32, 32) rgba(4.0, 0.25, 0.5, 1.0) +uniform 0 uint 3 +todo(glsl) draw quad +todo(sm>=6) probe (32, 32) rgba(8.0, 0.25, 0.5, 1.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 83264de9..5a311aae 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -845,6 +845,30 @@ static void read_uint64_t2(const char **line, struct u64vec2 *v) read_uint64(line, &v->y, true); } +static struct resource *parse_resource_reference(struct shader_runner *runner, const char **const line) +{ + enum resource_type type; + unsigned int slot = 0; + + if (match_string(*line, "dsv", line)) + type = RESOURCE_TYPE_DEPTH_STENCIL; + else if (match_string(*line, "rtv", line)) + type = RESOURCE_TYPE_RENDER_TARGET; + else if (match_string(*line, "srv", line)) + type = RESOURCE_TYPE_TEXTURE; + else if (match_string(*line, "uav", line)) + type = RESOURCE_TYPE_UAV; + else if (match_string(*line, "vb", line)) + type = RESOURCE_TYPE_VERTEX_BUFFER; + else + fatal_error("Malformed resource reference '%s'.\n", *line); + + if (type != RESOURCE_TYPE_DEPTH_STENCIL) + read_uint(line, &slot, false); + + return shader_runner_get_resource(runner, type, slot); +} + static void parse_test_directive(struct shader_runner *runner, const char *line) { bool skip_directive = false; @@ -1044,6 +1068,26 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) runner->last_render_failed = !runner->ops->draw(runner, topology, vertex_count, instance_count); } + else if (match_string(line, "copy", &line)) + { + struct resource *src, *dst; + + if (!(src = parse_resource_reference(runner, &line))) + fatal_error("Undefined source resource.\n"); + if (!(dst = parse_resource_reference(runner, &line))) + fatal_error("Undefined destination resource.\n"); + + if (src->desc.dimension != dst->desc.dimension + || src->desc.texel_size != dst->desc.texel_size + || src->desc.width != dst->desc.width + || src->desc.height != dst->desc.height + || src->desc.level_count != dst->desc.level_count + || src->desc.sample_count != dst->desc.sample_count) + fatal_error("Resource dimensions don't match.\n"); + + if (!(runner->ops->copy(runner, src, dst))) + fatal_error("Failed to copy resource.\n"); + } else if (match_string(line, "probe", &line)) { unsigned int left, top, right, bottom, ulps, slot; diff --git a/tests/shader_runner.h b/tests/shader_runner.h index be0eb38b..d79bc95f 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -230,6 +230,7 @@ struct shader_runner_ops void (*clear)(struct shader_runner *runner, struct resource *resource, const struct vec4 *clear_value); bool (*draw)(struct shader_runner *runner, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count, unsigned int instance_count); + bool (*copy)(struct shader_runner *runner, struct resource *src, struct resource *dst); bool (*dispatch)(struct shader_runner *runner, unsigned int x, unsigned int y, unsigned int z); struct resource_readback *(*get_resource_readback)(struct shader_runner *runner, struct resource *resource); void (*release_readback)(struct shader_runner *runner, struct resource_readback *rb); diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 5ce4b81f..375417aa 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -901,6 +901,17 @@ static bool d3d11_runner_draw(struct shader_runner *r, return true; } +static bool d3d11_runner_copy(struct shader_runner *r, struct resource *src, struct resource *dst) +{ + struct d3d11_shader_runner *runner = d3d11_shader_runner(r); + struct d3d11_resource *s = d3d11_resource(src); + struct d3d11_resource *d = d3d11_resource(dst); + + ID3D11DeviceContext_CopyResource(runner->immediate_context, d->resource, s->resource); + + return true; +} + struct d3d11_resource_readback { struct resource_readback rb; @@ -1000,6 +1011,7 @@ static const struct shader_runner_ops d3d11_runner_ops = .dispatch = d3d11_runner_dispatch, .clear = d3d11_runner_clear, .draw = d3d11_runner_draw, + .copy = d3d11_runner_copy, .get_resource_readback = d3d11_runner_get_resource_readback, .release_readback = d3d11_runner_release_readback, }; diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index d218db8e..0bff37b3 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -902,6 +902,33 @@ static bool d3d12_runner_draw(struct shader_runner *r, return true; } +static bool d3d12_runner_copy(struct shader_runner *r, struct resource *src, struct resource *dst) +{ + struct d3d12_shader_runner *runner = d3d12_shader_runner(r); + struct test_context *context = &runner->test_context; + struct d3d12_resource *s = d3d12_resource(src); + struct d3d12_resource *d = d3d12_resource(dst); + D3D12_RESOURCE_STATES src_state, dst_state; + HRESULT hr; + + src_state = resource_get_state(src); + dst_state = resource_get_state(dst); + + transition_resource_state(context->list, s->resource, src_state, D3D12_RESOURCE_STATE_COPY_SOURCE); + transition_resource_state(context->list, d->resource, dst_state, D3D12_RESOURCE_STATE_COPY_DEST); + ID3D12GraphicsCommandList_CopyResource(context->list, d->resource, s->resource); + transition_resource_state(context->list, d->resource, D3D12_RESOURCE_STATE_COPY_DEST, dst_state); + transition_resource_state(context->list, s->resource, D3D12_RESOURCE_STATE_COPY_SOURCE, src_state); + + hr = ID3D12GraphicsCommandList_Close(context->list); + ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr); + exec_command_list(context->queue, context->list); + wait_queue_idle(context->device, context->queue); + reset_command_list(context->list, context->allocator); + + return true; +} + static struct resource_readback *d3d12_runner_get_resource_readback(struct shader_runner *r, struct resource *res) { struct d3d12_shader_runner *runner = d3d12_shader_runner(r); @@ -933,6 +960,7 @@ static const struct shader_runner_ops d3d12_runner_ops = .dispatch = d3d12_runner_dispatch, .clear = d3d12_runner_clear, .draw = d3d12_runner_draw, + .copy = d3d12_runner_copy, .get_resource_readback = d3d12_runner_get_resource_readback, .release_readback = d3d12_runner_release_readback, }; diff --git a/tests/shader_runner_d3d9.c b/tests/shader_runner_d3d9.c index 3c210a00..e4315959 100644 --- a/tests/shader_runner_d3d9.c +++ b/tests/shader_runner_d3d9.c @@ -546,6 +546,11 @@ static bool d3d9_runner_draw(struct shader_runner *r, return true; } +static bool d3d9_runner_copy(struct shader_runner *r, struct resource *src, struct resource *dst) +{ + return false; +} + struct d3d9_resource_readback { struct resource_readback rb; @@ -599,6 +604,7 @@ static const struct shader_runner_ops d3d9_runner_ops = .dispatch = d3d9_runner_dispatch, .clear = d3d9_runner_clear, .draw = d3d9_runner_draw, + .copy = d3d9_runner_copy, .get_resource_readback = d3d9_runner_get_resource_readback, .release_readback = d3d9_runner_release_readback, }; diff --git a/tests/shader_runner_gl.c b/tests/shader_runner_gl.c index e03ff07a..4d7f7315 100644 --- a/tests/shader_runner_gl.c +++ b/tests/shader_runner_gl.c @@ -113,6 +113,7 @@ static bool check_gl_extensions(struct gl_runner *runner) { "GL_ARB_clip_control", "GL_ARB_compute_shader", + "GL_ARB_copy_image", "GL_ARB_sampler_objects", "GL_ARB_shader_image_load_store", "GL_ARB_texture_storage", @@ -1249,6 +1250,28 @@ static bool gl_runner_draw(struct shader_runner *r, return true; } +static bool gl_runner_copy(struct shader_runner *r, struct resource *src, struct resource *dst) +{ + struct gl_resource *s = gl_resource(src); + struct gl_resource *d = gl_resource(dst); + GLenum target = GL_TEXTURE_2D; + unsigned int l, w, h; + + if (src->desc.dimension == RESOURCE_DIMENSION_BUFFER) + return false; + + if (src->desc.sample_count > 1) + target = GL_TEXTURE_2D_MULTISAMPLE; + for (l = 0; l < src->desc.level_count; ++l) + { + w = get_level_dimension(src->desc.width, l); + h = get_level_dimension(src->desc.height, l); + glCopyImageSubData(s->id, target, l, 0, 0, 0, d->id, target, l, 0, 0, 0, w, h, 1); + } + + return true; +} + struct gl_resource_readback { struct resource_readback rb; @@ -1330,6 +1353,7 @@ static const struct shader_runner_ops gl_runner_ops = .dispatch = gl_runner_dispatch, .clear = gl_runner_clear, .draw = gl_runner_draw, + .copy = gl_runner_copy, .get_resource_readback = gl_runner_get_resource_readback, .release_readback = gl_runner_release_readback, }; diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index 079171e2..a99705b2 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -1256,6 +1256,66 @@ out: return ret; } +static VkImageLayout resource_get_layout(struct resource *r) +{ + if (r->desc.type == RESOURCE_TYPE_RENDER_TARGET) + return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (r->desc.type == RESOURCE_TYPE_DEPTH_STENCIL) + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (r->desc.type == RESOURCE_TYPE_TEXTURE) + return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + return VK_IMAGE_LAYOUT_GENERAL; +} + +static bool vulkan_runner_copy(struct shader_runner *r, struct resource *src, struct resource *dst) +{ + struct vulkan_shader_runner *runner = vulkan_shader_runner(r); + const struct vulkan_test_context *context = &runner->context; + VkImageAspectFlags aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + struct vulkan_resource *s = vulkan_resource(src); + struct vulkan_resource *d = vulkan_resource(dst); + VkImageLayout src_layout, dst_layout; + VkImageCopy vk_image_copy; + unsigned int l; + + if (src->desc.dimension == RESOURCE_DIMENSION_BUFFER) + return false; + + if (src->desc.type == RESOURCE_TYPE_DEPTH_STENCIL) + aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + + src_layout = resource_get_layout(src); + dst_layout = resource_get_layout(dst); + + begin_command_buffer(context); + transition_image_layout(context, s->image, aspect_mask, src_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + transition_image_layout(context, d->image, aspect_mask, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vk_image_copy.srcSubresource = (VkImageSubresourceLayers){.aspectMask = aspect_mask, .layerCount = 1}; + vk_image_copy.srcOffset = (VkOffset3D){.x = 0, .y = 0, .z = 0}; + vk_image_copy.dstSubresource = vk_image_copy.srcSubresource; + vk_image_copy.dstOffset = vk_image_copy.srcOffset; + vk_image_copy.extent.depth = 1; + + for (l = 0; l < src->desc.level_count; ++l) + { + vk_image_copy.srcSubresource.mipLevel = l; + vk_image_copy.dstSubresource.mipLevel = l; + vk_image_copy.extent.width = get_level_dimension(src->desc.width, l); + vk_image_copy.extent.height = get_level_dimension(src->desc.height, l); + + VK_CALL(vkCmdCopyImage(context->cmd_buffer, s->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + d->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vk_image_copy)); + } + + transition_image_layout(context, d->image, aspect_mask, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_layout); + transition_image_layout(context, s->image, aspect_mask, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_layout); + end_command_buffer(context); + + return true; +} + struct vulkan_resource_readback { struct resource_readback rb; @@ -1300,13 +1360,7 @@ static struct resource_readback *vulkan_runner_get_resource_readback(struct shad aspect_mask = (resource->r.desc.type == RESOURCE_TYPE_DEPTH_STENCIL) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - - if (resource->r.desc.type == RESOURCE_TYPE_RENDER_TARGET) - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - else if (resource->r.desc.type == RESOURCE_TYPE_DEPTH_STENCIL) - layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - else - layout = VK_IMAGE_LAYOUT_GENERAL; + layout = resource_get_layout(res); begin_command_buffer(context); @@ -1388,6 +1442,7 @@ static const struct shader_runner_ops vulkan_runner_ops = .dispatch = vulkan_runner_dispatch, .clear = vulkan_runner_clear, .draw = vulkan_runner_draw, + .copy = vulkan_runner_copy, .get_resource_readback = vulkan_runner_get_resource_readback, .release_readback = vulkan_runner_release_readback, }; @@ -1615,6 +1670,7 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) features.x = VK_TRUE ENABLE_FEATURE(fragmentStoresAndAtomics); + ENABLE_FEATURE(sampleRateShading); ENABLE_FEATURE(shaderClipDistance); ENABLE_FEATURE(shaderImageGatherExtended); ENABLE_FEATURE(shaderStorageImageWriteWithoutFormat); diff --git a/tests/vulkan_procs.h b/tests/vulkan_procs.h index 4dd69341..2c71bf07 100644 --- a/tests/vulkan_procs.h +++ b/tests/vulkan_procs.h @@ -60,6 +60,7 @@ VK_DEVICE_PFN(vkCmdBindPipeline) VK_DEVICE_PFN(vkCmdBindVertexBuffers) VK_DEVICE_PFN(vkCmdClearAttachments) VK_DEVICE_PFN(vkCmdCopyBufferToImage) +VK_DEVICE_PFN(vkCmdCopyImage) VK_DEVICE_PFN(vkCmdCopyImageToBuffer) VK_DEVICE_PFN(vkCmdDispatch) VK_DEVICE_PFN(vkCmdDraw)