Unknown state [2025-08-04]
This commit is contained in:
@@ -24,10 +24,12 @@ const apis: []const vk.ApiInfo = &(.{
|
|||||||
else => .{},
|
else => .{},
|
||||||
});
|
});
|
||||||
|
|
||||||
const Base = vk.BaseWrapper(apis);
|
pub const Base = vk.BaseWrapper(apis);
|
||||||
const Instance = vk.InstanceProxy(apis);
|
pub const Instance = vk.InstanceProxy(apis);
|
||||||
const Device = vk.DeviceProxy(apis);
|
pub const Device = vk.DeviceProxy(apis);
|
||||||
const Queue = vk.QueueProxy(apis);
|
pub const Queue = vk.QueueProxy(apis);
|
||||||
|
|
||||||
|
pub const SwapChain = @import("swapchain.zig").SwapChain;
|
||||||
|
|
||||||
const Core = @This();
|
const Core = @This();
|
||||||
|
|
||||||
|
282
shape/src/SwapChain.zig
Normal file
282
shape/src/SwapChain.zig
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
@@ -17,6 +17,9 @@ pub fn main() !void {
|
|||||||
std.log.debug("Created queue: {any}", .{core.q.handle});
|
std.log.debug("Created queue: {any}", .{core.q.handle});
|
||||||
std.log.debug("Created surface: {any}", .{core.surface});
|
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);
|
// var caps = try I.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, surface);
|
||||||
// const format = search: {
|
// const format = search: {
|
||||||
// const formats = try I.getPhysicalDeviceSurfaceFormatsAllocKHR(pdev, surface, alloc);
|
// const formats = try I.getPhysicalDeviceSurfaceFormatsAllocKHR(pdev, surface, alloc);
|
||||||
|
Reference in New Issue
Block a user