diff --git a/src/main.zig b/src/main.zig index 5a5accf..8f473f5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -50,6 +50,143 @@ const vertices = [_]Vertex{ const indices = [_]Index{ 4, 5, 6, 6, 5, 7 }; +const ChainImage = struct { + image: vk.Image = .null_handle, + view: vk.ImageView = .null_handle, + cmdbuf: vk.CommandBuffer = .null_handle, + fence: vk.Fence = .null_handle, + image_available: vk.Semaphore = .null_handle, + render_finished: vk.Semaphore = .null_handle, +}; + +pub fn create_swapchain( + chain: *std.MultiArrayList(ChainImage), + swapchain: *vk.SwapchainKHR, + ally: std.mem.Allocator, + pdev: vk.PhysicalDevice, + vki: gfx.InstanceDispatch, + window: *c.GLFWwindow, + dev: vk.Device, + vkd: gfx.DeviceDispatch, + pool: vk.CommandPool, + surface: vk.SurfaceKHR, + swap_image_count: u32, + format: vk.SurfaceFormatKHR, + present_mode: vk.PresentModeKHR, +) !vk.Extent2D { + const extent = try gfx.find_swap_extent(pdev, vki, surface, window); + + swapchain.* = try vkd.createSwapchainKHR(dev, &.{ + .surface = surface, + .min_image_count = swap_image_count, + .image_format = format.format, + .image_color_space = format.color_space, + .image_extent = extent, + .image_array_layers = 1, + .image_usage = .{ .color_attachment_bit = true }, + .image_sharing_mode = .exclusive, + .pre_transform = .{ .identity_bit_khr = true }, + .composite_alpha = .{ .opaque_bit_khr = true }, + .present_mode = present_mode, + .clipped = vk.TRUE, + .old_swapchain = swapchain.*, + }, null); + + var image_count: u32 = undefined; + _ = try vkd.getSwapchainImagesKHR(dev, swapchain.*, &image_count, null); + try chain.resize(ally, image_count); + _ = try vkd.getSwapchainImagesKHR(dev, swapchain.*, &image_count, chain.items(.image).ptr); + + // memset so that deinit_chain will succeed with .null_handle if error part-way through a loop. + @memset(chain.items(.view), .null_handle); + @memset(chain.items(.cmdbuf), .null_handle); + @memset(chain.items(.fence), .null_handle); + @memset(chain.items(.image_available), .null_handle); + errdefer deinit_chain(chain.*, dev, vkd, pool); + + for (chain.items(.image), chain.items(.view)) |image, *view| { + view.* = try vkd.createImageView(dev, &.{ + .image = image, + .view_type = .@"2d", + .format = format.format, + .components = .{ .r = .identity, .g = .identity, .b = .identity, .a = .identity }, + .subresource_range = .{ + .aspect_mask = .{ .color_bit = true }, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }, + }, null); + } + + for (chain.items(.fence)) |*fence| { + fence.* = try vkd.createFence(dev, &.{ .flags = .{ .signaled_bit = true } }, null); + } + + for (chain.items(.image_available)) |*sem| { + sem.* = try vkd.createSemaphore(dev, &.{}, null); + } + + for (chain.items(.render_finished)) |*sem| { + sem.* = try vkd.createSemaphore(dev, &.{}, null); + } + + try vkd.allocateCommandBuffers(dev, &.{ + .command_buffer_count = @intCast(chain.len), + .command_pool = pool, + .level = .primary, + }, chain.items(.cmdbuf).ptr); + + return extent; +} + +pub fn deinit_chain( + chain: std.MultiArrayList(ChainImage), + dev: vk.Device, + vkd: gfx.DeviceDispatch, + pool: vk.CommandPool, +) void { + vkd.freeCommandBuffers(dev, pool, @intCast(chain.len), chain.items(.cmdbuf).ptr); + for (chain.items(.view)) |view| vkd.destroyImageView(dev, view, null); + for (chain.items(.fence)) |fence| vkd.destroyFence(dev, fence, null); + for (chain.items(.image_available)) |sem| vkd.destroySemaphore(dev, sem, null); + for (chain.items(.render_finished)) |sem| vkd.destroySemaphore(dev, sem, null); +} + +fn render(dev: vk.Device, vkd: gfx.DeviceDispatch, swapchain: vk.SwapchainKHR, frame: ChainImage, queue: vk.Queue) !void { + _ = try vkd.waitForFences(dev, 1, @ptrCast(&frame.fence), vk.TRUE, std.math.maxInt(u64)); + + const result = try vkd.acquireNextImageKHR( + dev, + swapchain, + std.math.maxInt(u64), + frame.image_available, + .null_handle, + ); + + try vkd.resetFences(dev, 1, @ptrCast(&frame.fence)); + + try vkd.queueSubmit(queue, 1, @ptrCast(&vk.SubmitInfo{ + .wait_semaphore_count = 1, + .p_wait_semaphores = @ptrCast(&frame.image_available), + .p_wait_dst_stage_mask = @ptrCast(&vk.PipelineStageFlags{ .color_attachment_output_bit = true }), + .command_buffer_count = 1, + .p_command_buffers = @ptrCast(&frame.cmdbuf), + .signal_semaphore_count = 1, + .p_signal_semaphores = @ptrCast(&frame.render_finished), + }), frame.fence); + + _ = try vkd.queuePresentKHR(queue, &.{ + .wait_semaphore_count = 1, + .p_wait_semaphores = @ptrCast(&frame.render_finished), + .swapchain_count = 1, + .p_swapchains = @ptrCast(&swapchain), + .p_image_indices = @ptrCast(&result.image_index), + .p_results = null, + }); +} + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -94,7 +231,6 @@ pub fn main() !void { .color_space = .srgb_nonlinear_khr, }; const format = try gfx.find_surface_format(pdev, vki, surface, preferred_format); - extent = try gfx.find_swap_extent(pdev, vki, surface, window); const present_mode = try gfx.find_present_mode(pdev, vki, surface, .mailbox_khr); @@ -103,77 +239,9 @@ pub fn main() !void { var swapchain: vk.SwapchainKHR = .null_handle; defer vkd.destroySwapchainKHR(dev, swapchain, null); - const ChainImage = struct { - image: vk.Image = .null_handle, - view: vk.ImageView = .null_handle, - cmdbuf: vk.CommandBuffer = .null_handle, - fence: vk.Fence = .null_handle, - image_available: vk.Semaphore = .null_handle, - render_finished: vk.Semaphore = .null_handle, - }; - var chain = std.MultiArrayList(ChainImage){}; defer chain.deinit(ally); - defer vkd.freeCommandBuffers(dev, pool, @intCast(chain.len), chain.items(.cmdbuf).ptr); - defer for (chain.items(.view)) |view| vkd.destroyImageView(dev, view, null); - defer for (chain.items(.fence)) |fence| vkd.destroyFence(dev, fence, null); - defer for (chain.items(.image_available)) |sem| vkd.destroySemaphore(dev, sem, null); - defer for (chain.items(.render_finished)) |sem| vkd.destroySemaphore(dev, sem, null); - - swapchain = try vkd.createSwapchainKHR(dev, &.{ - .surface = surface, - .min_image_count = swap_image_count, - .image_format = format.format, - .image_color_space = format.color_space, - .image_extent = extent, - .image_array_layers = 1, - .image_usage = .{ .color_attachment_bit = true }, - .image_sharing_mode = .exclusive, - .pre_transform = .{ .identity_bit_khr = true }, - .composite_alpha = .{ .opaque_bit_khr = true }, - .present_mode = present_mode, - .clipped = vk.TRUE, - .old_swapchain = swapchain, - }, null); - - var image_count: u32 = undefined; - _ = try vkd.getSwapchainImagesKHR(dev, swapchain, &image_count, null); - try chain.resize(ally, image_count); - _ = try vkd.getSwapchainImagesKHR(dev, swapchain, &image_count, chain.items(.image).ptr); - - for (chain.items(.image), chain.items(.view)) |image, *view| { - view.* = try vkd.createImageView(dev, &.{ - .image = image, - .view_type = .@"2d", - .format = format.format, - .components = .{ .r = .identity, .g = .identity, .b = .identity, .a = .identity }, - .subresource_range = .{ - .aspect_mask = .{ .color_bit = true }, - .base_mip_level = 0, - .level_count = 1, - .base_array_layer = 0, - .layer_count = 1, - }, - }, null); - } - - for (chain.items(.fence)) |*fence| { - fence.* = try vkd.createFence(dev, &.{ .flags = .{ .signaled_bit = true } }, null); - } - - for (chain.items(.image_available)) |*sem| { - sem.* = try vkd.createSemaphore(dev, &.{}, null); - } - - for (chain.items(.render_finished)) |*sem| { - sem.* = try vkd.createSemaphore(dev, &.{}, null); - } - - try vkd.allocateCommandBuffers(dev, &.{ - .command_buffer_count = @intCast(chain.len), - .command_pool = pool, - .level = .primary, - }, chain.items(.cmdbuf).ptr); + defer deinit_chain(chain, dev, vkd, pool); const pipeline_layout = try vkd.createPipelineLayout(dev, &.{ .flags = .{}, @@ -213,6 +281,22 @@ pub fn main() !void { try gfx.uploadData(Index, pdev, vki, dev, vkd, queue, pool, index_buffer, &indices); + extent = try create_swapchain( + &chain, + &swapchain, + ally, + pdev, + vki, + window, + dev, + vkd, + pool, + surface, + swap_image_count, + format, + present_mode, + ); + for (chain.items(.image), chain.items(.view), chain.items(.cmdbuf)) |image, view, cmdbuf| { try record_cmdbuf(cmdbuf, vkd, image, view, extent, pipeline, vertex_buffer, index_buffer); } @@ -233,34 +317,47 @@ pub fn main() !void { const frame: ChainImage = chain.get(index); // const next_frame: ChainImage = chain.get((index + 1) % chain.len); - _ = try vkd.waitForFences(dev, 1, @ptrCast(&frame.fence), vk.TRUE, std.math.maxInt(u64)); - try vkd.resetFences(dev, 1, @ptrCast(&frame.fence)); + render(dev, vkd, swapchain, frame, queue) catch |err| switch (err) { + error.OutOfDateKHR => { + // try vkd.deviceWaitIdle(dev); + // _ = try vkd.waitForFences( + // dev, + // @intCast(chain.len), + // chain.items(.fence).ptr, + // vk.TRUE, + // std.math.maxInt(u64), + // ); + try vkd.deviceWaitIdle(dev); + + deinit_chain(chain, dev, vkd, pool); + + extent = try create_swapchain( + &chain, + &swapchain, + ally, + pdev, + vki, + window, + dev, + vkd, + pool, + surface, + swap_image_count, + format, + present_mode, + ); + + for (chain.items(.image), chain.items(.view), chain.items(.cmdbuf)) |image, view, cmdbuf| { + try record_cmdbuf(cmdbuf, vkd, image, view, extent, pipeline, vertex_buffer, index_buffer); + } + + continue; + }, + else => |errx| return errx, + }; // var index: u32 = undefined; // try vkd.acquireNextImageKHR(dev, swapchain, std.math.maxInt(u64), frame., fence); - const result = try vkd.acquireNextImageKHR(dev, swapchain, std.math.maxInt(u64), frame.image_available, .null_handle); - - // std.log.debug("frame {d}", .{result.image_index}); - // const frame = chain.get(result.image_index); - - try vkd.queueSubmit(queue, 1, @ptrCast(&vk.SubmitInfo{ - .wait_semaphore_count = 1, - .p_wait_semaphores = @ptrCast(&frame.image_available), - .p_wait_dst_stage_mask = @ptrCast(&vk.PipelineStageFlags{ .color_attachment_output_bit = true }), - .command_buffer_count = 1, - .p_command_buffers = @ptrCast(&frame.cmdbuf), - .signal_semaphore_count = 1, - .p_signal_semaphores = @ptrCast(&frame.render_finished), - }), frame.fence); - - _ = try vkd.queuePresentKHR(queue, &.{ - .wait_semaphore_count = 1, - .p_wait_semaphores = @ptrCast(&frame.render_finished), - .swapchain_count = 1, - .p_swapchains = @ptrCast(&swapchain), - .p_image_indices = @ptrCast(&result.image_index), - .p_results = null, - }); // const cmdbuf = cmdbufs[swapchain.image_index];