Complete all Vulkan wrappers. Maybe worth it.

This commit is contained in:
2025-12-05 22:07:06 +01:00
parent a372bcb981
commit 9baf42e838
11 changed files with 410 additions and 302 deletions

View File

@@ -9,6 +9,7 @@ const Queue = @import("Queue.zig");
const QueueType = @import("QueueType.zig").QueueType;
const Transient = @import("Transient.zig").Transient;
const VkAllocator = @import("VkAllocator.zig");
const WaitSemaphore = @import("WaitSemaphore.zig");
pub const Mode = union(enum) {
headless: void,
@@ -531,6 +532,69 @@ pub fn setObjectName(self: *const Engine, handle: anytype, comptime fmt: []const
}
}
pub const SubmitInfo = struct {
wait_semaphores: []const WaitSemaphore = &.{},
signal_semaphores: []const vk.Semaphore = &.{},
fence: vk.Fence = .null_handle,
};
pub fn queueSubmit(
self: *const Engine,
queue_type: QueueType,
command_buffer: vk.CommandBuffer,
submit_info: SubmitInfo,
) !void {
const queue = switch (queue_type) {
.graphics => self.graphics_queue.handle,
.compute => self.compute_queue.handle,
.transfer => self.transfer_queue.handle,
};
const command_buffers = [_]vk.CommandBuffer{command_buffer};
var wait_semaphores = std.MultiArrayList(WaitSemaphore){};
defer wait_semaphores.deinit(self.vk_allocator.allocator);
try wait_semaphores.ensureTotalCapacity(self.vk_allocator.allocator, submit_info.wait_semaphores.len);
for (submit_info.wait_semaphores) |wait_semaphore| {
wait_semaphores.appendAssumeCapacity(wait_semaphore);
}
const submits = [_]vk.SubmitInfo{
.{
.wait_semaphore_count = @intCast(wait_semaphores.len),
.p_wait_semaphores = wait_semaphores.items(.semaphore).ptr,
.p_wait_dst_stage_mask = wait_semaphores.items(.stage_flags).ptr,
.command_buffer_count = command_buffers.len,
.p_command_buffers = &command_buffers,
.signal_semaphore_count = @intCast(submit_info.signal_semaphores.len),
.p_signal_semaphores = submit_info.signal_semaphores.ptr,
},
};
try self.device.queueSubmit(queue, submits.len, &submits, submit_info.fence);
}
pub const PresentInfo = struct {
wait_semaphores: []const vk.Semaphore = &.{},
image_index: u32,
swapchain: vk.SwapchainKHR,
};
pub fn queuePresent(self: *Engine, present_info: PresentInfo) !vk.Result {
const swapchains = [_]vk.SwapchainKHR{present_info.swapchain};
const image_indices = [_]u32{present_info.image_index};
const res = try self.device.queuePresentKHR(self.mode.surface.presentation_queue.handle, &.{
.wait_semaphore_count = @intCast(present_info.wait_semaphores.len),
.p_wait_semaphores = present_info.wait_semaphores.ptr,
.swapchain_count = swapchains.len,
.p_swapchains = &swapchains,
.p_image_indices = &image_indices,
});
return res;
}
fn debugUtilsMessengerCallback(
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
message_type: vk.DebugUtilsMessageTypeFlagsEXT,
@@ -657,6 +721,12 @@ fn resolveCommandPool(self: *const Engine, queue_type: QueueType, transient: Tra
// --- VULKAN WRAPPERS ---------------------------------------------------------
pub const AcquireInfo = struct {
timeout: u64 = std.math.maxInt(u64),
semaphore: vk.Semaphore = .null_handle,
fence: vk.Fence = .null_handle,
};
pub const BufferCreateInfo = struct {
flags: vk.BufferCreateFlags = .{},
size: vk.DeviceSize,
@@ -807,6 +877,13 @@ pub const PipelineViewportStateCreateInfo = struct {
scissors: []const vk.Rect2D = &.{},
};
pub const RenderPassCreateInfo = struct {
flags: vk.RenderPassCreateFlags = .{},
attachments: []const vk.AttachmentDescription = &.{},
subpasses: []const SubpassDescription,
dependencies: []const vk.SubpassDependency = &.{},
};
pub const ShaderModuleCreateInfo = struct {
flags: vk.ShaderModuleCreateFlags = .{},
code: []align(@alignOf(u32)) const u8,
@@ -817,6 +894,33 @@ pub const SpecializationInfo = struct {
data: []const u8 = &.{},
};
pub const SubpassDescription = struct {
flags: vk.SubpassDescriptionFlags = .{},
pipeline_bind_point: vk.PipelineBindPoint,
input_attachments: []const vk.AttachmentReference = &.{},
color_attachments: []const vk.AttachmentReference = &.{},
resolve_attachments: ?[]const vk.AttachmentReference = null,
depth_stencil_attachment: ?vk.AttachmentReference = null,
preserve_attachments: []const u32 = &.{},
};
pub const SwapchainCreateInfo = struct {
flags: vk.SwapchainCreateFlagsKHR = .{},
surface: vk.SurfaceKHR,
min_image_count: u32,
image_format: vk.Format,
image_color_space: vk.ColorSpaceKHR,
image_extent: vk.Extent2D,
image_array_layers: u32,
image_usage: vk.ImageUsageFlags,
queue_family_indices: []const u32 = &.{},
pre_transform: vk.SurfaceTransformFlagsKHR,
composite_alpha: vk.CompositeAlphaFlagsKHR,
present_mode: vk.PresentModeKHR,
clipped: vk.Bool32,
old_swapchain: vk.SwapchainKHR = .null_handle,
};
pub const WriteDescriptorSet = struct {
dst_set: vk.DescriptorSet,
dst_binding: u32,
@@ -829,27 +933,14 @@ pub const WriteDescriptorSet = struct {
},
};
pub fn createBuffer(self: *Engine, create_info: BufferCreateInfo) !vk.Buffer {
var arena: std.heap.ArenaAllocator = .init(self.vk_allocator.allocator);
defer arena.deinit();
const allocator = arena.allocator();
var queue_family_indices_set: std.AutoArrayHashMapUnmanaged(u32, void) = .{};
for (create_info.queue_family_indices) |queue_family_index| {
try queue_family_indices_set.put(allocator, queue_family_index, {});
}
const queue_family_indices = queue_family_indices_set.keys();
const buffer = self.device.createBuffer(&.{
.flags = create_info.flags,
.size = create_info.size,
.usage = create_info.usage,
.sharing_mode = if (queue_family_indices.len > 1) .concurrent else .exclusive,
.queue_family_index_count = if (queue_family_indices.len > 1) @intCast(queue_family_indices.len) else 0,
.p_queue_family_indices = if (queue_family_indices.len > 1) queue_family_indices.ptr else null,
}, &self.vk_allocator.interface);
return buffer;
pub fn acquireNextImage(self: *Engine, swapchain: vk.SwapchainKHR, acquire_info: AcquireInfo) !vk.DeviceProxy.AcquireNextImageKHRResult {
const res = try self.device.acquireNextImageKHR(
swapchain,
acquire_info.timeout,
acquire_info.semaphore,
acquire_info.fence,
);
return res;
}
pub fn allocateCommandBuffer(self: *Engine, allocate_info: CommandBufferAllocateInfo) !vk.CommandBuffer {
@@ -904,6 +995,29 @@ pub fn bindImageMemory(self: *Engine, image: vk.Image, memory: vk.DeviceMemory,
try self.device.bindImageMemory(image, memory, memory_offset);
}
pub fn createBuffer(self: *Engine, create_info: BufferCreateInfo) !vk.Buffer {
var arena: std.heap.ArenaAllocator = .init(self.vk_allocator.allocator);
defer arena.deinit();
const allocator = arena.allocator();
var queue_family_indices_set: std.AutoArrayHashMapUnmanaged(u32, void) = .{};
for (create_info.queue_family_indices) |queue_family_index| {
try queue_family_indices_set.put(allocator, queue_family_index, {});
}
const queue_family_indices = queue_family_indices_set.keys();
const buffer = self.device.createBuffer(&.{
.flags = create_info.flags,
.size = create_info.size,
.usage = create_info.usage,
.sharing_mode = if (queue_family_indices.len > 1) .concurrent else .exclusive,
.queue_family_index_count = if (queue_family_indices.len > 1) @intCast(queue_family_indices.len) else 0,
.p_queue_family_indices = if (queue_family_indices.len > 1) queue_family_indices.ptr else null,
}, &self.vk_allocator.interface);
return buffer;
}
pub fn createDescriptorSetLayout(self: *Engine, create_info: DescriptorSetLayoutCreateInfo) !vk.DescriptorSetLayout {
var arena: std.heap.ArenaAllocator = .init(self.vk_allocator.allocator);
defer arena.deinit();
@@ -986,7 +1100,7 @@ pub fn createGraphicsPipeline(self: *Engine, create_info: GraphicsPipelineCreate
const allocator = arena.allocator();
const stages = try allocator.alloc(vk.PipelineShaderStageCreateInfo, create_info.stages.len);
for (stages, create_info.stages) |*x, *stage| {
for (stages, create_info.stages) |*x, stage| {
x.* = .{
.flags = stage.flags,
.stage = stage.stage,
@@ -1112,6 +1226,39 @@ pub fn createPipelineLayout(self: *Engine, create_info: PipelineLayoutCreateInfo
return pipeline_layout;
}
pub fn createRenderPass(self: *Engine, create_info: RenderPassCreateInfo) !vk.RenderPass {
var arena: std.heap.ArenaAllocator = .init(self.vk_allocator.allocator);
defer arena.deinit();
const allocator = arena.allocator();
const subpasses = try allocator.alloc(vk.SubpassDescription, create_info.subpasses.len);
for (subpasses, create_info.subpasses) |*x, *subpass| {
x.* = .{
.flags = subpass.flags,
.pipeline_bind_point = subpass.pipeline_bind_point,
.input_attachment_count = @intCast(subpass.input_attachments.len),
.p_input_attachments = subpass.input_attachments.ptr,
.color_attachment_count = @intCast(subpass.color_attachments.len),
.p_color_attachments = subpass.color_attachments.ptr,
.p_resolve_attachments = if (subpass.resolve_attachments) |resolve_attachments| resolve_attachments.ptr else null,
.p_depth_stencil_attachment = if (subpass.depth_stencil_attachment) |*y| y else null,
.preserve_attachment_count = @intCast(subpass.preserve_attachments.len),
.p_preserve_attachments = subpass.preserve_attachments.ptr,
};
}
const render_pass = try self.device.createRenderPass(&.{
.flags = create_info.flags,
.attachment_count = @intCast(create_info.attachments.len),
.p_attachments = create_info.attachments.ptr,
.subpass_count = @intCast(subpasses.len),
.p_subpasses = subpasses.ptr,
.dependency_count = @intCast(create_info.dependencies.len),
.p_dependencies = create_info.dependencies.ptr,
}, &self.vk_allocator.interface);
return render_pass;
}
pub fn createSampler(self: *Engine, create_info: vk.SamplerCreateInfo) !vk.Sampler {
const sampler = try self.device.createSampler(&create_info, &self.vk_allocator.interface);
return sampler;
@@ -1131,6 +1278,39 @@ pub fn createShaderModule(self: *Engine, create_info: ShaderModuleCreateInfo) !v
return shader_module;
}
pub fn createSwapchain(self: *Engine, create_info: SwapchainCreateInfo) !vk.SwapchainKHR {
var arena: std.heap.ArenaAllocator = .init(self.vk_allocator.allocator);
defer arena.deinit();
const allocator = arena.allocator();
var queue_family_indices_set: std.AutoArrayHashMapUnmanaged(u32, void) = .{};
for (create_info.queue_family_indices) |queue_family_index| {
try queue_family_indices_set.put(allocator, queue_family_index, {});
}
const queue_family_indices = queue_family_indices_set.keys();
const swapchain = try self.device.createSwapchainKHR(&.{
.flags = create_info.flags,
.surface = create_info.surface,
.min_image_count = create_info.min_image_count,
.image_format = create_info.image_format,
.image_color_space = create_info.image_color_space,
.image_extent = create_info.image_extent,
.image_array_layers = create_info.image_array_layers,
.image_usage = create_info.image_usage,
.image_sharing_mode = if (queue_family_indices.len > 1) .concurrent else .exclusive,
.queue_family_index_count = if (queue_family_indices.len > 1) @intCast(queue_family_indices.len) else 0,
.p_queue_family_indices = if (queue_family_indices.len > 1) queue_family_indices.ptr else null,
.pre_transform = create_info.pre_transform,
.composite_alpha = create_info.composite_alpha,
.present_mode = create_info.present_mode,
.clipped = create_info.clipped,
.old_swapchain = create_info.old_swapchain,
}, &self.vk_allocator.interface);
return swapchain;
}
pub fn destroyBuffer(self: *Engine, buffer: vk.Buffer) void {
self.device.destroyBuffer(buffer, &self.vk_allocator.interface);
}
@@ -1167,6 +1347,10 @@ pub fn destroyPipelineLayout(self: *Engine, pipeline_layout: vk.PipelineLayout)
self.device.destroyPipelineLayout(pipeline_layout, &self.vk_allocator.interface);
}
pub fn destroyRenderPass(self: *Engine, render_pass: vk.RenderPass) void {
self.device.destroyRenderPass(render_pass, &self.vk_allocator.interface);
}
pub fn destroySampler(self: *Engine, sampler: vk.Sampler) void {
self.device.destroySampler(sampler, &self.vk_allocator.interface);
}
@@ -1179,6 +1363,10 @@ pub fn destroyShaderModule(self: *Engine, shader_module: vk.ShaderModule) void {
self.device.destroyShaderModule(shader_module, &self.vk_allocator.interface);
}
pub fn destroySwapchain(self: *Engine, swapchain: vk.SwapchainKHR) void {
self.device.destroySwapchainKHR(swapchain, &self.vk_allocator.interface);
}
pub fn deviceWaitIdle(self: *Engine) !void {
try self.device.deviceWaitIdle();
}
@@ -1206,6 +1394,21 @@ pub fn getImageMemoryRequirements(self: *Engine, image: vk.Image) vk.MemoryRequi
return self.device.getImageMemoryRequirements(image);
}
pub fn getPhysicalDeviceSurfaceCapabilities(self: *Engine) !vk.SurfaceCapabilitiesKHR {
const surface_capabilities = try self.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(self.physical_device, self.mode.surface.surface);
return surface_capabilities;
}
pub fn getPhysicalDeviceSurfaceFormatsAlloc(self: *Engine, allocator: std.mem.Allocator) ![]vk.SurfaceFormatKHR {
const surface_formats = try self.instance.getPhysicalDeviceSurfaceFormatsAllocKHR(self.physical_device, self.mode.surface.surface, allocator);
return surface_formats;
}
pub fn getSwapchainImagesAlloc(self: *Engine, swapchain: vk.SwapchainKHR, allocator: std.mem.Allocator) ![]vk.Image {
const images = try self.device.getSwapchainImagesAllocKHR(swapchain, allocator);
return images;
}
pub fn mapMemory(self: *Engine, memory: vk.DeviceMemory, offset: vk.DeviceSize, size: vk.DeviceSize, flags: vk.MemoryMapFlags) ![]u8 {
const mapped_memory = try self.device.mapMemory(memory, offset, size, flags);
return @as([*]u8, @ptrCast(mapped_memory))[0..size];