From c519450c57348299b3e2ebb5a250afdf0de23b8d Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 3 Jul 2020 02:29:11 +0200 Subject: [PATCH] Only recreate command buffers after swapchain invalidate --- debug-env.sh | 1 + examples/graphics_context.zig | 12 ++- examples/main.zig | 149 ++++++++++++++++++++-------------- examples/swapchain.zig | 8 +- 4 files changed, 102 insertions(+), 68 deletions(-) create mode 100644 debug-env.sh diff --git a/debug-env.sh b/debug-env.sh new file mode 100644 index 0000000..832fb69 --- /dev/null +++ b/debug-env.sh @@ -0,0 +1 @@ +export VK_INSTANCE_LAYERS="VK_LAYER_LUNARG_monitor:VK_LAYER_KHRONOS_validation" diff --git a/examples/graphics_context.zig b/examples/graphics_context.zig index 852f0c8..d3953d4 100644 --- a/examples/graphics_context.zig +++ b/examples/graphics_context.zig @@ -71,16 +71,24 @@ pub const GraphicsContext = struct { graphics_queue: Queue, present_queue: Queue, - pub fn init(allocator: *Allocator, app_info: *const vk.ApplicationInfo, window: *c.GLFWwindow) !GraphicsContext { + pub fn init(allocator: *Allocator, app_name: [*:0]const u8, window: *c.GLFWwindow) !GraphicsContext { var self: GraphicsContext = undefined; self.vkb = try BaseDispatch.load(c.glfwGetInstanceProcAddress); var glfw_exts_count: u32 = 0; const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count); + const app_info = vk.ApplicationInfo{ + .p_application_name = app_name, + .application_version = vk.makeVersion(0, 0, 0), + .p_engine_name = app_name, + .engine_version = vk.makeVersion(0, 0, 0), + .api_version = vk.API_VERSION_1_2, + }; + self.instance = try self.vkb.createInstance(.{ .flags = .{}, - .p_application_info = app_info, + .p_application_info = &app_info, .enabled_layer_count = 0, .pp_enabled_layer_names = undefined, .enabled_extension_count = glfw_exts_count, diff --git a/examples/main.zig b/examples/main.zig index 4ad3502..d861072 100644 --- a/examples/main.zig +++ b/examples/main.zig @@ -3,15 +3,9 @@ const vk = @import("vulkan"); const c = @import("c.zig"); const GraphicsContext = @import("graphics_context.zig").GraphicsContext; const Swapchain = @import("swapchain.zig").Swapchain; +const Allocator = std.mem.Allocator; const app_name = "vulkan-zig example"; -const app_info = vk.ApplicationInfo{ - .p_application_name = app_name, - .application_version = vk.makeVersion(0, 0, 0), - .p_engine_name = app_name, - .engine_version = vk.makeVersion(0, 0, 0), - .api_version = vk.API_VERSION_1_2, -}; pub fn main() !void { if (c.glfwInit() != c.GLFW_TRUE) return error.GlfwInitFailed; @@ -29,12 +23,14 @@ pub fn main() !void { ) orelse return error.WindowInitFailed; defer c.glfwDestroyWindow(window); - const gc = try GraphicsContext.init(std.heap.page_allocator, &app_info, window); + const allocator = std.heap.page_allocator; + + const gc = try GraphicsContext.init(allocator, app_name, window); defer gc.deinit(); std.debug.print("Using device: {}\n", .{gc.deviceName()}); - var swapchain = try Swapchain.init(&gc, std.heap.page_allocator, extent); + var swapchain = try Swapchain.init(&gc, allocator, extent); defer swapchain.deinit(); const pool = try gc.vkd.createCommandPool(gc.dev, .{ @@ -43,61 +39,13 @@ pub fn main() !void { }, null); defer gc.vkd.destroyCommandPool(gc.dev, pool, null); + var cmdbufs = try createCommandBuffers(&gc, pool, allocator, swapchain); + defer destroyCommandBuffers(&gc, pool, allocator, cmdbufs); + while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) { - var cmdbuf: vk.CommandBuffer = undefined; - try gc.vkd.allocateCommandBuffers(gc.dev, .{ - .command_pool = pool, - .level = .primary, - .command_buffer_count = 1, - }, @ptrCast([*]vk.CommandBuffer, &cmdbuf)); - defer gc.vkd.freeCommandBuffers(gc.dev, pool, 1, @ptrCast([*]const vk.CommandBuffer, &cmdbuf)); + const cmdbuf = cmdbufs[swapchain.image_index]; - try gc.vkd.beginCommandBuffer(cmdbuf, .{ - .flags = .{.one_time_submit_bit = true}, - .p_inheritance_info = null, - }); - - const subresource_range = vk.ImageSubresourceRange{ - .aspect_mask = .{.color_bit = true}, - .base_mip_level = 0, - .level_count = 1, - .base_array_layer = 0, - .layer_count = 1, - }; - - const color = vk.ClearColorValue{.float_32 = .{1, 0, 1, 1}}; - - imageTransition( - &gc, - cmdbuf, - swapchain.currentImage(), - subresource_range, - .{.layout = .@"undefined", .stage = .{.top_of_pipe_bit = true}}, - .{.layout = .general, .stage = .{.top_of_pipe_bit = true}}, - ); - - gc.vkd.cmdClearColorImage( - cmdbuf, - swapchain.currentImage(), - .general, - color, - 1, - @ptrCast([*]const vk.ImageSubresourceRange, &subresource_range), - ); - - imageTransition( - &gc, - cmdbuf, - swapchain.currentImage(), - subresource_range, - .{.layout = .general, .stage = .{.top_of_pipe_bit = true}}, - .{.layout = .present_src_khr, .stage = .{.bottom_of_pipe_bit = true}}, - ); - - try gc.vkd.endCommandBuffer(cmdbuf); - const result = swapchain.present(cmdbuf); - try gc.vkd.queueWaitIdle(gc.graphics_queue.handle); - const state = result catch |err| switch (err) { + const state = swapchain.present(cmdbuf) catch |err| switch (err) { error.OutOfDateKHR => Swapchain.PresentState.suboptimal, else => |narrow| return narrow, }; @@ -108,13 +56,90 @@ pub fn main() !void { c.glfwGetWindowSize(window, &w, &h); try swapchain.recreate(.{.width = @intCast(u32, w), .height = @intCast(u32, h)}); + + destroyCommandBuffers(&gc, pool, allocator, cmdbufs); + cmdbufs = try createCommandBuffers(&gc, pool, allocator, swapchain); } c.glfwSwapBuffers(window); c.glfwPollEvents(); + + try gc.vkd.queueWaitIdle(gc.graphics_queue.handle); } } +fn createCommandBuffers( + gc: *const GraphicsContext, + pool: vk.CommandPool, + allocator: *Allocator, + swapchain: Swapchain, +) ![]vk.CommandBuffer { + const cmdbufs = try allocator.alloc(vk.CommandBuffer, swapchain.swap_images.len); + errdefer allocator.free(cmdbufs); + + try gc.vkd.allocateCommandBuffers(gc.dev, .{ + .command_pool = pool, + .level = .primary, + .command_buffer_count = @truncate(u32, cmdbufs.len), + }, cmdbufs.ptr); + errdefer gc.vkd.freeCommandBuffers(gc.dev, pool, @truncate(u32, cmdbufs.len), cmdbufs.ptr); + + const subresource_range = vk.ImageSubresourceRange{ + .aspect_mask = .{.color_bit = true}, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }; + + const color = vk.ClearColorValue{.float_32 = .{1, 0, 1, 1}}; + + for (cmdbufs) |cmdbuf, i| { + const image = swapchain.swap_images[i].image; + + try gc.vkd.beginCommandBuffer(cmdbuf, .{ + .flags = .{}, + .p_inheritance_info = null, + }); + + imageTransition( + gc, + cmdbuf, + image, + subresource_range, + .{.layout = .@"undefined", .stage = .{.top_of_pipe_bit = true}}, + .{.layout = .general, .stage = .{.top_of_pipe_bit = true}}, + ); + + gc.vkd.cmdClearColorImage( + cmdbuf, + image, + .general, + color, + 1, + @ptrCast([*]const vk.ImageSubresourceRange, &subresource_range), + ); + + imageTransition( + gc, + cmdbuf, + image, + subresource_range, + .{.layout = .general, .stage = .{.top_of_pipe_bit = true}}, + .{.layout = .present_src_khr, .stage = .{.bottom_of_pipe_bit = true}}, + ); + + try gc.vkd.endCommandBuffer(cmdbuf); + } + + return cmdbufs; +} + +fn destroyCommandBuffers(gc: *const GraphicsContext, pool: vk.CommandPool, allocator: *Allocator, cmdbufs: []vk.CommandBuffer) void { + gc.vkd.freeCommandBuffers(gc.dev, pool, @truncate(u32, cmdbufs.len), cmdbufs.ptr); + allocator.free(cmdbufs); +} + const ImageState = struct { layout: vk.ImageLayout, stage: vk.PipelineStageFlags, diff --git a/examples/swapchain.zig b/examples/swapchain.zig index b6208ac..e9be500 100644 --- a/examples/swapchain.zig +++ b/examples/swapchain.zig @@ -89,14 +89,14 @@ pub const Swapchain = struct { }; } - fn deinitExceptSwapchain(self: Swapchain) void { + fn deinitExceptSwapchain(self: Swapchain) !void { + _ = try self.gc.vkd.queueWaitIdle(self.gc.present_queue.handle); for (self.swap_images) |si| si.deinit(self.gc); self.gc.vkd.destroySemaphore(self.gc.dev, self.next_image_acquired, null); } pub fn deinit(self: Swapchain) void { - self.gc.vkd.deviceWaitIdle(self.gc.dev) catch return; - self.deinitExceptSwapchain(); + self.deinitExceptSwapchain() catch return; self.gc.vkd.destroySwapchainKHR(self.gc.dev, self.handle, null); } @@ -104,7 +104,7 @@ pub const Swapchain = struct { const gc = self.gc; const allocator = self.allocator; const old_handle = self.handle; - self.deinitExceptSwapchain(); + try self.deinitExceptSwapchain(); self.* = try initRecycle(gc, allocator, new_extent, old_handle); }