Unknown state [2025-08-04]

This commit is contained in:
2025-08-04 22:19:55 -04:00
parent 0596cd07d3
commit a145a60fa8
3 changed files with 291 additions and 4 deletions

View File

@@ -24,10 +24,12 @@ const apis: []const vk.ApiInfo = &(.{
else => .{},
});
const Base = vk.BaseWrapper(apis);
const Instance = vk.InstanceProxy(apis);
const Device = vk.DeviceProxy(apis);
const Queue = vk.QueueProxy(apis);
pub const Base = vk.BaseWrapper(apis);
pub const Instance = vk.InstanceProxy(apis);
pub const Device = vk.DeviceProxy(apis);
pub const Queue = vk.QueueProxy(apis);
pub const SwapChain = @import("swapchain.zig").SwapChain;
const Core = @This();

282
shape/src/SwapChain.zig Normal file
View File

@@ -0,0 +1,282 @@
const std = @import("std");
const vk = @import("vk");
const Core = @import("Core.zig");
fn _choose_format(core: *const Core, alloc: std.mem.Allocator) !vk.SurfaceFormatKHR {
const formats = try core.i.getPhysicalDeviceSurfaceFormatsAllocKHR(
core.pdev,
core.surface,
alloc,
);
defer alloc.free(formats);
for (formats) |format| {
if (format.color_space == .srgb_nonlinear_khr) return format;
} else {
return formats[0];
}
}
fn _choose_mode(core: *const Core, alloc: std.mem.Allocator) !vk.PresentModeKHR {
_ = core;
_ = alloc;
return .fifo_khr;
}
const Self = @This();
pub const Target = struct {
image_index: u32,
flight_index: u32,
image: vk.Image,
view: vk.ImageView,
acquired: vk.Semaphore, // this semaphore will be signaled when the target is acquired
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_barrier(target: Target) vk.ImageMemoryBarrier {
return 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 = target.image,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
};
}
pub fn bottom_of_pipe_barrier(target: Target) vk.ImageMemoryBarrier {
return 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 = target.image,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
};
}
};
const Sync = struct {
acquired: vk.Semaphore = .null_handle,
complete: vk.Semaphore = .null_handle,
available: vk.Fence = .null_handle,
};
const View = struct {
image: vk.Image,
view: vk.ImageView,
};
core: *const Core,
alloc: std.mem.Allocator,
frames_in_flight: u32,
flight_index: usize = 0,
flight_syncs: std.MultiArrayList(Sync) = .{},
cinfo: vk.SwapchainCreateInfoKHR = undefined,
handle: vk.SwapchainKHR = .null_handle,
chain: std.MultiArrayList(View) = .{},
pub fn init(core: *const Core, alloc: std.mem.Allocator, frames_in_flight: usize) !Self {
var self: Self = .{
.core = core,
.alloc = alloc,
.frames_in_flight = @intCast(frames_in_flight),
};
errdefer self.deinit();
try self.flight_syncs.resize(alloc, frames_in_flight);
for (self.flight_syncs.items(.acquired)) |*sem|
sem.* = try core.d.createSemaphore(&.{}, null);
for (self.flight_syncs.items(.complete)) |*sem|
sem.* = try core.d.createSemaphore(&.{}, null);
for (self.flight_syncs.items(.available)) |*fnc|
fnc.* = try core.d.createFence(&.{ .flags = .{ .signaled_bit = true } }, null);
const caps = try core.i.getPhysicalDeviceSurfaceCapabilitiesKHR(core.pdev, core.surface);
const format = try _choose_format(core, alloc);
const mode = try _choose_mode(core, alloc);
self.cinfo = .{
.surface = core.surface,
.min_image_count = std.math.clamp(
@min(3, caps.min_image_count + 1),
caps.min_image_count,
if (caps.max_image_count > 0) caps.max_image_count else 127,
),
.image_format = format.format,
.image_color_space = format.color_space,
.image_extent = undefined, // set in rebuild
.image_array_layers = 1,
.image_usage = .{ .color_attachment_bit = true },
.image_sharing_mode = .exclusive,
.pre_transform = .{ .identity_bit_khr = true },
.composite_alpha = .{ .opaque_bit_khr = true },
.present_mode = mode,
.clipped = vk.TRUE,
.old_swapchain = .null_handle,
};
// try self.rebuild();
return self;
}
pub fn rebuild(self: *Self) !void {
const caps = try self.core.i.getPhysicalDeviceSurfaceCapabilitiesKHR(self.core.pdev, self.core.surface);
self.cinfo.image_extent = caps.current_extent;
self.handle = try self.core.d.createSwapchainKHR(&self.cinfo, null);
self.core.d.destroySwapchainKHR(self.cinfo.old_swapchain, null);
self.cinfo.old_swapchain = self.handle;
for (self.chain.items(.view)) |view| self.core.d.destroyImageView(view, null);
@memset(self.chain.items(.view), .null_handle);
@memset(self.chain.items(.image), .null_handle);
var count: u32 = undefined;
std.debug.assert(
.success == try self.core.d.getSwapchainImagesKHR(
self.handle,
&count,
null,
),
);
try self.chain.resize(self.alloc, count);
std.debug.assert(
.success == try self.core.d.getSwapchainImagesKHR(
self.handle,
&count,
self.chain.items(.image).ptr,
),
);
for (self.chain.items(.image), self.chain.items(.view)) |image, *view| {
view.* = try self.core.d.createImageView(&vk.ImageViewCreateInfo{
.image = image,
.view_type = .@"2d",
.format = self.cinfo.image_format,
.components = .{
.r = .identity,
.g = .identity,
.b = .identity,
.a = .identity,
},
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
}, null);
}
}
pub fn deinit(self: *Self) void {
// The easiest way to ensure fences and semaphores are not in use for deletion. If it fails, the device must
// have failed somehow and sync is not necessary so just continue with cleanup.
self.core.d.deviceWaitIdle() catch {};
// images are owned by swapchain and not explicitly destroyed
for (self.chain.items(.view)) |view| self.core.d.destroyImageView(view, null);
self.chain.deinit(self.alloc);
self.core.d.destroySwapchainKHR(self.handle, null);
for (self.flight_syncs.items(.acquired)) |sem| self.core.d.destroySemaphore(sem, null);
for (self.flight_syncs.items(.complete)) |sem| self.core.d.destroySemaphore(sem, null);
for (self.flight_syncs.items(.available)) |fnc| self.core.d.destroyFence(fnc, null);
self.flight_syncs.deinit(self.alloc);
}
pub fn acquire(self: *Self) !?Target {
var target: Target = .{
.flight_index = @intCast(self.flight_index),
.acquired = self.flight_syncs.items(.acquired)[self.flight_index],
.complete = self.flight_syncs.items(.complete)[self.flight_index],
.available = self.flight_syncs.items(.available)[self.flight_index],
.image = undefined,
.view = undefined,
.image_index = undefined,
};
const timeout = std.math.maxInt(u64);
std.debug.assert(.success == try self.core.d.waitForFences(
1,
&.{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 (self.core.d.acquireNextImageKHR(
self.handle,
timeout,
target.acquired,
.null_handle,
)) |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 = self.chain.items(.image)[target.image_index];
target.view = self.chain.items(.view)[target.image_index];
try self.core.d.resetFences(1, &.{target.available});
self.flight_index = @mod(self.flight_index + 1, self.flight_syncs.len);
return target;
}
pub fn present(self: *Self, target: Target) !void {
if (self.core.q.presentKHR(&vk.PresentInfoKHR{
.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) {
.success => {},
.suboptimal_khr => self.handle = .null_handle,
else => unreachable,
} else |err| switch (err) {
error.OutOfDateKHR => self.handle = .null_handle,
else => return err,
}
}

View File

@@ -17,6 +17,9 @@ pub fn main() !void {
std.log.debug("Created queue: {any}", .{core.q.handle});
std.log.debug("Created surface: {any}", .{core.surface});
var sc = try Core.SwapChain(void).init(alloc, &core, 3);
defer sc.deinit();
// var caps = try I.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, surface);
// const format = search: {
// const formats = try I.getPhysicalDeviceSurfaceFormatsAllocKHR(pdev, surface, alloc);