Merge pull request #2037 from nikeinikei/main

vk: unify local uniform buffer
This commit is contained in:
Sasha Szpakowski
2024-03-13 18:33:56 -03:00
committed by GitHub
4 changed files with 28 additions and 73 deletions
+25 -6
View File
@@ -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"
@@ -153,6 +154,7 @@ Graphics::~Graphics()
{
defaultConstantTexCoord.set(nullptr);
defaultConstantColor.set(nullptr);
localUniformBuffer.set(nullptr);
Volatile::unloadAll();
cleanup();
@@ -650,6 +652,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 +1307,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 +1337,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 +2871,23 @@ int Graphics::getVsync() const
return vsync;
}
void Graphics::mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo)
{
size_t alignedSize = alignUp(size, minUniformBufferOffsetAlignment);
if (localUniformBuffer->getUsableSize() < alignedSize)
localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, localUniformBuffer->getSize() * 2), Acquire::NORETAIN);
auto mapInfo = localUniformBuffer->map(size);
memcpy(mapInfo.data, data, size);
bufferInfo.buffer = (VkBuffer)localUniformBuffer->getHandle();
bufferInfo.offset = localUniformBuffer->unmap(size);
bufferInfo.range = size;
localUniformBuffer->markUsed(alignedSize);
}
void Graphics::createColorResources()
{
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
+2 -1
View File
@@ -316,7 +316,6 @@ public:
void queueCleanUp(std::function<void()> cleanUp);
void addReadbackCallback(std::function<void()> 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 @@ public:
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 @@ private:
VmaAllocator vmaAllocator = VK_NULL_HANDLE;
StrongRef<love::graphics::Buffer> defaultConstantColor;
StrongRef<love::graphics::Buffer> defaultConstantTexCoord;
StrongRef<StreamBuffer> 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<std::vector<std::function<void()>>> cleanUpFunctions;
+1 -58
View File
@@ -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
@@ -157,14 +156,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 +185,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 +209,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 +223,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 +230,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 +394,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<VkDeviceSize>(std::ceil(static_cast<float>(size) / static_cast<float>(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 +928,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<graphics::Texture*, 3> textures = {
-8
View File
@@ -88,27 +88,20 @@ public:
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<VkDescriptorPoolSize> 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<StreamBuffer*> streamBuffers;
std::vector<std::vector<VkDescriptorPool>> descriptorPools;
std::vector<VkDescriptorBufferInfo> descriptorBuffers;
@@ -135,7 +128,6 @@ private:
std::unordered_map<std::string, int> attributes;
uint32_t currentFrame;
uint32_t currentUsedUniformStreamBuffersCount;
uint32_t currentDescriptorPool;
};