vulkan: dynamically increase size of available memory for uniforms

This commit is contained in:
niki
2022-07-31 03:31:35 +02:00
parent 29dcf3e8c0
commit 845fd16b4b
2 changed files with 40 additions and 12 deletions
+35 -11
View File
@@ -117,7 +117,7 @@ static const TBuiltInResource defaultTBuiltInResource = {
} }
}; };
static const uint32_t STREAMBUFFER_SIZE = 1024; static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16;
static VkShaderStageFlagBits getStageBit(ShaderStageType type) { static VkShaderStageFlagBits getStageBit(ShaderStageType type) {
switch (type) { switch (type) {
@@ -174,8 +174,10 @@ void Shader::unloadVolatile() {
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
}); });
for (const auto streamBuffer : streamBuffers) { for (const auto streamBufferVector : streamBuffers) {
delete streamBuffer; for (const auto streamBuffer : streamBufferVector) {
delete streamBuffer;
}
} }
shaderModules.clear(); shaderModules.clear();
shaderStages.clear(); shaderStages.clear();
@@ -200,24 +202,46 @@ static VkDescriptorImageInfo createDescriptorImageInfo(graphics::Texture* textur
} }
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t imageIndex) { void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
// detect wether a new frame has begun
if (currentImage != imageIndex) { if (currentImage != imageIndex) {
currentImage = imageIndex; currentImage = imageIndex;
count = 0; count = 0;
streamBuffers[currentImage]->nextFrame();
// we needed more memory last frame, let's collapse all buffers into a single one.
if (streamBuffers.at(currentImage).size() > 1) {
size_t newSize = 0;
for (auto streamBuffer : streamBuffers.at(currentImage)) {
newSize += streamBuffer->getSize();
delete streamBuffer;
}
streamBuffers.at(currentImage).clear();
streamBuffers.at(currentImage).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, newSize));
}
// no collapse necessary, can just call nextFrame to reset the current (only) streambuffer
else {
streamBuffers.at(currentImage).at(0)->nextFrame();
}
} }
// still the same frame
else { else {
if (count >= STREAMBUFFER_SIZE) { auto usedStreamBufferMemory = count * uniformBufferSizeAligned;
throw love::Exception("uniform stream buffer: out of memory (fixme: resize)"); if (usedStreamBufferMemory >= streamBuffers.at(currentImage).back()->getSize()) {
// we ran out of memory in the current frame, need to allocate more.
streamBuffers.at(currentImage).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
count = 0;
} }
} }
auto mapInfo = streamBuffers[currentImage]->map(uniformBufferSizeAligned); // additional data is always added onto the last stream buffer in the current frame
auto currentStreamBuffer = streamBuffers.at(currentImage).back();
auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
memcpy(mapInfo.data, &uniformData, uniformBufferSizeAligned); memcpy(mapInfo.data, &uniformData, uniformBufferSizeAligned);
streamBuffers[currentImage]->unmap(uniformBufferSizeAligned); currentStreamBuffer->unmap(uniformBufferSizeAligned);
streamBuffers[currentImage]->markUsed(uniformBufferSizeAligned); currentStreamBuffer->markUsed(uniformBufferSizeAligned);
VkDescriptorBufferInfo bufferInfo{}; VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = (VkBuffer)streamBuffers[currentImage]->getHandle(); bufferInfo.buffer = (VkBuffer)currentStreamBuffer->getHandle();
bufferInfo.offset = count * uniformBufferSizeAligned; bufferInfo.offset = count * uniformBufferSizeAligned;
bufferInfo.range = sizeof(BuiltinUniformData); bufferInfo.range = sizeof(BuiltinUniformData);
@@ -471,7 +495,7 @@ void Shader::createStreamBuffers() {
const auto numImagesInFlight = vgfx->getNumImagesInFlight(); const auto numImagesInFlight = vgfx->getNumImagesInFlight();
streamBuffers.resize(numImagesInFlight); streamBuffers.resize(numImagesInFlight);
for (uint32_t i = 0; i < numImagesInFlight; i++) { for (uint32_t i = 0; i < numImagesInFlight; i++) {
streamBuffers[i] = new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_SIZE * uniformBufferSizeAligned); streamBuffers[i].push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
} }
} }
+5 -1
View File
@@ -64,7 +64,10 @@ private:
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
std::vector<StreamBuffer*> streamBuffers; // we don't know how much memory we need per frame for the uniform buffer descriptors
// we keep a vector of stream buffers per frame in flight
// that gets dynamically increased if more memory is needed
std::vector<std::vector<StreamBuffer*>> streamBuffers;
std::vector<VkPipelineShaderStageCreateInfo> shaderStages; std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
std::vector<VkShaderModule> shaderModules; std::vector<VkShaderModule> shaderModules;
@@ -92,6 +95,7 @@ private:
graphics::Texture* crtexture; graphics::Texture* crtexture;
uint32_t currentImage; uint32_t currentImage;
// todo: give this variable a better name
uint32_t count; uint32_t count;
}; };
} }