@@ -235,13 +235,111 @@ void Renderer::Cleanup() {
235235
236236 // Wait for the device to be idle before cleaning up
237237 device.waitIdle ();
238+
239+ // Clean up swapchain-bound resources (depth, offscreen color, pipelines, views, etc.)
240+ cleanupSwapChain ();
241+
242+ // Release per-entity resources and return pooled memory to the MemoryPool
238243 for (auto & resources : entityResources | std::views::values) {
239- // Memory pool handles unmapping automatically, no need to manually unmap
244+ // Descriptor sets are RAII and freed with descriptorPool; just clear holders
240245 resources.basicDescriptorSets .clear ();
241246 resources.pbrDescriptorSets .clear ();
247+
248+ // Destroy UBO buffers and return pooled allocations
242249 resources.uniformBuffers .clear ();
250+ for (auto & alloc : resources.uniformBufferAllocations ) {
251+ if (alloc) {
252+ try { memoryPool->deallocate (std::move (alloc)); }
253+ catch (const std::exception& e) {
254+ std::cerr << " Warning: failed to deallocate UBO allocation during Cleanup: " << e.what () << std::endl;
255+ }
256+ }
257+ }
243258 resources.uniformBufferAllocations .clear ();
244259 resources.uniformBuffersMapped .clear ();
260+
261+ // Destroy instance buffer and return pooled allocation
262+ resources.instanceBuffer = nullptr ;
263+ if (resources.instanceBufferAllocation ) {
264+ try { memoryPool->deallocate (std::move (resources.instanceBufferAllocation )); }
265+ catch (const std::exception& e) {
266+ std::cerr << " Warning: failed to deallocate instance buffer allocation during Cleanup: " << e.what () << std::endl;
267+ }
268+ }
269+ resources.instanceBufferMapped = nullptr ;
270+ }
271+ entityResources.clear ();
272+
273+ // Release light storage buffers
274+ for (auto & lsb : lightStorageBuffers) {
275+ lsb.buffer = nullptr ;
276+ if (lsb.allocation ) {
277+ try { memoryPool->deallocate (std::move (lsb.allocation )); }
278+ catch (const std::exception& e) {
279+ std::cerr << " Warning: failed to deallocate light storage buffer during Cleanup: " << e.what () << std::endl;
280+ }
281+ }
282+ lsb.mapped = nullptr ;
283+ lsb.capacity = 0 ;
284+ lsb.size = 0 ;
285+ }
286+ lightStorageBuffers.clear ();
287+
288+ // Release mesh device-local buffers and return pooled allocations
289+ for (auto & [mesh, mres] : meshResources) {
290+ mres.vertexBuffer = nullptr ;
291+ if (mres.vertexBufferAllocation ) {
292+ try { memoryPool->deallocate (std::move (mres.vertexBufferAllocation )); }
293+ catch (const std::exception& e) {
294+ std::cerr << " Warning: failed to deallocate vertex buffer allocation during Cleanup: " << e.what () << std::endl;
295+ }
296+ }
297+ mres.indexBuffer = nullptr ;
298+ if (mres.indexBufferAllocation ) {
299+ try { memoryPool->deallocate (std::move (mres.indexBufferAllocation )); }
300+ catch (const std::exception& e) {
301+ std::cerr << " Warning: failed to deallocate index buffer allocation during Cleanup: " << e.what () << std::endl;
302+ }
303+ }
304+ // Staging buffers are RAII and not pooled
305+ mres.stagingVertexBuffer = nullptr ;
306+ mres.stagingVertexBufferMemory = nullptr ;
307+ mres.stagingIndexBuffer = nullptr ;
308+ mres.stagingIndexBufferMemory = nullptr ;
309+ mres.vertexBufferSizeBytes = 0 ;
310+ mres.indexBufferSizeBytes = 0 ;
311+ mres.indexCount = 0 ;
312+ }
313+ meshResources.clear ();
314+
315+ // Release textures and return pooled allocations
316+ {
317+ std::unique_lock<std::shared_mutex> texLock (textureResourcesMutex);
318+ for (auto & [key, tres] : textureResources) {
319+ tres.textureSampler = nullptr ;
320+ tres.textureImageView = nullptr ;
321+ tres.textureImage = nullptr ;
322+ if (tres.textureImageAllocation ) {
323+ try { memoryPool->deallocate (std::move (tres.textureImageAllocation )); }
324+ catch (const std::exception& e) {
325+ std::cerr << " Warning: failed to deallocate texture image allocation during Cleanup: " << e.what () << std::endl;
326+ }
327+ }
328+ }
329+ textureResources.clear ();
330+ textureAliases.clear ();
331+ textureToEntities.clear ();
332+ }
333+
334+ // Release default texture resources if allocated
335+ defaultTextureResources.textureSampler = nullptr ;
336+ defaultTextureResources.textureImageView = nullptr ;
337+ defaultTextureResources.textureImage = nullptr ;
338+ if (defaultTextureResources.textureImageAllocation ) {
339+ try { memoryPool->deallocate (std::move (defaultTextureResources.textureImageAllocation )); }
340+ catch (const std::exception& e) {
341+ std::cerr << " Warning: failed to deallocate default texture image allocation during Cleanup: " << e.what () << std::endl;
342+ }
245343 }
246344 // Also clear global descriptor sets that are allocated from descriptorPool, so they are
247345 // destroyed while the pool is still valid (avoid vkFreeDescriptorSets invalid pool errors)
0 commit comments