FIX: position swapchain to RGBA32F(RT shadow quality in far dist), memory allocation errors

This commit is contained in:
2025-11-24 14:46:36 +09:00
parent 1bff14571c
commit fdb8835a3c
6 changed files with 62 additions and 13 deletions

View File

@@ -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);

View File

@@ -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();

View File

@@ -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");

View File

@@ -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);

View File

@@ -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");
}

View File

@@ -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();