Refactor literally everything

This commit is contained in:
2025-11-26 01:19:20 +01:00
parent d6a4b8c1fe
commit 9f2d1e4608
22 changed files with 2070 additions and 1034 deletions

View File

@@ -6,11 +6,19 @@ const vk = @import("vulkan");
const Engine = @import("Engine.zig");
const QSM = @import("QueueSharingMode.zig");
engine: *Engine,
params: Params,
render_pass: vk.RenderPass,
extent: vk.Extent2D = .{ .width = 0, .height = 0 },
swapchain: vk.SwapchainKHR = .null_handle,
swapchain_images: []SwapchainImage = &.{},
image_index: u32 = 0,
semaphore_image_acquired: vk.Semaphore = .null_handle,
pub const PresentResult = enum {
optimal,
suboptimal,
};
pub fn init(engine: *Engine) !Swapchain {
const params: Params = try .init(engine);
@@ -20,7 +28,7 @@ pub fn init(engine: *Engine) !Swapchain {
.{
.format = params.surface_format.format,
.samples = .{ .@"1_bit" = true },
.load_op = .dont_care,
.load_op = .clear,
.store_op = .store,
.stencil_load_op = .dont_care,
.stencil_store_op = .dont_care,
@@ -54,47 +62,49 @@ pub fn init(engine: *Engine) !Swapchain {
errdefer engine.device.destroyRenderPass(render_pass, &engine.vk_allocator.interface);
var swapchain: Swapchain = .{
.engine = engine,
.params = params,
.render_pass = render_pass,
};
try recreate(&swapchain);
try recreate(&swapchain, engine);
return swapchain;
}
pub fn deinit(self: *Swapchain) void {
const allocator = self.engine.vk_allocator.allocator;
pub fn deinit(self: *Swapchain, engine: *Engine) void {
const allocator = engine.vk_allocator.allocator;
for (self.swapchain_images) |swapchain_image| {
swapchain_image.deinit(self.engine);
swapchain_image.deinit(engine);
}
allocator.free(self.swapchain_images);
if (self.swapchain != .null_handle) {
self.engine.device.destroySwapchainKHR(self.swapchain, &self.engine.vk_allocator.interface);
engine.device.destroySwapchainKHR(self.swapchain, &engine.vk_allocator.interface);
}
self.engine.device.destroyRenderPass(self.render_pass, &self.engine.vk_allocator.interface);
engine.device.destroyRenderPass(self.render_pass, &engine.vk_allocator.interface);
self.* = undefined;
}
pub fn recreate(self: *Swapchain) !void {
const mode = &self.engine.mode.surface;
const allocator = self.engine.vk_allocator.allocator;
pub fn recreate(self: *Swapchain, engine: *Engine) !void {
const mode = &engine.mode.surface;
const allocator = engine.vk_allocator.allocator;
const old_swapchain = self.swapchain;
const old_swapchain_images = self.swapchain_images;
const old_semaphore_image_acquired = self.semaphore_image_acquired;
const extent = try getCurrentExtent(self.engine);
const extent = try getCurrentExtent(engine);
std.log.debug("Recreating swapchain with extent of {d}×{d}...", .{ extent.width, extent.height });
// --- CREATE NEW SWAPCHAIN ------------------------------------------------
const surface_capabilities = try self.engine.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(self.engine.physical_device, mode.surface);
const surface_capabilities = try engine.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(engine.physical_device, mode.surface);
const qsm = QSM.resolve(self.engine.graphics_queue.allocation.family, mode.presentation_queue.allocation.family);
const new_swapchain = try self.engine.device.createSwapchainKHR(&.{
const qsm = QSM.resolve(engine.graphics_queue.allocation.family, mode.presentation_queue.allocation.family);
const new_swapchain = try engine.device.createSwapchainKHR(&.{
.surface = mode.surface,
.min_image_count = self.params.image_count,
.image_format = self.params.surface_format.format,
@@ -110,8 +120,8 @@ pub fn recreate(self: *Swapchain) !void {
.present_mode = .fifo_khr,
.clipped = .true,
.old_swapchain = old_swapchain,
}, &self.engine.vk_allocator.interface);
errdefer self.engine.device.destroySwapchainKHR(new_swapchain, &self.engine.vk_allocator.interface);
}, &engine.vk_allocator.interface);
errdefer engine.device.destroySwapchainKHR(new_swapchain, &engine.vk_allocator.interface);
// --- DESTROY OLD SWAPCHAIN AND ITS IMAGES --------------------------------
@@ -120,29 +130,36 @@ pub fn recreate(self: *Swapchain) !void {
// null and deinit the old swapchain and images.
for (old_swapchain_images) |swapchain_image| {
swapchain_image.deinit(self.engine);
swapchain_image.deinit(engine);
}
allocator.free(self.swapchain_images);
self.swapchain_images = &.{};
if (old_swapchain != .null_handle) {
self.engine.device.destroySwapchainKHR(old_swapchain, &self.engine.vk_allocator.interface);
engine.device.destroySwapchainKHR(old_swapchain, &engine.vk_allocator.interface);
self.swapchain = .null_handle;
}
self.extent = .{ .width = 0, .height = 0 };
if (old_semaphore_image_acquired != .null_handle) {
engine.destroySemaphore(old_semaphore_image_acquired);
self.semaphore_image_acquired = .null_handle;
}
// --- CREATE NEW SWAPCHAIN IMAGES -----------------------------------------
const new_swapchain_images = blk: {
const images = try self.engine.device.getSwapchainImagesAllocKHR(new_swapchain, allocator);
const images = try engine.device.getSwapchainImagesAllocKHR(new_swapchain, allocator);
defer allocator.free(images);
var swapchain_images: std.ArrayList(SwapchainImage) = try .initCapacity(allocator, images.len);
errdefer swapchain_images.deinit(allocator);
errdefer for (swapchain_images.items) |x| x.deinit(self.engine);
errdefer for (swapchain_images.items) |x| x.deinit(engine);
for (images) |image| {
swapchain_images.appendAssumeCapacity(try SwapchainImage.init(self.engine, .{
swapchain_images.appendAssumeCapacity(try SwapchainImage.init(engine, .{
.image = image,
.format = self.params.surface_format.format,
.render_pass = self.render_pass,
@@ -154,20 +171,105 @@ pub fn recreate(self: *Swapchain) !void {
};
errdefer {
for (new_swapchain_images) |swapchain_image| {
swapchain_image.deinit(self.engine);
swapchain_image.deinit(engine);
}
allocator.free(new_swapchain_images);
}
// --- ACQUIRE NEXT IMAGE --------------------------------------------------
var semaphore_image_acquired = try engine.createSemaphore();
errdefer engine.destroySemaphore(semaphore_image_acquired);
const res = try engine.device.acquireNextImageKHR(new_swapchain, std.math.maxInt(u64), semaphore_image_acquired, .null_handle);
if (res.result == .not_ready or res.result == .timeout) {
return error.ImageAcquireFailed;
}
std.mem.swap(vk.Semaphore, &new_swapchain_images[res.image_index].semaphore_image_acquired, &semaphore_image_acquired);
// --- COMMIT --------------------------------------------------------------
self.extent = extent;
self.swapchain = new_swapchain;
self.swapchain_images = new_swapchain_images;
self.image_index = res.image_index;
self.semaphore_image_acquired = semaphore_image_acquired;
std.log.debug("Swapchain recreated.", .{});
}
fn getCurrentExtent(self: *Engine) !vk.Extent2D {
const mode = &self.mode.surface;
const surface_capabilities = try self.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(self.physical_device, mode.surface);
pub fn present(self: *Swapchain, engine: *Engine, command_buffer: vk.CommandBuffer) !PresentResult {
const device = engine.device;
const mode = &engine.mode.surface;
std.log.debug("Presenting command buffer {X}.", .{@intFromEnum(command_buffer)});
// --- WAIT FOR CURRENT FRAME TO FINISH ------------------------------------
const current_swapchain_image = &self.swapchain_images[self.image_index];
try engine.waitForFence(current_swapchain_image.fence);
if (current_swapchain_image.command_buffer != .null_handle) {
device.freeCommandBuffers(engine.graphics_command_pool, 1, @ptrCast(&current_swapchain_image.command_buffer));
current_swapchain_image.command_buffer = .null_handle;
}
try engine.resetFence(current_swapchain_image.fence);
// --- SUBMIT COMMAND BUFFER -----------------------------------------------
const wait_semaphores = [_]vk.Semaphore{
current_swapchain_image.semaphore_image_acquired,
};
const pipeline_stages_flags = [_]vk.PipelineStageFlags{
.{ .top_of_pipe_bit = true },
};
std.debug.assert(wait_semaphores.len == pipeline_stages_flags.len);
const signal_semaphores = [_]vk.Semaphore{
current_swapchain_image.semaphore_render_finished,
};
current_swapchain_image.command_buffer = command_buffer;
try device.queueSubmit(engine.graphics_queue.handle, 1, &.{
.{
.wait_semaphore_count = wait_semaphores.len,
.p_wait_semaphores = &wait_semaphores,
.p_wait_dst_stage_mask = &pipeline_stages_flags,
.command_buffer_count = 1,
.p_command_buffers = @ptrCast(&command_buffer),
.signal_semaphore_count = signal_semaphores.len,
.p_signal_semaphores = &signal_semaphores,
},
}, current_swapchain_image.fence);
// --- PRESENT CURRENT FRAME -----------------------------------------------
_ = try device.queuePresentKHR(mode.presentation_queue.handle, &.{
.wait_semaphore_count = 1,
.p_wait_semaphores = @ptrCast(&current_swapchain_image.semaphore_render_finished),
.swapchain_count = 1,
.p_swapchains = @ptrCast(&self.swapchain),
.p_image_indices = @ptrCast(&self.image_index),
});
// --- ACQUIRE NEXT FRAME --------------------------------------------------
const res = try device.acquireNextImageKHR(self.swapchain, std.math.maxInt(u64), self.semaphore_image_acquired, .null_handle);
std.mem.swap(vk.Semaphore, &self.swapchain_images[res.image_index].semaphore_image_acquired, &self.semaphore_image_acquired);
self.image_index = res.image_index;
return switch (res.result) {
.success => .optimal,
.suboptimal_khr => .suboptimal,
else => unreachable,
};
}
fn getCurrentExtent(engine: *Engine) !vk.Extent2D {
const mode = &engine.mode.surface;
const surface_capabilities = try engine.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(engine.physical_device, mode.surface);
if (surface_capabilities.current_extent.width != std.math.maxInt(u32) and surface_capabilities.current_extent.height != std.math.maxInt(u32)) {
return surface_capabilities.current_extent;
@@ -223,6 +325,8 @@ const Params = struct {
if (surface_capabilities.max_image_count > 0) surface_capabilities.max_image_count else std.math.maxInt(u32),
);
std.log.debug("Using surface format \"{s}\" and color space \"{s}\" with {d} images.", .{ @tagName(surface_format.format), @tagName(surface_format.color_space), image_count });
return .{
.surface_format = surface_format,
.image_count = image_count,
@@ -237,6 +341,7 @@ const SwapchainImage = struct {
semaphore_render_finished: vk.Semaphore,
fence: vk.Fence,
framebuffer: vk.Framebuffer,
command_buffer: vk.CommandBuffer,
const InitProps = struct {
image: vk.Image,
@@ -246,16 +351,10 @@ const SwapchainImage = struct {
};
fn init(engine: *Engine, props: InitProps) !SwapchainImage {
const image_view = try engine.device.createImageView(&.{
const image_view = try engine.createImageView(.{
.image = props.image,
.view_type = .@"2d",
.format = props.format,
.components = .{
.r = .identity,
.g = .identity,
.b = .identity,
.a = .identity,
},
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
@@ -263,31 +362,28 @@ const SwapchainImage = struct {
.base_array_layer = 0,
.layer_count = 1,
},
}, &engine.vk_allocator.interface);
errdefer engine.device.destroyImageView(image_view, &engine.vk_allocator.interface);
});
errdefer engine.destroyImageView(image_view);
const semaphore_image_acquired = try engine.device.createSemaphore(&.{}, &engine.vk_allocator.interface);
errdefer engine.device.destroySemaphore(semaphore_image_acquired, &engine.vk_allocator.interface);
const semaphore_image_acquired = try engine.createSemaphore();
errdefer engine.destroySemaphore(semaphore_image_acquired);
const semaphore_render_finished = try engine.device.createSemaphore(&.{}, &engine.vk_allocator.interface);
errdefer engine.device.destroySemaphore(semaphore_render_finished, &engine.vk_allocator.interface);
const semaphore_render_finished = try engine.createSemaphore();
errdefer engine.destroySemaphore(semaphore_render_finished);
const fence = try engine.device.createFence(&.{
const fence = try engine.createFence(.{
.flags = .{ .signaled_bit = true },
}, &engine.vk_allocator.interface);
errdefer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
});
errdefer engine.destroyFence(fence);
const attachments = [_]vk.ImageView{image_view};
const framebuffer = try engine.device.createFramebuffer(&.{
const framebuffer = try engine.createFramebuffer(.{
.render_pass = props.render_pass,
.attachment_count = attachments.len,
.p_attachments = &attachments,
.attachments = &.{image_view},
.width = props.extent.width,
.height = props.extent.height,
.layers = 1,
}, &engine.vk_allocator.interface);
errdefer engine.device.destroyFramebuffer(framebuffer, &engine.vk_allocator.interface);
});
errdefer engine.destroyFramebuffer(framebuffer);
return .{
.image = props.image,
@@ -296,20 +392,16 @@ const SwapchainImage = struct {
.semaphore_render_finished = semaphore_render_finished,
.fence = fence,
.framebuffer = framebuffer,
.command_buffer = .null_handle,
};
}
fn deinit(self: SwapchainImage, engine: *Engine) void {
self.waitForFence(engine) catch return;
engine.device.destroyFramebuffer(self.framebuffer, &engine.vk_allocator.interface);
engine.device.destroyFence(self.fence, &engine.vk_allocator.interface);
engine.device.destroySemaphore(self.semaphore_render_finished, &engine.vk_allocator.interface);
engine.device.destroySemaphore(self.semaphore_image_acquired, &engine.vk_allocator.interface);
engine.device.destroyImageView(self.image_view, &engine.vk_allocator.interface);
}
fn waitForFence(self: SwapchainImage, engine: *Engine) !void {
const fences = [_]vk.Fence{self.fence};
_ = try engine.device.waitForFences(fences.len, &fences, .true, std.math.maxInt(u64));
engine.waitForFence(self.fence) catch {};
engine.destroyFramebuffer(self.framebuffer);
engine.destroyFence(self.fence);
engine.destroySemaphore(self.semaphore_render_finished);
engine.destroySemaphore(self.semaphore_image_acquired);
engine.destroyImageView(self.image_view);
}
};