git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit8f73c62bebd2e804fb046a4626d5b8ad83fc638b
parent678151708c
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-05 23:01
fix(vk/image): a dropped renderer frees its upload staging buffer

ImageStage::destroy freed every image and frame buffer but not the
staging buffer it keeps between uploads, so gpu-allocator reported
"leak detected: ... name: image-staging" whenever a renderer that had
uploaded an image was dropped. The device went with it, so nothing
leaked past the session -- but a renderer dropped and rebuilt inside
one (a layer app hiding its surface, next commit) would have left one
per cycle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 src/vk/image.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/vk/image.rs b/src/vk/image.rs
index e3e782c..b9c6e7d 100644
--- a/src/vk/image.rs
+++ b/src/vk/image.rs
@@ -896,6 +896,13 @@ impl ImageStage {
                 let mut b = std::mem::replace(buf, AllocatedBuffer::null());
                 destroy_cpu_buffer(device, allocator, &mut b);
             }
+            // The upload staging buffer, kept between uploads. Missed here
+            // until 2026-10-05: gpu-allocator reported it leaked whenever a
+            // renderer that had uploaded an image was dropped (a reconnect,
+            // or a layer app hiding its surface).
+            if let Some(mut staging) = self.staging.take() {
+                destroy_cpu_buffer(device, allocator, &mut staging);
+            }
             device.destroy_sampler(self.sampler, None);
             device.destroy_descriptor_pool(self.descriptor_pool, None);
             device.destroy_descriptor_set_layout(self.descriptor_set_layout, None);