mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
Merge pull request #2037 from nikeinikei/main
vk: unify local uniform buffer
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user