well-behaved swapchain
This commit is contained in:
@@ -4,7 +4,7 @@ const vkgen = @import("vulkan-zig");
|
|||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{
|
const optimize = b.standardOptimizeOption(.{
|
||||||
.preferred_optimize_mode = .ReleaseSafe,
|
// .preferred_optimize_mode = .ReleaseSafe,
|
||||||
});
|
});
|
||||||
|
|
||||||
const vk = b.dependency("vulkan-zig", .{
|
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
|
// Hooks: setup, teardown, fixed, frame, present
|
||||||
|
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
|
std.log.info("use_debug_messenger: {}", .{config.render.use_debug_messenger});
|
||||||
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
const alloc = gpa.allocator();
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
@@ -7,7 +7,6 @@ const builtin = @import("builtin");
|
|||||||
const vk = @import("vk");
|
const vk = @import("vk");
|
||||||
|
|
||||||
const nu = @import("../nu.zig");
|
const nu = @import("../nu.zig");
|
||||||
// const au = @import("Render/au.zig");
|
|
||||||
|
|
||||||
const ctx = @import("Render/ctx.zig");
|
const ctx = @import("Render/ctx.zig");
|
||||||
const SwapChain = @import("Render/SwapChain.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);
|
_sc = try SwapChain.init(alloc, _flights.len);
|
||||||
errdefer _sc.deinit();
|
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 {
|
pub fn teardown() void {
|
||||||
@@ -94,7 +99,7 @@ pub fn teardown() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn render() !void {
|
pub fn render() !void {
|
||||||
const target = try _sc.acquire();
|
const target = try _sc.acquire() orelse return;
|
||||||
const flight = &_flights[target.flight_index];
|
const flight = &_flights[target.flight_index];
|
||||||
|
|
||||||
const render_area: vk.Rect2D = .{
|
const render_area: vk.Rect2D = .{
|
||||||
@@ -116,7 +121,7 @@ pub fn render() !void {
|
|||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
1,
|
1,
|
||||||
&.{target.top_of_pipe()},
|
&.{target.top_of_pipe_barrier()},
|
||||||
);
|
);
|
||||||
|
|
||||||
cmd.beginRendering(&vk.RenderingInfo{
|
cmd.beginRendering(&vk.RenderingInfo{
|
||||||
@@ -133,7 +138,7 @@ pub fn render() !void {
|
|||||||
.resolve_image_layout = .undefined,
|
.resolve_image_layout = .undefined,
|
||||||
.load_op = .clear,
|
.load_op = .clear,
|
||||||
.store_op = .store,
|
.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,
|
0,
|
||||||
null,
|
null,
|
||||||
1,
|
1,
|
||||||
&.{target.bottom_of_pipe()},
|
&.{target.bottom_of_pipe_barrier()},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
try cmd.endCommandBuffer();
|
try cmd.endCommandBuffer();
|
||||||
|
@@ -44,7 +44,7 @@ pub const Target = struct {
|
|||||||
complete: vk.Semaphore, // this semaphore should be signaled when the render is complete
|
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
|
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{
|
return vk.ImageMemoryBarrier{
|
||||||
.src_access_mask = .{},
|
.src_access_mask = .{},
|
||||||
.dst_access_mask = .{ .color_attachment_write_bit = true },
|
.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{
|
return vk.ImageMemoryBarrier{
|
||||||
.src_access_mask = .{ .color_attachment_write_bit = true },
|
.src_access_mask = .{ .color_attachment_write_bit = true },
|
||||||
.dst_access_mask = .{},
|
.dst_access_mask = .{},
|
||||||
@@ -142,15 +142,16 @@ pub fn init(alloc: std.mem.Allocator, flight_count: usize) !Self {
|
|||||||
.old_swapchain = .null_handle,
|
.old_swapchain = .null_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// try self.rebuild();
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rebuild(self: *Self) !void {
|
pub fn rebuild(self: *Self) !void {
|
||||||
std.debug.assert(self.handle == .null_handle); // don't rebuild if we weren't marked
|
|
||||||
|
|
||||||
const caps = try ctx.getPhysicalDeviceSurfaceCapabilities();
|
const caps = try ctx.getPhysicalDeviceSurfaceCapabilities();
|
||||||
self.cinfo.image_extent = caps.current_extent;
|
self.cinfo.image_extent = caps.current_extent;
|
||||||
|
|
||||||
|
try ctx.D.queueWaitIdle(ctx.queue.*);
|
||||||
self.handle = try ctx.D.createSwapchainKHR(&self.cinfo, null);
|
self.handle = try ctx.D.createSwapchainKHR(&self.cinfo, null);
|
||||||
ctx.D.destroySwapchainKHR(self.cinfo.old_swapchain, null);
|
ctx.D.destroySwapchainKHR(self.cinfo.old_swapchain, null);
|
||||||
self.cinfo.old_swapchain = self.handle;
|
self.cinfo.old_swapchain = self.handle;
|
||||||
@@ -215,7 +216,7 @@ pub fn deinit(self: *Self) void {
|
|||||||
self.flight_syncs.deinit(self.alloc);
|
self.flight_syncs.deinit(self.alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acquire(self: *Self) !Target {
|
pub fn acquire(self: *Self) !?Target {
|
||||||
var target: Target = .{
|
var target: Target = .{
|
||||||
.flight_index = @intCast(self.flight_index),
|
.flight_index = @intCast(self.flight_index),
|
||||||
.acquired = self.flight_syncs.items(.acquired)[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);
|
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(
|
std.debug.assert(.success == try ctx.D.waitForFences(
|
||||||
1,
|
1,
|
||||||
&fences,
|
&.{target.available},
|
||||||
vk.TRUE,
|
vk.TRUE,
|
||||||
std.math.maxInt(u64),
|
std.math.maxInt(u64),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// two attempts
|
||||||
|
|
||||||
|
target.image_index = for (0..2) |_| {
|
||||||
|
if (self.handle == .null_handle) try self.rebuild();
|
||||||
|
|
||||||
if (ctx.D.acquireNextImageKHR(
|
if (ctx.D.acquireNextImageKHR(
|
||||||
self.handle,
|
self.handle,
|
||||||
timeout,
|
timeout,
|
||||||
target.acquired,
|
target.acquired,
|
||||||
.null_handle,
|
.null_handle,
|
||||||
)) |res| {
|
)) |res| switch (res.result) {
|
||||||
switch (res.result) {
|
.success, .suboptimal_khr => break res.image_index,
|
||||||
.success, .suboptimal_khr => {},
|
|
||||||
else => unreachable,
|
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)[target.image_index];
|
||||||
target.image = self.chain.items(.image)[res.image_index];
|
target.view = self.chain.items(.view)[target.image_index];
|
||||||
target.view = self.chain.items(.view)[res.image_index];
|
|
||||||
|
|
||||||
try ctx.D.resetFences(1, &.{target.available});
|
try ctx.D.resetFences(1, &.{target.available});
|
||||||
self.flight_index = @mod(self.flight_index + 1, self.flight_syncs.len);
|
self.flight_index = @mod(self.flight_index + 1, self.flight_syncs.len);
|
||||||
|
|
||||||
return target;
|
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 {
|
pub fn present(self: *Self, target: Target) !void {
|
||||||
if (ctx.Q.presentKHR(&vk.PresentInfoKHR{
|
if (ctx.Q.presentKHR(&vk.PresentInfoKHR{
|
||||||
.wait_semaphore_count = 1, // todo extra semaphores?
|
.wait_semaphore_count = 1,
|
||||||
.p_wait_semaphores = &.{target.complete},
|
.p_wait_semaphores = &.{target.complete},
|
||||||
.swapchain_count = 1,
|
.swapchain_count = 1,
|
||||||
.p_swapchains = &.{self.handle},
|
.p_swapchains = &.{self.handle},
|
||||||
.p_image_indices = &.{target.image_index},
|
.p_image_indices = &.{target.image_index},
|
||||||
.p_results = null,
|
.p_results = null,
|
||||||
})) |res| {
|
})) |res| switch(res) {
|
||||||
switch (res) {
|
|
||||||
.success => {},
|
.success => {},
|
||||||
.suboptimal_khr => {
|
.suboptimal_khr => self.handle = .null_handle,
|
||||||
self.handle = .null_handle;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
} else |err| switch(err) {
|
||||||
} else |err| switch (err) {
|
error.OutOfDateKHR => self.handle = .null_handle,
|
||||||
error.OutOfDateKHR => {
|
|
||||||
self.handle = .null_handle;
|
|
||||||
std.log.debug("Dropped frame", .{});
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
else => return err,
|
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) &.{
|
pub const instance_exts: []const vk.ApiInfo = if (config.use_debug_messenger) &.{
|
||||||
vk.extensions.ext_debug_utils,
|
vk.extensions.ext_debug_utils,
|
||||||
vk.extensions.khr_surface,
|
vk.extensions.khr_surface,
|
||||||
} else &.{};
|
} else &.{
|
||||||
|
vk.extensions.khr_surface,
|
||||||
|
};
|
||||||
|
|
||||||
pub const device_exts: []const vk.ApiInfo = &.{
|
pub const device_exts: []const vk.ApiInfo = &.{
|
||||||
vk.extensions.khr_swapchain,
|
vk.extensions.khr_swapchain,
|
||||||
@@ -70,10 +72,16 @@ var _queue: vk.Queue = undefined;
|
|||||||
pub const queue: *const vk.Queue = &_queue;
|
pub const queue: *const vk.Queue = &_queue;
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator) !void {
|
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);
|
_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();
|
errdefer _destroy_instance();
|
||||||
_I = InstanceProxy.init(_instance, iw);
|
_I = InstanceProxy.init(_instance, iw);
|
||||||
|
|
||||||
@@ -86,7 +94,10 @@ pub fn init(alloc: std.mem.Allocator) !void {
|
|||||||
_pdevice = try _select_pdevice(alloc);
|
_pdevice = try _select_pdevice(alloc);
|
||||||
_family = try _select_queue_family_index(alloc); // only one queue supported
|
_family = try _select_queue_family_index(alloc); // only one queue supported
|
||||||
_device = try _create_device(alloc);
|
_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();
|
errdefer _destroy_device();
|
||||||
_D = DeviceProxy.init(_device, dw);
|
_D = DeviceProxy.init(_device, dw);
|
||||||
_queue = D.getDeviceQueue(_family, 0); // only one queue supported
|
_queue = D.getDeviceQueue(_family, 0); // only one queue supported
|
||||||
|
@@ -54,6 +54,8 @@ pub fn setup(_: std.mem.Allocator) !void {
|
|||||||
null,
|
null,
|
||||||
) orelse std.debug.panic("GLFW Create Window Failed", .{});
|
) orelse std.debug.panic("GLFW Create Window Failed", .{});
|
||||||
|
|
||||||
|
_ = c.glfwSetFramebufferSizeCallback(handle, &resize_callback);
|
||||||
|
|
||||||
// bus.connect(handle);
|
// bus.connect(handle);
|
||||||
// errdefer bus.disconnect(handle);
|
// errdefer bus.disconnect(handle);
|
||||||
}
|
}
|
||||||
@@ -75,3 +77,19 @@ pub fn next() bool {
|
|||||||
|
|
||||||
return true;
|
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