From 790c7955c75da5a7d55dfa6d7c49100fb8a393d9 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Mon, 1 Apr 2024 23:44:36 -0400 Subject: [PATCH] swapchain with vulkan-tutorial --- src/gfx.zig | 2 +- src/main.zig | 325 ++++++++++++++++++++++++++++----------------------- 2 files changed, 180 insertions(+), 147 deletions(-) diff --git a/src/gfx.zig b/src/gfx.zig index 1975ef6..8ec9b96 100644 --- a/src/gfx.zig +++ b/src/gfx.zig @@ -267,7 +267,7 @@ pub fn find_swap_image_count( surface: vk.SurfaceKHR, ) !u32 { const caps = try vki.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, surface); - var count = caps.min_image_count + 1; + var count = @max(3, caps.min_image_count + 1); if (caps.max_image_count > 0) { count = @min(count, caps.max_image_count); } diff --git a/src/main.zig b/src/main.zig index e0a328c..8fceabd 100644 --- a/src/main.zig +++ b/src/main.zig @@ -84,6 +84,11 @@ pub fn main() !void { const queue = vkd.getDeviceQueue(dev, family, 0); + const pool = try vkd.createCommandPool(dev, &.{ + .queue_family_index = family, + }, null); + defer vkd.destroyCommandPool(dev, pool, null); + const preferred_format: vk.SurfaceFormatKHR = .{ .format = .b8g8r8a8_srgb, .color_space = .srgb_nonlinear_khr, @@ -98,12 +103,29 @@ pub fn main() !void { var swapchain: vk.SwapchainKHR = .null_handle; defer vkd.destroySwapchainKHR(dev, swapchain, null); - var image_buf: [8]vk.Image = undefined; - @memset(&image_buf, .null_handle); - var images: []vk.Image = &.{}; - var image_views_buf: [8]vk.ImageView = undefined; - @memset(&image_views_buf, .null_handle); - var image_views: []vk.ImageView = &.{}; + 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); + + const frame_fence = try vkd.createFence(dev, &.{ .flags = .{ .signaled_bit = true } }, null); + defer vkd.destroyFence(dev, frame_fence, null); + const image_available = try vkd.createSemaphore(dev, &.{}, null); + defer vkd.destroySemaphore(dev, image_available, null); + const render_finished = try vkd.createSemaphore(dev, &.{}, null); + defer vkd.destroySemaphore(dev, render_finished, null); swapchain = try vkd.createSwapchainKHR(dev, &.{ .surface = surface, @@ -121,13 +143,12 @@ pub fn main() !void { .old_swapchain = swapchain, }, null); - var image_count: u32 = @intCast(image_buf.len); - _ = try vkd.getSwapchainImagesKHR(dev, swapchain, &image_count, &image_buf); - images = image_buf[0..image_count]; - image_views = image_views_buf[0..image_count]; - defer for (image_views) |view| vkd.destroyImageView(dev, view, 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 (images, image_views) |image, *view| { + for (chain.items(.image), chain.items(.view)) |image, *view| { view.* = try vkd.createImageView(dev, &.{ .image = image, .view_type = .@"2d", @@ -143,6 +164,24 @@ pub fn main() !void { }, 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); + const pipeline_layout = try vkd.createPipelineLayout(dev, &.{ .flags = .{}, .set_layout_count = 0, @@ -155,11 +194,6 @@ pub fn main() !void { const pipeline = try createPipeline(dev, pipeline_layout, format, vkd); defer vkd.destroyPipeline(dev, pipeline, null); - const pool = try vkd.createCommandPool(dev, &.{ - .queue_family_index = family, - }, null); - defer vkd.destroyCommandPool(dev, pool, null); - const vertex_buffer = try vkd.createBuffer(dev, &.{ .size = @sizeOf(@TypeOf(vertices)), .usage = .{ .transfer_dst_bit = true, .vertex_buffer_bit = true }, @@ -186,16 +220,11 @@ pub fn main() !void { try gfx.uploadData(Index, pdev, vki, dev, vkd, queue, pool, index_buffer, &indices); - // var cmdbufs = try createCommandBuffers( - // &gc, - // pool, - // ally, - // vertex_buffer, - // index_buffer, - // pipeline, - // swapchain, - // ); - // defer destroyCommandBuffers(&gc, pool, ally, cmdbufs); + 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); + } + + // var index: u32 = 0; while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) { var w: c_int = undefined; @@ -208,6 +237,37 @@ pub fn main() !void { continue; } + _ = try vkd.waitForFences(dev, 1, @ptrCast(&frame_fence), vk.TRUE, std.math.maxInt(u64)); + try vkd.resetFences(dev, 1, @ptrCast(&frame_fence)); + + // const frame: ChainImage = chain.get(); + + // 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), 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(&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(&render_finished), + }), frame_fence); + + _ = try vkd.queuePresentKHR(queue, &.{ + .wait_semaphore_count = 1, + .p_wait_semaphores = @ptrCast(&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]; // const state = swapchain.present(cmdbuf) catch |err| switch (err) { @@ -240,28 +300,16 @@ pub fn main() !void { try vkd.deviceWaitIdle(dev); } -fn createCommandBuffers( - views: []const vk.Image, - images: []const vk.ImageView, - dev: vk.Device, +fn record_cmdbuf( + cmdbuf: vk.CommandBuffer, vkd: gfx.DeviceDispatch, - pool: vk.CommandPool, - allocator: Allocator, + image: vk.Image, + view: vk.ImageView, + extent: vk.Extent2D, + pipeline: vk.Pipeline, vertex_buffer: vk.Buffer, index_buffer: vk.Buffer, - pipeline: vk.Pipeline, - extent: vk.Extent2D, -) ![]vk.CommandBuffer { - const cmdbufs = try allocator.alloc(vk.CommandBuffer, images.len); - errdefer allocator.free(cmdbufs); - - try vkd.allocateCommandBuffers(dev, &.{ - .command_pool = pool, - .level = .primary, - .command_buffer_count = @as(u32, @truncate(cmdbufs.len)), - }, cmdbufs.ptr); - errdefer vkd.freeCommandBuffers(dev, pool, @truncate(cmdbufs.len), cmdbufs.ptr); - +) !void { const clear = vk.ClearValue{ .color = .{ .float_32 = .{ 0, 0, 0, 1 } }, }; @@ -269,8 +317,8 @@ fn createCommandBuffers( const viewport = vk.Viewport{ .x = 0, .y = 0, - .width = @as(f32, @floatFromInt(extent.width)), - .height = @as(f32, @floatFromInt(extent.height)), + .width = @floatFromInt(extent.width), + .height = @floatFromInt(extent.height), .min_depth = 0, .max_depth = 1, }; @@ -280,114 +328,99 @@ fn createCommandBuffers( .extent = extent, }; - for (cmdbufs, images, views) |cmdbuf, image, view| { - try vkd.beginCommandBuffer(cmdbuf, &.{}); + try vkd.beginCommandBuffer(cmdbuf, &.{}); - vkd.cmdPipelineBarrier( - cmdbuf, - .{ .top_of_pipe_bit = true }, - .{ .color_attachment_output_bit = true }, - .{}, - 0, - null, - 0, - null, - 1, - @ptrCast(&vk.ImageMemoryBarrier{ - .src_access_mask = .{}, - .dst_access_mask = .{ .color_attachment_write_bit = true }, - .old_layout = .undefined, - .new_layout = .color_attachment_optimal, - .src_queue_family_index = 0, - .dst_queue_family_index = 0, - .image = image, - .subresource_range = .{ - .aspect_mask = .{ .color_bit = true }, - .base_mip_level = 0, - .level_count = 1, - .base_array_layer = 0, - .layer_count = 1, - }, - }), - ); - - vkd.cmdSetViewport(cmdbuf, 0, 1, @ptrCast(&viewport)); - vkd.cmdSetScissor(cmdbuf, 0, 1, @ptrCast(&scissor)); - - const color_attachments = [_]vk.RenderingAttachmentInfoKHR{ - .{ - .image_view = view, - .image_layout = .color_attachment_optimal, - .resolve_mode = .{}, - .resolve_image_view = .null_handle, - .resolve_image_layout = .undefined, - .load_op = .clear, - .store_op = .store, - .clear_value = clear, + vkd.cmdPipelineBarrier( + cmdbuf, + .{ .top_of_pipe_bit = true }, + .{ .color_attachment_output_bit = true }, + .{}, + 0, + null, + 0, + null, + 1, + @ptrCast(&vk.ImageMemoryBarrier{ + .src_access_mask = .{}, + .dst_access_mask = .{ .color_attachment_write_bit = true }, + .old_layout = .undefined, + .new_layout = .color_attachment_optimal, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + .image = image, + .subresource_range = .{ + .aspect_mask = .{ .color_bit = true }, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, }, - }; + }), + ); - const render_info = vk.RenderingInfoKHR{ - .render_area = scissor, // since we always do full-frame changes - .layer_count = 1, - .view_mask = 0, - .color_attachment_count = color_attachments.len, - .p_color_attachments = &color_attachments, - }; + vkd.cmdSetViewport(cmdbuf, 0, 1, @ptrCast(&viewport)); + vkd.cmdSetScissor(cmdbuf, 0, 1, @ptrCast(&scissor)); - vkd.cmdBeginRenderingKHR(cmdbuf, &render_info); + const color_attachments = [_]vk.RenderingAttachmentInfoKHR{ + .{ + .image_view = view, + .image_layout = .color_attachment_optimal, + .resolve_mode = .{}, + .resolve_image_view = .null_handle, + .resolve_image_layout = .undefined, + .load_op = .clear, + .store_op = .store, + .clear_value = clear, + }, + }; - vkd.cmdBindPipeline(cmdbuf, .graphics, pipeline); - const offset = [_]vk.DeviceSize{0}; - vkd.cmdBindVertexBuffers(cmdbuf, 0, 1, @ptrCast(&vertex_buffer), &offset); - vkd.cmdBindIndexBuffer(cmdbuf, index_buffer, 0, .uint16); - vkd.cmdDrawIndexed(cmdbuf, indices.len, 1, 0, 0, 0); + const render_info = vk.RenderingInfoKHR{ + .render_area = scissor, // since we always do full-frame changes + .layer_count = 1, + .view_mask = 0, + .color_attachment_count = color_attachments.len, + .p_color_attachments = &color_attachments, + }; - vkd.cmdEndRenderingKHR(cmdbuf); + vkd.cmdBeginRenderingKHR(cmdbuf, &render_info); - vkd.cmdPipelineBarrier( - 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 }, - .dst_access_mask = .{}, - .old_layout = .color_attachment_optimal, - .new_layout = .present_src_khr, - .src_queue_family_index = 0, - .dst_queue_family_index = 0, - .image = image, - .subresource_range = .{ - .aspect_mask = .{ .color_bit = true }, - .base_mip_level = 0, - .level_count = 1, - .base_array_layer = 0, - .layer_count = 1, - }, - }), - ); + vkd.cmdBindPipeline(cmdbuf, .graphics, pipeline); + const offset = [_]vk.DeviceSize{0}; + vkd.cmdBindVertexBuffers(cmdbuf, 0, 1, @ptrCast(&vertex_buffer), &offset); + vkd.cmdBindIndexBuffer(cmdbuf, index_buffer, 0, .uint16); + vkd.cmdDrawIndexed(cmdbuf, indices.len, 1, 0, 0, 0); - try vkd.endCommandBuffer(cmdbuf); - } + vkd.cmdEndRenderingKHR(cmdbuf); - return cmdbufs; -} + vkd.cmdPipelineBarrier( + 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 }, + .dst_access_mask = .{}, + .old_layout = .color_attachment_optimal, + .new_layout = .present_src_khr, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + .image = image, + .subresource_range = .{ + .aspect_mask = .{ .color_bit = true }, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }, + }), + ); -fn destroyCommandBuffers( - dev: vk.Device, - vkd: gfx.DeviceDispatch, - pool: vk.CommandPool, - allocator: Allocator, - cmdbufs: []vk.CommandBuffer, -) void { - vkd.freeCommandBuffers(dev, pool, @truncate(cmdbufs.len), cmdbufs.ptr); - allocator.free(cmdbufs); + try vkd.endCommandBuffer(cmdbuf); } fn createPipeline(dev: vk.Device, layout: vk.PipelineLayout, format: vk.SurfaceFormatKHR, vkd: gfx.DeviceDispatch) !vk.Pipeline {