From f87fae29e831499517352ef848c324aae0ea2746 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Fri, 1 May 2026 22:12:39 +0200 Subject: [PATCH] ci skip --- README.md | 301 ++++++++++++++------------ src/soft/SoftBuffer.zig | 60 +++-- src/soft/SoftCommandBuffer.zig | 134 +++++++++--- src/soft/SoftPhysicalDevice.zig | 2 +- src/soft/device/Renderer.zig | 16 +- src/soft/device/vertex_dispatcher.zig | 4 +- src/vulkan/CommandBuffer.zig | 14 +- src/vulkan/Device.zig | 5 +- src/vulkan/lib_vulkan.zig | 80 +++++-- src/vulkan/wsi/PresentImage.zig | 47 ++++ src/vulkan/wsi/SurfaceKHR.zig | 11 + src/vulkan/wsi/SwapchainKHR.zig | 53 +++++ src/vulkan/wsi/WaylandSurfaceKHR.zig | 0 13 files changed, 506 insertions(+), 221 deletions(-) create mode 100644 src/vulkan/wsi/PresentImage.zig create mode 100644 src/vulkan/wsi/SurfaceKHR.zig create mode 100644 src/vulkan/wsi/SwapchainKHR.zig create mode 100644 src/vulkan/wsi/WaylandSurfaceKHR.zig diff --git a/README.md b/README.md index 1938f4a..26a081d 100644 --- a/README.md +++ b/README.md @@ -34,147 +34,168 @@ Use at your own risk. If thy machine shudders, weeps, or attempts to flee - know \ -⚠️ Implemented, yet perchance not fully tested nor proven conformant, but rather working in a manner most general to thee and thine. +⚠️ Implemented, yet perchance not fully tested nor proven conformant, but rather working in a manner most general to thee and thine.\ +Assume thou that functions lacking in this array are, for now, not intended to be wrought. -Name | Status ------------------------------------------------|-------- -vkAllocateCommandBuffers | ✅ Implemented -vkAllocateDescriptorSets | ✅ Implemented -vkAllocateMemory | ✅ Implemented -vkBeginCommandBuffer | ✅ Implemented -vkBindBufferMemory | ✅ Implemented -vkBindImageMemory | ✅ Implemented -vkCmdBeginQuery | ⚙️ WIP -vkCmdBeginRenderPass | ✅ Implemented -vkCmdBindDescriptorSets | ✅ Implemented -vkCmdBindIndexBuffer | ⚙️ WIP -vkCmdBindPipeline | ✅ Implemented -vkCmdBindVertexBuffers | ✅ Implemented -vkCmdBlitImage | ✅ Implemented -vkCmdClearAttachments | ✅ Implemented -vkCmdClearColorImage | ✅ Implemented -vkCmdClearDepthStencilImage | ⚙️ WIP -vkCmdCopyBuffer | ✅ Implemented -vkCmdCopyBufferToImage | ✅ Implemented -vkCmdCopyImage | ✅ Implemented -vkCmdCopyImageToBuffer | ✅ Implemented -vkCmdCopyQueryPoolResults | ⚙️ WIP -vkCmdDispatch | ✅ Implemented -vkCmdDispatchIndirect | ✅ Implemented -vkCmdDraw | ✅ Implemented -vkCmdDrawIndexed | ⚙️ WIP -vkCmdDrawIndexedIndirect | ⚙️ WIP -vkCmdDrawIndirect | ⚙️ WIP -vkCmdEndQuery | ⚙️ WIP -vkCmdEndRenderPass | ✅ Implemented -vkCmdExecuteCommands | ✅ Implemented -vkCmdFillBuffer | ✅ Implemented -vkCmdNextSubpass | ⚙️ WIP -vkCmdPipelineBarrier | ✅ Implemented -vkCmdPushConstants | ⚙️ WIP -vkCmdResetEvent | ✅ Implemented -vkCmdResetQueryPool | ⚙️ WIP -vkCmdResolveImage | ⚙️ WIP -vkCmdSetBlendConstants | ⚙️ WIP -vkCmdSetDepthBias | ⚙️ WIP -vkCmdSetDepthBounds | ⚙️ WIP -vkCmdSetEvent | ✅ Implemented -vkCmdSetLineWidth | ⚙️ WIP -vkCmdSetScissor | ⚙️ WIP -vkCmdSetStencilCompareMask | ⚙️ WIP -vkCmdSetStencilReference | ⚙️ WIP -vkCmdSetStencilWriteMask | ⚙️ WIP -vkCmdSetViewport | ✅ Implemented -vkCmdUpdateBuffer | ⚙️ WIP -vkCmdWaitEvents | ✅ Implemented -vkCmdWriteTimestamp | ⚙️ WIP -vkCreateBuffer | ✅ Implemented -vkCreateBufferView | ⚙️ WIP -vkCreateCommandPool | ✅ Implemented -vkCreateComputePipelines | ✅ Implemented -vkCreateDescriptorPool | ✅ Implemented -vkCreateDescriptorSetLayout | ✅ Implemented -vkCreateDevice | ✅ Implemented -vkCreateEvent | ✅ Implemented -vkCreateFence | ✅ Implemented -vkCreateFramebuffer | ✅ Implemented -vkCreateGraphicsPipelines | ✅ Implemented -vkCreateImage | ✅ Implemented -vkCreateImageView | ✅ Implemented -vkCreateInstance | ✅ Implemented -vkCreatePipelineCache | ⚙️ WIP -vkCreatePipelineLayout | ✅ Implemented -vkCreateQueryPool | ⚙️ WIP -vkCreateRenderPass | ✅ Implemented -vkCreateSampler | ⚙️ WIP -vkCreateSemaphore | ⚙️ WIP -vkCreateShaderModule | ✅ Implemented -vkDestroyBuffer | ✅ Implemented -vkDestroyBufferView | ⚙️ WIP -vkDestroyCommandPool | ✅ Implemented -vkDestroyDescriptorPool | ✅ Implemented -vkDestroyDescriptorSetLayout | ✅ Implemented -vkDestroyDevice | ✅ Implemented -vkDestroyEvent | ✅ Implemented -vkDestroyFence | ✅ Implemented -vkDestroyFramebuffer | ✅ Implemented -vkDestroyImage | ✅ Implemented -vkDestroyImageView | ✅ Implemented -vkDestroyInstance | ✅ Implemented -vkDestroyPipeline | ✅ Implemented -vkDestroyPipelineCache | ✅ Implemented -vkDestroyPipelineLayout | ✅ Implemented -vkDestroyQueryPool | ✅ Implemented -vkDestroyRenderPass | ✅ Implemented -vkDestroySampler | ✅ Implemented -vkDestroySemaphore | ✅ Implemented -vkDestroyShaderModule | ✅ Implemented -vkDeviceWaitIdle | ✅ Implemented -vkEndCommandBuffer | ✅ Implemented -vkEnumerateDeviceExtensionProperties | ⚙️ WIP -vkEnumerateDeviceLayerProperties | ⚙️ WIP -vkEnumerateInstanceExtensionProperties | ⚙️ WIP -vkEnumerateInstanceLayerProperties | ⚙️ WIP -vkEnumeratePhysicalDevices | ✅ Implemented -vkFlushMappedMemoryRanges | ✅ Implemented -vkFreeCommandBuffers | ✅ Implemented -vkFreeDescriptorSets | ✅ Implemented -vkFreeMemory | ✅ Implemented -vkGetBufferMemoryRequirements | ✅ Implemented -vkGetDeviceMemoryCommitment | ⚙️ WIP -vkGetDeviceProcAddr | ✅ Implemented -vkGetDeviceQueue | ✅ Implemented -vkGetEventStatus | ✅ Implemented -vkGetFenceStatus | ✅ Implemented -vkGetImageMemoryRequirements | ✅ Implemented -vkGetImageSparseMemoryRequirements | ⚙️ WIP -vkGetImageSubresourceLayout | ✅ Implemented -vkGetInstanceProcAddr | ✅ Implemented -vkGetPhysicalDeviceFeatures | ✅ Implemented -vkGetPhysicalDeviceFormatProperties | ✅ Implemented -vkGetPhysicalDeviceImageFormatProperties | ✅ Implemented -vkGetPhysicalDeviceMemoryProperties | ✅ Implemented -vkGetPhysicalDeviceProperties | ✅ Implemented -vkGetPhysicalDeviceQueueFamilyProperties | ✅ Implemented -vkGetPhysicalDeviceSparseImageFormatProperties | ⚙️ WIP -vkGetPipelineCacheData | ⚙️ WIP -vkGetQueryPoolResults | ⚙️ WIP -vkGetRenderAreaGranularity | ⚙️ WIP -vkInvalidateMappedMemoryRanges | ✅ Implemented -vkMapMemory | ✅ Implemented -vkMergePipelineCaches | ⚙️ WIP -vkQueueBindSparse | ⚙️ WIP -vkQueueSubmit | ✅ Implemented -vkQueueWaitIdle | ✅ Implemented -vkResetCommandBuffer | ✅ Implemented -vkResetCommandPool | ✅ Implemented -vkResetDescriptorPool | ✅ Implemented -vkResetEvent | ✅ Implemented -vkResetFences | ✅ Implemented -vkSetEvent | ✅ Implemented -vkUnmapMemory | ✅ Implemented -vkUpdateDescriptorSets | ✅ Implemented -vkWaitForFences | ✅ Implemented +Name | Status +-------------------------------------------------|-------- +vkAcquireNextImageKHR | ⚙️ WIP +vkAllocateCommandBuffers | ✅ Implemented +vkAllocateDescriptorSets | ✅ Implemented +vkAllocateMemory | ✅ Implemented +vkBeginCommandBuffer | ✅ Implemented +vkBindBufferMemory | ✅ Implemented +vkBindImageMemory | ✅ Implemented +vkCmdBeginQuery | ⚙️ WIP +vkCmdBeginRenderPass | ✅ Implemented +vkCmdBindDescriptorSets | ✅ Implemented +vkCmdBindIndexBuffer | ✅ Implemented +vkCmdBindPipeline | ✅ Implemented +vkCmdBindVertexBuffers | ✅ Implemented +vkCmdBlitImage | ✅ Implemented +vkCmdClearAttachments | ✅ Implemented +vkCmdClearColorImage | ✅ Implemented +vkCmdClearDepthStencilImage | ⚙️ WIP +vkCmdCopyBuffer | ✅ Implemented +vkCmdCopyBufferToImage | ✅ Implemented +vkCmdCopyImage | ✅ Implemented +vkCmdCopyImageToBuffer | ✅ Implemented +vkCmdCopyQueryPoolResults | ⚙️ WIP +vkCmdDispatch | ✅ Implemented +vkCmdDispatchIndirect | ✅ Implemented +vkCmdDraw | ✅ Implemented +vkCmdDrawIndexed | ✅ Implemented +vkCmdDrawIndexedIndirect | ✅ Implemented +vkCmdDrawIndirect | ✅ Implemented +vkCmdEndQuery | ⚙️ WIP +vkCmdEndRenderPass | ✅ Implemented +vkCmdExecuteCommands | ✅ Implemented +vkCmdFillBuffer | ✅ Implemented +vkCmdNextSubpass | ⚙️ WIP +vkCmdPipelineBarrier | ✅ Implemented +vkCmdPushConstants | ⚙️ WIP +vkCmdResetEvent | ✅ Implemented +vkCmdResetQueryPool | ⚙️ WIP +vkCmdResolveImage | ⚙️ WIP +vkCmdSetBlendConstants | ⚙️ WIP +vkCmdSetDepthBias | ⚙️ WIP +vkCmdSetDepthBounds | ⚙️ WIP +vkCmdSetEvent | ✅ Implemented +vkCmdSetLineWidth | ⚙️ WIP +vkCmdSetScissor | ⚙️ WIP +vkCmdSetStencilCompareMask | ⚙️ WIP +vkCmdSetStencilReference | ⚙️ WIP +vkCmdSetStencilWriteMask | ⚙️ WIP +vkCmdSetViewport | ✅ Implemented +vkCmdUpdateBuffer | ⚙️ WIP +vkCmdWaitEvents | ✅ Implemented +vkCmdWriteTimestamp | ⚙️ WIP +vkCreateBuffer | ✅ Implemented +vkCreateBufferView | ⚙️ WIP +vkCreateCommandPool | ✅ Implemented +vkCreateComputePipelines | ✅ Implemented +vkCreateDescriptorPool | ✅ Implemented +vkCreateDescriptorSetLayout | ✅ Implemented +vkCreateDevice | ✅ Implemented +vkCreateEvent | ✅ Implemented +vkCreateFence | ✅ Implemented +vkCreateFramebuffer | ✅ Implemented +vkCreateGraphicsPipelines | ✅ Implemented +vkCreateImage | ✅ Implemented +vkCreateImageView | ✅ Implemented +vkCreateInstance | ✅ Implemented +vkCreatePipelineCache | ⚙️ WIP +vkCreatePipelineLayout | ✅ Implemented +vkCreateQueryPool | ⚙️ WIP +vkCreateRenderPass | ✅ Implemented +vkCreateSampler | ⚙️ WIP +vkCreateSemaphore | ⚙️ WIP +vkCreateShaderModule | ✅ Implemented +vkCreateSwapchainKHR | ⚙️ WIP +vkCreateSwapchainKHR | ✅ Implemented +vkCreateWaylandSurfaceKHR | ✅ Implemented +vkCreateWin32SurfaceKHR | ⚙️ WIP +vkCreateXcbSurfaceKHR | ⚙️ WIP +vkCreateXlibSurfaceKHR | ⚙️ WIP +vkDestroyBuffer | ✅ Implemented +vkDestroyBufferView | ⚙️ WIP +vkDestroyCommandPool | ✅ Implemented +vkDestroyDescriptorPool | ✅ Implemented +vkDestroyDescriptorSetLayout | ✅ Implemented +vkDestroyDevice | ✅ Implemented +vkDestroyEvent | ✅ Implemented +vkDestroyFence | ✅ Implemented +vkDestroyFramebuffer | ✅ Implemented +vkDestroyImage | ✅ Implemented +vkDestroyImageView | ✅ Implemented +vkDestroyInstance | ✅ Implemented +vkDestroyPipeline | ✅ Implemented +vkDestroyPipelineCache | ✅ Implemented +vkDestroyPipelineLayout | ✅ Implemented +vkDestroyQueryPool | ✅ Implemented +vkDestroyRenderPass | ✅ Implemented +vkDestroySampler | ✅ Implemented +vkDestroySemaphore | ✅ Implemented +vkDestroyShaderModule | ✅ Implemented +vkDestroySurfaceKHR | ✅ Implemented +vkDestroySwapchainKHR | ⚙️ WIP +vkDestroySwapchainKHR | ✅ Implemented +vkDeviceWaitIdle | ✅ Implemented +vkEndCommandBuffer | ✅ Implemented +vkEnumerateDeviceExtensionProperties | ⚙️ WIP +vkEnumerateDeviceLayerProperties | ⚙️ WIP +vkEnumerateInstanceExtensionProperties | ⚙️ WIP +vkEnumerateInstanceLayerProperties | ⚙️ WIP +vkEnumeratePhysicalDevices | ✅ Implemented +vkFlushMappedMemoryRanges | ✅ Implemented +vkFreeCommandBuffers | ✅ Implemented +vkFreeDescriptorSets | ✅ Implemented +vkFreeMemory | ✅ Implemented +vkGetBufferMemoryRequirements | ✅ Implemented +vkGetDeviceMemoryCommitment | ⚙️ WIP +vkGetDeviceProcAddr | ✅ Implemented +vkGetDeviceQueue | ✅ Implemented +vkGetEventStatus | ✅ Implemented +vkGetFenceStatus | ✅ Implemented +vkGetImageMemoryRequirements | ✅ Implemented +vkGetImageSparseMemoryRequirements | ⚙️ WIP +vkGetImageSubresourceLayout | ✅ Implemented +vkGetInstanceProcAddr | ✅ Implemented +vkGetPhysicalDeviceFeatures | ✅ Implemented +vkGetPhysicalDeviceFormatProperties | ✅ Implemented +vkGetPhysicalDeviceImageFormatProperties | ✅ Implemented +vkGetPhysicalDeviceMemoryProperties | ✅ Implemented +vkGetPhysicalDeviceProperties | ✅ Implemented +vkGetPhysicalDeviceQueueFamilyProperties | ✅ Implemented +vkGetPhysicalDeviceSparseImageFormatProperties | ⚙️ WIP +vkGetPhysicalDeviceSurfaceCapabilitiesKHR | ⚙️ WIP +vkGetPhysicalDeviceSurfaceFormatsKHR | ⚙️ WIP +vkGetPhysicalDeviceSurfacePresentModesKHR | ⚙️ WIP +vkGetPhysicalDeviceSurfaceSupportKHR | ⚙️ WIP +vkGetPhysicalDeviceWaylandPresentationSupportKHR | ⚙️ WIP +vkGetPhysicalDeviceWind32PresentationSupportKHR | ⚙️ WIP +vkGetPhysicalDeviceXcbPresentationSupportKHR | ⚙️ WIP +vkGetPhysicalDeviceXlibPresentationSupportKHR | ⚙️ WIP +vkGetPipelineCacheData | ⚙️ WIP +vkGetQueryPoolResults | ⚙️ WIP +vkGetRenderAreaGranularity | ⚙️ WIP +vkGetSwapchainImagesKHR | ⚙️ WIP +vkInvalidateMappedMemoryRanges | ✅ Implemented +vkMapMemory | ✅ Implemented +vkMergePipelineCaches | ⚙️ WIP +vkQueueBindSparse | ⚙️ WIP +vkQueuePresentKHR | ⚙️ WIP +vkQueueSubmit | ✅ Implemented +vkQueueWaitIdle | ✅ Implemented +vkResetCommandBuffer | ✅ Implemented +vkResetCommandPool | ✅ Implemented +vkResetDescriptorPool | ✅ Implemented +vkResetEvent | ✅ Implemented +vkResetFences | ✅ Implemented +vkSetEvent | ✅ Implemented +vkUnmapMemory | ✅ Implemented +vkUpdateDescriptorSets | ✅ Implemented +vkWaitForFences | ✅ Implemented [Here](https://vulkan-driver-cts-report.kbz8.me/) shalt thou find a most meticulous account of the Vulkan 1.0 conformance trials, set forth for thy scrutiny. diff --git a/src/soft/SoftBuffer.zig b/src/soft/SoftBuffer.zig index bec6c3c..ad977a1 100644 --- a/src/soft/SoftBuffer.zig +++ b/src/soft/SoftBuffer.zig @@ -49,32 +49,66 @@ pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequ pub fn copyBuffer(self: *const Self, dst: *Self, regions: []const vk.BufferCopy) VkError!void { for (regions) |region| { - const src_memory = if (self.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; - const dst_memory = if (dst.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; - - const src_map: []u8 = @as([*]u8, @ptrCast(try src_memory.map(self.interface.offset + region.src_offset, region.size)))[0..region.size]; - const dst_map: []u8 = @as([*]u8, @ptrCast(try dst_memory.map(dst.interface.offset + region.dst_offset, region.size)))[0..region.size]; + const src_map = try self.mapAsSliceWithAddedOffset(u8, region.src_offset, region.size); + const dst_map = try dst.mapAsSliceWithAddedOffset(u8, region.dst_offset, region.size); @memcpy(dst_map, src_map); - - src_memory.unmap(); - dst_memory.unmap(); } } pub fn fillBuffer(self: *Self, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void { const memory = if (self.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; - var memory_map: []u32 = @as([*]u32, @ptrCast(@alignCast(try memory.map(offset, size))))[0..size]; - var bytes = if (size == vk.WHOLE_SIZE) memory.size - offset else size; + const map = try self.mapAsSliceWithOffset(u32, offset, bytes); + var i: usize = 0; while (bytes >= 4) : ({ bytes -= 4; i += 1; }) { - memory_map[i] = data; + map[i] = data; } - - memory.unmap(); +} + +pub inline fn mapAs(self: *const Self, comptime T: type) VkError!*T { + return self.mapAsWithAddedOffset(T, 0); +} + +pub inline fn mapTo(self: *const Self, comptime T: type) VkError!T { + return self.mapToWithAddedOffset(T, 0); +} + +pub inline fn mapAsSlice(self: *const Self, comptime T: type, size: usize) VkError![]T { + return self.mapAsSliceWithAddedOffset(T, 0, size); +} + +pub inline fn mapAsWithAddedOffset(self: *const Self, comptime T: type, offset: usize) VkError!*T { + return self.mapAsWithOffset(T, self.interface.offset + offset); +} + +pub inline fn mapToWithAddedOffset(self: *const Self, comptime T: type, offset: usize) VkError!T { + return self.mapToWithOffset(T, self.interface.offset + offset); +} + +pub inline fn mapAsSliceWithAddedOffset(self: *const Self, comptime T: type, size: usize, offset: usize) VkError![]T { + return self.mapAsSliceWithOffset(T, self.interface.offset + offset, size); +} + +pub fn mapAsWithOffset(self: *const Self, comptime T: type, offset: usize) VkError!*T { + const memory = if (self.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; + const map = @as([*]u8, @ptrCast(@alignCast(try memory.map(offset, @sizeOf(T)))))[0..@sizeOf(T)]; + return @alignCast(std.mem.bytesAsValue(T, map)); +} + +pub fn mapToWithOffset(self: *const Self, comptime T: type, offset: usize) VkError!T { + const memory = if (self.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; + const map = @as([*]u8, @ptrCast(@alignCast(try memory.map(offset, @sizeOf(T)))))[0..@sizeOf(T)]; + return std.mem.bytesToValue(T, map); +} + +pub fn mapAsSliceWithOffset(self: *const Self, comptime T: type, offset: usize, size: usize) VkError![]T { + const memory = if (self.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; + const map = @as([*]u8, @ptrCast(@alignCast(try memory.map(offset, size))))[0..size]; + return @alignCast(std.mem.bytesAsSlice(T, map)); } diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index 19186f8..db71fe8 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -61,6 +61,8 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v .dispatchIndirect = dispatchIndirect, .draw = draw, .drawIndexed = drawIndexed, + .drawIndexedIndirect = drawIndexedIndirect, + .drawIndirect = drawIndirect, .end = end, .endRenderPass = endRenderPass, .executeCommands = executeCommands, @@ -545,10 +547,8 @@ pub fn dispatchIndirect(interface: *Interface, buffer: *base.Buffer, offset: vk. pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { const impl: *Impl = @ptrCast(@alignCast(context)); - const size = 3 * @sizeOf(u32); - const memory = if (impl.buffer.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; - const map: []u32 = @as([*]u32, @ptrCast(@alignCast(try memory.map(impl.offset, size))))[0..3]; - try device.compute.dispatch(map[0], map[1], map[2]); + const command = try impl.buffer.mapAsWithOffset(vk.DispatchIndirectCommand, impl.offset); + try device.compute.dispatch(command.x, command.y, command.z); } }; @@ -561,37 +561,6 @@ pub fn dispatchIndirect(interface: *Interface, buffer: *base.Buffer, offset: vk. self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } -pub fn drawIndexed(interface: *Interface, index_count: usize, instance_count: usize, first_index: usize, vertex_offset: usize, first_instance: usize) VkError!void { - const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); - const allocator = self.command_allocator.allocator(); - - const CommandImpl = struct { - const Impl = @This(); - - index_count: usize, - first_index: usize, - instance_count: usize, - first_instance: usize, - vertex_offset: usize, - - pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { - const impl: *Impl = @ptrCast(@alignCast(context)); - try device.renderer.drawIndexed(impl.index_count, impl.instance_count, impl.first_index, impl.first_instance, impl.vertex_offset); - } - }; - - const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; - errdefer allocator.destroy(cmd); - cmd.* = .{ - .index_count = index_count, - .first_index = first_index, - .instance_count = instance_count, - .first_instance = first_instance, - .vertex_offset = vertex_offset, - }; - self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; -} - pub fn draw(interface: *Interface, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const allocator = self.command_allocator.allocator(); @@ -621,6 +590,101 @@ pub fn draw(interface: *Interface, vertex_count: usize, instance_count: usize, f self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } +pub fn drawIndexed(interface: *Interface, index_count: usize, instance_count: usize, first_index: usize, vertex_offset: i32, first_instance: usize) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + index_count: usize, + first_index: usize, + instance_count: usize, + first_instance: usize, + vertex_offset: i32, + + pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + try device.renderer.drawIndexed(impl.index_count, impl.instance_count, impl.first_index, impl.first_instance, impl.vertex_offset); + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .index_count = index_count, + .first_index = first_index, + .instance_count = instance_count, + .first_instance = first_instance, + .vertex_offset = vertex_offset, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; +} + +pub fn drawIndexedIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + buffer: *SoftBuffer, + offset: usize, + count: usize, + stride: usize, + + pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + for (0..impl.count) |index| { + const command = try impl.buffer.mapAsWithOffset(vk.DrawIndexedIndirectCommand, impl.offset + index * impl.stride); + try device.renderer.drawIndexed(command.index_count, command.instance_count, command.first_index, command.first_instance, command.vertex_offset); + } + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .buffer = @alignCast(@fieldParentPtr("interface", buffer)), + .offset = offset, + .count = count, + .stride = stride, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; +} + +pub fn drawIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + buffer: *SoftBuffer, + offset: usize, + count: usize, + stride: usize, + + pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + for (0..impl.count) |index| { + const command = try impl.buffer.mapAsWithOffset(vk.DrawIndirectCommand, impl.offset + index * impl.stride); + try device.renderer.draw(command.vertex_count, command.instance_count, command.first_vertex, command.first_instance); + } + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .buffer = @alignCast(@fieldParentPtr("interface", buffer)), + .offset = offset, + .count = count, + .stride = stride, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; +} + pub fn endRenderPass(interface: *Interface) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const allocator = self.command_allocator.allocator(); diff --git a/src/soft/SoftPhysicalDevice.zig b/src/soft/SoftPhysicalDevice.zig index 123b1b4..756ea4f 100644 --- a/src/soft/SoftPhysicalDevice.zig +++ b/src/soft/SoftPhysicalDevice.zig @@ -13,7 +13,7 @@ const Self = @This(); pub const Interface = base.PhysicalDevice; // Device name should always be the same so avoid reprocessing it multiple times -var device_name = [_]u8{0} ** vk.MAX_PHYSICAL_DEVICE_NAME_SIZE; +var device_name: [vk.MAX_PHYSICAL_DEVICE_NAME_SIZE]u8 = @splat(0); interface: Interface, diff --git a/src/soft/device/Renderer.zig b/src/soft/device/Renderer.zig index 069c4a0..63aa109 100644 --- a/src/soft/device/Renderer.zig +++ b/src/soft/device/Renderer.zig @@ -123,7 +123,7 @@ pub fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_verte try self.postVertexDraw(allocator, &draw_call); } -pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: usize) VkError!void { +pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: i32) VkError!void { const io = self.device.interface.io(); var arena: std.heap.ArenaAllocator = .init(self.device.device_allocator.allocator()); @@ -154,7 +154,7 @@ pub fn deinit(self: *Self) void { _ = self; } -fn vertexShaderStage(self: *Self, allocator: std.mem.Allocator, draw_call: *DrawCall, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize, indices: ?[]const u32) !void { +fn vertexShaderStage(self: *Self, allocator: std.mem.Allocator, draw_call: *DrawCall, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize, indices: ?[]const i32) !void { const pipeline = self.state.pipeline orelse return; const batch_size = (pipeline.stages.getPtr(.vertex) orelse return).runtimes.len; @@ -196,11 +196,11 @@ fn postVertexDraw(self: *Self, allocator: std.mem.Allocator, draw_call: *DrawCal }; for (draw_call.fragments) |fragment| { - render_target.writeFloat4( + try render_target.writeFloat4( .{ .x = @intFromFloat(fragment.position[0]), .y = @intFromFloat(fragment.position[1]), - .z = 0, + .z = 0, // FIXME }, .{ .aspect_mask = render_target_view.subresource_range.aspect_mask, @@ -209,7 +209,7 @@ fn postVertexDraw(self: *Self, allocator: std.mem.Allocator, draw_call: *DrawCal }, render_target_view.format, fragment.color, - ) catch {}; + ); } } @@ -342,7 +342,7 @@ fn fragmentShaderStage(self: *Self, draw_call: *DrawCall) !void { wg.await(self.device.interface.io()) catch return VkError.DeviceLost; } -fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize, first_index: usize, vertex_offset: usize) VkError![]u32 { +fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize, first_index: usize, vertex_offset: i32) VkError![]i32 { const index_buffer = self.state.data.graphics.index_buffer; const buffer = index_buffer.buffer; const buffer_memory = if (buffer.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; @@ -355,7 +355,7 @@ fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize const byte_size = index_count * index_size; const index_memory: []const u8 = @as([*]const u8, @ptrCast(@alignCast(try buffer_memory.map(byte_offset, byte_size))))[0..byte_size]; - const indices = allocator.alloc(u32, index_count) catch return VkError.OutOfDeviceMemory; + const indices = allocator.alloc(i32, index_count) catch return VkError.OutOfDeviceMemory; for (indices, 0..) |*index, i| { const offset = i * index_size; const raw_index: u32 = switch (index_size) { @@ -364,7 +364,7 @@ fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize 4 => @intCast(std.mem.readInt(u32, index_memory[offset..][0..4], .little)), else => unreachable, }; - index.* = @intCast(vertex_offset + raw_index); + index.* = vertex_offset + @as(i32, @intCast(raw_index)); } return indices; diff --git a/src/soft/device/vertex_dispatcher.zig b/src/soft/device/vertex_dispatcher.zig index 3e9a088..036d60e 100644 --- a/src/soft/device/vertex_dispatcher.zig +++ b/src/soft/device/vertex_dispatcher.zig @@ -20,7 +20,7 @@ pub const RunData = struct { vertex_count: usize, first_vertex: usize, first_instance: usize, - indices: ?[]const u32, + indices: ?[]const i32, instance_index: usize, draw_call: *Renderer.DrawCall, }; @@ -44,7 +44,7 @@ inline fn run(data: RunData) !void { var invocation_index: usize = data.batch_id; while (invocation_index < data.vertex_count) : (invocation_index += data.batch_size) { - const vertex_index = if (data.indices) |indices| indices[invocation_index] else data.first_vertex + invocation_index; + const vertex_index: usize = if (data.indices) |indices| @intCast(indices[invocation_index]) else data.first_vertex + invocation_index; const instance_index = data.first_instance + data.instance_index; setupBuiltins(rt, vertex_index, instance_index) catch |err| switch (err) { diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 8d8e357..b81cdb8 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -54,7 +54,9 @@ pub const DispatchTable = struct { dispatch: *const fn (*Self, u32, u32, u32) VkError!void, dispatchIndirect: *const fn (*Self, *Buffer, vk.DeviceSize) VkError!void, draw: *const fn (*Self, usize, usize, usize, usize) VkError!void, - drawIndexed: *const fn (*Self, usize, usize, usize, usize, usize) VkError!void, + drawIndexed: *const fn (*Self, usize, usize, usize, i32, usize) VkError!void, + drawIndexedIndirect: *const fn (*Self, *Buffer, usize, usize, usize) VkError!void, + drawIndirect: *const fn (*Self, *Buffer, usize, usize, usize) VkError!void, end: *const fn (*Self) VkError!void, endRenderPass: *const fn (*Self) VkError!void, executeCommands: *const fn (*Self, *Self) VkError!void, @@ -215,10 +217,18 @@ pub inline fn draw(self: *Self, vertex_count: usize, instance_count: usize, firs try self.dispatch_table.draw(self, vertex_count, instance_count, first_vertex, first_instance); } -pub inline fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, vertex_offset: usize, first_instance: usize) VkError!void { +pub inline fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, vertex_offset: i32, first_instance: usize) VkError!void { try self.dispatch_table.drawIndexed(self, index_count, instance_count, first_index, vertex_offset, first_instance); } +pub inline fn drawIndexedIndirect(self: *Self, buffer: *Buffer, offset: usize, count: usize, stride: usize) VkError!void { + try self.dispatch_table.drawIndexedIndirect(self, buffer, offset, count, stride); +} + +pub inline fn drawIndirect(self: *Self, buffer: *Buffer, offset: usize, count: usize, stride: usize) VkError!void { + try self.dispatch_table.drawIndirect(self, buffer, offset, count, stride); +} + pub inline fn endRenderPass(self: *Self) VkError!void { try self.dispatch_table.endRenderPass(self); } diff --git a/src/vulkan/Device.zig b/src/vulkan/Device.zig index acf6e5a..a191dc4 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -31,6 +31,9 @@ const RenderPass = @import("RenderPass.zig"); const Sampler = @import("Sampler.zig"); const ShaderModule = @import("ShaderModule.zig"); +const SurfaceKHR = @import("wsi/SurfaceKHR.zig"); +const SwapchainKHR = @import("wsi/SwapchainKHR.zig"); + const Self = @This(); pub const ObjectType: vk.ObjectType = .device; @@ -203,7 +206,7 @@ pub inline fn createShaderModule(self: *Self, allocator: std.mem.Allocator, info return self.dispatch_table.createShaderModule(self, allocator, info); } -pub inline fn waitIdle(self: *Self) VkError!void { +pub fn waitIdle(self: *Self) VkError!void { var it = self.queues.iterator(); while (it.next()) |family| { for (family.value_ptr.items) |queue| { diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index cf9f616..d646795 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -44,6 +44,10 @@ pub const RenderPass = @import("RenderPass.zig"); pub const Sampler = @import("Sampler.zig"); pub const ShaderModule = @import("ShaderModule.zig"); +pub const SurfaceKHR = @import("wsi/SurfaceKHR.zig"); +pub const SwapchainKHR = @import("wsi/SwapchainKHR.zig"); +pub const WaylandSurfaceKHR = @import("wsi/WaylandSurfaceKHR.zig"); + fn entryPointBeginLogTrace(comptime scope: @EnumLiteral()) void { std.log.scoped(scope).debug("Calling {s}...", .{@tagName(scope)}); } @@ -1817,7 +1821,7 @@ pub export fn strollCmdDraw(p_cmd: vk.CommandBuffer, vertex_count: u32, instance cmd.draw(vertex_count, instance_count, first_vertex, first_instance) catch |err| return errorLogger(err); } -pub export fn strollCmdDrawIndexed(p_cmd: vk.CommandBuffer, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: u32, first_instance: u32) callconv(vk.vulkan_call_conv) void { +pub export fn strollCmdDrawIndexed(p_cmd: vk.CommandBuffer, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32) callconv(vk.vulkan_call_conv) void { entryPointBeginLogTrace(.vkCmdDrawIndexed); defer entryPointEndLogTrace(); @@ -1830,15 +1834,8 @@ pub export fn strollCmdDrawIndexedIndirect(p_cmd: vk.CommandBuffer, p_buffer: vk defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - const buffer = Dispatchable(Buffer).fromHandleObject(p_buffer) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; - _ = buffer; - _ = offset; - _ = count; - _ = stride; + const buffer = NonDispatchable(Buffer).fromHandleObject(p_buffer) catch |err| return errorLogger(err); + cmd.drawIndexedIndirect(buffer, offset, count, stride) catch |err| return errorLogger(err); } pub export fn strollCmdDrawIndirect(p_cmd: vk.CommandBuffer, p_buffer: vk.Buffer, offset: vk.DeviceSize, count: u32, stride: u32) callconv(vk.vulkan_call_conv) void { @@ -1846,15 +1843,8 @@ pub export fn strollCmdDrawIndirect(p_cmd: vk.CommandBuffer, p_buffer: vk.Buffer defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - const buffer = Dispatchable(Buffer).fromHandleObject(p_buffer) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; - _ = buffer; - _ = offset; - _ = count; - _ = stride; + const buffer = NonDispatchable(Buffer).fromHandleObject(p_buffer) catch |err| return errorLogger(err); + cmd.drawIndirect(buffer, offset, count, stride) catch |err| return errorLogger(err); } pub export fn strollCmdEndQuery(p_cmd: vk.CommandBuffer, p_pool: vk.QueryPool, query: u32) callconv(vk.vulkan_call_conv) void { @@ -2201,3 +2191,55 @@ pub export fn strollResetCommandBuffer(p_cmd: vk.CommandBuffer, flags: vk.Comman cmd.reset(flags) catch |err| return toVkResult(err); return .success; } + +// WSI functions =================================================================================================================================== + +pub export fn strollCreateSwapchainKHR(p_device: vk.Device, info: *const vk.SwapchainCreateInfoKHR, callbacks: ?*const vk.AllocationCallbacks, p_swapchain: *vk.Swapchain) callconv(vk.vulkan_call_conv) vk.Result { + entryPointBeginLogTrace(.vkCreateSwapchainKHR); + defer entryPointEndLogTrace(); + + if (info.s_type != .swapchain_create_info_khr) { + return .error_validation_failed; + } + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const swapchain = SwapchainKHR.create(device, allocator, info) catch |err| return toVkResult(err); + p_swapchain.* = (NonDispatchable(SwapchainKHR).wrap(allocator, swapchain) catch |err| return toVkResult(err)).toVkHandle(vk.SwapchainKHR); + return .success; +} + +pub export fn strollDestroySwapchainKHR(p_device: vk.Device, p_swapchain: vk.Swapchain, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { + entryPointBeginLogTrace(.vkDestroySwapchainKHR); + defer entryPointEndLogTrace(); + + Dispatchable(Device).checkHandleValidity(p_device) catch |err| return errorLogger(err); + + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); + const non_dispatchable = NonDispatchable(SwapchainKHR).fromHandle(p_swapchain) catch |err| return errorLogger(err); + non_dispatchable.intrusiveDestroy(allocator); +} + +pub export fn strollCreateWaylandSurfaceKHR(p_device: vk.Device, info: *const vk.WaylandSurfaceCreateInfoKHR, callbacks: ?*const vk.AllocationCallbacks, p_surface: *vk.SurfaceKHR) callconv(vk.vulkan_call_conv) vk.Result { + entryPointBeginLogTrace(.vkCreateWaylandSurfaceKHR); + defer entryPointEndLogTrace(); + + if (info.s_type != .surface_create_info_khr) { + return .error_validation_failed; + } + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const surface = WaylandSurfaceKHR.create(device, allocator, info) catch |err| return toVkResult(err); + p_surface.* = (NonDispatchable(SurfaceKHR).wrap(allocator, surface) catch |err| return toVkResult(err)).toVkHandle(vk.SurfaceKHR); + return .success; +} + +pub export fn strollDestroySurfaceKHR(p_device: vk.Device, p_surface: vk.SurfaceKHR, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { + entryPointBeginLogTrace(.vkDestroySurfaceKHR); + defer entryPointEndLogTrace(); + + Dispatchable(Device).checkHandleValidity(p_device) catch |err| return errorLogger(err); + + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); + const non_dispatchable = NonDispatchable(SurfaceKHR).fromHandle(p_surface) catch |err| return errorLogger(err); + non_dispatchable.intrusiveDestroy(allocator); +} diff --git a/src/vulkan/wsi/PresentImage.zig b/src/vulkan/wsi/PresentImage.zig new file mode 100644 index 0000000..e7b9ffb --- /dev/null +++ b/src/vulkan/wsi/PresentImage.zig @@ -0,0 +1,47 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const VkError = @import("../error_set.zig").VkError; + +const Device = @import("../Device.zig"); +const DeviceMemory = @import("../DeviceMemory.zig"); +const Image = @import("../Image.zig"); + +pub const State = enum { + Available, + Drawing, + Presenting, +}; + +const Self = @This(); + +image: *Image, +memory: *DeviceMemory, +state: State, + +pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.ImageCreateInfo) VkError!Self { + const image = try device.createImage(allocator, info); + errdefer image.destroy(allocator); + + const requirements: vk.MemoryRequirements = undefined; + try image.getMemoryRequirements(&requirements); + + const memory = try device.allocateMemory(allocator, &.{ + .allocation_size = requirements.size, + .memory_type_index = requirements.memory_type_bits, + }); + errdefer memory.destroy(allocator); + + try image.bindMemory(memory, 0); + + return .{ + .image = image, + .memory = memory, + .state = .Available, + }; +} + +pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { + self.image.destroy(allocator); + self.memory.destroy(allocator); +} diff --git a/src/vulkan/wsi/SurfaceKHR.zig b/src/vulkan/wsi/SurfaceKHR.zig new file mode 100644 index 0000000..c3faa23 --- /dev/null +++ b/src/vulkan/wsi/SurfaceKHR.zig @@ -0,0 +1,11 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const lib = @import("lib.zig"); + +const VkError = @import("../error_set.zig").VkError; + +const Device = @import("../Device.zig"); + +const Self = @This(); + +pub const ObjectType: vk.ObjectType = .surface_khr; diff --git a/src/vulkan/wsi/SwapchainKHR.zig b/src/vulkan/wsi/SwapchainKHR.zig new file mode 100644 index 0000000..1ab6a32 --- /dev/null +++ b/src/vulkan/wsi/SwapchainKHR.zig @@ -0,0 +1,53 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const lib = @import("lib.zig"); + +const VkError = @import("../error_set.zig").VkError; + +const Device = @import("../Device.zig"); +const SurfaceKHR = @import("SurfaceKHR.zig"); +const PresentImage = @import("PresentImage.zig"); + +const Self = @This(); +pub const ObjectType: vk.ObjectType = .swapchain_khr; + +owner: *Device, +surface: *SurfaceKHR, +images: []PresentImage, + +pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.SwapchainCreateInfoKHR) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + const images = allocator.alloc(PresentImage, info.min_image_count) catch return VkError.OutOfHostMemory; + errdefer { + allocator.free(images); + } + + for (images) |*image| { + image.* = try .init(device, allocator, .{ + .format = info.image_format, + .image_type = .@"2d", + .extent = .{ + .width = info.image_extent.width, + .height = info.image_extent.height, + .depth = 1, + }, + .mip_levels = 1, + .array_layers = info.image_array_layers, + .samples = .@"1_bit", + .tiling = .optimal, + .usage = info.image_usage, + .sharing_mode = info.image_sharing_mode, + .p_queue_family_indices = info.p_queue_family_indices, + .queue_family_index_count = info.queue_family_index_count, + .initial_layout = .general, + }); + } + + self.* = .{ + .owner = device, + .images = images, + }; + return self; +} diff --git a/src/vulkan/wsi/WaylandSurfaceKHR.zig b/src/vulkan/wsi/WaylandSurfaceKHR.zig new file mode 100644 index 0000000..e69de29