FIX: position swapchain to RGBA32F(RT shadow quality in far dist), memory allocation errors
This commit is contained in:
@@ -255,15 +255,20 @@ void IBLManager::unload()
|
||||
if (_spec.image)
|
||||
{
|
||||
rm->destroy_image(_spec);
|
||||
_spec = {};
|
||||
}
|
||||
if (_diff.image && _diff.image != _spec.image) { rm->destroy_image(_diff); }
|
||||
_diff = {};
|
||||
// Handle potential aliasing: _diff may have been set to _spec in load().
|
||||
if (_diff.image && _diff.image != _spec.image)
|
||||
{
|
||||
rm->destroy_image(_diff);
|
||||
}
|
||||
if (_brdf.image)
|
||||
{
|
||||
rm->destroy_image(_brdf);
|
||||
_brdf = {};
|
||||
}
|
||||
|
||||
_spec = {};
|
||||
_diff = {};
|
||||
_brdf = {};
|
||||
if (_iblSetLayout && _ctx && _ctx->getDevice())
|
||||
{
|
||||
vkDestroyDescriptorSetLayout(_ctx->getDevice()->device(), _iblSetLayout, nullptr);
|
||||
|
||||
@@ -121,17 +121,29 @@ void DeviceManager::init_vulkan(SDL_Window *window)
|
||||
|
||||
void DeviceManager::cleanup()
|
||||
{
|
||||
// Optional VMA stats print
|
||||
if (_allocator && vmaDebugEnabled())
|
||||
// Always query VMA stats once before destroying the allocator so we can
|
||||
// spot leaks that would trigger the vk_mem_alloc.h assertion:
|
||||
// "Some allocations were not freed before destruction of this memory block!"
|
||||
if (_allocator)
|
||||
{
|
||||
VmaTotalStatistics stats{};
|
||||
vmaCalculateStatistics(_allocator, &stats);
|
||||
const VmaStatistics& s = stats.total.statistics;
|
||||
fmt::print("[VMA] Blocks: {} | Allocations: {} | BlockBytes: {} | AllocationBytes: {}\n",
|
||||
(size_t)s.blockCount,
|
||||
(size_t)s.allocationCount,
|
||||
(unsigned long long)s.blockBytes,
|
||||
(unsigned long long)s.allocationBytes);
|
||||
const VmaStatistics &s = stats.total.statistics;
|
||||
|
||||
if (s.allocationCount != 0)
|
||||
{
|
||||
fmt::print("[VMA] WARNING: {} live allocations ({} bytes) remain before allocator destruction – this will trip vk_mem_alloc.h assertion: \"Some allocations were not freed before destruction of this memory block!\"\n",
|
||||
(size_t)s.allocationCount,
|
||||
(unsigned long long)s.allocationBytes);
|
||||
}
|
||||
else if (vmaDebugEnabled())
|
||||
{
|
||||
fmt::print("[VMA] Blocks: {} | Allocations: {} | BlockBytes: {} | AllocationBytes: {}\n",
|
||||
(size_t)s.blockCount,
|
||||
(size_t)s.allocationCount,
|
||||
(unsigned long long)s.blockBytes,
|
||||
(unsigned long long)s.allocationBytes);
|
||||
}
|
||||
}
|
||||
vkDestroySurfaceKHR(_instance, _surface, nullptr);
|
||||
_deletionQueue.flush();
|
||||
|
||||
@@ -420,6 +420,14 @@ void VulkanEngine::cleanup()
|
||||
print_vma_stats(_deviceManager.get(), "after AssetManager");
|
||||
dump_vma_json(_deviceManager.get(), "after_AssetManager");
|
||||
|
||||
// Release IBL GPU resources (spec/diffuse cubes + BRDF LUT)
|
||||
if (_iblManager)
|
||||
{
|
||||
_iblManager->unload();
|
||||
}
|
||||
print_vma_stats(_deviceManager.get(), "after IBLManager");
|
||||
dump_vma_json(_deviceManager.get(), "after_IBLManager");
|
||||
|
||||
// Ensure ray tracing resources (BLAS/TLAS/instance buffers) are freed before VMA is destroyed
|
||||
if (_rayManager) { _rayManager->cleanup(); }
|
||||
print_vma_stats(_deviceManager.get(), "after RTManager");
|
||||
|
||||
@@ -64,7 +64,7 @@ void SwapchainManager::init_swapchain()
|
||||
VK_CHECK(vkCreateImageView(_deviceManager->device(), &dview_info, nullptr, &_depthImage.imageView));
|
||||
|
||||
// GBuffer (SRGB not used to keep linear lighting)
|
||||
_gBufferPosition = _resourceManager->create_image(drawImageExtent, VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
_gBufferPosition = _resourceManager->create_image(drawImageExtent, VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
_gBufferNormal = _resourceManager->create_image(drawImageExtent, VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
|
||||
@@ -310,6 +310,20 @@ void LightingPass::draw_lighting(VkCommandBuffer cmd,
|
||||
|
||||
void LightingPass::cleanup()
|
||||
{
|
||||
if (_context && _context->getResources())
|
||||
{
|
||||
if (_fallbackIbl2D.image)
|
||||
{
|
||||
_context->getResources()->destroy_image(_fallbackIbl2D);
|
||||
_fallbackIbl2D = {};
|
||||
}
|
||||
if (_fallbackBrdfLut2D.image)
|
||||
{
|
||||
_context->getResources()->destroy_image(_fallbackBrdfLut2D);
|
||||
_fallbackBrdfLut2D = {};
|
||||
}
|
||||
}
|
||||
|
||||
_deletionQueue.flush();
|
||||
fmt::print("LightingPass::cleanup()\n");
|
||||
}
|
||||
|
||||
@@ -317,6 +317,16 @@ void SceneManager::cleanup()
|
||||
clearMeshInstances();
|
||||
clearGLTFInstances();
|
||||
|
||||
// On engine shutdown we know VulkanEngine::cleanup() has already called
|
||||
// vkDeviceWaitIdle(), so it is safe to destroy all remaining GLTF scenes
|
||||
// immediately instead of deferring them through pendingGLTFRelease.
|
||||
if (!pendingGLTFRelease.empty())
|
||||
{
|
||||
fmt::println("[SceneManager] cleanup: forcing {} pending GLTF releases before shutdown",
|
||||
pendingGLTFRelease.size());
|
||||
pendingGLTFRelease.clear(); // drop strong refs → ~LoadedGLTF::clearAll() runs
|
||||
}
|
||||
|
||||
// Drop our references to GLTF scenes. Their destructors call clearAll()
|
||||
// exactly once to release GPU resources.
|
||||
loadedScenes.clear();
|
||||
|
||||
Reference in New Issue
Block a user