1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-07 16:54:14 +01:00

[dxvk] Prepare swapchain blitter for compositing HUD and cursor

This will be necessary for non-linear color spaces to get proper blending.
This commit is contained in:
Philip Rebohle 2025-01-13 12:37:20 +01:00 committed by Philip Rebohle
parent 8be30d7d5a
commit a09d372caf
8 changed files with 115 additions and 14 deletions

View File

@ -318,11 +318,36 @@ namespace dxvk {
gammaDescriptor.imageLayout = m_gammaView->image()->info().layout;
}
std::array<VkWriteDescriptorSet, 2> descriptorWrites = {{
VkDescriptorImageInfo hudDescriptor = { };
if (m_hudView) {
hudDescriptor.imageView = m_hudView->handle();
hudDescriptor.imageLayout = m_hudImage->info().layout;
}
VkDescriptorImageInfo cursorDescriptor = { };
cursorDescriptor.sampler = m_samplerCursorNearest->handle();
if (m_cursorView) {
VkExtent3D extent = m_cursorImage->info().extent;
if (m_cursorRect.extent.width != extent.width
|| m_cursorRect.extent.height != extent.height)
cursorDescriptor.sampler = m_samplerCursorLinear->handle();
cursorDescriptor.imageLayout = m_cursorImage->info().layout;
cursorDescriptor.imageView = m_cursorView->handle();
}
std::array<VkWriteDescriptorSet, 4> descriptorWrites = {{
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
set, 0, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageDescriptor },
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
set, 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &gammaDescriptor },
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
set, 2, 0, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &hudDescriptor },
{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
set, 3, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &cursorDescriptor },
}};
ctx.cmd->updateDescriptorSets(
@ -474,6 +499,18 @@ namespace dxvk {
samplerInfo.setUsePixelCoordinates(false);
m_samplerGamma = m_device->createSampler(samplerInfo);
samplerInfo.setAddressModes(
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
m_samplerCursorLinear = m_device->createSampler(samplerInfo);
samplerInfo.setFilter(VK_FILTER_NEAREST, VK_FILTER_NEAREST,
VK_SAMPLER_MIPMAP_MODE_NEAREST);
m_samplerCursorNearest = m_device->createSampler(samplerInfo);
}
@ -527,10 +564,11 @@ namespace dxvk {
VkDescriptorSetLayout DxvkSwapchainBlitter::createSetLayout() {
auto vk = m_device->vkd();
std::array<VkDescriptorSetLayoutBinding, 3> bindings = {{
std::array<VkDescriptorSetLayoutBinding, 4> bindings = {{
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
{ 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
{ 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT },
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
{ 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
}};
VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
@ -574,13 +612,15 @@ namespace dxvk {
const DxvkSwapchainPipelineKey& key) {
auto vk = m_device->vkd();
static const std::array<VkSpecializationMapEntry, 6> specMap = {{
static const std::array<VkSpecializationMapEntry, 8> specMap = {{
{ 0, offsetof(SpecConstants, sampleCount), sizeof(VkSampleCountFlagBits) },
{ 1, offsetof(SpecConstants, gammaBound), sizeof(VkBool32) },
{ 2, offsetof(SpecConstants, srcSpace), sizeof(VkColorSpaceKHR) },
{ 3, offsetof(SpecConstants, srcIsSrgb), sizeof(VkBool32) },
{ 4, offsetof(SpecConstants, dstSpace), sizeof(VkColorSpaceKHR) },
{ 5, offsetof(SpecConstants, dstIsSrgb), sizeof(VkBool32) },
{ 6, offsetof(SpecConstants, compositeHud), sizeof(VkBool32) },
{ 7, offsetof(SpecConstants, compositeCursor),sizeof(VkBool32) },
}};
SpecConstants specConstants = { };
@ -590,6 +630,8 @@ namespace dxvk {
specConstants.srcIsSrgb = key.srcIsSrgb;
specConstants.dstSpace = key.dstSpace;
specConstants.dstIsSrgb = lookupFormatInfo(key.dstFormat)->flags.test(DxvkFormatFlag::ColorSpaceSrgb);
specConstants.compositeCursor = key.compositeCursor;
specConstants.compositeHud = key.compositeHud;
// Avoid redundant color space conversions if color spaces
// and images properties match and we don't do a resolve

View File

@ -47,6 +47,10 @@ namespace dxvk {
VkBool32 needsGamma = VK_FALSE;
/// Bit indicating whether alpha blending is required
VkBool32 needsBlending = VK_FALSE;
/// Bit indicating whether the HUD needs to be composited
VkBool32 compositeHud = VK_FALSE;
/// Bit indicating whether the software cursor needs to be composited
VkBool32 compositeCursor = VK_FALSE;
size_t hash() const {
DxvkHashState hash;
@ -58,6 +62,8 @@ namespace dxvk {
hash.add(uint32_t(needsBlit));
hash.add(uint32_t(needsGamma));
hash.add(uint32_t(needsBlending));
hash.add(uint32_t(compositeHud));
hash.add(uint32_t(compositeCursor));
return hash;
}
@ -69,7 +75,9 @@ namespace dxvk {
&& dstFormat == other.dstFormat
&& needsBlit == other.needsBlit
&& needsGamma == other.needsGamma
&& needsBlending == other.needsBlending;
&& needsBlending == other.needsBlending
&& compositeHud == other.compositeHud
&& compositeCursor == other.compositeCursor;
}
};
@ -155,12 +163,16 @@ namespace dxvk {
VkBool32 srcIsSrgb;
VkColorSpaceKHR dstSpace;
VkBool32 dstIsSrgb;
VkBool32 compositeHud;
VkBool32 compositeCursor;
};
struct PushConstants {
VkOffset2D srcOffset;
VkExtent2D srcExtent;
VkOffset2D dstOffset;
VkOffset2D cursorOffset;
VkExtent2D cursorExtent;
};
struct ShaderModule {
@ -190,6 +202,11 @@ namespace dxvk {
Rc<DxvkSampler> m_samplerPresent;
Rc<DxvkSampler> m_samplerGamma;
Rc<DxvkSampler> m_samplerCursorLinear;
Rc<DxvkSampler> m_samplerCursorNearest;
Rc<DxvkImage> m_hudImage;
Rc<DxvkImageView> m_hudView;
VkDescriptorSetLayout m_setLayout = VK_NULL_HANDLE;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;

View File

@ -1,5 +1,7 @@
#include "dxvk_color_space.glsl"
#extension GL_EXT_samplerless_texture_functions : require
layout(constant_id = 0) const uint c_samples = 0u;
layout(constant_id = 1) const bool c_gamma = false;
@ -7,18 +9,53 @@ layout(constant_id = 2) const uint c_src_color_space = VK_COLOR_SPACE_SRGB_NONLI
layout(constant_id = 3) const bool c_src_is_srgb = true;
layout(constant_id = 4) const uint c_dst_color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
layout(constant_id = 5) const bool c_dst_is_srgb = true;
layout(constant_id = 6) const bool c_composite_hud = false;
layout(constant_id = 7) const bool c_composite_cursor = false;
layout(set = 0, binding = 0) uniform sampler2D s_image;
layout(set = 0, binding = 0) uniform sampler2DMS s_image_ms;
layout(set = 0, binding = 1) uniform sampler1D s_gamma;
layout(set = 0, binding = 2) uniform texture2D s_hud;
layout(set = 0, binding = 3) uniform sampler2D s_cursor;
layout(push_constant)
uniform present_info_t {
ivec2 src_offset;
ivec2 src_extent;
ivec2 dst_offset;
ivec2 cursor_offset;
ivec2 cursor_extent;
};
vec4 blend_sc_rgb(vec4 dst, vec4 src) {
return mix(dst, vec4(src.rgb, 1.0f), src.aaaa);
}
vec4 blend_linear_sdr(vec4 dst, vec4 src) {
src.rgb = nits_to_sc_rgb(src.rgb * SDR_NITS);
return blend_sc_rgb(dst, src);
}
vec4 composite_image(vec4 color) {
ivec2 coord = ivec2(gl_FragCoord.xy);
if (c_composite_hud)
color = blend_linear_sdr(color, texelFetch(s_hud, coord, 0));
if (c_composite_cursor) {
ivec2 rel_ofs = coord - cursor_offset;
if (max(rel_ofs.x, rel_ofs.y) >= 0 && all(lessThan(rel_ofs, cursor_extent)))
color = blend_linear_sdr(color, texture(s_cursor, vec2(rel_ofs) / vec2(cursor_extent)));
}
return color;
}
vec4 input_to_sc_rgb(vec4 color) {
switch (c_src_color_space) {
default:

View File

@ -10,5 +10,6 @@ void main() {
ivec2 coord = ivec2(gl_FragCoord.xy) + src_offset - dst_offset;
o_color = input_to_sc_rgb(texelFetch(s_image, coord, 0));
o_color = composite_image(o_color);
o_color = sc_rgb_to_output(o_color);
}

View File

@ -10,5 +10,6 @@ layout(location = 0) out vec4 o_color;
void main() {
vec2 coord = vec2(src_offset) + vec2(src_extent) * i_coord;
o_color = input_to_sc_rgb(textureLod(s_image, coord, 0.0f));
o_color = composite_image(o_color);
o_color = sc_rgb_to_output(o_color);
}

View File

@ -13,5 +13,6 @@ void main() {
for (uint i = 1; i < c_samples; i++)
o_color += input_to_sc_rgb(texelFetch(s_image_ms, coord, int(i)));
o_color = sc_rgb_to_output(o_color / float(c_samples));
o_color = composite_image(o_color / float(c_samples));
o_color = sc_rgb_to_output(o_color);
}

View File

@ -31,5 +31,6 @@ void main() {
fragCount = bitfieldInsert(fragCount, 0, fragShift, 4);
}
o_color = sc_rgb_to_output(o_color / float(c_samples));
o_color = composite_image(o_color / float(c_samples));
o_color = sc_rgb_to_output(o_color);
}

View File

@ -61,5 +61,6 @@ void main() {
o_color += input_to_sc_rgb(texelFetch(s_image_ms, cint + coffset, int(i)));
}
o_color = sc_rgb_to_output(o_color / float(c_samples));
o_color = composite_image(o_color / float(c_samples));
o_color = sc_rgb_to_output(o_color);
}