From 0759e8d5134f228d32f9919aee7844d41ba5f23c Mon Sep 17 00:00:00 2001 From: niki Date: Mon, 11 Jul 2022 01:13:50 +0200 Subject: [PATCH] vulkan: fix some memory leaks --- src/modules/graphics/vulkan/Buffer.cpp | 21 ++++++++++++++++---- src/modules/graphics/vulkan/Buffer.h | 10 ++++++++-- src/modules/graphics/vulkan/Graphics.cpp | 10 +++++++++- src/modules/graphics/vulkan/Graphics.h | 1 + src/modules/graphics/vulkan/ShaderStage.cpp | 18 +++++++++++++++-- src/modules/graphics/vulkan/ShaderStage.h | 10 +++++++--- src/modules/graphics/vulkan/StreamBuffer.cpp | 16 ++++++++++++++- src/modules/graphics/vulkan/StreamBuffer.h | 9 +++++++-- src/modules/graphics/vulkan/Texture.cpp | 21 ++++++++++++++++---- src/modules/graphics/vulkan/Texture.h | 8 ++++++-- 10 files changed, 103 insertions(+), 21 deletions(-) diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index a6090455d..b7affc80f 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -26,22 +26,35 @@ namespace love { } Buffer::Buffer(VmaAllocator allocator, love::graphics::Graphics* gfx, const Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength) - : love::graphics::Buffer(gfx, settings, format, size, arraylength) { + : love::graphics::Buffer(gfx, settings, format, size, arraylength), usageFlags(settings.usageFlags), allocator(allocator) { + loadVolatile(); + } + bool Buffer::loadVolatile() { VkBufferCreateInfo bufferInfo{}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = getVulkanUsageFlags(settings.usageFlags); + bufferInfo.size = getSize(); + bufferInfo.usage = getVulkanUsageFlags(usageFlags); VmaAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo); + + return true; + } + + void Buffer::unloadVolatile() { + if (buffer == VK_NULL_HANDLE) + return; + + vmaDestroyBuffer(allocator, buffer, allocation); + buffer = VK_NULL_HANDLE; } Buffer::~Buffer() { - // fixme + unloadVolatile(); } void* Buffer::map(MapType map, size_t offset, size_t size) { diff --git a/src/modules/graphics/vulkan/Buffer.h b/src/modules/graphics/vulkan/Buffer.h index d9abe1038..ac84e0456 100644 --- a/src/modules/graphics/vulkan/Buffer.h +++ b/src/modules/graphics/vulkan/Buffer.h @@ -1,16 +1,20 @@ #include "graphics/Buffer.h" #include #include "vk_mem_alloc.h" +#include "graphics/Volatile.h" namespace love { namespace graphics { namespace vulkan { - class Buffer : public love::graphics::Buffer { + class Buffer : public love::graphics::Buffer, public Volatile { public: Buffer(VmaAllocator allocator, love::graphics::Graphics* gfx, const Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength); virtual ~Buffer(); + virtual bool loadVolatile() override; + virtual void unloadVolatile() override; + void* map(MapType map, size_t offset, size_t size) override; void unmap(size_t usedoffset, size_t usedsize) override; bool fill(size_t offset, size_t size, const void* data) override; @@ -25,9 +29,11 @@ namespace love { private: // todo use a staging buffer for improved performance - VkBuffer buffer; + VkBuffer buffer = VK_NULL_HANDLE; + VmaAllocator allocator; VmaAllocation allocation; VmaAllocationInfo allocInfo; + BufferUsageFlags usageFlags; }; } } diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index c1b004ce2..bfd00a7d9 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -302,6 +302,7 @@ namespace love { std::cout << "unSetMode "; created = false; + Volatile::unloadAll(); cleanup(); } @@ -1280,6 +1281,7 @@ namespace love { if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { throw love::Exception("failed to create pipeline layout"); } + graphicsPipelineLayouts.push_back(pipelineLayout); VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -1485,12 +1487,18 @@ namespace love { } graphicsPipelines.clear(); currentGraphicsPipeline = VK_NULL_HANDLE; - // vkDestroyPipelineLayout(device, pipelineLayout, nullptr); FIXME + for (const auto pipelineLayout : graphicsPipelineLayouts) { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + } + graphicsPipelineLayouts.clear(); vkDestroyRenderPass(device, renderPass, nullptr); for (size_t i = 0; i < swapChainImageViews.size(); i++) { vkDestroyImageView(device, swapChainImageViews[i], nullptr); } vkDestroySwapchainKHR(device, swapChain, nullptr); + for (auto p : uniformBufferMap) { + delete p.second; + } uniformBufferMap.clear(); descriptorSetsMap.clear(); } diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 3884142bb..91668f6d8 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -190,6 +190,7 @@ namespace love { VkRenderPass renderPass = VK_NULL_HANDLE; VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE; std::vector> graphicsPipelines; // FIXME improve performance by using a hash map + std::vector graphicsPipelineLayouts; std::vector swapChainFramBuffers; VkCommandPool commandPool = VK_NULL_HANDLE; std::vector commandBuffers; diff --git a/src/modules/graphics/vulkan/ShaderStage.cpp b/src/modules/graphics/vulkan/ShaderStage.cpp index 8a04cba4c..bcce9d5c0 100644 --- a/src/modules/graphics/vulkan/ShaderStage.cpp +++ b/src/modules/graphics/vulkan/ShaderStage.cpp @@ -185,7 +185,13 @@ namespace love { } ShaderStage::ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey) - : love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) { + : love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey), gfx(gfx) { + loadVolatile(); + } + + bool ShaderStage::loadVolatile() { + auto stage = getStageType(); + auto glsl = getSource(); auto code = compileShaderWithGlslang(glsl, stage); VkShaderModuleCreateInfo createInfo{}; @@ -201,8 +207,16 @@ namespace love { } } + void ShaderStage::unloadVolatile() { + if (shaderModule == VK_NULL_HANDLE) + return; + + vkDestroyShaderModule(device, shaderModule, nullptr); + shaderModule = VK_NULL_HANDLE; + } + ShaderStage::~ShaderStage() { - // vkDestroyShaderModule(device, shaderModule, nullptr); + unloadVolatile(); } } } diff --git a/src/modules/graphics/vulkan/ShaderStage.h b/src/modules/graphics/vulkan/ShaderStage.h index 13770960b..6f06ae0db 100644 --- a/src/modules/graphics/vulkan/ShaderStage.h +++ b/src/modules/graphics/vulkan/ShaderStage.h @@ -8,11 +8,15 @@ namespace love { namespace graphics { namespace vulkan { - class ShaderStage final : public graphics::ShaderStage { + class ShaderStage final : public graphics::ShaderStage, public Volatile { public: ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey); virtual ~ShaderStage(); + virtual bool loadVolatile() override; + + virtual void unloadVolatile() override; + VkShaderModule getShaderModule() const { return shaderModule; } @@ -22,9 +26,9 @@ namespace love { } private: - VkShaderModule shaderModule; + VkShaderModule shaderModule = VK_NULL_HANDLE; VkDevice device; - + love::graphics::Graphics* gfx; }; } } diff --git a/src/modules/graphics/vulkan/StreamBuffer.cpp b/src/modules/graphics/vulkan/StreamBuffer.cpp index c3fc81e20..2c204bfc5 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.cpp +++ b/src/modules/graphics/vulkan/StreamBuffer.cpp @@ -18,6 +18,10 @@ namespace love { StreamBuffer::StreamBuffer(VmaAllocator allocator, BufferUsage mode, size_t size) : love::graphics::StreamBuffer(mode, size), allocator(allocator) { + loadVolatile(); + } + + bool StreamBuffer::loadVolatile() { VkBufferCreateInfo bufferInfo{}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = getSize(); @@ -31,10 +35,20 @@ namespace love { vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo); usedGPUMemory = 0; + + return true; + } + + void StreamBuffer::unloadVolatile() { + if (buffer == VK_NULL_HANDLE) + return; + + vmaDestroyBuffer(allocator, buffer, allocation); + buffer = VK_NULL_HANDLE; } StreamBuffer::~StreamBuffer() { - // vmaDestroyBuffer(allocator, buffer, allocation); + unloadVolatile(); } love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize) { diff --git a/src/modules/graphics/vulkan/StreamBuffer.h b/src/modules/graphics/vulkan/StreamBuffer.h index 4c3e79843..2939cf10f 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.h +++ b/src/modules/graphics/vulkan/StreamBuffer.h @@ -1,6 +1,7 @@ #ifndef LOVE_GRAPHICS_VULKAN_STREAMBUFFER_H #define LOVE_GRAPHICS_VULKAN_STREAMBUFFER_H +#include "graphics/Volatile.h" #include "modules/graphics/StreamBuffer.h" #include "vulkan/vulkan.h" @@ -9,11 +10,15 @@ namespace love { namespace graphics { namespace vulkan { - class StreamBuffer : public love::graphics::StreamBuffer { + class StreamBuffer : public love::graphics::StreamBuffer, public graphics::Volatile { public: StreamBuffer(VmaAllocator allocator, BufferUsage mode, size_t size); virtual ~StreamBuffer(); + virtual bool loadVolatile() override; + + virtual void unloadVolatile() override; + MapInfo map(size_t minsize) override; size_t unmap(size_t usedSize) override; void markUsed(size_t usedSize) override; @@ -28,7 +33,7 @@ namespace love { VmaAllocator allocator; VmaAllocation allocation; VmaAllocationInfo allocInfo; - VkBuffer buffer; + VkBuffer buffer = VK_NULL_HANDLE; size_t usedGPUMemory; }; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 3a479245a..74eae5c9b 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -9,7 +9,11 @@ namespace love { namespace graphics { namespace vulkan { Texture::Texture(love::graphics::Graphics* gfx, const Settings& settings, const Slices* data) - : love::graphics::Texture(gfx, settings, data), gfx(gfx) { + : love::graphics::Texture(gfx, settings, data), gfx(gfx), data(data) { + loadVolatile(); + } + + bool Texture::loadVolatile() { allocator = vgfx->getVmaAllocator(); device = vgfx->getDevice(); @@ -59,10 +63,19 @@ namespace love { createTextureSampler(); } + void Texture::unloadVolatile() { + if (textureImage == VK_NULL_HANDLE) + return; + + vkDestroySampler(device, textureSampler, nullptr); + vkDestroyImageView(device, textureImageView, nullptr); + vmaDestroyImage(allocator, textureImage, nullptr); + + textureImage = VK_NULL_HANDLE; + } + Texture::~Texture() { - // vkDestroySampler(device, textureSampler, nullptr); - // vkDestroyImageView(device, textureImageView, nullptr); - // vmaDestroyImage(allocator, textureImage, nullptr); + unloadVolatile(); } void Texture::createTextureImageView() { diff --git a/src/modules/graphics/vulkan/Texture.h b/src/modules/graphics/vulkan/Texture.h index 42d32a2f1..c3310dd07 100644 --- a/src/modules/graphics/vulkan/Texture.h +++ b/src/modules/graphics/vulkan/Texture.h @@ -12,11 +12,14 @@ namespace love { namespace graphics { namespace vulkan { - class Texture : public graphics::Texture { + class Texture : public graphics::Texture, public Volatile { public: Texture(love::graphics::Graphics* gfx, const Settings& settings, const Slices* data); ~Texture(); + virtual bool loadVolatile() override; + virtual void unloadVolatile() override; + void copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) override { std::cout << "Texture::copyFromBuffer "; }; void copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) override { std::cout << "Texture::copyToBuffer "; }; @@ -41,10 +44,11 @@ namespace love { graphics::Graphics* gfx; VkDevice device; VmaAllocator allocator; - VkImage textureImage; + VkImage textureImage = VK_NULL_HANDLE; VmaAllocation textureImageAllocation; VkImageView textureImageView; VkSampler textureSampler; + const Slices* data; }; } }