forked from mirror/vulkan-zig
Only recreate command buffers after swapchain invalidate
This commit is contained in:
1
debug-env.sh
Normal file
1
debug-env.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export VK_INSTANCE_LAYERS="VK_LAYER_LUNARG_monitor:VK_LAYER_KHRONOS_validation"
|
||||||
@@ -71,16 +71,24 @@ pub const GraphicsContext = struct {
|
|||||||
graphics_queue: Queue,
|
graphics_queue: Queue,
|
||||||
present_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;
|
var self: GraphicsContext = undefined;
|
||||||
self.vkb = try BaseDispatch.load(c.glfwGetInstanceProcAddress);
|
self.vkb = try BaseDispatch.load(c.glfwGetInstanceProcAddress);
|
||||||
|
|
||||||
var glfw_exts_count: u32 = 0;
|
var glfw_exts_count: u32 = 0;
|
||||||
const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count);
|
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(.{
|
self.instance = try self.vkb.createInstance(.{
|
||||||
.flags = .{},
|
.flags = .{},
|
||||||
.p_application_info = app_info,
|
.p_application_info = &app_info,
|
||||||
.enabled_layer_count = 0,
|
.enabled_layer_count = 0,
|
||||||
.pp_enabled_layer_names = undefined,
|
.pp_enabled_layer_names = undefined,
|
||||||
.enabled_extension_count = glfw_exts_count,
|
.enabled_extension_count = glfw_exts_count,
|
||||||
|
|||||||
@@ -3,15 +3,9 @@ const vk = @import("vulkan");
|
|||||||
const c = @import("c.zig");
|
const c = @import("c.zig");
|
||||||
const GraphicsContext = @import("graphics_context.zig").GraphicsContext;
|
const GraphicsContext = @import("graphics_context.zig").GraphicsContext;
|
||||||
const Swapchain = @import("swapchain.zig").Swapchain;
|
const Swapchain = @import("swapchain.zig").Swapchain;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const app_name = "vulkan-zig example";
|
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 {
|
pub fn main() !void {
|
||||||
if (c.glfwInit() != c.GLFW_TRUE) return error.GlfwInitFailed;
|
if (c.glfwInit() != c.GLFW_TRUE) return error.GlfwInitFailed;
|
||||||
@@ -29,12 +23,14 @@ pub fn main() !void {
|
|||||||
) orelse return error.WindowInitFailed;
|
) orelse return error.WindowInitFailed;
|
||||||
defer c.glfwDestroyWindow(window);
|
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();
|
defer gc.deinit();
|
||||||
|
|
||||||
std.debug.print("Using device: {}\n", .{gc.deviceName()});
|
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();
|
defer swapchain.deinit();
|
||||||
|
|
||||||
const pool = try gc.vkd.createCommandPool(gc.dev, .{
|
const pool = try gc.vkd.createCommandPool(gc.dev, .{
|
||||||
@@ -43,61 +39,13 @@ pub fn main() !void {
|
|||||||
}, null);
|
}, null);
|
||||||
defer gc.vkd.destroyCommandPool(gc.dev, pool, 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) {
|
while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) {
|
||||||
var cmdbuf: vk.CommandBuffer = undefined;
|
const cmdbuf = cmdbufs[swapchain.image_index];
|
||||||
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));
|
|
||||||
|
|
||||||
try gc.vkd.beginCommandBuffer(cmdbuf, .{
|
const state = swapchain.present(cmdbuf) catch |err| switch (err) {
|
||||||
.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) {
|
|
||||||
error.OutOfDateKHR => Swapchain.PresentState.suboptimal,
|
error.OutOfDateKHR => Swapchain.PresentState.suboptimal,
|
||||||
else => |narrow| return narrow,
|
else => |narrow| return narrow,
|
||||||
};
|
};
|
||||||
@@ -108,13 +56,90 @@ pub fn main() !void {
|
|||||||
c.glfwGetWindowSize(window, &w, &h);
|
c.glfwGetWindowSize(window, &w, &h);
|
||||||
|
|
||||||
try swapchain.recreate(.{.width = @intCast(u32, w), .height = @intCast(u32, 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.glfwSwapBuffers(window);
|
||||||
c.glfwPollEvents();
|
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 {
|
const ImageState = struct {
|
||||||
layout: vk.ImageLayout,
|
layout: vk.ImageLayout,
|
||||||
stage: vk.PipelineStageFlags,
|
stage: vk.PipelineStageFlags,
|
||||||
|
|||||||
@@ -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);
|
for (self.swap_images) |si| si.deinit(self.gc);
|
||||||
self.gc.vkd.destroySemaphore(self.gc.dev, self.next_image_acquired, null);
|
self.gc.vkd.destroySemaphore(self.gc.dev, self.next_image_acquired, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: Swapchain) void {
|
pub fn deinit(self: Swapchain) void {
|
||||||
self.gc.vkd.deviceWaitIdle(self.gc.dev) catch return;
|
self.deinitExceptSwapchain() catch return;
|
||||||
self.deinitExceptSwapchain();
|
|
||||||
self.gc.vkd.destroySwapchainKHR(self.gc.dev, self.handle, null);
|
self.gc.vkd.destroySwapchainKHR(self.gc.dev, self.handle, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ pub const Swapchain = struct {
|
|||||||
const gc = self.gc;
|
const gc = self.gc;
|
||||||
const allocator = self.allocator;
|
const allocator = self.allocator;
|
||||||
const old_handle = self.handle;
|
const old_handle = self.handle;
|
||||||
self.deinitExceptSwapchain();
|
try self.deinitExceptSwapchain();
|
||||||
self.* = try initRecycle(gc, allocator, new_extent, old_handle);
|
self.* = try initRecycle(gc, allocator, new_extent, old_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user