From dda8de09d2cbff83e88dd468865b8e948da4eb3e Mon Sep 17 00:00:00 2001 From: Artur Wasmut <awasmut@uni-koblenz.de> Date: Tue, 10 Aug 2021 14:41:31 +0200 Subject: [PATCH] [#105] add ugly pbr grass textures for testing. Implement ugly variable descriptor count extensions. --- include/vkcv/DescriptorConfig.hpp | 4 +- include/vkcv/DescriptorWrites.hpp | 5 +- .../cube/Grass001_1K_AmbientOcclusion.jpg | 3 ++ .../resources/cube/Grass001_1K_Color.jpg | 3 ++ .../cube/Grass001_1K_Displacement.jpg | 3 ++ .../resources/cube/Grass001_1K_Normal.jpg | 3 ++ .../resources/cube/Grass001_1K_Roughness.jpg | 3 ++ .../resources/shaders/shader.frag | 7 +-- .../resources/shaders/shader.vert | 22 +++++++- projects/bindless_textures/src/main.cpp | 35 ++++++++++++- src/vkcv/Context.cpp | 1 + src/vkcv/DescriptorConfig.cpp | 6 ++- src/vkcv/DescriptorManager.cpp | 50 ++++++++++++++++--- src/vkcv/ShaderProgram.cpp | 27 ++++++++-- 14 files changed, 151 insertions(+), 21 deletions(-) create mode 100644 projects/bindless_textures/resources/cube/Grass001_1K_AmbientOcclusion.jpg create mode 100644 projects/bindless_textures/resources/cube/Grass001_1K_Color.jpg create mode 100644 projects/bindless_textures/resources/cube/Grass001_1K_Displacement.jpg create mode 100644 projects/bindless_textures/resources/cube/Grass001_1K_Normal.jpg create mode 100644 projects/bindless_textures/resources/cube/Grass001_1K_Roughness.jpg diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp index 767492eb..0fadd75d 100644 --- a/include/vkcv/DescriptorConfig.hpp +++ b/include/vkcv/DescriptorConfig.hpp @@ -41,12 +41,14 @@ namespace vkcv uint32_t bindingID, DescriptorType descriptorType, uint32_t descriptorCount, - ShaderStage shaderStage + ShaderStage shaderStage, + bool variableCount = false ) noexcept; uint32_t bindingID; DescriptorType descriptorType; uint32_t descriptorCount; ShaderStage shaderStage; + bool variableCount; }; } diff --git a/include/vkcv/DescriptorWrites.hpp b/include/vkcv/DescriptorWrites.hpp index 28de2ed7..ff72a911 100644 --- a/include/vkcv/DescriptorWrites.hpp +++ b/include/vkcv/DescriptorWrites.hpp @@ -4,12 +4,13 @@ namespace vkcv { struct SampledImageDescriptorWrite { - inline SampledImageDescriptorWrite(uint32_t binding, ImageHandle image, uint32_t mipLevel = 0, bool useGeneralLayout = false) - : binding(binding), image(image), mipLevel(mipLevel), useGeneralLayout(useGeneralLayout) {}; + inline SampledImageDescriptorWrite(uint32_t binding, ImageHandle image, uint32_t mipLevel = 0, bool useGeneralLayout = false, uint32_t arrayIndex = 0) + : binding(binding), image(image), mipLevel(mipLevel), useGeneralLayout(useGeneralLayout), arrayIndex(arrayIndex) {}; uint32_t binding; ImageHandle image; uint32_t mipLevel; bool useGeneralLayout; + uint32_t arrayIndex; }; struct StorageImageDescriptorWrite { diff --git a/projects/bindless_textures/resources/cube/Grass001_1K_AmbientOcclusion.jpg b/projects/bindless_textures/resources/cube/Grass001_1K_AmbientOcclusion.jpg new file mode 100644 index 00000000..2217fb53 --- /dev/null +++ b/projects/bindless_textures/resources/cube/Grass001_1K_AmbientOcclusion.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6c88f8f3facd9e91f8dd160bd8c4a602e433872ed18e08015a9fa9dfff889de +size 901465 diff --git a/projects/bindless_textures/resources/cube/Grass001_1K_Color.jpg b/projects/bindless_textures/resources/cube/Grass001_1K_Color.jpg new file mode 100644 index 00000000..b8aa1533 --- /dev/null +++ b/projects/bindless_textures/resources/cube/Grass001_1K_Color.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:878b8fe4747d9ce693220edea1915de550e8f14d402d26a0915f162d40f84e91 +size 1763328 diff --git a/projects/bindless_textures/resources/cube/Grass001_1K_Displacement.jpg b/projects/bindless_textures/resources/cube/Grass001_1K_Displacement.jpg new file mode 100644 index 00000000..89789cba --- /dev/null +++ b/projects/bindless_textures/resources/cube/Grass001_1K_Displacement.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e8300e1107bee7e681059d9da0a7e3ca422977e8b6f496e16452a4c94b3d385 +size 912347 diff --git a/projects/bindless_textures/resources/cube/Grass001_1K_Normal.jpg b/projects/bindless_textures/resources/cube/Grass001_1K_Normal.jpg new file mode 100644 index 00000000..3163d639 --- /dev/null +++ b/projects/bindless_textures/resources/cube/Grass001_1K_Normal.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:684426b49e841e267f12f06dc955b5b1d01b3ba3659bea0c5d73be889700929f +size 2336471 diff --git a/projects/bindless_textures/resources/cube/Grass001_1K_Roughness.jpg b/projects/bindless_textures/resources/cube/Grass001_1K_Roughness.jpg new file mode 100644 index 00000000..10e6ac33 --- /dev/null +++ b/projects/bindless_textures/resources/cube/Grass001_1K_Roughness.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d952ffb098faf9ac5eb25134eabac08f0c65d927a448b5e7b4f9c72510cfcbe0 +size 822659 diff --git a/projects/bindless_textures/resources/shaders/shader.frag b/projects/bindless_textures/resources/shaders/shader.frag index ba9ee901..7b211cb2 100644 --- a/projects/bindless_textures/resources/shaders/shader.frag +++ b/projects/bindless_textures/resources/shaders/shader.frag @@ -4,12 +4,13 @@ layout(location = 0) in vec3 passNormal; layout(location = 1) in vec2 passUV; +layout(location = 2) in flat int passTextureIndex; layout(location = 0) out vec3 outColor; -layout(set=0, binding=0) uniform texture2D materialTextures[]; -layout(set=0, binding=1) uniform sampler textureSampler; +layout(set=0, binding=0) uniform sampler textureSampler; +layout(set=0, binding=1) uniform texture2D materialTextures[]; void main() { - outColor = texture(sampler2D(materialTextures[1], textureSampler), passUV).rgb; + outColor = texture(sampler2D(materialTextures[passTextureIndex], textureSampler), passUV).rgb; } \ No newline at end of file diff --git a/projects/bindless_textures/resources/shaders/shader.vert b/projects/bindless_textures/resources/shaders/shader.vert index 76855152..57727e4a 100644 --- a/projects/bindless_textures/resources/shaders/shader.vert +++ b/projects/bindless_textures/resources/shaders/shader.vert @@ -7,13 +7,33 @@ layout(location = 2) in vec2 inUV; layout(location = 0) out vec3 passNormal; layout(location = 1) out vec2 passUV; +layout(location = 2) out flat int passTextureIndex; layout( push_constant ) uniform constants{ mat4 mvp; }; -void main() { +void main() +{ gl_Position = mvp * vec4(inPosition, 1.0); passNormal = inNormal; passUV = inUV; + + if(inNormal.x > 0.9) + passTextureIndex = 0; + + if(inNormal.x < -0.9) + passTextureIndex = 1; + + if(inNormal.y > 0.9) + passTextureIndex = 2; + + if(inNormal.y < -0.9) + passTextureIndex = 3; + + if(inNormal.z > 0.9) + passTextureIndex = 4; + + if(inNormal.z < -0.9) + passTextureIndex = 5; } \ No newline at end of file diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp index 496c6405..ae5e0306 100644 --- a/projects/bindless_textures/src/main.cpp +++ b/projects/bindless_textures/src/main.cpp @@ -30,6 +30,26 @@ int main(int argc, const char** argv) { vkcv::asset::Scene mesh; + // TEST DATA + std::vector<vkcv::Image> texturesArray; + const std::string grassPaths[5] = { "resources/cube/Grass001_1K_AmbientOcclusion.jpg", + "resources/cube/Grass001_1K_Color.jpg", + "resources/cube/Grass001_1K_Displacement.jpg", + "resources/cube/Grass001_1K_Normal.jpg", + "resources/cube/Grass001_1K_Roughness.jpg" }; + for(uint32_t i = 0; i < 5; i++) + { + std::filesystem::path grassPath(grassPaths[i]); + vkcv::asset::TextureData grassTexture = vkcv::asset::loadTexture(grassPath); + + vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, grassTexture.width, grassTexture.height); + texture.fill(grassTexture.data.data()); + texture.generateMipChainImmediate(); + texture.switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + + texturesArray.push_back(texture); + } + const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; int result = vkcv::asset::loadScene(path, mesh); @@ -135,6 +155,7 @@ int main(int argc, const char** argv) { texture.fill(tex.data.data()); texture.generateMipChainImmediate(); texture.switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + texturesArray.push_back(texture); vkcv::SamplerHandle sampler = core.createSampler( vkcv::SamplerFilterType::LINEAR, @@ -149,8 +170,18 @@ int main(int argc, const char** argv) { vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; + std::vector<vkcv::SampledImageDescriptorWrite> texturesArrayWrites; + for(uint32_t i = 0; i < 6; i++) + { + texturesArrayWrites.push_back(vkcv::SampledImageDescriptorWrite(1, + texturesArray[i].getHandle(), + 0, + false, + i)); + } + + setWrites.sampledImageWrites = texturesArrayWrites; + setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(0, sampler) }; core.writeDescriptorSet(descriptorSet, setWrites); diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index c143635f..7e9a6b72 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -325,6 +325,7 @@ namespace vkcv // NOTE: what about // shaderSampledImageArrayNonUniformIndexing ? descriptorIndexingFeatures.descriptorBindingPartiallyBound = true; + descriptorIndexingFeatures.descriptorBindingVariableDescriptorCount = true; descriptorIndexingFeatures.runtimeDescriptorArray = true; deviceFeatures2.setPNext(&descriptorIndexingFeatures); } diff --git a/src/vkcv/DescriptorConfig.cpp b/src/vkcv/DescriptorConfig.cpp index 54e879ac..8d02f889 100644 --- a/src/vkcv/DescriptorConfig.cpp +++ b/src/vkcv/DescriptorConfig.cpp @@ -5,11 +5,13 @@ namespace vkcv { uint32_t bindingID, DescriptorType descriptorType, uint32_t descriptorCount, - ShaderStage shaderStage) noexcept + ShaderStage shaderStage, + bool variableCount) noexcept : bindingID(bindingID), descriptorType(descriptorType), descriptorCount(descriptorCount), - shaderStage(shaderStage) {} + shaderStage(shaderStage), + variableCount(variableCount){} } diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp index 0df359a1..8e43259f 100644 --- a/src/vkcv/DescriptorManager.cpp +++ b/src/vkcv/DescriptorManager.cpp @@ -48,20 +48,46 @@ namespace vkcv { std::vector<vk::DescriptorSetLayoutBinding> setBindings = {}; - //create each set's binding - for (auto binding : bindings) { + // When using a variable descriptor count, the reflected bindings' descriptorCount value is 0. + // However, a proper value has to be specified. Problem is, this value still counts towards Vulkan's limits, + // which is why we can't really use something like UINT32_MAX. So, 128 has been chosen. + const uint32_t variableDescriptorCountLimit = 128; + + //create set's bindings + for (auto binding : bindings) + { vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding( binding.bindingID, convertDescriptorTypeFlag(binding.descriptorType), binding.descriptorCount, convertShaderStageFlag(binding.shaderStage)); + + if(binding.variableCount) + // magic number + descriptorSetLayoutBinding.descriptorCount = variableDescriptorCountLimit; + setBindings.push_back(descriptorSetLayoutBinding); } - DescriptorSet set; - - //create the descriptor set's layout from the bindings gathered above + std::vector<vk::DescriptorBindingFlags> bindingFlags; + // create binding flags + for (auto binding : bindings) + { + if (binding.variableCount) + { + bindingFlags.push_back(vk::DescriptorBindingFlagBitsEXT::eVariableDescriptorCount | + vk::DescriptorBindingFlagBitsEXT::ePartiallyBound); + } else + { + bindingFlags.push_back({}); + } + } + vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo(static_cast<uint32_t>(bindingFlags.size()), bindingFlags.data()); + //create the descriptor set's layout from the binding and flag information gathered above vk::DescriptorSetLayoutCreateInfo layoutInfo({}, setBindings); + layoutInfo.setPNext(&bindingFlagsInfo); + + DescriptorSet set; if (m_Device.createDescriptorSetLayout(&layoutInfo, nullptr, &set.layout) != vk::Result::eSuccess) { vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout"); return DescriptorSetHandle(); @@ -69,6 +95,9 @@ namespace vkcv //create and allocate the set based on the layout that have been gathered above vk::DescriptorSetAllocateInfo allocInfo(m_Pools.back(), 1, &set.layout); + vk::DescriptorSetVariableDescriptorCountAllocateInfo variableAllocInfo = {1, &variableDescriptorCountLimit}; + allocInfo.setPNext(&variableAllocInfo); + auto result = m_Device.allocateDescriptorSets(&allocInfo, &set.vulkanHandle); if(result != vk::Result::eSuccess) { @@ -100,6 +129,7 @@ namespace vkcv size_t imageInfoIndex; size_t bufferInfoIndex; uint32_t binding; + uint32_t arrayElementIndex; vk::DescriptorType type; }; @@ -116,7 +146,8 @@ namespace vkcv std::vector<WriteDescriptorSetInfo> writeInfos; - for (const auto& write : writes.sampledImageWrites) { + for (const auto& write : writes.sampledImageWrites) + { vk::ImageLayout layout = write.useGeneralLayout ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal; const vk::DescriptorImageInfo imageInfo( nullptr, @@ -130,6 +161,7 @@ namespace vkcv imageInfos.size(), 0, write.binding, + write.arrayIndex, vk::DescriptorType::eSampledImage, }; @@ -149,6 +181,7 @@ namespace vkcv imageInfos.size(), 0, write.binding, + 0, vk::DescriptorType::eStorageImage }; @@ -173,6 +206,7 @@ namespace vkcv 0, bufferInfos.size(), write.binding, + 0, write.dynamic? vk::DescriptorType::eUniformBufferDynamic : vk::DescriptorType::eUniformBuffer @@ -199,6 +233,7 @@ namespace vkcv 0, bufferInfos.size(), write.binding, + 0, write.dynamic? vk::DescriptorType::eStorageBufferDynamic : vk::DescriptorType::eStorageBuffer @@ -222,6 +257,7 @@ namespace vkcv imageInfos.size(), 0, write.binding, + 0, vk::DescriptorType::eSampler }; @@ -234,7 +270,7 @@ namespace vkcv vk::WriteDescriptorSet vulkanWrite( set, write.binding, - static_cast<uint32_t>(0), + write.arrayElementIndex, 1, write.type, (write.imageInfoIndex > 0? &(imageInfos[write.imageInfoIndex - 1]) : nullptr), diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp index 971797d9..1308a1b2 100644 --- a/src/vkcv/ShaderProgram.cpp +++ b/src/vkcv/ShaderProgram.cpp @@ -175,12 +175,33 @@ namespace vkcv { for (uint32_t i = 0; i < resources.separate_images.size(); i++) { auto& u = resources.separate_images[i]; const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); - std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet), - DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::IMAGE_SAMPLED, base_type.vecsize, shaderStage)); + + // we require the type (not base type!) to query array information + const spirv_cross::SPIRType& type = comp.get_type(u.type_id); + + uint32_t descriptorCount = 1; + bool variableCount = false; + + if(type.array_size_literal[0]) + { + if(type.array[0] == 0) + variableCount = true; + + descriptorCount = type.array[0]; + } + + DescriptorBinding descBinding(comp.get_decoration(u.id, spv::DecorationBinding), + DescriptorType::IMAGE_SAMPLED, + descriptorCount, + shaderStage, + variableCount); + + std::pair<uint32_t, DescriptorBinding> descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet), descBinding); + + bindings.push_back(descriptor); if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet); - } for (uint32_t i = 0; i < resources.storage_images.size(); i++) { -- GitLab