debugging the swapchain recreate bugs

This commit is contained in:
David Allemang
2024-03-30 23:59:16 -04:00
parent 538c234213
commit 10dcd3125a
3 changed files with 55 additions and 34 deletions

View File

@@ -93,6 +93,8 @@ pub fn main() !void {
std.debug.print("type: {any}\n", .{props.device_type}); std.debug.print("type: {any}\n", .{props.device_type});
// props.device_type // props.device_type
std.debug.print("max_push_constants_size: {d}\n", .{props.limits.max_push_constants_size});
var family_count: u32 = undefined; var family_count: u32 = undefined;
vki.getPhysicalDeviceQueueFamilyProperties(pdev, &family_count, null); vki.getPhysicalDeviceQueueFamilyProperties(pdev, &family_count, null);
const families = try ally.alloc(vk.QueueFamilyProperties, family_count); const families = try ally.alloc(vk.QueueFamilyProperties, family_count);

View File

@@ -164,7 +164,7 @@ fn create_device(
pdev_search: for (pdevs) |pdev| { pdev_search: for (pdevs) |pdev| {
const props = vki.getPhysicalDeviceProperties(pdev); const props = vki.getPhysicalDeviceProperties(pdev);
// if (props.device_type != .discrete_gpu) continue :pdev_search; if (props.device_type != .discrete_gpu) continue :pdev_search;
var format_count: u32 = undefined; var format_count: u32 = undefined;
_ = try vki.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &format_count, null); _ = try vki.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &format_count, null);
@@ -348,6 +348,7 @@ pub fn main() !void {
defer destroyCommandBuffers(&gc, pool, ally, cmdbufs); defer destroyCommandBuffers(&gc, pool, ally, cmdbufs);
while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) { while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) {
std.log.debug("new frame", .{ });
var w: c_int = undefined; var w: c_int = undefined;
var h: c_int = undefined; var h: c_int = undefined;
c.glfwGetFramebufferSize(window, &w, &h); c.glfwGetFramebufferSize(window, &w, &h);
@@ -364,13 +365,19 @@ pub fn main() !void {
error.OutOfDateKHR => Swapchain.PresentState.suboptimal, error.OutOfDateKHR => Swapchain.PresentState.suboptimal,
else => |narrow| return narrow, else => |narrow| return narrow,
}; };
std.log.debug("state: {}", .{state});
if (state == .suboptimal or extent.width != @as(u32, @intCast(w)) or extent.height != @as(u32, @intCast(h))) { if (state == .suboptimal or extent.width != @as(u32, @intCast(w)) or extent.height != @as(u32, @intCast(h))) {
extent.width = @intCast(w); extent.width = @intCast(w);
extent.height = @intCast(h); extent.height = @intCast(h);
std.log.debug("about to recreate", .{ });
try swapchain.recreate(extent); try swapchain.recreate(extent);
std.log.debug("about to destroy command buffers", .{ });
destroyCommandBuffers(&gc, pool, ally, cmdbufs); destroyCommandBuffers(&gc, pool, ally, cmdbufs);
std.log.debug("about to create command buffers", .{ });
cmdbufs = try createCommandBuffers( cmdbufs = try createCommandBuffers(
&gc, &gc,
pool, pool,
@@ -499,8 +506,17 @@ fn createCommandBuffers(
for (cmdbufs, swapchain.swap_images) |cmdbuf, image| { for (cmdbufs, swapchain.swap_images) |cmdbuf, image| {
try gc.vkd.beginCommandBuffer(cmdbuf, &.{}); try gc.vkd.beginCommandBuffer(cmdbuf, &.{});
const pre_render_barriers: []const vk.ImageMemoryBarrier = &.{ gc.vkd.cmdPipelineBarrier(
vk.ImageMemoryBarrier{ cmdbuf,
.{ .top_of_pipe_bit = true },
.{ .color_attachment_output_bit = true },
.{},
0,
null,
0,
null,
1,
@ptrCast(&vk.ImageMemoryBarrier{
.src_access_mask = .{}, .src_access_mask = .{},
.dst_access_mask = .{ .color_attachment_write_bit = true }, .dst_access_mask = .{ .color_attachment_write_bit = true },
.old_layout = .undefined, .old_layout = .undefined,
@@ -515,19 +531,7 @@ fn createCommandBuffers(
.base_array_layer = 0, .base_array_layer = 0,
.layer_count = 1, .layer_count = 1,
}, },
}, }),
};
gc.vkd.cmdPipelineBarrier(
cmdbuf,
.{ .top_of_pipe_bit = true },
.{ .color_attachment_output_bit = true },
.{},
0,
null,
0,
null,
@intCast(pre_render_barriers.len),
pre_render_barriers.ptr,
); );
gc.vkd.cmdSetViewport(cmdbuf, 0, 1, @ptrCast(&viewport)); gc.vkd.cmdSetViewport(cmdbuf, 0, 1, @ptrCast(&viewport));
@@ -564,8 +568,17 @@ fn createCommandBuffers(
gc.vkd.cmdEndRenderingKHR(cmdbuf); gc.vkd.cmdEndRenderingKHR(cmdbuf);
const post_render_barriers: []const vk.ImageMemoryBarrier = &.{ gc.vkd.cmdPipelineBarrier(
vk.ImageMemoryBarrier{ cmdbuf,
.{ .color_attachment_output_bit = true },
.{ .bottom_of_pipe_bit = true },
.{},
0,
null,
0,
null,
1,
@ptrCast(&vk.ImageMemoryBarrier{
.src_access_mask = .{ .color_attachment_write_bit = true }, .src_access_mask = .{ .color_attachment_write_bit = true },
.dst_access_mask = .{}, .dst_access_mask = .{},
.old_layout = .color_attachment_optimal, .old_layout = .color_attachment_optimal,
@@ -580,19 +593,7 @@ fn createCommandBuffers(
.base_array_layer = 0, .base_array_layer = 0,
.layer_count = 1, .layer_count = 1,
}, },
}, }),
};
gc.vkd.cmdPipelineBarrier(
cmdbuf,
.{ .color_attachment_output_bit = true },
.{ .bottom_of_pipe_bit = true },
.{},
0,
null,
0,
null,
@intCast(post_render_barriers.len),
post_render_barriers.ptr,
); );
try gc.vkd.endCommandBuffer(cmdbuf); try gc.vkd.endCommandBuffer(cmdbuf);

View File

@@ -111,9 +111,18 @@ pub const Swapchain = struct {
var next_image_acquired = try gc.vkd.createSemaphore(gc.dev, &.{}, null); var next_image_acquired = try gc.vkd.createSemaphore(gc.dev, &.{}, null);
errdefer gc.vkd.destroySemaphore(gc.dev, next_image_acquired, null); errdefer gc.vkd.destroySemaphore(gc.dev, next_image_acquired, null);
const result = try gc.vkd.acquireNextImageKHR(gc.dev, handle, std.math.maxInt(u64), next_image_acquired, .null_handle); const result = try gc.vkd.acquireNextImageKHR(
if (result.result != .success) { gc.dev,
return error.ImageAcquireFailed; handle,
std.math.maxInt(u64),
next_image_acquired,
.null_handle,
);
switch (result.result) {
vk.Result.success, vk.Result.suboptimal_khr => {},
vk.Result.timeout => return error.Timeout,
vk.Result.not_ready => return error.NotReady,
else => unreachable,
} }
std.mem.swap(vk.Semaphore, &swap_images[result.image_index].image_acquired, &next_image_acquired); std.mem.swap(vk.Semaphore, &swap_images[result.image_index].image_acquired, &next_image_acquired);
@@ -267,6 +276,15 @@ const SwapImage = struct {
} }
fn deinit(self: SwapImage, gc: *const Context) void { fn deinit(self: SwapImage, gc: *const Context) void {
// todo critical: this waitForFence deadlocks when recreating swapchain on nvidia.
// Something about the main "present" loop is fucked. Can't just ignore the fence; validation layers show errors
// that you can't destroy a fence while a queue depends on it (details may be wrong... I don't fully understand)
// I suspect this is more an issue with the vulkan-zig example, so I probably need to revisit vulkan-tutorial or
// try to rebuild the swapchain infrastructure myself.
//
// I do think it's clunky how the swapchain is created and recreated; duplicate logic in creation and recreation
// that could maybe be avoided with .null_handle? Maybe there's some more straightforward way to handle it.
self.waitForFence(gc) catch return; self.waitForFence(gc) catch return;
gc.vkd.destroyImageView(gc.dev, self.view, null); gc.vkd.destroyImageView(gc.dev, self.view, null);
gc.vkd.destroySemaphore(gc.dev, self.image_acquired, null); gc.vkd.destroySemaphore(gc.dev, self.image_acquired, null);