From 81a215d0bfd9d8dbe70e5b046cde92b737641511 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 3 Feb 2022 13:49:44 +0100 Subject: [PATCH] vkd3d: Implement COLOR -> STENCIL copy if stencil export is supported. Fallback is a bit more involved. Cleans up the FIXME to not report benign issues. Signed-off-by: Hans-Kristian Arntzen --- libs/vkd3d/command.c | 14 ++++-- libs/vkd3d/meson.build | 1 + libs/vkd3d/meta.c | 50 ++++++++++++++++--- libs/vkd3d/shaders/fs_copy_image_stencil.frag | 28 +++++++++++ libs/vkd3d/vkd3d_private.h | 2 + libs/vkd3d/vkd3d_shaders.h | 1 + 6 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 libs/vkd3d/shaders/fs_copy_image_stencil.frag diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index ad7ad6d4..e589f73f 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -5994,6 +5994,7 @@ static void d3d12_command_list_copy_image(struct d3d12_command_list *list, pipeline_key.view_type = vkd3d_meta_get_copy_image_view_type(dst_resource->desc.Dimension); pipeline_key.sample_count = vk_samples_from_dxgi_sample_desc(&dst_resource->desc.SampleDesc); pipeline_key.layout = dst_layout; + pipeline_key.dst_aspect_mask = region->dstSubresource.aspectMask; if (FAILED(hr = vkd3d_meta_get_copy_image_pipeline(&list->device->meta_ops, &pipeline_key, &pipeline_info))) { @@ -6364,12 +6365,17 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyTextureRegion(d3d12_command &src_resource->desc, &dst_resource->desc, src_format, dst_format, src_box, dst_x, dst_y, dst_z); - if ((dst_format->vk_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) - && (dst_format->vk_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) - && (image_copy.dstSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) + /* If aspect masks do not match, we have to use fallback copies with a render pass, and there + * is no standard way to write to stencil without fallbacks. + * Checking aspect masks here is equivalent to checking formats. vkCmdCopyImage can only be + * used for compatible formats and depth stencil formats are only compatible with themselves. */ + if (dst_format->vk_aspect_mask != src_format->vk_aspect_mask && + (image_copy.dstSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && + !list->device->vk_info.EXT_shader_stencil_export) { - FIXME("Destination depth-stencil format %#x is not supported for STENCIL dst copy.\n", + FIXME("Destination depth-stencil format %#x is not supported for STENCIL dst copy with render pass fallback.\n", dst_format->dxgi_format); + return; } writes_full_subresource = d3d12_image_copy_writes_full_subresource(dst_resource, diff --git a/libs/vkd3d/meson.build b/libs/vkd3d/meson.build index 3a32bace..60c9d6e0 100644 --- a/libs/vkd3d/meson.build +++ b/libs/vkd3d/meson.build @@ -19,6 +19,7 @@ vkd3d_shaders =[ 'shaders/fs_copy_image_float.frag', 'shaders/fs_copy_image_uint.frag', + 'shaders/fs_copy_image_stencil.frag', 'shaders/gs_fullscreen.geom', 'shaders/vs_fullscreen.vert', diff --git a/libs/vkd3d/meta.c b/libs/vkd3d/meta.c index fdcabbd7..d28b6fa6 100644 --- a/libs/vkd3d/meta.c +++ b/libs/vkd3d/meta.c @@ -606,6 +606,16 @@ HRESULT vkd3d_copy_image_ops_init(struct vkd3d_copy_image_ops *meta_copy_image_o goto fail; } + if (device->vk_info.EXT_shader_stencil_export) + { + if ((vr = vkd3d_meta_create_shader_module(device, SPIRV_CODE(fs_copy_image_stencil), + &meta_copy_image_ops->vk_fs_stencil_module)) < 0) + { + ERR("Failed to create shader modules, vr %d.\n", vr); + goto fail; + } + } + return S_OK; fail: @@ -631,6 +641,7 @@ void vkd3d_copy_image_ops_cleanup(struct vkd3d_copy_image_ops *meta_copy_image_o VK_CALL(vkDestroyPipelineLayout(device->vk_device, meta_copy_image_ops->vk_pipeline_layout, NULL)); VK_CALL(vkDestroyShaderModule(device->vk_device, meta_copy_image_ops->vk_fs_float_module, NULL)); VK_CALL(vkDestroyShaderModule(device->vk_device, meta_copy_image_ops->vk_fs_uint_module, NULL)); + VK_CALL(vkDestroyShaderModule(device->vk_device, meta_copy_image_ops->vk_fs_stencil_module, NULL)); pthread_mutex_destroy(&meta_copy_image_ops->mutex); @@ -793,13 +804,30 @@ static HRESULT vkd3d_meta_create_copy_image_pipeline(struct vkd3d_meta_ops *meta ds_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; ds_state.pNext = NULL; ds_state.flags = 0; - ds_state.depthTestEnable = VK_TRUE; - ds_state.depthWriteEnable = VK_TRUE; + ds_state.depthTestEnable = (key->dst_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) ? VK_TRUE : VK_FALSE; + ds_state.depthWriteEnable = ds_state.depthTestEnable; ds_state.depthCompareOp = VK_COMPARE_OP_ALWAYS; ds_state.depthBoundsTestEnable = VK_FALSE; - ds_state.stencilTestEnable = VK_FALSE; - memset(&ds_state.front, 0, sizeof(ds_state.front)); - memset(&ds_state.back, 0, sizeof(ds_state.back)); + + if (key->dst_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) + { + ds_state.stencilTestEnable = VK_TRUE; + ds_state.front.reference = 0; + ds_state.front.writeMask = 0xff; + ds_state.front.compareMask = 0xff; + ds_state.front.passOp = VK_STENCIL_OP_REPLACE; + ds_state.front.failOp = VK_STENCIL_OP_KEEP; + ds_state.front.depthFailOp = VK_STENCIL_OP_KEEP; + ds_state.front.compareOp = VK_COMPARE_OP_ALWAYS; + ds_state.back = ds_state.front; + } + else + { + ds_state.stencilTestEnable = VK_FALSE; + memset(&ds_state.front, 0, sizeof(ds_state.front)); + memset(&ds_state.back, 0, sizeof(ds_state.back)); + } + ds_state.minDepthBounds = 0.0f; ds_state.maxDepthBounds = 1.0f; @@ -822,11 +850,21 @@ static HRESULT vkd3d_meta_create_copy_image_pipeline(struct vkd3d_meta_ops *meta key->sample_count, key->format, key->layout, &pipeline->vk_render_pass)) < 0) return hresult_from_vk_result(vr); - /* Special path when copying stencil -> color. */ if (key->format->vk_format == VK_FORMAT_R8_UINT) + { + /* Special path when copying stencil -> color. */ vk_module = meta_copy_image_ops->vk_fs_uint_module; + } + else if (key->dst_aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) + { + /* FragStencilRef path. */ + vk_module = meta_copy_image_ops->vk_fs_stencil_module; + } else + { + /* Depth or float color path. */ vk_module = meta_copy_image_ops->vk_fs_float_module; + } if ((vr = vkd3d_meta_create_graphics_pipeline(meta_ops, meta_copy_image_ops->vk_pipeline_layout, pipeline->vk_render_pass, diff --git a/libs/vkd3d/shaders/fs_copy_image_stencil.frag b/libs/vkd3d/shaders/fs_copy_image_stencil.frag new file mode 100644 index 00000000..a57ec4fb --- /dev/null +++ b/libs/vkd3d/shaders/fs_copy_image_stencil.frag @@ -0,0 +1,28 @@ +#version 450 + +#extension GL_EXT_samplerless_texture_functions : enable +#extension GL_ARB_shader_stencil_export : enable + +#define MODE_1D 0 +#define MODE_2D 1 +#define MODE_MS 2 + +layout(constant_id = 0) const uint c_mode = MODE_2D; + +layout(binding = 0) uniform utexture1DArray tex_1d; +layout(binding = 0) uniform utexture2DArray tex_2d; +layout(binding = 0) uniform utexture2DMSArray tex_ms; + +layout(push_constant) +uniform u_info_t { + ivec2 offset; +} u_info; + +void main() { + ivec3 coord = ivec3(u_info.offset + ivec2(gl_FragCoord.xy), gl_Layer); + uint value; + if (c_mode == MODE_1D) value = texelFetch(tex_1d, coord.xz, 0).r; + if (c_mode == MODE_2D) value = texelFetch(tex_2d, coord, 0).r; + if (c_mode == MODE_MS) value = texelFetch(tex_ms, coord, gl_SampleID).r; + gl_FragStencilRefARB = int(value); +} diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 97b62a72..423e3109 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -2481,6 +2481,7 @@ struct vkd3d_copy_image_pipeline_key VkImageViewType view_type; VkSampleCountFlagBits sample_count; VkImageLayout layout; + VkImageAspectFlags dst_aspect_mask; }; struct vkd3d_copy_image_pipeline @@ -2497,6 +2498,7 @@ struct vkd3d_copy_image_ops VkPipelineLayout vk_pipeline_layout; VkShaderModule vk_fs_float_module; VkShaderModule vk_fs_uint_module; + VkShaderModule vk_fs_stencil_module; pthread_mutex_t mutex; diff --git a/libs/vkd3d/vkd3d_shaders.h b/libs/vkd3d/vkd3d_shaders.h index 16ee6e4a..9f96323c 100644 --- a/libs/vkd3d/vkd3d_shaders.h +++ b/libs/vkd3d/vkd3d_shaders.h @@ -50,6 +50,7 @@ enum vkd3d_meta_copy_mode #include #include #include +#include #include #include