Actual deleak, debug object names

This commit is contained in:
2025-11-29 00:28:32 +01:00
parent 81a56f393e
commit 493937f870
8 changed files with 123 additions and 6 deletions

View File

@@ -447,6 +447,65 @@ pub fn allocate(self: *const Engine, memory_requirements: vk.MemoryRequirements,
return error.NoSuitableMemoryType;
}
pub fn setObjectName(self: *const Engine, handle: anytype, comptime fmt: []const u8, args: anytype) void {
if (debug) {
const HandleType = @TypeOf(handle);
const type_name = @typeName(HandleType);
if (@as(std.builtin.TypeId, @typeInfo(HandleType)) != .@"enum") {
@compileError("Cannot set object name for a handle of type " ++ type_name ++ ", which is not an enum.");
}
const object_type: vk.ObjectType = switch (HandleType) {
vk.Instance => .instance,
vk.PhysicalDevice => .physical_device,
vk.Device => .device,
vk.Queue => .queue,
vk.Semaphore => .semaphore,
vk.CommandBuffer => .command_buffer,
vk.Fence => .fence,
vk.DeviceMemory => .device_memory,
vk.Buffer => .buffer,
vk.Image => .image,
vk.Event => .event,
vk.QueryPool => .query_pool,
vk.BufferView => .buffer_view,
vk.ImageView => .image_view,
vk.ShaderModule => .shader_module,
vk.PipelineCache => .pipeline_cache,
vk.PipelineLayout => .pipeline_layout,
vk.RenderPass => .render_pass,
vk.Pipeline => .pipeline,
vk.DescriptorSetLayout => .descriptor_set_layout,
vk.Sampler => .sampler,
vk.DescriptorPool => .descriptor_pool,
vk.DescriptorSet => .descriptor_set,
vk.Framebuffer => .framebuffer,
vk.CommandPool => .command_pool,
vk.SurfaceKHR => .surface_khr,
vk.SwapchainKHR => .swapchain_khr,
else => @compileError("Unsupported type " ++ type_name ++ " for setting and object name"),
};
const handle_value: u64 = @intFromEnum(handle);
var buf: [256]u8 = undefined;
const name = std.fmt.bufPrintZ(&buf, fmt, args) catch |err| {
std.log.debug("Failed to set object name for {s}#{X}: {s}", .{ type_name, handle_value, @errorName(err) });
return;
};
self.device.setDebugUtilsObjectNameEXT(&.{
.object_type = object_type,
.object_handle = handle_value,
.p_object_name = name.ptr,
}) catch |err| {
std.log.debug("Failed to set object name for {s}#{X}: {s}", .{ type_name, handle_value, @errorName(err) });
return;
};
}
}
fn debugUtilsMessengerCallback(
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
message_type: vk.DebugUtilsMessageTypeFlagsEXT,

View File

@@ -29,6 +29,7 @@ pub const InitInfo = struct {
usage: Usage,
target_queue: TargetQueue,
array_capacity: u32 = 0,
name: ?[]const u8 = null,
};
pub fn GenericBuffer(comptime Header: type, comptime Element: type) type {
@@ -66,10 +67,16 @@ pub fn GenericBuffer(comptime Header: type, comptime Element: type) type {
.queue_family_indices = &.{ target_queue_family, transfer_queue_family },
});
errdefer engine.destroyBuffer(buffer);
if (init_info.name) |name| {
engine.setObjectName(buffer, "B {s} [{s}, {s}]", .{ name, @typeName(Header), @typeName(Element) });
}
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
const device_memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
errdefer engine.freeMemory(device_memory);
if (init_info.name) |name| {
engine.setObjectName(device_memory, "DM {s} [{s}, {s}]", .{ name, @typeName(Header), @typeName(Element) });
}
try engine.device.bindBufferMemory(buffer, device_memory, 0);

View File

@@ -104,6 +104,7 @@ pub fn init(engine: *Engine) !Swapchain {
}, &engine.vk_allocator.interface);
};
errdefer engine.device.destroyRenderPass(render_pass, &engine.vk_allocator.interface);
engine.setObjectName(render_pass, "RP", .{});
var swapchain: Swapchain = .{
.params = params,
@@ -133,6 +134,7 @@ pub fn deinit(self: *Swapchain, engine: *Engine) void {
}
engine.device.destroyRenderPass(self.render_pass, &engine.vk_allocator.interface);
engine.destroySemaphore(self.semaphore_image_acquired);
self.* = undefined;
}
@@ -173,6 +175,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
.old_swapchain = old_swapchain,
}, &engine.vk_allocator.interface);
errdefer engine.device.destroySwapchainKHR(new_swapchain, &engine.vk_allocator.interface);
engine.setObjectName(new_swapchain, "SC {d}×{d}", .{ extent.width, extent.height });
// --- DESTROY OLD SWAPCHAIN AND ITS IMAGES --------------------------------
@@ -209,6 +212,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
.height = extent.height,
.target_queue = .graphics,
.usage = .depth,
.name = "@Depth",
});
errdefer new_depth_texture.deinit(engine);
@@ -223,13 +227,14 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
errdefer for (swapchain_images.items) |*x| x.deinit(engine);
for (images) |image| {
for (images, 0..) |image, index| {
swapchain_images.appendAssumeCapacity(try SwapchainImage.init(engine, .{
.image = image,
.format = self.params.surface_format.format,
.render_pass = self.render_pass,
.extent = extent,
.depth_stencil_image_view = new_depth_texture.image_view,
.index = index,
}));
}
@@ -246,6 +251,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
var semaphore_image_acquired = try engine.createSemaphore();
errdefer engine.destroySemaphore(semaphore_image_acquired);
engine.setObjectName(semaphore_image_acquired, "S Acquired[E]", .{});
const res = try engine.device.acquireNextImageKHR(new_swapchain, std.math.maxInt(u64), semaphore_image_acquired, .null_handle);
if (res.result == .not_ready or res.result == .timeout) {
@@ -407,6 +413,8 @@ const SwapchainImage = struct {
render_pass: vk.RenderPass,
extent: vk.Extent2D,
depth_stencil_image_view: vk.ImageView,
index: usize,
};
fn init(engine: *Engine, props: InitProps) !SwapchainImage {
@@ -423,17 +431,21 @@ const SwapchainImage = struct {
},
});
errdefer engine.destroyImageView(image_view);
engine.setObjectName(image_view, "IV Swapchain[{d}]", .{props.index});
const semaphore_image_acquired = try engine.createSemaphore();
errdefer engine.destroySemaphore(semaphore_image_acquired);
engine.setObjectName(image_view, "S Acquired[{d}]", .{props.index});
const semaphore_render_finished = try engine.createSemaphore();
errdefer engine.destroySemaphore(semaphore_render_finished);
engine.setObjectName(image_view, "S Rendered[{d}]", .{props.index});
const fence = try engine.createFence(.{
.flags = .{ .signaled_bit = true },
});
errdefer engine.destroyFence(fence);
engine.setObjectName(image_view, "F Rendered[{d}]", .{props.index});
const framebuffer = try engine.createFramebuffer(.{
.render_pass = props.render_pass,
@@ -443,6 +455,7 @@ const SwapchainImage = struct {
.layers = 1,
});
errdefer engine.destroyFramebuffer(framebuffer);
engine.setObjectName(image_view, "FB Swapchain[{d}]", .{props.index});
return .{
.image = props.image,

View File

@@ -67,6 +67,7 @@ pub const InitInfo = struct {
height: u32,
usage: Usage,
target_queue: TargetQueue,
name: ?[]const u8 = null,
};
image: vk.Image,
@@ -111,10 +112,16 @@ pub fn init(engine: *Engine, init_info: InitInfo) !Texture {
.initial_layout = .undefined,
});
errdefer engine.destroyImage(image);
if (init_info.name) |name| {
engine.setObjectName(image, "I {s} [{s}]", .{ name, @tagName(init_info.usage) });
}
const memory_requirements = engine.device.getImageMemoryRequirements(image);
const device_memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
errdefer engine.freeMemory(device_memory);
if (init_info.name) |name| {
engine.setObjectName(device_memory, "DM {s} [{s}]", .{ name, @tagName(init_info.usage) });
}
try engine.device.bindImageMemory(image, device_memory, 0);
@@ -134,6 +141,9 @@ pub fn init(engine: *Engine, init_info: InitInfo) !Texture {
},
});
errdefer engine.destroyImageView(image_view);
if (init_info.name) |name| {
engine.setObjectName(image_view, "IV {s} [{s}]", .{ name, @tagName(init_info.usage) });
}
return .{
.image = image,