diff --git a/meson.build b/meson.build index 1c3b248..7b4d510 100644 --- a/meson.build +++ b/meson.build @@ -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@' diff --git a/src/composite.comp b/src/composite.comp new file mode 100644 index 0000000..cf84cab --- /dev/null +++ b/src/composite.comp @@ -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)); +} diff --git a/src/composite.comp.hlsl b/src/composite.comp.hlsl deleted file mode 100644 index 8f991b3..0000000 --- a/src/composite.comp.hlsl +++ /dev/null @@ -1,96 +0,0 @@ -[[vk::binding(0, 0)]] RWTexture2D 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); - } -} diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp index 9c58735..5ccc89f 100644 --- a/src/rendervulkan.cpp +++ b/src/rendervulkan.cpp @@ -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 )