mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
vulkan: clean up framebuffers when textures they reference are deleted
Fixes corruption/crashing in some situations if a new texture's image view has the same pointer as a previously deleted texture's image view.
This commit is contained in:
@@ -59,8 +59,6 @@ static const std::vector<const char*> deviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
constexpr uint32_t USAGES_POLL_INTERVAL = 5000;
|
||||
|
||||
constexpr int DEFAULT_VERTEX_BUFFER_BINDING = 0;
|
||||
constexpr int VERTEX_BUFFER_BINDING_START = 1;
|
||||
|
||||
@@ -577,7 +575,6 @@ void Graphics::present(void *screenshotCallbackdata)
|
||||
updatePendingReadbacks();
|
||||
updateTemporaryResources();
|
||||
|
||||
frameCounter++;
|
||||
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
|
||||
beginFrame();
|
||||
@@ -703,7 +700,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
createQuadIndexBuffer();
|
||||
createFanIndexBuffer();
|
||||
|
||||
frameCounter = 0;
|
||||
currentFrame = 0;
|
||||
}
|
||||
|
||||
@@ -1314,12 +1310,6 @@ void Graphics::beginFrame()
|
||||
{
|
||||
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
if (frameCounter >= USAGES_POLL_INTERVAL)
|
||||
{
|
||||
cleanupUnusedObjects();
|
||||
frameCounter = 0;
|
||||
}
|
||||
|
||||
if (swapChain != VK_NULL_HANDLE)
|
||||
{
|
||||
while (true)
|
||||
@@ -2152,6 +2142,54 @@ VkFramebuffer Graphics::getFramebuffer(FramebufferConfiguration &configuration)
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
void Graphics::cleanupFramebuffers(VkImageView imageView, PixelFormat format)
|
||||
{
|
||||
bool depthstencil = isPixelFormatDepthStencil(format);
|
||||
|
||||
for (auto it = framebuffers.begin(); it != framebuffers.end();)
|
||||
{
|
||||
bool foundView = false;
|
||||
|
||||
if (depthstencil)
|
||||
{
|
||||
if (it->first.staticData.depthView == imageView)
|
||||
foundView = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (VkImageView view : it->first.colorViews)
|
||||
{
|
||||
if (view == imageView)
|
||||
{
|
||||
foundView = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundView)
|
||||
{
|
||||
for (VkImageView view : it->first.colorResolveViews)
|
||||
{
|
||||
if (view == imageView)
|
||||
{
|
||||
foundView = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundView)
|
||||
{
|
||||
vkDestroyFramebuffer(device, it->second, nullptr);
|
||||
it = framebuffers.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::createDefaultShaders()
|
||||
{
|
||||
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
|
||||
@@ -2737,36 +2775,6 @@ VkSampler Graphics::createSampler(const SamplerState &samplerState)
|
||||
return sampler;
|
||||
}
|
||||
|
||||
template<typename Configuration, typename ObjectHandle, typename ConfigurationHasher, typename Deleter>
|
||||
static void eraseUnusedObjects(
|
||||
std::unordered_map<Configuration, ObjectHandle, ConfigurationHasher> &objects,
|
||||
std::unordered_map<ObjectHandle, bool> &usages,
|
||||
Deleter deleter,
|
||||
VkDevice device)
|
||||
{
|
||||
std::vector<Configuration> deletionKeys;
|
||||
|
||||
for (const auto &entry : objects)
|
||||
{
|
||||
if (!usages[entry.second])
|
||||
{
|
||||
deletionKeys.push_back(entry.first);
|
||||
usages.erase(entry.second);
|
||||
deleter(device, entry.second, nullptr);
|
||||
}
|
||||
else
|
||||
usages[entry.second] = false;
|
||||
}
|
||||
|
||||
for (const auto &key : deletionKeys)
|
||||
objects.erase(key);
|
||||
}
|
||||
|
||||
void Graphics::cleanupUnusedObjects()
|
||||
{
|
||||
eraseUnusedObjects(framebuffers, framebufferUsages, vkDestroyFramebuffer, device);
|
||||
}
|
||||
|
||||
void Graphics::requestSwapchainRecreation()
|
||||
{
|
||||
if (swapChain != VK_NULL_HANDLE)
|
||||
@@ -3242,16 +3250,21 @@ void Graphics::cleanupSwapChain()
|
||||
{
|
||||
if (colorImage)
|
||||
{
|
||||
cleanupFramebuffers(colorImageView, swapChainPixelFormat);
|
||||
vkDestroyImageView(device, colorImageView, nullptr);
|
||||
vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
|
||||
}
|
||||
if (depthImage)
|
||||
{
|
||||
cleanupFramebuffers(depthImageView, swapChainPixelFormat);
|
||||
vkDestroyImageView(device, depthImageView, nullptr);
|
||||
vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
|
||||
}
|
||||
for (const auto &swapChainImageView : swapChainImageViews)
|
||||
{
|
||||
cleanupFramebuffers(swapChainImageView, swapChainPixelFormat);
|
||||
vkDestroyImageView(device, swapChainImageView, nullptr);
|
||||
}
|
||||
swapChainImageViews.clear();
|
||||
vkDestroySwapchainKHR(device, swapChain, nullptr);
|
||||
swapChainImages.clear();
|
||||
|
||||
@@ -281,6 +281,8 @@ public:
|
||||
int getVsync() const;
|
||||
void mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo);
|
||||
|
||||
void cleanupFramebuffers(VkImageView imageView, PixelFormat format);
|
||||
|
||||
VkPipeline createGraphicsPipeline(Shader *shader, const GraphicsPipelineConfigurationCore &configuration, const GraphicsPipelineConfigurationNoDynamicState *noDynamicStateConfiguration);
|
||||
|
||||
uint32 getDeviceApiVersion() const { return deviceApiVersion; }
|
||||
@@ -346,7 +348,6 @@ private:
|
||||
void endRenderPass();
|
||||
void applyScissor();
|
||||
VkSampler createSampler(const SamplerState &sampler);
|
||||
void cleanupUnusedObjects();
|
||||
void requestSwapchainRecreation();
|
||||
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
@@ -389,7 +390,6 @@ private:
|
||||
int vsync = 1;
|
||||
VkDeviceSize minUniformBufferOffsetAlignment = 0;
|
||||
bool imageRequested = false;
|
||||
uint32_t frameCounter = 0;
|
||||
size_t currentFrame = 0;
|
||||
uint32_t imageIndex = 0;
|
||||
bool swapChainRecreationRequested = false;
|
||||
|
||||
@@ -301,9 +301,16 @@ void Texture::unloadVolatile()
|
||||
vgfx->queueCleanUp([
|
||||
device = device,
|
||||
allocator = allocator,
|
||||
imageData = std::move(*data)] () {
|
||||
imageData = *data,
|
||||
vgfx = vgfx,
|
||||
renderTarget = renderTarget,
|
||||
format = format] () {
|
||||
if (imageData.imageView != VK_NULL_HANDLE)
|
||||
{
|
||||
if (renderTarget)
|
||||
vgfx->cleanupFramebuffers(imageData.imageView, format);
|
||||
vkDestroyImageView(device, imageData.imageView, nullptr);
|
||||
}
|
||||
if (imageData.allocation != VK_NULL_HANDLE)
|
||||
vmaDestroyImage(allocator, imageData.image, imageData.allocation);
|
||||
for (const auto &views : imageData.renderTargetImageViews)
|
||||
|
||||
Reference in New Issue
Block a user