Skip to content

Commit

Permalink
Merge pull request love2d#2037 from nikeinikei/main
Browse files Browse the repository at this point in the history
vk: unify local uniform buffer
  • Loading branch information
slime73 authored Mar 13, 2024
2 parents 19d714d + 07c5c44 commit f388736
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 73 deletions.
31 changes: 25 additions & 6 deletions src/modules/graphics/vulkan/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -153,6 +154,7 @@ Graphics::~Graphics()
{
defaultConstantTexCoord.set(nullptr);
defaultConstantColor.set(nullptr);
localUniformBuffer.set(nullptr);

Volatile::unloadAll();
cleanup();
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/modules/graphics/vulkan/Graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,6 @@ class Graphics final : public love::graphics::Graphics
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();
Expand All @@ -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; }

Expand Down Expand Up @@ -444,6 +444,7 @@ class Graphics final : public love::graphics::Graphics
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;
Expand Down
59 changes: 1 addition & 58 deletions src/modules/graphics/vulkan/Shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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();
}

Expand All @@ -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);
}
Expand All @@ -246,33 +223,14 @@ 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();
auto dst = localUniformData.data() + builtinUniformDataOffset.value;
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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 = {
Expand Down
8 changes: 0 additions & 8 deletions src/modules/graphics/vulkan/Shader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<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;
Expand All @@ -135,7 +128,6 @@ class Shader final
std::unordered_map<std::string, int> attributes;

uint32_t currentFrame;
uint32_t currentUsedUniformStreamBuffersCount;
uint32_t currentDescriptorPool;
};

Expand Down

0 comments on commit f388736

Please sign in to comment.