vulkan: unify local uniform buffer

This commit is contained in:
niki
2024-03-10 14:41:37 +01:00
parent b6c47cd3ec
commit 54f27a8277
4 changed files with 25 additions and 72 deletions
+22 -6
View File
@@ -153,6 +153,7 @@ Graphics::~Graphics()
{ {
defaultConstantTexCoord.set(nullptr); defaultConstantTexCoord.set(nullptr);
defaultConstantColor.set(nullptr); defaultConstantColor.set(nullptr);
localUniformBuffer.set(nullptr);
Volatile::unloadAll(); Volatile::unloadAll();
cleanup(); cleanup();
@@ -650,6 +651,9 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
createSyncObjects(); createSyncObjects();
} }
if (localUniformBuffer == nullptr)
localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, 1024 * 512 * 1), Acquire::NORETAIN);
beginFrame(); beginFrame();
if (createBaseObjects) if (createBaseObjects)
@@ -1302,9 +1306,11 @@ void Graphics::beginFrame()
Vulkan::resetShaderSwitches(); Vulkan::resetShaderSwitches();
for (const auto shader : usedShadersInFrame) for (const auto &shader : usedShadersInFrame)
shader->newFrame(); shader->newFrame();
usedShadersInFrame.clear(); usedShadersInFrame.clear();
localUniformBuffer->nextFrame();
} }
void Graphics::startRecordingGraphicsCommands() void Graphics::startRecordingGraphicsCommands()
@@ -1330,11 +1336,6 @@ void Graphics::endRecordingGraphicsCommands() {
throw love::Exception("failed to record command buffer"); throw love::Exception("failed to record command buffer");
} }
const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const
{
return minUniformBufferOffsetAlignment;
}
VkCommandBuffer Graphics::getCommandBufferForDataTransfer() VkCommandBuffer Graphics::getCommandBufferForDataTransfer()
{ {
if (renderPassState.active) if (renderPassState.active)
@@ -2869,6 +2870,21 @@ int Graphics::getVsync() const
return vsync; return vsync;
} }
void Graphics::mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo)
{
size_t alignedSize = static_cast<size_t>(std::ceil(static_cast<float>(size) / static_cast<float>(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() void Graphics::createColorResources()
{ {
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
+2 -1
View File
@@ -316,7 +316,6 @@ public:
void queueCleanUp(std::function<void()> cleanUp); void queueCleanUp(std::function<void()> cleanUp);
void addReadbackCallback(std::function<void()> callback); void addReadbackCallback(std::function<void()> callback);
void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr); void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr);
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
VkSampler getCachedSampler(const SamplerState &sampler); VkSampler getCachedSampler(const SamplerState &sampler);
void setComputeShader(Shader *computeShader); void setComputeShader(Shader *computeShader);
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
@@ -325,6 +324,7 @@ public:
VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const; VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const;
void setVsync(int vsync); void setVsync(int vsync);
int getVsync() const; int getVsync() const;
void mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo);
uint32 getDeviceApiVersion() const { return deviceApiVersion; } uint32 getDeviceApiVersion() const { return deviceApiVersion; }
@@ -444,6 +444,7 @@ private:
VmaAllocator vmaAllocator = VK_NULL_HANDLE; VmaAllocator vmaAllocator = VK_NULL_HANDLE;
StrongRef<love::graphics::Buffer> defaultConstantColor; StrongRef<love::graphics::Buffer> defaultConstantColor;
StrongRef<love::graphics::Buffer> defaultConstantTexCoord; StrongRef<love::graphics::Buffer> defaultConstantTexCoord;
StrongRef<StreamBuffer> localUniformBuffer;
// functions that need to be called to cleanup objects that were needed for rendering a frame. // 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. // We need a vector for each frame in flight.
std::vector<std::vector<std::function<void()>>> cleanUpFunctions; std::vector<std::vector<std::function<void()>>> cleanUpFunctions;
+1 -57
View File
@@ -157,14 +157,11 @@ bool Shader::loadVolatile()
builtinUniformInfo[i] = nullptr; builtinUniformInfo[i] = nullptr;
compileShaders(); compileShaders();
calculateUniformBufferSizeAligned();
createDescriptorSetLayout(); createDescriptorSetLayout();
createPipelineLayout(); createPipelineLayout();
createDescriptorPoolSizes(); createDescriptorPoolSizes();
createStreamBuffers();
descriptorPools.resize(MAX_FRAMES_IN_FLIGHT); descriptorPools.resize(MAX_FRAMES_IN_FLIGHT);
currentFrame = 0; currentFrame = 0;
currentUsedUniformStreamBuffersCount = 0;
newFrame(); newFrame();
return true; return true;
@@ -189,12 +186,8 @@ void Shader::unloadVolatile()
vkDestroyPipeline(device, computePipeline, nullptr); vkDestroyPipeline(device, computePipeline, nullptr);
}); });
for (const auto streamBuffer : streamBuffers)
streamBuffer->release();
shaderModules.clear(); shaderModules.clear();
shaderStages.clear(); shaderStages.clear();
streamBuffers.clear();
descriptorPools.clear(); descriptorPools.clear();
} }
@@ -217,23 +210,8 @@ void Shader::newFrame()
{ {
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
currentUsedUniformStreamBuffersCount = 0;
currentDescriptorPool = 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]) for (VkDescriptorPool pool : descriptorPools[currentFrame])
vkResetDescriptorPool(device, pool, 0); vkResetDescriptorPool(device, pool, 0);
} }
@@ -246,13 +224,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind
if (!localUniformData.empty()) 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) if (builtinUniformDataOffset.hasValue)
{ {
auto builtinData = vgfx->getCurrentBuiltinUniformData(); auto builtinData = vgfx->getCurrentBuiltinUniformData();
@@ -260,19 +231,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind
memcpy(dst, &builtinData, sizeof(builtinData)); memcpy(dst, &builtinData, sizeof(builtinData));
} }
auto currentStreamBuffer = streamBuffers.back(); vgfx->mapLocalUniformData(localUniformData.data(), localUniformData.size(), descriptorBuffers[bufferIndex++]);
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++;
} }
// TODO: iteration order must match the order at the end of compileShaders right now. // 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<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) void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename)
{ {
using namespace spirv_cross; 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) void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture)
{ {
std::array<graphics::Texture*, 3> textures = { std::array<graphics::Texture*, 3> textures = {
-8
View File
@@ -88,27 +88,20 @@ public:
void setMainTex(graphics::Texture *texture); void setMainTex(graphics::Texture *texture);
private: private:
void calculateUniformBufferSizeAligned();
void compileShaders(); void compileShaders();
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createPipelineLayout(); void createPipelineLayout();
void createDescriptorPoolSizes(); void createDescriptorPoolSizes();
void createStreamBuffers();
void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename);
void createDescriptorPool(); void createDescriptorPool();
VkDescriptorSet allocateDescriptorSet(); VkDescriptorSet allocateDescriptorSet();
VkDeviceSize uniformBufferSizeAligned;
VkPipeline computePipeline; VkPipeline computePipeline;
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
std::vector<VkDescriptorPoolSize> descriptorPoolSizes; 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<std::vector<VkDescriptorPool>> descriptorPools;
std::vector<VkDescriptorBufferInfo> descriptorBuffers; std::vector<VkDescriptorBufferInfo> descriptorBuffers;
@@ -135,7 +128,6 @@ private:
std::unordered_map<std::string, int> attributes; std::unordered_map<std::string, int> attributes;
uint32_t currentFrame; uint32_t currentFrame;
uint32_t currentUsedUniformStreamBuffersCount;
uint32_t currentDescriptorPool; uint32_t currentDescriptorPool;
}; };