From 54b0b09cc91533dfcafda98ab1c9ad349679ad67 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 5 Mar 2025 11:05:21 +0100 Subject: [PATCH] [dxvk] Refactor resolve shaders Removes some code duplication while adding support for non-AVERAGE resolves for plain color images. Also nuke the AMD path since it is no longer used. --- src/dxvk/dxvk_meta_resolve.cpp | 5 +- src/dxvk/meson.build | 1 - src/dxvk/shaders/dxvk_resolve_common.glsl | 35 ++++++++ src/dxvk/shaders/dxvk_resolve_frag_d.frag | 50 +++--------- src/dxvk/shaders/dxvk_resolve_frag_ds.frag | 79 ++++--------------- src/dxvk/shaders/dxvk_resolve_frag_f.frag | 17 ++-- src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag | 56 ------------- src/dxvk/shaders/dxvk_resolve_frag_i.frag | 16 +++- src/dxvk/shaders/dxvk_resolve_frag_u.frag | 18 ++++- 9 files changed, 104 insertions(+), 173 deletions(-) create mode 100644 src/dxvk/shaders/dxvk_resolve_common.glsl delete mode 100644 src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag diff --git a/src/dxvk/dxvk_meta_resolve.cpp b/src/dxvk/dxvk_meta_resolve.cpp index 7362dc4c4..be8b0be6f 100644 --- a/src/dxvk/dxvk_meta_resolve.cpp +++ b/src/dxvk/dxvk_meta_resolve.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -52,9 +51,7 @@ namespace dxvk { DxvkMetaResolveObjects::DxvkMetaResolveObjects(const DxvkDevice* device) : m_vkd (device->vkd()), - m_shaderFragF (device->features().amdShaderFragmentMask - ? createShaderModule(dxvk_resolve_frag_f_amd) - : createShaderModule(dxvk_resolve_frag_f)), + m_shaderFragF (createShaderModule(dxvk_resolve_frag_f)), m_shaderFragU (createShaderModule(dxvk_resolve_frag_u)), m_shaderFragI (createShaderModule(dxvk_resolve_frag_i)), m_shaderFragD (createShaderModule(dxvk_resolve_frag_d)) { diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 31ca70406..b6222ddd3 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -50,7 +50,6 @@ dxvk_shaders = files([ 'shaders/dxvk_resolve_frag_d.frag', 'shaders/dxvk_resolve_frag_ds.frag', 'shaders/dxvk_resolve_frag_f.frag', - 'shaders/dxvk_resolve_frag_f_amd.frag', 'shaders/dxvk_resolve_frag_i.frag', 'shaders/dxvk_resolve_frag_u.frag', diff --git a/src/dxvk/shaders/dxvk_resolve_common.glsl b/src/dxvk/shaders/dxvk_resolve_common.glsl new file mode 100644 index 000000000..3183c9337 --- /dev/null +++ b/src/dxvk/shaders/dxvk_resolve_common.glsl @@ -0,0 +1,35 @@ +#define VK_RESOLVE_MODE_NONE (0) +#define VK_RESOLVE_MODE_SAMPLE_ZERO_BIT (1 << 0) +#define VK_RESOLVE_MODE_AVERAGE_BIT (1 << 1) +#define VK_RESOLVE_MODE_MIN_BIT (1 << 2) +#define VK_RESOLVE_MODE_MAX_BIT (1 << 3) + +#define resolve_fn(name, type, load_fn) \ +type name(ivec3 coord, int samples, uint mode) { \ + if (mode == VK_RESOLVE_MODE_NONE) \ + return type(0); \ + type value = load_fn(coord, 0); \ + \ + switch (mode) { \ + case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: \ + return value; \ + \ + case VK_RESOLVE_MODE_AVERAGE_BIT: \ + for (int i = 1; i < samples; i++) \ + value += load_fn(coord, i); \ + value /= type(c_samples); \ + break; \ + \ + case VK_RESOLVE_MODE_MIN_BIT: \ + for (int i = 1; i < samples; i++) \ + value = min(value, load_fn(coord, i)); \ + break; \ + \ + case VK_RESOLVE_MODE_MAX_BIT: \ + for (int i = 1; i < c_samples; i++) \ + value = min(value, load_fn(coord, i)); \ + break; \ + } \ + \ + return value; \ +} diff --git a/src/dxvk/shaders/dxvk_resolve_frag_d.frag b/src/dxvk/shaders/dxvk_resolve_frag_d.frag index 70152d014..a0b91ec6d 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_d.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_d.frag @@ -1,56 +1,28 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable #extension GL_EXT_samplerless_texture_functions : enable -#define VK_RESOLVE_MODE_NONE (0) -#define VK_RESOLVE_MODE_SAMPLE_ZERO_BIT (1 << 0) -#define VK_RESOLVE_MODE_AVERAGE_BIT (1 << 1) -#define VK_RESOLVE_MODE_MIN_BIT (1 << 2) -#define VK_RESOLVE_MODE_MAX_BIT (1 << 3) +#include "dxvk_resolve_common.glsl" layout(constant_id = 0) const int c_samples = 1; -layout(constant_id = 1) const int c_mode_d = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; +layout(constant_id = 1) const int c_mode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; layout(binding = 0) uniform texture2DMSArray s_depth; +float load_depth(ivec3 coord, int s) { + return texelFetch(s_depth, coord, s).r; +} + +resolve_fn(resolve_depth, float, load_depth) + layout(push_constant) uniform u_info_t { ivec2 offset; } u_info; -float resolve_depth(ivec3 coord) { - float depth = 0.0f; - - switch (c_mode_d) { - case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: - depth = texelFetch(s_depth, coord, 0).r; - break; - - case VK_RESOLVE_MODE_AVERAGE_BIT: - depth = texelFetch(s_depth, coord, 0).r; - for (int i = 1; i < c_samples; i++) - depth += texelFetch(s_depth, coord, i).r; - depth /= float(c_samples); - break; - - case VK_RESOLVE_MODE_MIN_BIT: - depth = texelFetch(s_depth, coord, 0).r; - for (int i = 1; i < c_samples; i++) - depth = min(depth, texelFetch(s_depth, coord, i).r); - break; - - case VK_RESOLVE_MODE_MAX_BIT: - depth = texelFetch(s_depth, coord, 0).r; - for (int i = 1; i < c_samples; i++) - depth = max(depth, texelFetch(s_depth, coord, i).r); - break; - } - - return depth; -} - void main() { ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); - gl_FragDepth = resolve_depth(coord); -} \ No newline at end of file + gl_FragDepth = resolve_depth(coord, c_samples, c_mode); +} diff --git a/src/dxvk/shaders/dxvk_resolve_frag_ds.frag b/src/dxvk/shaders/dxvk_resolve_frag_ds.frag index b92a03d71..a7bda7c93 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_ds.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_ds.frag @@ -1,13 +1,10 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable #extension GL_ARB_shader_stencil_export : enable #extension GL_EXT_samplerless_texture_functions : enable -#define VK_RESOLVE_MODE_NONE (0) -#define VK_RESOLVE_MODE_SAMPLE_ZERO_BIT (1 << 0) -#define VK_RESOLVE_MODE_AVERAGE_BIT (1 << 1) -#define VK_RESOLVE_MODE_MIN_BIT (1 << 2) -#define VK_RESOLVE_MODE_MAX_BIT (1 << 3) +#include "dxvk_resolve_common.glsl" layout(constant_id = 0) const int c_samples = 1; layout(constant_id = 1) const int c_mode_d = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; @@ -16,69 +13,25 @@ layout(constant_id = 2) const int c_mode_s = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; layout(binding = 0) uniform texture2DMSArray s_depth; layout(binding = 1) uniform utexture2DMSArray s_stencil; +float load_depth(ivec3 coord, int s) { + return texelFetch(s_depth, coord, s).r; +} + +uint load_stencil(ivec3 coord, int s) { + return texelFetch(s_stencil, coord, s).r; +} + +resolve_fn(resolve_depth, float, load_depth) +resolve_fn(resolve_stencil, uint, load_stencil) + layout(push_constant) uniform u_info_t { ivec2 offset; } u_info; -float resolve_depth(ivec3 coord) { - float depth = 0.0f; - - switch (c_mode_d) { - case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: - depth = texelFetch(s_depth, coord, 0).r; - break; - - case VK_RESOLVE_MODE_AVERAGE_BIT: - depth = texelFetch(s_depth, coord, 0).r; - for (int i = 1; i < c_samples; i++) - depth += texelFetch(s_depth, coord, i).r; - depth /= float(c_samples); - break; - - case VK_RESOLVE_MODE_MIN_BIT: - depth = texelFetch(s_depth, coord, 0).r; - for (int i = 1; i < c_samples; i++) - depth = min(depth, texelFetch(s_depth, coord, i).r); - break; - - case VK_RESOLVE_MODE_MAX_BIT: - depth = texelFetch(s_depth, coord, 0).r; - for (int i = 1; i < c_samples; i++) - depth = max(depth, texelFetch(s_depth, coord, i).r); - break; - } - - return depth; -} - -int resolve_stencil(ivec3 coord) { - uint stencil = 0u; - - switch (c_mode_s) { - case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: - stencil = texelFetch(s_stencil, coord, 0).r; - break; - - case VK_RESOLVE_MODE_MIN_BIT: - stencil = texelFetch(s_stencil, coord, 0).r; - for (int i = 1; i < c_samples; i++) - stencil = min(stencil, texelFetch(s_stencil, coord, i).r); - break; - - case VK_RESOLVE_MODE_MAX_BIT: - stencil = texelFetch(s_stencil, coord, 0).r; - for (int i = 1; i < c_samples; i++) - stencil = max(stencil, texelFetch(s_stencil, coord, i).r); - break; - } - - return int(stencil); -} - void main() { ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); - gl_FragDepth = resolve_depth(coord); - gl_FragStencilRefARB = resolve_stencil(coord); -} \ No newline at end of file + gl_FragDepth = resolve_depth(coord, c_samples, c_mode_d); + gl_FragStencilRefARB = int(resolve_stencil(coord, c_samples, c_mode_s)); +} diff --git a/src/dxvk/shaders/dxvk_resolve_frag_f.frag b/src/dxvk/shaders/dxvk_resolve_frag_f.frag index 2c7442c14..8fbd642de 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_f.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_f.frag @@ -1,13 +1,23 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable #extension GL_EXT_samplerless_texture_functions : enable +#include "dxvk_resolve_common.glsl" + layout(constant_id = 0) const int c_samples = 1; +layout(constant_id = 1) const int c_mode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; layout(binding = 0) uniform texture2DMSArray s_image; layout(location = 0) out vec4 o_color; +vec4 load_color(ivec3 coord, int s) { + return texelFetch(s_image, coord, s); +} + +resolve_fn(resolve_color, vec4, load_color) + layout(push_constant) uniform u_info_t { ivec2 offset; @@ -15,8 +25,5 @@ uniform u_info_t { void main() { ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); - vec4 color = vec4(0.0f); - for (int i = 0; i < c_samples; i++) - color += texelFetch(s_image, coord, i); - o_color = color / float(c_samples); -} \ No newline at end of file + o_color = resolve_color(coord, c_samples, c_mode); +} diff --git a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag b/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag deleted file mode 100644 index a550e3507..000000000 --- a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag +++ /dev/null @@ -1,56 +0,0 @@ -#version 450 - -#extension GL_EXT_samplerless_texture_functions : enable -#extension GL_EXT_spirv_intrinsics : enable - -// GL_AMD_shader_fragment_mask was never updated to support -// sampler-less functions, so we have to define these manually -spirv_instruction(extensions = ["SPV_AMD_shader_fragment_mask"], capabilities = [5010], id = 5011) -uint fragment_mask_fetch(texture2DMSArray tex, ivec3 coord); - -spirv_instruction(extensions = ["SPV_AMD_shader_fragment_mask"], capabilities = [5010], id = 5012) -vec4 fragment_fetch(texture2DMSArray tex, ivec3 coord, uint index); - -layout(constant_id = 0) const int c_samples = 1; - -layout(set = 0, binding = 0) -uniform texture2DMSArray s_image; - -layout(location = 0) out vec4 o_color; - -layout(push_constant) -uniform u_info_t { - ivec2 offset; -} u_info; - -void main() { - ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); - - // get a four-bit fragment index for each sample - uint fragMask = fragment_mask_fetch(s_image, coord); - - // count number of occurences of each fragment - // index in one four-bit counter for each sample - uint fragCount = 0u; - - for (int i = 0; i < 4 * c_samples; i += 4) { - uint fragIndex = bitfieldExtract(fragMask, i, 4); - fragCount += 1u << (fragIndex << 2); - } - - // perform necessary texture lookups to compute - // final fragment color - o_color = vec4(0.0f); - - while (fragCount != 0) { - int fragIndex = findLSB(fragCount) >> 2; - int fragShift = fragIndex << 2; - - o_color += fragment_fetch(s_image, coord, fragIndex) - * float(bitfieldExtract(fragCount, fragShift, 4)); - - fragCount = bitfieldInsert(fragCount, 0, fragShift, 4); - } - - o_color /= float(c_samples); -} diff --git a/src/dxvk/shaders/dxvk_resolve_frag_i.frag b/src/dxvk/shaders/dxvk_resolve_frag_i.frag index a721897a5..094954457 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_i.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_i.frag @@ -1,11 +1,23 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable #extension GL_EXT_samplerless_texture_functions : enable +#include "dxvk_resolve_common.glsl" + +layout(constant_id = 0) const int c_samples = 1; +layout(constant_id = 1) const int c_mode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; + layout(binding = 0) uniform itexture2DMSArray s_image; layout(location = 0) out ivec4 o_color; +ivec4 load_color(ivec3 coord, int s) { + return texelFetch(s_image, coord, s); +} + +resolve_fn(resolve_color, ivec4, load_color) + layout(push_constant) uniform u_info_t { ivec2 offset; @@ -13,5 +25,5 @@ uniform u_info_t { void main() { ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); - o_color = texelFetch(s_image, coord, 0); -} \ No newline at end of file + o_color = resolve_color(coord, c_samples, c_mode); +} diff --git a/src/dxvk/shaders/dxvk_resolve_frag_u.frag b/src/dxvk/shaders/dxvk_resolve_frag_u.frag index f7b4e73da..ab8b3d18a 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_u.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_u.frag @@ -1,10 +1,22 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable #extension GL_EXT_samplerless_texture_functions : enable +#include "dxvk_resolve_common.glsl" + +layout(constant_id = 0) const int c_samples = 1; +layout(constant_id = 1) const int c_mode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; + layout(binding = 0) uniform utexture2DMSArray s_image; -layout(location = 0) out uvec4 o_color; +layout(location = 0) out vec4 o_color; + +uvec4 load_color(ivec3 coord, int s) { + return texelFetch(s_image, coord, s); +} + +resolve_fn(resolve_color, uvec4, load_color) layout(push_constant) uniform u_info_t { @@ -13,5 +25,5 @@ uniform u_info_t { void main() { ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); - o_color = texelFetch(s_image, coord, 0); -} \ No newline at end of file + o_color = resolve_color(coord, c_samples, c_mode); +}