From ed8a60b5393a608e98506c185572eb0352187977 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Thu, 23 Apr 2026 02:50:18 +0200 Subject: [PATCH] adding some base commadns --- README.md | 26 ++-- build.zig | 2 - src/soft/SoftCommandBuffer.zig | 121 +++++++++++++++++- src/soft/SoftPhysicalDevice.zig | 14 +- src/soft/SoftQueue.zig | 3 +- ...puteRoutines.zig => ComputeDispatcher.zig} | 4 +- src/soft/device/Device.zig | 29 +++-- src/soft/device/PipelineState.zig | 9 -- src/soft/device/Renderer.zig | 63 +++++++++ src/soft/lib.zig | 3 + src/vulkan/CommandBuffer.zig | 41 ++++-- src/vulkan/CommandPool.zig | 1 - src/vulkan/Framebuffer.zig | 30 ++++- src/vulkan/RenderPass.zig | 22 +++- src/vulkan/lib_vulkan.zig | 37 ++---- 15 files changed, 310 insertions(+), 95 deletions(-) rename src/soft/device/{ComputeRoutines.zig => ComputeDispatcher.zig} (99%) delete mode 100644 src/soft/device/PipelineState.zig create mode 100644 src/soft/device/Renderer.zig diff --git a/README.md b/README.md index 0f2c1db..4e99623 100644 --- a/README.md +++ b/README.md @@ -45,14 +45,14 @@ vkBeginCommandBuffer | ✅ Implemented vkBindBufferMemory | ✅ Implemented vkBindImageMemory | ✅ Implemented vkCmdBeginQuery | ⚙️ WIP -vkCmdBeginRenderPass | ⚙️ WIP +vkCmdBeginRenderPass | ✅ Implemented vkCmdBindDescriptorSets | ✅ Implemented vkCmdBindIndexBuffer | ⚙️ WIP vkCmdBindPipeline | ✅ Implemented -vkCmdBindVertexBuffers | ⚙️ WIP +vkCmdBindVertexBuffers | ✅ Implemented vkCmdBlitImage | ✅ Implemented vkCmdClearAttachments | ⚙️ WIP -vkCmdClearColorImage | ⚙️ WIP +vkCmdClearColorImage | ✅ Implemented vkCmdClearDepthStencilImage | ⚙️ WIP vkCmdCopyBuffer | ✅ Implemented vkCmdCopyBufferToImage | ✅ Implemented @@ -66,8 +66,8 @@ vkCmdDrawIndexed | ⚙️ WIP vkCmdDrawIndexedIndirect | ⚙️ WIP vkCmdDrawIndirect | ⚙️ WIP vkCmdEndQuery | ⚙️ WIP -vkCmdEndRenderPass | ⚙️ WIP -vkCmdExecuteCommands | ⚙️ WIP +vkCmdEndRenderPass | ✅ Implemented +vkCmdExecuteCommands | ✅ Implemented vkCmdFillBuffer | ✅ Implemented vkCmdNextSubpass | ⚙️ WIP vkCmdPipelineBarrier | ✅ Implemented @@ -97,7 +97,7 @@ vkCreateDescriptorSetLayout | ✅ Implemented vkCreateDevice | ✅ Implemented vkCreateEvent | ⚙️ WIP vkCreateFence | ✅ Implemented -vkCreateFramebuffer | ⚙️ WIP +vkCreateFramebuffer | ✅ Implemented vkCreateGraphicsPipelines | ⚙️ WIP vkCreateImage | ✅ Implemented vkCreateImageView | ✅ Implemented @@ -105,7 +105,7 @@ vkCreateInstance | ✅ Implemented vkCreatePipelineCache | ⚙️ WIP vkCreatePipelineLayout | ✅ Implemented vkCreateQueryPool | ⚙️ WIP -vkCreateRenderPass | ⚙️ WIP +vkCreateRenderPass | ✅ Implemented vkCreateSampler | ⚙️ WIP vkCreateSemaphore | ⚙️ WIP vkCreateShaderModule | ✅ Implemented @@ -117,17 +117,17 @@ vkDestroyDescriptorSetLayout | ✅ Implemented vkDestroyDevice | ✅ Implemented vkDestroyEvent | ⚙️ WIP vkDestroyFence | ✅ Implemented -vkDestroyFramebuffer | ⚙️ WIP +vkDestroyFramebuffer | ✅ Implemented vkDestroyImage | ✅ Implemented vkDestroyImageView | ✅ Implemented vkDestroyInstance | ✅ Implemented vkDestroyPipeline | ✅ Implemented -vkDestroyPipelineCache | ⚙️ WIP +vkDestroyPipelineCache | ✅ Implemented vkDestroyPipelineLayout | ✅ Implemented -vkDestroyQueryPool | ⚙️ WIP -vkDestroyRenderPass | ⚙️ WIP -vkDestroySampler | ⚙️ WIP -vkDestroySemaphore | ⚙️ WIP +vkDestroyQueryPool | ✅ Implemented +vkDestroyRenderPass | ✅ Implemented +vkDestroySampler | ✅ Implemented +vkDestroySemaphore | ✅ Implemented vkDestroyShaderModule | ✅ Implemented vkDeviceWaitIdle | ✅ Implemented vkEndCommandBuffer | ✅ Implemented diff --git a/build.zig b/build.zig index d3ea65a..7fa9366 100644 --- a/build.zig +++ b/build.zig @@ -290,8 +290,6 @@ fn addMultithreadedCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *c run.addArg(mustpass_path); run.addArg("--output"); run.addArg("./cts"); - run.addArg("--timeout"); - run.addArg("300"); if (jobs_count) |count| { run.addArg(b.fmt("-j{d}", .{count})); } diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index 979718a..bb1941b 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -3,15 +3,15 @@ const vk = @import("vulkan"); const base = @import("base"); const lib = @import("lib.zig"); -const InterfaceFactory = @import("interface").Interface; - -const VkError = base.VkError; const Device = base.Device; +const VkError = base.VkError; const SoftBuffer = @import("SoftBuffer.zig"); +const SoftDescriptorSet = @import("SoftDescriptorSet.zig"); +const SoftFramebuffer = @import("SoftFramebuffer.zig"); const SoftImage = @import("SoftImage.zig"); const SoftPipeline = @import("SoftPipeline.zig"); -const SoftDescriptorSet = @import("SoftDescriptorSet.zig"); +const SoftRenderPass = @import("SoftRenderPass.zig"); const ExecutionDevice = @import("device/Device.zig"); const blitter = @import("device/blitter.zig"); @@ -45,8 +45,10 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v interface.dispatch_table = &.{ .begin = begin, + .beginRenderPass = beginRenderPass, .bindDescriptorSets = bindDescriptorSets, .bindPipeline = bindPipeline, + .bindVertexBuffer = bindVertexBuffer, .blitImage = blitImage, .clearColorImage = clearColorImage, .copyBuffer = copyBuffer, @@ -55,7 +57,9 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v .copyImageToBuffer = copyImageToBuffer, .dispatch = dispatch, .dispatchIndirect = dispatchIndirect, + .draw = draw, .end = end, + .endRenderPass = endRenderPass, .executeCommands = executeCommands, .fillBuffer = fillBuffer, .pipelineBarrier = pipelineBarrier, @@ -113,6 +117,36 @@ pub fn reset(interface: *Interface, _: vk.CommandBufferResetFlags) VkError!void // Commands ==================================================================================================== +pub fn beginRenderPass(interface: *Interface, render_pass: *base.RenderPass, framebuffer: *base.Framebuffer, render_area: vk.Rect2D, clear_values: ?[]const vk.ClearValue) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + render_pass: *SoftRenderPass, + framebuffer: *SoftFramebuffer, + render_area: vk.Rect2D, + clear_values: ?[]const vk.ClearValue, + + pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + device.renderer.render_pass = impl.render_pass; + device.renderer.framebuffer = impl.framebuffer; + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .render_pass = @alignCast(@fieldParentPtr("interface", render_pass)), + .framebuffer = @alignCast(@fieldParentPtr("interface", framebuffer)), + .render_area = render_area, + .clear_values = clear_values, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; +} + pub fn bindDescriptorSets(interface: *Interface, bind_point: vk.PipelineBindPoint, first_set: u32, sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*base.DescriptorSet, dynamic_offsets: []const u32) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const allocator = self.command_allocator.allocator(); @@ -171,6 +205,37 @@ pub fn bindPipeline(interface: *Interface, bind_point: vk.PipelineBindPoint, pip self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } +pub fn bindVertexBuffer(interface: *Interface, index: usize, buffer: *base.Buffer, offset: usize) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + buffer: *const SoftBuffer, + offset: usize, + index: usize, + + pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + device.renderer.dynamic_state.vertex_buffers[impl.index] = .{ + .buffer = impl.buffer, + .offset = impl.offset, + .size = 0, + }; + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .buffer = @alignCast(@fieldParentPtr("interface", buffer)), + .offset = offset, + .index = index, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; +} + pub fn blitImage(interface: *Interface, src: *base.Image, _: vk.ImageLayout, dst: *base.Image, _: vk.ImageLayout, regions: []const vk.ImageBlit, filter: vk.Filter) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const allocator = self.command_allocator.allocator(); @@ -361,7 +426,7 @@ pub fn dispatch(interface: *Interface, group_count_x: u32, group_count_y: u32, g pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { const impl: *Impl = @ptrCast(@alignCast(context)); - try device.compute_routines.dispatch(impl.group_count_x, impl.group_count_y, impl.group_count_z); + try device.compute.dispatch(impl.group_count_x, impl.group_count_y, impl.group_count_z); } }; @@ -390,7 +455,7 @@ pub fn dispatchIndirect(interface: *Interface, buffer: *base.Buffer, offset: vk. 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_routines.dispatch(map[0], map[1], map[2]); + try device.compute.dispatch(map[0], map[1], map[2]); } }; @@ -403,6 +468,50 @@ 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 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(); + + const CommandImpl = struct { + const Impl = @This(); + + vertex_count: usize, + first_vertex: usize, + instance_count: usize, + first_instance: usize, + + pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + _ = impl; + _ = device; + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .vertex_count = vertex_count, + .first_vertex = first_vertex, + .instance_count = instance_count, + .first_instance = first_instance, + }; + 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(); + + const CommandImpl = struct { + pub fn execute(_: *anyopaque, device: *ExecutionDevice) VkError!void { + device.renderer.render_pass = null; + device.renderer.framebuffer = null; + } + }; + + self.commands.append(allocator, .{ .ptr = undefined, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; +} + pub fn executeCommands(interface: *Interface, commands: *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 15b01be..76a98ab 100644 --- a/src/soft/SoftPhysicalDevice.zig +++ b/src/soft/SoftPhysicalDevice.zig @@ -1,7 +1,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const root = @import("lib.zig"); +const lib = @import("lib.zig"); const cpuinfo = @cImport(@cInclude("cpuinfo.h")); const SoftDevice = @import("SoftDevice.zig"); @@ -34,9 +34,9 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*S .release = destroy, }; - interface.props.api_version = @bitCast(root.VULKAN_VERSION); - interface.props.driver_version = @bitCast(root.DRIVER_VERSION); - interface.props.device_id = root.DEVICE_ID; + interface.props.api_version = @bitCast(lib.VULKAN_VERSION); + interface.props.driver_version = @bitCast(lib.DRIVER_VERSION); + interface.props.device_id = lib.DEVICE_ID; interface.props.device_type = .cpu; interface.props.limits = .{ .max_image_dimension_1d = 4096, @@ -68,8 +68,8 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*S .max_descriptor_set_sampled_images = 96, .max_descriptor_set_storage_images = 24, .max_descriptor_set_input_attachments = 4, - .max_vertex_input_attributes = 16, - .max_vertex_input_bindings = 16, + .max_vertex_input_attributes = lib.MAX_VERTEX_INPUT_ATTRIBUTES, + .max_vertex_input_bindings = lib.MAX_VERTEX_INPUT_BINDINGS, .max_vertex_input_attribute_offset = 2047, .max_vertex_input_binding_stride = 2048, .max_vertex_output_components = 64, @@ -207,7 +207,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*S defer command_allocator.free(name); var writer = std.Io.Writer.fixed(device_name[0 .. vk.MAX_PHYSICAL_DEVICE_NAME_SIZE - 1]); - writer.print("{s} [" ++ root.DRIVER_NAME ++ " StrollDriver]", .{name}) catch return VkError.InitializationFailed; + writer.print("{s} [" ++ lib.DRIVER_NAME ++ " StrollDriver]", .{name}) catch return VkError.InitializationFailed; } @memcpy(&interface.props.device_name, &device_name); diff --git a/src/soft/SoftQueue.zig b/src/soft/SoftQueue.zig index c0a71c7..e182732 100644 --- a/src/soft/SoftQueue.zig +++ b/src/soft/SoftQueue.zig @@ -92,8 +92,7 @@ fn taskRunner(self: *Self, info: Interface.SubmitInfo, p_fence: ?*base.Fence, ru command_buffers.deinit(soft_device.device_allocator.allocator()); } - var execution_device: ExecutionDevice = .init; - execution_device.setup(soft_device); + var execution_device: ExecutionDevice = .init(soft_device); defer execution_device.deinit(); for (info.command_buffers.items) |command_buffer| { diff --git a/src/soft/device/ComputeRoutines.zig b/src/soft/device/ComputeDispatcher.zig similarity index 99% rename from src/soft/device/ComputeRoutines.zig rename to src/soft/device/ComputeDispatcher.zig index 2d480b2..803b404 100644 --- a/src/soft/device/ComputeRoutines.zig +++ b/src/soft/device/ComputeDispatcher.zig @@ -4,7 +4,7 @@ const base = @import("base"); const spv = @import("spv"); const lib = @import("../lib.zig"); -const PipelineState = @import("PipelineState.zig"); +const PipelineState = @import("Device.zig").PipelineState; const SoftDevice = @import("../SoftDevice.zig"); const SoftPipeline = @import("../SoftPipeline.zig"); @@ -45,7 +45,7 @@ pub fn init(device: *SoftDevice, state: *PipelineState) Self { }; } -pub fn destroy(self: *Self) void { +pub fn deinit(self: *Self) void { _ = self; } diff --git a/src/soft/device/Device.zig b/src/soft/device/Device.zig index 4fbb073..63d62d5 100644 --- a/src/soft/device/Device.zig +++ b/src/soft/device/Device.zig @@ -4,36 +4,45 @@ const base = @import("base"); const SoftDescriptorSet = @import("../SoftDescriptorSet.zig"); const SoftDevice = @import("../SoftDevice.zig"); +const SoftFramebuffer = @import("../SoftFramebuffer.zig"); const SoftPipeline = @import("../SoftPipeline.zig"); +const SoftRenderPass = @import("../SoftRenderPass.zig"); -const ComputeRoutines = @import("ComputeRoutines.zig"); -const PipelineState = @import("PipelineState.zig"); +const ComputeDispatcher = @import("ComputeDispatcher.zig"); +const Renderer = @import("Renderer.zig"); const VkError = base.VkError; const Self = @This(); -compute_routines: ComputeRoutines, +pub const PipelineState = struct { + pipeline: ?*SoftPipeline, + sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*SoftDescriptorSet, +}; + +compute: ComputeDispatcher, +renderer: Renderer, /// .graphics = 0 /// .compute = 1 pipeline_states: [2]PipelineState, -pub const init: Self = .{ - .compute_routines = undefined, - .pipeline_states = undefined, -}; +pub fn init(device: *SoftDevice) Self { + var self: Self = undefined; -pub fn setup(self: *Self, device: *SoftDevice) void { for (self.pipeline_states[0..]) |*state| { state.* = .{ .pipeline = null, .sets = [_]?*SoftDescriptorSet{null} ** base.VULKAN_MAX_DESCRIPTOR_SETS, }; } - self.compute_routines = .init(device, &self.pipeline_states[@intFromEnum(vk.PipelineBindPoint.compute)]); + self.compute = .init(device, &self.pipeline_states[@intFromEnum(vk.PipelineBindPoint.compute)]); + self.renderer = .init(); + + return self; } pub fn deinit(self: *Self) void { - self.compute_routines.destroy(); + self.compute.deinit(); + self.renderer.deinit(); } diff --git a/src/soft/device/PipelineState.zig b/src/soft/device/PipelineState.zig deleted file mode 100644 index 588ae64..0000000 --- a/src/soft/device/PipelineState.zig +++ /dev/null @@ -1,9 +0,0 @@ -const std = @import("std"); -const vk = @import("vulkan"); -const base = @import("base"); - -const SoftDescriptorSet = @import("../SoftDescriptorSet.zig"); -const SoftPipeline = @import("../SoftPipeline.zig"); - -pipeline: ?*SoftPipeline, -sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*SoftDescriptorSet, diff --git a/src/soft/device/Renderer.zig b/src/soft/device/Renderer.zig new file mode 100644 index 0000000..96592e5 --- /dev/null +++ b/src/soft/device/Renderer.zig @@ -0,0 +1,63 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const lib = @import("../lib.zig"); + +const SoftBuffer = @import("../SoftBuffer.zig"); +const SoftDescriptorSet = @import("../SoftDescriptorSet.zig"); +const SoftDevice = @import("../SoftDevice.zig"); +const SoftFramebuffer = @import("../SoftFramebuffer.zig"); +const SoftPipeline = @import("../SoftPipeline.zig"); +const SoftRenderPass = @import("../SoftRenderPass.zig"); + +const VkError = base.VkError; + +const Self = @This(); + +const VertexInputBindingState = struct { + input_rate: vk.VertexInputRate, + stride: usize, +}; + +const VertexInputAttributeState = struct { + format: vk.Format, + offset: usize, + binding: usize, +}; + +pub const VertexBuffer = struct { + buffer: *const SoftBuffer, + offset: usize, + size: usize, +}; + +pub const DynamicState = struct { + viewport: vk.Viewport, + scissor: vk.Rect2D, + + line_width: f32, + cull_mode: vk.CullModeFlags, + front_face: vk.FrontFace, + primitive_topology: vk.PrimitiveTopology, + + vertex_input_bindings: [lib.MAX_VERTEX_INPUT_BINDINGS]VertexInputBindingState, + vertex_input_attributes: [lib.MAX_VERTEX_INPUT_ATTRIBUTES]VertexInputAttributeState, + + vertex_buffers: [lib.MAX_VERTEX_INPUT_BINDINGS]VertexBuffer, +}; + +render_pass: ?*SoftRenderPass, +framebuffer: ?*SoftFramebuffer, +dynamic_state: DynamicState, + +pub fn init() Self { + return .{ + .render_pass = null, + .framebuffer = null, + .dynamic_state = undefined, + }; +} + +pub fn deinit(self: *Self) void { + _ = self; +} diff --git a/src/soft/lib.zig b/src/soft/lib.zig index d7a9afa..85c8fc6 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -55,6 +55,9 @@ pub const MIN_UNIFORM_BUFFER_ALIGNMENT = 256; /// Vulkan 1.2 requires buffer offset alignment to be at most 256. pub const MIN_STORAGE_BUFFER_ALIGNMENT = 256; +pub const MAX_VERTEX_INPUT_BINDINGS = 16; +pub const MAX_VERTEX_INPUT_ATTRIBUTES = 32; + pub const std_options = base.std_options; comptime { diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 46b1f98..eaa4730 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -6,14 +6,15 @@ const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; const VkError = @import("error_set.zig").VkError; const VulkanAllocator = @import("VulkanAllocator.zig"); -const Device = @import("Device.zig"); - const Buffer = @import("Buffer.zig"); const CommandPool = @import("CommandPool.zig"); +const DescriptorSet = @import("DescriptorSet.zig"); +const Device = @import("Device.zig"); const Event = @import("Event.zig"); +const Framebuffer = @import("Framebuffer.zig"); const Image = @import("Image.zig"); const Pipeline = @import("Pipeline.zig"); -const DescriptorSet = @import("DescriptorSet.zig"); +const RenderPass = @import("RenderPass.zig"); const State = enum { Initial, @@ -38,8 +39,10 @@ dispatch_table: *const DispatchTable, pub const DispatchTable = struct { begin: *const fn (*Self, *const vk.CommandBufferBeginInfo) VkError!void, + beginRenderPass: *const fn (*Self, *RenderPass, *Framebuffer, vk.Rect2D, ?[]const vk.ClearValue) VkError!void, bindDescriptorSets: *const fn (*Self, vk.PipelineBindPoint, u32, [lib.VULKAN_MAX_DESCRIPTOR_SETS]?*DescriptorSet, []const u32) VkError!void, bindPipeline: *const fn (*Self, vk.PipelineBindPoint, *Pipeline) VkError!void, + bindVertexBuffer: *const fn (*Self, usize, *Buffer, usize) VkError!void, blitImage: *const fn (*Self, *Image, vk.ImageLayout, *Image, vk.ImageLayout, []const vk.ImageBlit, vk.Filter) VkError!void, clearColorImage: *const fn (*Self, *Image, vk.ImageLayout, *const vk.ClearColorValue, vk.ImageSubresourceRange) VkError!void, copyBuffer: *const fn (*Self, *Buffer, *Buffer, []const vk.BufferCopy) VkError!void, @@ -48,7 +51,9 @@ pub const DispatchTable = struct { copyImageToBuffer: *const fn (*Self, *Image, vk.ImageLayout, *Buffer, []const vk.BufferImageCopy) VkError!void, 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, end: *const fn (*Self) VkError!void, + endRenderPass: *const fn (*Self) VkError!void, executeCommands: *const fn (*Self, *Self) VkError!void, fillBuffer: *const fn (*Self, *Buffer, vk.DeviceSize, vk.DeviceSize, u32) VkError!void, pipelineBarrier: *const fn (*Self, vk.PipelineStageFlags, vk.PipelineStageFlags, vk.DependencyFlags, []const vk.MemoryBarrier, []const vk.BufferMemoryBarrier, []const vk.ImageMemoryBarrier) VkError!void, @@ -91,7 +96,7 @@ pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { self.vtable.destroy(self, allocator); } -pub inline fn begin(self: *Self, info: *const vk.CommandBufferBeginInfo) VkError!void { +pub fn begin(self: *Self, info: *const vk.CommandBufferBeginInfo) VkError!void { if (!self.pool.flags.reset_command_buffer_bit) { self.transitionState(.Recording, &.{.Initial}) catch return VkError.ValidationFailed; } else { @@ -102,13 +107,13 @@ pub inline fn begin(self: *Self, info: *const vk.CommandBufferBeginInfo) VkError self.begin_info = info.*; } -pub inline fn end(self: *Self) VkError!void { +pub fn end(self: *Self) VkError!void { self.transitionState(.Executable, &.{.Recording}) catch return VkError.ValidationFailed; try self.dispatch_table.end(self); self.begin_info = null; } -pub inline fn reset(self: *Self, flags: vk.CommandBufferResetFlags) VkError!void { +pub fn reset(self: *Self, flags: vk.CommandBufferResetFlags) VkError!void { if (!self.pool.flags.reset_command_buffer_bit) { return VkError.ValidationFailed; } @@ -117,7 +122,7 @@ pub inline fn reset(self: *Self, flags: vk.CommandBufferResetFlags) VkError!void try self.dispatch_table.reset(self, flags); } -pub inline fn submit(self: *Self) VkError!void { +pub fn submit(self: *Self) VkError!void { if (self.begin_info) |begin_info| { if (!begin_info.flags.simultaneous_use_bit) { self.transitionState(.Pending, &.{.Executable}) catch return VkError.ValidationFailed; @@ -127,7 +132,7 @@ pub inline fn submit(self: *Self) VkError!void { self.transitionState(.Pending, &.{ .Pending, .Executable }) catch return VkError.ValidationFailed; } -pub inline fn finish(self: *Self) VkError!void { +pub fn finish(self: *Self) VkError!void { if (self.begin_info) |begin_info| { if (!begin_info.flags.one_time_submit_bit) { self.transitionState(.Invalid, &.{.Pending}) catch return VkError.ValidationFailed; @@ -139,7 +144,11 @@ pub inline fn finish(self: *Self) VkError!void { // Commands ==================================================================================================== -pub inline fn bindDescriptorSets(self: *Self, bind_point: vk.PipelineBindPoint, first_set: u32, sets: []const vk.DescriptorSet, dynamic_offsets: []const u32) VkError!void { +pub inline fn beginRenderPass(self: *Self, render_pass: *RenderPass, framebuffer: *Framebuffer, render_area: vk.Rect2D, clear_values: ?[]const vk.ClearValue) VkError!void { + try self.dispatch_table.beginRenderPass(self, render_pass, framebuffer, render_area, clear_values); +} + +pub fn bindDescriptorSets(self: *Self, bind_point: vk.PipelineBindPoint, first_set: u32, sets: []const vk.DescriptorSet, dynamic_offsets: []const u32) VkError!void { std.debug.assert(sets.len < lib.VULKAN_MAX_DESCRIPTOR_SETS); var inner_sets = [_]?*DescriptorSet{null} ** lib.VULKAN_MAX_DESCRIPTOR_SETS; for (sets, inner_sets[0..sets.len]) |set, *inner_set| { @@ -152,11 +161,15 @@ pub inline fn bindPipeline(self: *Self, bind_point: vk.PipelineBindPoint, pipeli try self.dispatch_table.bindPipeline(self, bind_point, pipeline); } +pub inline fn bindVertexBuffer(self: *Self, index: usize, buffer: *Buffer, offset: usize) VkError!void { + try self.dispatch_table.bindVertexBuffer(self, index, buffer, offset); +} + pub inline fn blitImage(self: *Self, src: *Image, src_layout: vk.ImageLayout, dst: *Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageBlit, filter: vk.Filter) VkError!void { try self.dispatch_table.blitImage(self, src, src_layout, dst, dst_layout, regions, filter); } -pub inline fn clearColorImage(self: *Self, image: *Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, ranges: []const vk.ImageSubresourceRange) VkError!void { +pub fn clearColorImage(self: *Self, image: *Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, ranges: []const vk.ImageSubresourceRange) VkError!void { for (ranges) |range| { try self.dispatch_table.clearColorImage(self, image, layout, color, range); } @@ -186,6 +199,14 @@ pub inline fn dispatchIndirect(self: *Self, buffer: *Buffer, offset: vk.DeviceSi try self.dispatch_table.dispatchIndirect(self, buffer, offset); } +pub inline fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void { + try self.dispatch_table.draw(self, vertex_count, instance_count, first_vertex, first_instance); +} + +pub inline fn endRenderPass(self: *Self) VkError!void { + try self.dispatch_table.endRenderPass(self); +} + pub inline fn executeCommands(self: *Self, commands: *Self) VkError!void { try self.dispatch_table.executeCommands(self, commands); } diff --git a/src/vulkan/CommandPool.zig b/src/vulkan/CommandPool.zig index acce024..f5aa9ce 100644 --- a/src/vulkan/CommandPool.zig +++ b/src/vulkan/CommandPool.zig @@ -99,7 +99,6 @@ pub inline fn reset(self: *Self, flags: vk.CommandPoolResetFlags) VkError!void { for (self.buffers.items) |non_dis_cmd| { non_dis_cmd.intrusiveDestroy(allocator); } - self.buffers.shrinkAndFree(allocator, BUFFER_POOL_BASE_CAPACITY); self.buffers.clearRetainingCapacity(); } } diff --git a/src/vulkan/Framebuffer.zig b/src/vulkan/Framebuffer.zig index bf6d55c..2591a3c 100644 --- a/src/vulkan/Framebuffer.zig +++ b/src/vulkan/Framebuffer.zig @@ -1,16 +1,22 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); +const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; +const VulkanAllocator = @import("VulkanAllocator.zig"); const VkError = @import("error_set.zig").VkError; const Device = @import("Device.zig"); +const ImageView = @import("ImageView.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .framebuffer; owner: *Device, +width: usize, +height: usize, +layers: usize, +attachments: []*ImageView, vtable: *const VTable, @@ -19,14 +25,30 @@ pub const VTable = struct { }; pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.FramebufferCreateInfo) VkError!Self { - _ = allocator; - _ = info; + const object_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object); + + const attachments = object_allocator.allocator().alloc(*ImageView, info.attachment_count) catch return VkError.OutOfHostMemory; + errdefer object_allocator.allocator().free(attachments); + + if (info.p_attachments) |base_attachements| { + for (base_attachements, attachments, 0..info.attachment_count) |base_attachment, *attachment, _| { + attachment.* = try NonDispatchable(ImageView).fromHandleObject(base_attachment); + } + } else { + return VkError.ValidationFailed; + } + return .{ .owner = device, + .width = @intCast(info.width), + .height = @intCast(info.height), + .layers = @intCast(info.layers), + .attachments = attachments, .vtable = undefined, }; } -pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { +pub fn destroy(self: *Self, allocator: std.mem.Allocator) void { + allocator.free(self.attachments); self.vtable.destroy(self, allocator); } diff --git a/src/vulkan/RenderPass.zig b/src/vulkan/RenderPass.zig index d0e5885..02e9e0c 100644 --- a/src/vulkan/RenderPass.zig +++ b/src/vulkan/RenderPass.zig @@ -1,7 +1,7 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); +const VulkanAllocator = @import("VulkanAllocator.zig"); const VkError = @import("error_set.zig").VkError; @@ -11,6 +11,7 @@ const Self = @This(); pub const ObjectType: vk.ObjectType = .render_pass; owner: *Device, +attachments: []vk.AttachmentDescription, vtable: *const VTable, @@ -19,14 +20,27 @@ pub const VTable = struct { }; pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.RenderPassCreateInfo) VkError!Self { - _ = allocator; - _ = info; + const object_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object); + + const attachments = object_allocator.allocator().alloc(vk.AttachmentDescription, info.attachment_count) catch return VkError.OutOfHostMemory; + errdefer object_allocator.allocator().free(attachments); + + if (info.p_attachments) |base_attachements| { + for (base_attachements, attachments, 0..info.attachment_count) |base_attachment, *attachment, _| { + attachment.* = base_attachment; + } + } else { + return VkError.ValidationFailed; + } + return .{ .owner = device, + .attachments = attachments, .vtable = undefined, }; } -pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { +pub fn destroy(self: *Self, allocator: std.mem.Allocator) void { + allocator.free(self.attachments); self.vtable.destroy(self, allocator); } diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index 2084876..8c629e0 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -1569,10 +1569,10 @@ pub export fn strollWaitForFences(p_device: vk.Device, count: u32, p_fences: [*] Dispatchable(Device).checkHandleValidity(p_device) catch |err| return toVkResult(err); - loop: for (p_fences, 0..count) |p_fence, _| { + for (p_fences, 0..count) |p_fence, _| { const fence = NonDispatchable(Fence).fromHandleObject(p_fence) catch |err| return toVkResult(err); fence.wait(timeout) catch |err| return toVkResult(err); - if (waitForAll == .false) break :loop; + if (waitForAll == .false) break; } return .success; } @@ -1612,11 +1612,12 @@ pub export fn strollCmdBeginRenderPass(p_cmd: vk.CommandBuffer, info: *const vk. if (info.s_type != .render_pass_begin_info) { return errorLogger(VkError.ValidationFailed); } + const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); + const render_pass = NonDispatchable(RenderPass).fromHandleObject(info.render_pass) catch |err| return errorLogger(err); + const framebuffer = NonDispatchable(Framebuffer).fromHandleObject(info.framebuffer) catch |err| return errorLogger(err); + cmd.beginRenderPass(render_pass, framebuffer, info.render_area, if (info.p_clear_values) |clear_values| clear_values[0..info.clear_value_count] else null) catch |err| return errorLogger(err); - notImplementedWarning(); - - _ = cmd; _ = contents; } @@ -1668,14 +1669,10 @@ pub export fn strollCmdBindVertexBuffers(p_cmd: vk.CommandBuffer, first: u32, co defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; - _ = first; - _ = count; - _ = p_buffers; - _ = offsets; + for (p_buffers, offsets, 0..count) |p_buffer, offset, i| { + const buffer = NonDispatchable(Buffer).fromHandleObject(p_buffer) catch |err| return errorLogger(err); + cmd.bindVertexBuffer(first + i, buffer, offset) catch |err| return errorLogger(err); + } } pub export fn strollCmdBlitImage( @@ -1821,14 +1818,7 @@ pub export fn strollCmdDraw(p_cmd: vk.CommandBuffer, vertex_count: u32, instance defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; - _ = vertex_count; - _ = instance_count; - _ = first_vertex; - _ = first_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 { @@ -1897,10 +1887,7 @@ pub export fn strollCmdEndRenderPass(p_cmd: vk.CommandBuffer) callconv(vk.vulkan defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; + cmd.endRenderPass() catch |err| return errorLogger(err); } pub export fn strollCmdExecuteCommands(p_cmd: vk.CommandBuffer, count: u32, p_cmds: [*]const vk.CommandBuffer) callconv(vk.vulkan_call_conv) void {