From 54f27a8277b6d462987b4340356e2a17b95739e1 Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 10 Mar 2024 14:41:37 +0100 Subject: [PATCH 1/3] vulkan: unify local uniform buffer --- src/modules/graphics/vulkan/Graphics.cpp | 28 +++++++++--- src/modules/graphics/vulkan/Graphics.h | 3 +- src/modules/graphics/vulkan/Shader.cpp | 58 +----------------------- src/modules/graphics/vulkan/Shader.h | 8 ---- 4 files changed, 25 insertions(+), 72 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 7687d8bb6..ab1f799ef 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -153,6 +153,7 @@ Graphics::~Graphics() { defaultConstantTexCoord.set(nullptr); defaultConstantColor.set(nullptr); + localUniformBuffer.set(nullptr); Volatile::unloadAll(); cleanup(); @@ -650,6 +651,9 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int createSyncObjects(); } + if (localUniformBuffer == nullptr) + localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, 1024 * 512 * 1), Acquire::NORETAIN); + beginFrame(); if (createBaseObjects) @@ -1302,9 +1306,11 @@ void Graphics::beginFrame() Vulkan::resetShaderSwitches(); - for (const auto shader : usedShadersInFrame) + for (const auto &shader : usedShadersInFrame) shader->newFrame(); usedShadersInFrame.clear(); + + localUniformBuffer->nextFrame(); } void Graphics::startRecordingGraphicsCommands() @@ -1330,11 +1336,6 @@ void Graphics::endRecordingGraphicsCommands() { throw love::Exception("failed to record command buffer"); } -const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const -{ - return minUniformBufferOffsetAlignment; -} - VkCommandBuffer Graphics::getCommandBufferForDataTransfer() { if (renderPassState.active) @@ -2869,6 +2870,21 @@ int Graphics::getVsync() const return vsync; } +void Graphics::mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo) +{ + size_t alignedSize = static_cast(std::ceil(static_cast(size) / static_cast(minUniformBufferOffsetAlignment))) * minUniformBufferOffsetAlignment; + + if (localUniformBuffer->getUsableSize() < alignedSize) + localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, localUniformBuffer->getSize() * 2), Acquire::NORETAIN); + + auto mapInfo = localUniformBuffer->map(alignedSize); + memcpy(mapInfo.data, data, size); + + bufferInfo.buffer = (VkBuffer)localUniformBuffer->getHandle(); + bufferInfo.offset = localUniformBuffer->unmap(alignedSize); + bufferInfo.range = size; +} + void Graphics::createColorResources() { if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index d64aa3bff..a000120bf 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -316,7 +316,6 @@ class Graphics final : public love::graphics::Graphics void queueCleanUp(std::function cleanUp); void addReadbackCallback(std::function callback); void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr); - const VkDeviceSize getMinUniformBufferOffsetAlignment() const; VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); @@ -325,6 +324,7 @@ class Graphics final : public love::graphics::Graphics VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const; void setVsync(int vsync); int getVsync() const; + void mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo); uint32 getDeviceApiVersion() const { return deviceApiVersion; } @@ -444,6 +444,7 @@ class Graphics final : public love::graphics::Graphics VmaAllocator vmaAllocator = VK_NULL_HANDLE; StrongRef defaultConstantColor; StrongRef defaultConstantTexCoord; + StrongRef localUniformBuffer; // functions that need to be called to cleanup objects that were needed for rendering a frame. // We need a vector for each frame in flight. std::vector>> cleanUpFunctions; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index f28b8bfd8..ba2a1d9a2 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -157,14 +157,11 @@ bool Shader::loadVolatile() builtinUniformInfo[i] = nullptr; compileShaders(); - calculateUniformBufferSizeAligned(); createDescriptorSetLayout(); createPipelineLayout(); createDescriptorPoolSizes(); - createStreamBuffers(); descriptorPools.resize(MAX_FRAMES_IN_FLIGHT); currentFrame = 0; - currentUsedUniformStreamBuffersCount = 0; newFrame(); return true; @@ -189,12 +186,8 @@ void Shader::unloadVolatile() vkDestroyPipeline(device, computePipeline, nullptr); }); - for (const auto streamBuffer : streamBuffers) - streamBuffer->release(); - shaderModules.clear(); shaderStages.clear(); - streamBuffers.clear(); descriptorPools.clear(); } @@ -217,23 +210,8 @@ void Shader::newFrame() { currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; - currentUsedUniformStreamBuffersCount = 0; currentDescriptorPool = 0; - if (streamBuffers.size() > 1) - { - size_t newSize = 0; - for (auto streamBuffer : streamBuffers) - { - newSize += streamBuffer->getSize(); - streamBuffer->release(); - } - streamBuffers.clear(); - streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, newSize)); - } - else if (streamBuffers.size() == 1) - streamBuffers.at(0)->nextFrame(); - for (VkDescriptorPool pool : descriptorPools[currentFrame]) vkResetDescriptorPool(device, pool, 0); } @@ -246,13 +224,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind if (!localUniformData.empty()) { - auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned; - if (usedStreamBufferMemory >= streamBuffers.back()->getSize()) - { - streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned)); - currentUsedUniformStreamBuffersCount = 0; - } - if (builtinUniformDataOffset.hasValue) { auto builtinData = vgfx->getCurrentBuiltinUniformData(); @@ -260,19 +231,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind memcpy(dst, &builtinData, sizeof(builtinData)); } - auto currentStreamBuffer = streamBuffers.back(); - - auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned); - memcpy(mapInfo.data, localUniformData.data(), localUniformData.size()); - auto offset = currentStreamBuffer->unmap(uniformBufferSizeAligned); - currentStreamBuffer->markUsed(uniformBufferSizeAligned); - - VkDescriptorBufferInfo &bufferInfo = descriptorBuffers[bufferIndex++]; - bufferInfo.buffer = (VkBuffer)currentStreamBuffer->getHandle(); - bufferInfo.offset = offset; - bufferInfo.range = localUniformData.size(); - - currentUsedUniformStreamBuffersCount++; + vgfx->mapLocalUniformData(localUniformData.data(), localUniformData.size(), descriptorBuffers[bufferIndex++]); } // TODO: iteration order must match the order at the end of compileShaders right now. @@ -436,14 +395,6 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe } } -void Shader::calculateUniformBufferSizeAligned() -{ - auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment(); - size_t size = localUniformStagingData.size(); - auto factor = static_cast(std::ceil(static_cast(size) / static_cast(minAlignment))); - uniformBufferSizeAligned = factor * minAlignment; -} - void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) { using namespace spirv_cross; @@ -978,13 +929,6 @@ void Shader::createDescriptorPoolSizes() } } -void Shader::createStreamBuffers() -{ - size_t size = STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned; - if (size > 0) - streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, size)); -} - void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) { std::array textures = { diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 7639fdaf4..cbca89218 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -88,27 +88,20 @@ class Shader final void setMainTex(graphics::Texture *texture); private: - void calculateUniformBufferSizeAligned(); void compileShaders(); void createDescriptorSetLayout(); void createPipelineLayout(); void createDescriptorPoolSizes(); - void createStreamBuffers(); void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); void createDescriptorPool(); VkDescriptorSet allocateDescriptorSet(); - VkDeviceSize uniformBufferSizeAligned; - VkPipeline computePipeline; 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 that gets dynamically increased if more memory is needed - std::vector streamBuffers; std::vector> descriptorPools; std::vector descriptorBuffers; @@ -135,7 +128,6 @@ class Shader final std::unordered_map attributes; uint32_t currentFrame; - uint32_t currentUsedUniformStreamBuffersCount; uint32_t currentDescriptorPool; }; From 295fb214d524e72fc7136a8647e28e71f59d075e Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 11 Mar 2024 13:47:43 +0100 Subject: [PATCH 2/3] vulkan: remove unused constant and use correct sizes for mapping the local uniform stream buffer --- src/modules/graphics/vulkan/Graphics.cpp | 6 ++++-- src/modules/graphics/vulkan/Shader.cpp | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index ab1f799ef..2e1360f1b 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -2877,12 +2877,14 @@ void Graphics::mapLocalUniformData(void *data, size_t size, VkDescriptorBufferIn if (localUniformBuffer->getUsableSize() < alignedSize) localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, localUniformBuffer->getSize() * 2), Acquire::NORETAIN); - auto mapInfo = localUniformBuffer->map(alignedSize); + auto mapInfo = localUniformBuffer->map(size); memcpy(mapInfo.data, data, size); bufferInfo.buffer = (VkBuffer)localUniformBuffer->getHandle(); - bufferInfo.offset = localUniformBuffer->unmap(alignedSize); + bufferInfo.offset = localUniformBuffer->unmap(size); bufferInfo.range = size; + + localUniformBuffer->markUsed(alignedSize); } void Graphics::createColorResources() diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index ba2a1d9a2..1c70616c0 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -36,7 +36,6 @@ namespace graphics namespace vulkan { -static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16; static const uint32_t DESCRIPTOR_POOL_SIZE = 1000; class BindingMapper From 07c5c44ea36851f42afc71f0f9182ba53b26d1fc Mon Sep 17 00:00:00 2001 From: niki Date: Wed, 13 Mar 2024 22:16:33 +0100 Subject: [PATCH 3/3] vulkan: simplify code with alignUp --- src/modules/graphics/vulkan/Graphics.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 2e1360f1b..939ed5be3 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -21,6 +21,7 @@ #include "common/Exception.h" #include "common/pixelformat.h" #include "common/version.h" +#include "common/memory.h" #include "window/Window.h" #include "Buffer.h" #include "Graphics.h" @@ -2872,7 +2873,7 @@ int Graphics::getVsync() const void Graphics::mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo) { - size_t alignedSize = static_cast(std::ceil(static_cast(size) / static_cast(minUniformBufferOffsetAlignment))) * minUniformBufferOffsetAlignment; + size_t alignedSize = alignUp(size, minUniformBufferOffsetAlignment); if (localUniformBuffer->getUsableSize() < alignedSize) localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, localUniformBuffer->getSize() * 2), Acquire::NORETAIN);