From ef80e11b4d966c742e1eac1b8c80dadd0b8b0ded Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 11 Sep 2022 13:02:38 +0200 Subject: [PATCH] vulkan: add support for uniform texture arrays --- src/modules/graphics/vulkan/Graphics.cpp | 15 --- src/modules/graphics/vulkan/Graphics.h | 18 ++- src/modules/graphics/vulkan/Shader.cpp | 152 ++++++++++++----------- src/modules/graphics/vulkan/Shader.h | 2 + 4 files changed, 90 insertions(+), 97 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 9714fb15c..e378c838a 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -55,11 +55,6 @@ const VkDevice Graphics::getDevice() const return device; } -const VkPhysicalDevice Graphics::getPhysicalDevice() const -{ - return physicalDevice; -} - const VmaAllocator Graphics::getVmaAllocator() const { return vmaAllocator; @@ -2072,16 +2067,6 @@ std::set &Graphics::getUsedShadersInFrame() return usedShadersInFrame; } -const OptionalDeviceFeatures &Graphics::getOptionalDeviceFeatures() const -{ - return optionalDeviceFeatures; -} - -const OptionalDeviceExtensionFunctions &Graphics::getExtensionFunctions() const -{ - return ext; -} - VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) { auto it = samplers.find(samplerState); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 7289cc323..00ab90b38 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -122,7 +122,7 @@ struct GraphicsPipelineConfiguration { VkRenderPass renderPass; VertexAttributes vertexAttributes; - Shader* shader = nullptr; + Shader *shader = nullptr; bool wireFrame; BlendState blendState; ColorChannelMask colorChannelMask; @@ -168,10 +168,10 @@ struct SamplerStateHasher struct BatchedDrawBuffers { - StreamBuffer* vertexBuffer1; - StreamBuffer* vertexBuffer2; - StreamBuffer* indexBuffer; - StreamBuffer* constantColorBuffer; + StreamBuffer *vertexBuffer1; + StreamBuffer *vertexBuffer2; + StreamBuffer *indexBuffer; + StreamBuffer *constantColorBuffer; ~BatchedDrawBuffers() { @@ -231,7 +231,6 @@ public: const char *getName() const override; const VkDevice getDevice() const; - const VkPhysicalDevice getPhysicalDevice() const; const VmaAllocator getVmaAllocator() const; // implementation for virtual functions @@ -282,14 +281,11 @@ public: const VkDeviceSize getMinUniformBufferOffsetAlignment() const; graphics::Texture *getDefaultTexture() const; - VkSampler getCachedSampler(const SamplerState&); + VkSampler getCachedSampler(const SamplerState &); - void setComputeShader(Shader*); + void setComputeShader(Shader *); std::set &getUsedShadersInFrame(); - const OptionalDeviceFeatures &getOptionalDeviceFeatures() const; - const OptionalDeviceExtensionFunctions &getExtensionFunctions() const; - graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); protected: diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index a311735a6..edfa64e64 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -159,7 +159,6 @@ Shader::Shader(StrongRef stages[]) { auto gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); vgfx = dynamic_cast(gfx); - auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures(); loadVolatile(); } @@ -175,6 +174,7 @@ bool Shader::loadVolatile() calculateUniformBufferSizeAligned(); createDescriptorSetLayout(); createPipelineLayout(); + createDescriptorPoolSizes(); createStreamBuffers(); descriptorSetsVector.resize(vgfx->getNumImagesInFlight()); currentFrame = 0; @@ -230,7 +230,7 @@ VkPipeline Shader::getComputePipeline() const return computePipeline; } -static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler) +static VkDescriptorImageInfo *createDescriptorImageInfo(graphics::Texture *texture, bool sampler) { auto vkTexture = (Texture*)texture; @@ -270,10 +270,6 @@ void Shader::newFrame(uint32_t frameIndex) currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); - std::vector descriptorWrite{}; - - std::vector imageInfos; - // update everything other than uniform buffers for (const auto &[key, val] : uniformInfos) { // fixme: other types. @@ -284,14 +280,25 @@ void Shader::newFrame(uint32_t frameIndex) write.dstBinding = val.location; write.dstArrayElement = 0; write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write.descriptorCount = 1; + write.descriptorCount = val.count; - VkDescriptorImageInfo* imageInfo = createDescriptorImageInfo(val.textures[0], true); // fixme: arrays - imageInfos.push_back(imageInfo); + std::vector imageInfos; - write.pImageInfo = imageInfo; + for (int i = 0; i < val.count; i++) + { + auto vkTexture = dynamic_cast(val.textures[i]); - descriptorWrite.push_back(write); + VkDescriptorImageInfo imageInfo{}; + imageInfo.imageLayout = vkTexture->getImageLayout(); + imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle(); + imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle(); + + imageInfos.push_back(imageInfo); + } + + write.pImageInfo = imageInfos.data(); + + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); } if (val.baseType == UNIFORM_STORAGETEXTURE) { VkWriteDescriptorSet write{}; @@ -300,20 +307,26 @@ void Shader::newFrame(uint32_t frameIndex) write.dstBinding = val.location; write.dstArrayElement = 0; write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - write.descriptorCount = 1; + write.descriptorCount = val.count; - VkDescriptorImageInfo* imageInfo = createDescriptorImageInfo(val.textures[0], false); // fixme: arrays - imageInfos.push_back(imageInfo); + std::vector imageInfos; - write.pImageInfo = imageInfo; - descriptorWrite.push_back(write); + for (int i = 0; i < val.count; i++) + { + auto vkTexture = dynamic_cast(val.textures[i]); + + VkDescriptorImageInfo imageInfo{}; + imageInfo.imageLayout = vkTexture->getImageLayout(); + imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle(); + + imageInfos.push_back(imageInfo); + } + + write.pImageInfo = imageInfos.data(); + + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); } } - - vkUpdateDescriptorSets(device, static_cast(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr); - - for (const auto imageInfo : imageInfos) - delete imageInfo; } void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) @@ -334,7 +347,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind memcpy(dst, &builtinData, sizeof(builtinData)); } - // additional data is always added onto the last stream buffer in the current frame auto currentStreamBuffer = streamBuffers.at(currentFrame).back(); auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned); @@ -928,6 +940,30 @@ void Shader::createPipelineLayout() } } +void Shader::createDescriptorPoolSizes() +{ + if (!localUniformData.empty()) + { + VkDescriptorPoolSize size{}; + size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + size.descriptorCount = 1; + + descriptorPoolSizes.push_back(size); + } + + for (const auto &[key, val] : uniformInfos) + { + VkDescriptorPoolSize size{}; + auto type = Vulkan::getDescriptorType(val.baseType); + if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + continue; + } + size.type = type; + size.descriptorCount = 1; + descriptorPoolSizes.push_back(size); + } +} + void Shader::createStreamBuffers() { const auto numImagesInFlight = vgfx->getNumImagesInFlight(); @@ -938,29 +974,25 @@ void Shader::createStreamBuffers() void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) { - // if the shader doesn't actually use these textures they might get optimized out - // in that case this function becomes a noop. - if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y] != nullptr) - { - auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0]; - ytexture->retain(); - oldTexture->release(); - builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0] = ytexture; - } - if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB] != nullptr) - { - auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0]; - cbtexture->retain(); - oldTexture->release(); - builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0] = cbtexture; - } - if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR] != nullptr) - { - auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0]; - crtexture->retain(); - oldTexture->release(); - builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0] = crtexture; - } + std::array textures = { + ytexture, cbtexture, crtexture + }; + + std::array builtIns = { + BUILTIN_TEXTURE_VIDEO_Y, + BUILTIN_TEXTURE_VIDEO_CB, + BUILTIN_TEXTURE_VIDEO_CR, + }; + + static_assert(textures.size() == builtIns.size()); + + for (size_t i = 0; i < textures.size(); i++) + if (builtinUniformInfo[builtIns[i]] != nullptr) + { + textures[i]->retain(); + builtinUniformInfo[builtIns[i]]->textures[0]->release(); + builtinUniformInfo[builtIns[i]]->textures[0] = textures[i]; + } } bool Shader::hasUniform(const std::string &name) const @@ -972,9 +1004,8 @@ void Shader::setMainTex(graphics::Texture *texture) { if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) { - auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]; texture->retain(); - oldTexture->release(); + builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release(); builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture; } } @@ -983,32 +1014,11 @@ VkDescriptorSet Shader::allocateDescriptorSet() { if (freeDescriptorSets.empty()) { - // fixme: we can optimize this, since sizes should never change for a given shader. - std::vector sizes; - - VkDescriptorPoolSize size{}; - size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - size.descriptorCount = 1; - - sizes.push_back(size); - - for (const auto &[key, val] : uniformInfos) - { - VkDescriptorPoolSize size{}; - auto type = Vulkan::getDescriptorType(val.baseType); - if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - continue; - } - size.type = type; - size.descriptorCount = 1; - sizes.push_back(size); - } - VkDescriptorPoolCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; createInfo.maxSets = DESCRIPTOR_POOL_SIZE; - createInfo.poolSizeCount = static_cast(sizes.size()); - createInfo.pPoolSizes = sizes.data(); + createInfo.poolSizeCount = static_cast(descriptorPoolSizes.size()); + createInfo.pPoolSizes = descriptorPoolSizes.data(); VkDescriptorPool pool; if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) @@ -1019,7 +1029,7 @@ VkDescriptorSet Shader::allocateDescriptorSet() VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = descriptorPools.back(); + allocInfo.descriptorPool = pool; allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE; allocInfo.pSetLayouts = layouts.data(); diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index dbd418c02..757ad1f42 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -74,6 +74,7 @@ private: void compileShaders(); void createDescriptorSetLayout(); void createPipelineLayout(); + void createDescriptorPoolSizes(); void createStreamBuffers(); void buildLocalUniforms( spirv_cross::Compiler &comp, @@ -89,6 +90,7 @@ private: VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; + std::vector descriptorPoolSizes; // we don't know how much memory we need per frame for the uniform buffer descriptors // we keep a vector of stream buffers per frame in flight