well-behaved swapchain
This commit is contained in:
@@ -4,7 +4,7 @@ const vkgen = @import("vulkan-zig");
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{
|
||||
.preferred_optimize_mode = .ReleaseSafe,
|
||||
// .preferred_optimize_mode = .ReleaseSafe,
|
||||
});
|
||||
|
||||
const vk = b.dependency("vulkan-zig", .{
|
||||
|
@@ -18,6 +18,8 @@ pub const engine = Engine(Window, Render, root.nu_modules);
|
||||
// Hooks: setup, teardown, fixed, frame, present
|
||||
|
||||
pub fn main() void {
|
||||
std.log.info("use_debug_messenger: {}", .{config.render.use_debug_messenger});
|
||||
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
|
@@ -7,7 +7,6 @@ const builtin = @import("builtin");
|
||||
const vk = @import("vk");
|
||||
|
||||
const nu = @import("../nu.zig");
|
||||
// const au = @import("Render/au.zig");
|
||||
|
||||
const ctx = @import("Render/ctx.zig");
|
||||
const SwapChain = @import("Render/SwapChain.zig");
|
||||
@@ -85,6 +84,12 @@ pub fn setup(alloc: std.mem.Allocator) !void {
|
||||
|
||||
_sc = try SwapChain.init(alloc, _flights.len);
|
||||
errdefer _sc.deinit();
|
||||
|
||||
nu.Window.add_resize_callback(&on_resize);
|
||||
}
|
||||
|
||||
fn on_resize(_: u32, _: u32) void {
|
||||
_sc.rebuild() catch @panic("rebuild on resize failed");
|
||||
}
|
||||
|
||||
pub fn teardown() void {
|
||||
@@ -94,7 +99,7 @@ pub fn teardown() void {
|
||||
}
|
||||
|
||||
pub fn render() !void {
|
||||
const target = try _sc.acquire();
|
||||
const target = try _sc.acquire() orelse return;
|
||||
const flight = &_flights[target.flight_index];
|
||||
|
||||
const render_area: vk.Rect2D = .{
|
||||
@@ -116,7 +121,7 @@ pub fn render() !void {
|
||||
0,
|
||||
null,
|
||||
1,
|
||||
&.{target.top_of_pipe()},
|
||||
&.{target.top_of_pipe_barrier()},
|
||||
);
|
||||
|
||||
cmd.beginRendering(&vk.RenderingInfo{
|
||||
@@ -133,7 +138,7 @@ pub fn render() !void {
|
||||
.resolve_image_layout = .undefined,
|
||||
.load_op = .clear,
|
||||
.store_op = .store,
|
||||
.clear_value = .{ .color = .{ .float_32 = .{ 1, 0, 0, 1 } } },
|
||||
.clear_value = .{ .color = .{ .float_32 = .{ 0.1, 0.1, 0.1, 1 } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -149,7 +154,7 @@ pub fn render() !void {
|
||||
0,
|
||||
null,
|
||||
1,
|
||||
&.{target.bottom_of_pipe()},
|
||||
&.{target.bottom_of_pipe_barrier()},
|
||||
);
|
||||
}
|
||||
try cmd.endCommandBuffer();
|
||||
|
@@ -44,7 +44,7 @@ pub const Target = struct {
|
||||
complete: vk.Semaphore, // this semaphore should be signaled when the render is complete
|
||||
available: vk.Fence, // this fence should be signaled when the target flight is available
|
||||
|
||||
pub fn top_of_pipe(target: Target) vk.ImageMemoryBarrier {
|
||||
pub fn top_of_pipe_barrier(target: Target) vk.ImageMemoryBarrier {
|
||||
return vk.ImageMemoryBarrier{
|
||||
.src_access_mask = .{},
|
||||
.dst_access_mask = .{ .color_attachment_write_bit = true },
|
||||
@@ -63,7 +63,7 @@ pub const Target = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bottom_of_pipe(target: Target) vk.ImageMemoryBarrier {
|
||||
pub fn bottom_of_pipe_barrier(target: Target) vk.ImageMemoryBarrier {
|
||||
return vk.ImageMemoryBarrier{
|
||||
.src_access_mask = .{ .color_attachment_write_bit = true },
|
||||
.dst_access_mask = .{},
|
||||
@@ -142,15 +142,16 @@ pub fn init(alloc: std.mem.Allocator, flight_count: usize) !Self {
|
||||
.old_swapchain = .null_handle,
|
||||
};
|
||||
|
||||
// try self.rebuild();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
fn rebuild(self: *Self) !void {
|
||||
std.debug.assert(self.handle == .null_handle); // don't rebuild if we weren't marked
|
||||
|
||||
pub fn rebuild(self: *Self) !void {
|
||||
const caps = try ctx.getPhysicalDeviceSurfaceCapabilities();
|
||||
self.cinfo.image_extent = caps.current_extent;
|
||||
|
||||
try ctx.D.queueWaitIdle(ctx.queue.*);
|
||||
self.handle = try ctx.D.createSwapchainKHR(&self.cinfo, null);
|
||||
ctx.D.destroySwapchainKHR(self.cinfo.old_swapchain, null);
|
||||
self.cinfo.old_swapchain = self.handle;
|
||||
@@ -215,7 +216,7 @@ pub fn deinit(self: *Self) void {
|
||||
self.flight_syncs.deinit(self.alloc);
|
||||
}
|
||||
|
||||
pub fn acquire(self: *Self) !Target {
|
||||
pub fn acquire(self: *Self) !?Target {
|
||||
var target: Target = .{
|
||||
.flight_index = @intCast(self.flight_index),
|
||||
.acquired = self.flight_syncs.items(.acquired)[self.flight_index],
|
||||
@@ -228,74 +229,59 @@ pub fn acquire(self: *Self) !Target {
|
||||
|
||||
const timeout = std.math.maxInt(u64);
|
||||
|
||||
for (0..5) |_| {
|
||||
if (self.handle == .null_handle) {
|
||||
try self.rebuild();
|
||||
std.debug.assert(self.handle != .null_handle);
|
||||
}
|
||||
|
||||
const fences: [1]vk.Fence = .{target.available};
|
||||
std.debug.assert(.success == try ctx.D.waitForFences(
|
||||
1,
|
||||
&fences,
|
||||
&.{target.available},
|
||||
vk.TRUE,
|
||||
std.math.maxInt(u64),
|
||||
));
|
||||
|
||||
// two attempts
|
||||
|
||||
target.image_index = for (0..2) |_| {
|
||||
if (self.handle == .null_handle) try self.rebuild();
|
||||
|
||||
if (ctx.D.acquireNextImageKHR(
|
||||
self.handle,
|
||||
timeout,
|
||||
target.acquired,
|
||||
.null_handle,
|
||||
)) |res| {
|
||||
switch (res.result) {
|
||||
.success, .suboptimal_khr => {},
|
||||
)) |res| switch (res.result) {
|
||||
.success, .suboptimal_khr => break res.image_index,
|
||||
else => unreachable,
|
||||
} else |err| switch (err) {
|
||||
error.OutOfDateKHR => {
|
||||
self.handle = .null_handle;
|
||||
},
|
||||
else => return err,
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
};
|
||||
|
||||
target.image_index = res.image_index;
|
||||
target.image = self.chain.items(.image)[res.image_index];
|
||||
target.view = self.chain.items(.view)[res.image_index];
|
||||
target.image = self.chain.items(.image)[target.image_index];
|
||||
target.view = self.chain.items(.view)[target.image_index];
|
||||
|
||||
try ctx.D.resetFences(1, &.{target.available});
|
||||
self.flight_index = @mod(self.flight_index + 1, self.flight_syncs.len);
|
||||
|
||||
return target;
|
||||
} else |err| switch (err) {
|
||||
error.OutOfDateKHR => {
|
||||
self.handle = .null_handle;
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
}
|
||||
} else {
|
||||
return error.CannotRecreateSwapchain;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn present(self: *Self, target: Target) !void {
|
||||
if (ctx.Q.presentKHR(&vk.PresentInfoKHR{
|
||||
.wait_semaphore_count = 1, // todo extra semaphores?
|
||||
.wait_semaphore_count = 1,
|
||||
.p_wait_semaphores = &.{target.complete},
|
||||
.swapchain_count = 1,
|
||||
.p_swapchains = &.{self.handle},
|
||||
.p_image_indices = &.{target.image_index},
|
||||
.p_results = null,
|
||||
})) |res| {
|
||||
switch (res) {
|
||||
})) |res| switch(res) {
|
||||
.success => {},
|
||||
.suboptimal_khr => {
|
||||
self.handle = .null_handle;
|
||||
return;
|
||||
},
|
||||
.suboptimal_khr => self.handle = .null_handle,
|
||||
else => unreachable,
|
||||
}
|
||||
} else |err| switch(err) {
|
||||
error.OutOfDateKHR => {
|
||||
self.handle = .null_handle;
|
||||
std.log.debug("Dropped frame", .{});
|
||||
return;
|
||||
},
|
||||
error.OutOfDateKHR => self.handle = .null_handle,
|
||||
else => return err,
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,9 @@ pub const versions: []const vk.ApiInfo = &.{
|
||||
pub const instance_exts: []const vk.ApiInfo = if (config.use_debug_messenger) &.{
|
||||
vk.extensions.ext_debug_utils,
|
||||
vk.extensions.khr_surface,
|
||||
} else &.{};
|
||||
} else &.{
|
||||
vk.extensions.khr_surface,
|
||||
};
|
||||
|
||||
pub const device_exts: []const vk.ApiInfo = &.{
|
||||
vk.extensions.khr_swapchain,
|
||||
@@ -70,10 +72,16 @@ var _queue: vk.Queue = undefined;
|
||||
pub const queue: *const vk.Queue = &_queue;
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) !void {
|
||||
_B = try BaseWrapper.load(glfwGetInstanceProcAddress);
|
||||
_B = if (config.use_debug_messenger)
|
||||
try BaseWrapper.load(glfwGetInstanceProcAddress)
|
||||
else
|
||||
BaseWrapper.loadNoFail(glfwGetInstanceProcAddress);
|
||||
|
||||
_instance = try _create_instance(alloc);
|
||||
_iw = try InstanceWrapper.load(_instance, glfwGetInstanceProcAddress);
|
||||
_iw = if (config.use_debug_messenger)
|
||||
try InstanceWrapper.load(_instance, glfwGetInstanceProcAddress)
|
||||
else
|
||||
InstanceWrapper.loadNoFail(_instance, glfwGetInstanceProcAddress);
|
||||
errdefer _destroy_instance();
|
||||
_I = InstanceProxy.init(_instance, iw);
|
||||
|
||||
@@ -86,7 +94,10 @@ pub fn init(alloc: std.mem.Allocator) !void {
|
||||
_pdevice = try _select_pdevice(alloc);
|
||||
_family = try _select_queue_family_index(alloc); // only one queue supported
|
||||
_device = try _create_device(alloc);
|
||||
_dw = try DeviceWrapper.load(_device, iw.dispatch.vkGetDeviceProcAddr);
|
||||
_dw = if (config.use_debug_messenger)
|
||||
try DeviceWrapper.load(_device, iw.dispatch.vkGetDeviceProcAddr)
|
||||
else
|
||||
DeviceWrapper.loadNoFail(_device, iw.dispatch.vkGetDeviceProcAddr);
|
||||
errdefer _destroy_device();
|
||||
_D = DeviceProxy.init(_device, dw);
|
||||
_queue = D.getDeviceQueue(_family, 0); // only one queue supported
|
||||
|
@@ -54,6 +54,8 @@ pub fn setup(_: std.mem.Allocator) !void {
|
||||
null,
|
||||
) orelse std.debug.panic("GLFW Create Window Failed", .{});
|
||||
|
||||
_ = c.glfwSetFramebufferSizeCallback(handle, &resize_callback);
|
||||
|
||||
// bus.connect(handle);
|
||||
// errdefer bus.disconnect(handle);
|
||||
}
|
||||
@@ -75,3 +77,19 @@ pub fn next() bool {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var _resize_callbacks: std.BoundedArray(*const fn (u32, u32) void, 16) = .{};
|
||||
|
||||
fn resize_callback(_: ?*c.GLFWwindow, w: c_int, h: c_int) callconv(.C) void {
|
||||
for (_resize_callbacks.slice()) |cb| {
|
||||
cb(@intCast(w), @intCast(h));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_resize_callback(cb: *const fn (u32, u32) void) void {
|
||||
_resize_callbacks.appendAssumeCapacity(cb);
|
||||
}
|
||||
|
||||
pub fn set_title(title: [:0]const u8) void {
|
||||
c.glfwSetWindowTitle(handle, title);
|
||||
}
|
||||
|
Reference in New Issue
Block a user