Move to combined samplers and rewrite composite shader in GLSL

Cleans up the composite shader significantly as well as it uses
arrays of descriptors/samplers now.

This all gets unrolled as the loop is spec-constant sized.
This commit is contained in:
Joshua Ashton 2021-04-21 16:38:25 +01:00 committed by Pierre-Loup A. Griffais
parent f537a40483
commit e818aec744
4 changed files with 86 additions and 152 deletions

View file

@ -61,7 +61,7 @@ shadercompiler = find_program('glslangValidator')
spirv_shader = custom_target('shader_target',
output : 'composite.h',
input : 'src/composite.comp.hlsl',
input : 'src/composite.comp',
command : [
shadercompiler, '-V', '-e', 'main', '--vn',
'composite_spv', '@INPUT@', '-o', '@OUTPUT@'

58
src/composite.comp Normal file
View file

@ -0,0 +1,58 @@
#version 450
#extension GL_EXT_scalar_block_layout : require
layout(
local_size_x = 8,
local_size_y = 8,
local_size_z = 1) in;
const int MaxLayers = 4;
layout(constant_id = 0) const int c_layerCount = 1;
layout(constant_id = 1) const bool c_swapChannels = false;
layout(binding = 0, rgba8) writeonly uniform image2D dst;
layout(std430, binding = 1)
uniform layers_t {
vec2 u_scale[MaxLayers];
vec2 u_offset[MaxLayers];
float u_opacity[MaxLayers];
};
layout(binding = 2) uniform sampler2D s_samplers[MaxLayers];
vec4 sampleLayer(uint layerIdx, vec2 uv) {
vec2 coord = (uv + u_offset[layerIdx]) * u_scale[layerIdx];
return texture(s_samplers[layerIdx], coord);
}
void main() {
uvec2 coord = uvec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
uvec2 outSize = imageSize(dst);
if (coord.x >= outSize.x || coord.y >= outSize.y)
return;
vec2 uv = vec2(coord);
vec4 outputValue = vec4(0.0f);
if (c_layerCount > 0)
outputValue = sampleLayer(0, uv);
for (int i = 1; i < c_layerCount; i++) {
vec4 layerColor = sampleLayer(i, uv);
float layerAlpha = u_opacity[i] * layerColor.a;
outputValue = layerColor * layerAlpha + outputValue * (1.0f - layerAlpha);
}
if (c_swapChannels)
outputValue = outputValue.bgra;
imageStore(dst, ivec2(coord), outputValue);
// Indicator to quickly tell if we're in the compositing path or not.
if (false && coord.x > 50 && coord.x < 100 && coord.y > 50 && coord.y < 100)
imageStore(dst, ivec2(coord), vec4(1.0f, 0.0f, 1.0f, 1.0f));
}

View file

@ -1,96 +0,0 @@
[[vk::binding(0, 0)]] RWTexture2D<float4> outImage;
[[vk::binding(1, 0)]] cbuffer compositeDesc
{
float flScale0X;
float flScale0Y;
float flScale1X;
float flScale1Y;
float flScale2X;
float flScale2Y;
float flScale3X;
float flScale3Y;
float flOffset0X;
float flOffset0Y;
float flOffset1X;
float flOffset1Y;
float flOffset2X;
float flOffset2Y;
float flOffset3X;
float flOffset3Y;
float flOpacity0;
float flOpacity1;
float flOpacity2;
float flOpacity3;
}
[[vk::binding(2, 0)]] Texture2D inLayerTex0;
[[vk::binding(3, 0)]] SamplerState sampler0;
[[vk::binding(4, 0)]] Texture2D inLayerTex1;
[[vk::binding(5, 0)]] SamplerState sampler1;
[[vk::binding(6, 0)]] Texture2D inLayerTex2;
[[vk::binding(7, 0)]] SamplerState sampler2;
[[vk::binding(8, 0)]] Texture2D inLayerTex3;
[[vk::binding(9, 0)]] SamplerState sampler3;
[[vk::constant_id(0)]] const int nLayerCount = 1;
[[vk::constant_id(1)]] const bool bSwapChannels = false;
[numthreads(8, 8, 1)]
void main(
uint3 groupId : SV_GroupID,
uint3 groupThreadId : SV_GroupThreadID,
uint3 dispatchThreadId : SV_DispatchThreadID,
uint groupIndex : SV_GroupIndex)
{
uint2 index = uint2(dispatchThreadId.x, dispatchThreadId.y);
uint2 outSize;
outImage.GetDimensions( outSize.x, outSize.y );
if ( index.x >= outSize.x || index.y >= outSize.y )
{
return;
}
float4 outputValue;
if ( nLayerCount >= 1 )
{
outputValue = inLayerTex0.Sample( sampler0, ( float2( index ) + float2( flOffset0X, flOffset0Y ) ) * float2( flScale0X, flScale0Y ) );
}
if ( nLayerCount >= 2 )
{
float4 layerSample = inLayerTex1.Sample( sampler1, ( float2( index ) + float2( flOffset1X, flOffset1Y ) ) * float2( flScale1X, flScale1Y ) );
float layerAlpha = flOpacity1 * layerSample.a;
outputValue = layerSample * layerAlpha + outputValue * ( 1.0 - layerAlpha );
}
if ( nLayerCount >= 3 )
{
float4 layerSample = inLayerTex2.Sample( sampler2, ( float2( index ) + float2( flOffset2X, flOffset2Y ) ) * float2( flScale2X, flScale2Y ) );
float layerAlpha = flOpacity2 * layerSample.a;
outputValue = layerSample * layerAlpha + outputValue * ( 1.0 - layerAlpha );
}
if ( bSwapChannels )
{
outImage [index] = outputValue.bgra;
}
else
{
outImage [index] = outputValue;
}
// indicator to quickly tell if we're in the compositing path or not
if ( 0 && index.x > 50 && index.x < 100 && index.y > 50 && index.y < 100 )
{
outImage [index] = float4(1.0,0.0,1.0,1.0);
}
}

View file

@ -980,11 +980,7 @@ retry:
k_nMaxSets * 1,
},
{
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
k_nMaxSets * k_nMaxLayers,
},
{
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
k_nMaxSets * k_nMaxLayers,
},
};
@ -1017,29 +1013,23 @@ retry:
vecLayoutBindings.push_back( descriptorSetLayoutBindings ); // first binding is target storage image
descriptorSetLayoutBindings.binding = 1;
descriptorSetLayoutBindings.descriptorCount = 1;
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
vecLayoutBindings.push_back( descriptorSetLayoutBindings ); // second binding is composite description buffer
for ( uint32_t i = 0; i < k_nMaxLayers; i++ )
{
descriptorSetLayoutBindings.binding = 2 + ( i * 2 );
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
vecLayoutBindings.push_back( descriptorSetLayoutBindings );
descriptorSetLayoutBindings.binding = 2 + ( i * 2 ) + 1;
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
vecLayoutBindings.push_back( descriptorSetLayoutBindings );
}
descriptorSetLayoutBindings.binding = 2;
descriptorSetLayoutBindings.descriptorCount = k_nMaxLayers;
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
vecLayoutBindings.push_back( descriptorSetLayoutBindings );
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo =
{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.bindingCount = 2 + ( k_nMaxLayers * 2 ),
.bindingCount = (uint32_t)vecLayoutBindings.size(),
.pBindings = vecLayoutBindings.data()
};
@ -1832,6 +1822,7 @@ void vulkan_update_descriptor( struct VulkanPipeline_t *pPipeline )
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
}
std::array< VkDescriptorImageInfo, k_nMaxLayers > imageDescriptors;
for ( uint32_t i = 0; i < k_nMaxLayers; i++ )
{
VkSampler sampler = VK_NULL_HANDLE;
@ -1871,48 +1862,29 @@ void vulkan_update_descriptor( struct VulkanPipeline_t *pPipeline )
{
VkDescriptorImageInfo imageInfo = {
.sampler = sampler,
.imageView = pTex->m_vkImageView,
// TODO figure out what it is exactly for the wayland surfaces
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};
VkWriteDescriptorSet writeDescriptorSet = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = descriptorSet,
.dstBinding = 2 + (i * 2),
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.pImageInfo = &imageInfo,
.pBufferInfo = nullptr,
.pTexelBufferView = nullptr,
};
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
}
{
VkDescriptorImageInfo imageInfo = {
.sampler = sampler,
};
VkWriteDescriptorSet writeDescriptorSet = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = descriptorSet,
.dstBinding = 2 + (i * 2) + 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.pImageInfo = &imageInfo,
.pBufferInfo = nullptr,
.pTexelBufferView = nullptr,
};
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
imageDescriptors[ i ] = imageInfo;
}
}
VkWriteDescriptorSet writeDescriptorSet = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = descriptorSet,
.dstBinding = 2,
.dstArrayElement = 0,
.descriptorCount = imageDescriptors.size(),
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = imageDescriptors.data(),
.pBufferInfo = nullptr,
.pTexelBufferView = nullptr,
};
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
}
bool vulkan_composite( struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline, bool bScreenshot )