diff --git a/.gitea/workflows/Build.yml b/.gitea/workflows/Build.yml index efb3c45..a9595d1 100644 --- a/.gitea/workflows/Build.yml +++ b/.gitea/workflows/Build.yml @@ -23,7 +23,7 @@ jobs: node-version: 24 - name: Building - run: zig build + run: zig build soft - name: Generating docs run: zig build docs diff --git a/README.md b/README.md index 24e247c..3619fbb 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ vkCmdBindIndexBuffer | ⚙️ WIP vkCmdBindPipeline | ✅ Implemented vkCmdBindVertexBuffers | ✅ Implemented vkCmdBlitImage | ✅ Implemented -vkCmdClearAttachments | ⚙️ WIP +vkCmdClearAttachments | ✅ Implemented vkCmdClearColorImage | ✅ Implemented vkCmdClearDepthStencilImage | ⚙️ WIP vkCmdCopyBuffer | ✅ Implemented @@ -72,21 +72,21 @@ vkCmdFillBuffer | ✅ Implemented vkCmdNextSubpass | ⚙️ WIP vkCmdPipelineBarrier | ✅ Implemented vkCmdPushConstants | ⚙️ WIP -vkCmdResetEvent | ⚙️ WIP +vkCmdResetEvent | ✅ Implemented vkCmdResetQueryPool | ⚙️ WIP vkCmdResolveImage | ⚙️ WIP vkCmdSetBlendConstants | ⚙️ WIP vkCmdSetDepthBias | ⚙️ WIP vkCmdSetDepthBounds | ⚙️ WIP -vkCmdSetEvent | ⚙️ WIP +vkCmdSetEvent | ✅ Implemented vkCmdSetLineWidth | ⚙️ WIP vkCmdSetScissor | ⚙️ WIP vkCmdSetStencilCompareMask | ⚙️ WIP vkCmdSetStencilReference | ⚙️ WIP vkCmdSetStencilWriteMask | ⚙️ WIP -vkCmdSetViewport | ⚙️ WIP +vkCmdSetViewport | ✅ Implemented vkCmdUpdateBuffer | ⚙️ WIP -vkCmdWaitEvents | ⚙️ WIP +vkCmdWaitEvents | ✅ Implemented vkCmdWriteTimestamp | ⚙️ WIP vkCreateBuffer | ✅ Implemented vkCreateBufferView | ⚙️ WIP @@ -95,7 +95,7 @@ vkCreateComputePipelines | ✅ Implemented vkCreateDescriptorPool | ✅ Implemented vkCreateDescriptorSetLayout | ✅ Implemented vkCreateDevice | ✅ Implemented -vkCreateEvent | ⚙️ WIP +vkCreateEvent | ✅ Implemented vkCreateFence | ✅ Implemented vkCreateFramebuffer | ✅ Implemented vkCreateGraphicsPipelines | ⚙️ WIP @@ -115,7 +115,7 @@ vkDestroyCommandPool | ✅ Implemented vkDestroyDescriptorPool | ✅ Implemented vkDestroyDescriptorSetLayout | ✅ Implemented vkDestroyDevice | ✅ Implemented -vkDestroyEvent | ⚙️ WIP +vkDestroyEvent | ✅ Implemented vkDestroyFence | ✅ Implemented vkDestroyFramebuffer | ✅ Implemented vkDestroyImage | ✅ Implemented @@ -144,7 +144,7 @@ vkGetBufferMemoryRequirements | ✅ Implemented vkGetDeviceMemoryCommitment | ⚙️ WIP vkGetDeviceProcAddr | ✅ Implemented vkGetDeviceQueue | ✅ Implemented -vkGetEventStatus | ⚙️ WIP +vkGetEventStatus | ✅ Implemented vkGetFenceStatus | ✅ Implemented vkGetImageMemoryRequirements | ✅ Implemented vkGetImageSparseMemoryRequirements | ⚙️ WIP @@ -169,9 +169,9 @@ vkQueueWaitIdle | ✅ Implemented vkResetCommandBuffer | ✅ Implemented vkResetCommandPool | ✅ Implemented vkResetDescriptorPool | ✅ Implemented -vkResetEvent | ⚙️ WIP +vkResetEvent | ✅ Implemented vkResetFences | ✅ Implemented -vkSetEvent | ⚙️ WIP +vkSetEvent | ✅ Implemented vkUnmapMemory | ✅ Implemented vkUpdateDescriptorSets | ✅ Implemented vkWaitForFences | ✅ Implemented diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index 343ec5b..c01b7e4 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -50,6 +50,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v .bindPipeline = bindPipeline, .bindVertexBuffer = bindVertexBuffer, .blitImage = blitImage, + .clearAttachment = clearAttachment, .clearColorImage = clearColorImage, .copyBuffer = copyBuffer, .copyBufferToImage = copyBufferToImage, @@ -67,7 +68,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v .resetEvent = resetEvent, .setEvent = setEvent, .setViewport = setViewport, - .waitEvents = waitEvents, + .waitEvent = waitEvent, }; self.* = .{ @@ -287,6 +288,45 @@ pub fn blitImage(interface: *Interface, src: *base.Image, _: vk.ImageLayout, dst self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } +pub fn clearAttachment(interface: *Interface, attachment: vk.ClearAttachment, rect: vk.ClearRect) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + attachment: vk.ClearAttachment, + rect: vk.ClearRect, + + pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + + if (device.renderer.framebuffer) |framebuffer| { + const image_view = framebuffer.interface.attachments[impl.attachment.color_attachment]; + const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.image)); + const clear_format = try image.getClearFormat(); + + try blitter.clear( + impl.attachment.clear_value, + clear_format, + image, + image_view.format, + image_view.subresource_range, + null, + ); + } + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .attachment = attachment, + .rect = rect, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; +} + pub fn clearColorImage(interface: *Interface, image: *base.Image, _: vk.ImageLayout, color: *const vk.ClearColorValue, range: vk.ImageSubresourceRange) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const allocator = self.command_allocator.allocator(); @@ -609,17 +649,53 @@ pub fn pipelineBarrier(interface: *Interface, src_stage: vk.PipelineStageFlags, } pub fn resetEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void { - // No-op - _ = interface; - _ = event; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + _ = stage; + + const CommandImpl = struct { + const Impl = @This(); + + event: *base.Event, + + pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + try impl.event.reset(); + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .event = event, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } pub fn setEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void { - // No-op - _ = interface; - _ = event; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + _ = stage; + + const CommandImpl = struct { + const Impl = @This(); + + event: *base.Event, + + pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + try impl.event.signal(); + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .event = event, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } pub fn setViewport(interface: *Interface, first: u32, viewports: []const vk.Viewport) VkError!void { @@ -647,13 +723,31 @@ pub fn setViewport(interface: *Interface, first: u32, viewports: []const vk.View self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } -pub fn waitEvents(interface: *Interface, events: []*const base.Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { - // No-op - _ = interface; - _ = events; +pub fn waitEvent(interface: *Interface, event: *base.Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + _ = src_stage; _ = dst_stage; _ = memory_barriers; _ = buffer_barriers; _ = image_barriers; + + const CommandImpl = struct { + const Impl = @This(); + + event: *base.Event, + + pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void { + const impl: *Impl = @ptrCast(@alignCast(context)); + try impl.event.wait(); + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .event = event, + }; + self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; } diff --git a/src/soft/SoftEvent.zig b/src/soft/SoftEvent.zig index bbffc43..ced8ed4 100644 --- a/src/soft/SoftEvent.zig +++ b/src/soft/SoftEvent.zig @@ -74,7 +74,7 @@ pub fn signal(interface: *Interface) VkError!void { self.condition.broadcast(io); } -pub fn wait(interface: *Interface, timeout: u64) VkError!void { +pub fn wait(interface: *Interface) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const io = interface.owner.io(); @@ -82,14 +82,5 @@ pub fn wait(interface: *Interface, timeout: u64) VkError!void { defer self.mutex.unlock(io); if (self.is_signaled) return; - if (timeout == 0) return VkError.Timeout; - - if (timeout != std.math.maxInt(@TypeOf(timeout))) { - const duration: std.Io.Clock.Duration = .{ - .raw = .fromNanoseconds(@intCast(timeout)), - .clock = .cpu_process, - }; - duration.sleep(io) catch return VkError.DeviceLost; - } self.condition.wait(io, &self.mutex) catch return VkError.DeviceLost; } diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 07226d2..cd60f4b 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -44,6 +44,7 @@ pub const DispatchTable = struct { 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, + clearAttachment: *const fn (*Self, vk.ClearAttachment, vk.ClearRect) 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, copyBufferToImage: *const fn (*Self, *Buffer, *Image, vk.ImageLayout, []const vk.BufferImageCopy) VkError!void, @@ -61,7 +62,7 @@ pub const DispatchTable = struct { resetEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void, setEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void, setViewport: *const fn (*Self, u32, []const vk.Viewport) VkError!void, - waitEvents: *const fn (*Self, []*const Event, vk.PipelineStageFlags, vk.PipelineStageFlags, []const vk.MemoryBarrier, []const vk.BufferMemoryBarrier, []const vk.ImageMemoryBarrier) VkError!void, + waitEvent: *const fn (*Self, *Event, vk.PipelineStageFlags, vk.PipelineStageFlags, []const vk.MemoryBarrier, []const vk.BufferMemoryBarrier, []const vk.ImageMemoryBarrier) VkError!void, }; pub const VTable = struct { @@ -170,6 +171,10 @@ pub inline fn blitImage(self: *Self, src: *Image, src_layout: vk.ImageLayout, ds try self.dispatch_table.blitImage(self, src, src_layout, dst, dst_layout, regions, filter); } +pub fn clearAttachment(self: *Self, attachment: vk.ClearAttachment, rect: vk.ClearRect) VkError!void { + try self.dispatch_table.clearAttachment(self, attachment, rect); +} + 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); @@ -216,7 +221,15 @@ pub inline fn fillBuffer(self: *Self, buffer: *Buffer, offset: vk.DeviceSize, si try self.dispatch_table.fillBuffer(self, buffer, offset, size, data); } -pub inline fn pipelineBarrier(self: *Self, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, dependency: vk.DependencyFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { +pub inline fn pipelineBarrier( + self: *Self, + src_stage: vk.PipelineStageFlags, + dst_stage: vk.PipelineStageFlags, + dependency: vk.DependencyFlags, + memory_barriers: []const vk.MemoryBarrier, + buffer_barriers: []const vk.BufferMemoryBarrier, + image_barriers: []const vk.ImageMemoryBarrier, +) VkError!void { try self.dispatch_table.pipelineBarrier(self, src_stage, dst_stage, dependency, memory_barriers, buffer_barriers, image_barriers); } @@ -232,6 +245,14 @@ pub inline fn setViewport(self: *Self, first: u32, viewports: []const vk.Viewpor try self.dispatch_table.setViewport(self, first, viewports); } -pub inline fn waitEvents(self: *Self, events: []*const Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { - try self.dispatch_table.waitEvents(self, events, src_stage, dst_stage, memory_barriers, buffer_barriers, image_barriers); +pub inline fn waitEvent( + self: *Self, + event: *Event, + src_stage: vk.PipelineStageFlags, + dst_stage: vk.PipelineStageFlags, + memory_barriers: []const vk.MemoryBarrier, + buffer_barriers: []const vk.BufferMemoryBarrier, + image_barriers: []const vk.ImageMemoryBarrier, +) VkError!void { + try self.dispatch_table.waitEvent(self, event, src_stage, dst_stage, memory_barriers, buffer_barriers, image_barriers); } diff --git a/src/vulkan/Event.zig b/src/vulkan/Event.zig index 059043b..8c2006b 100644 --- a/src/vulkan/Event.zig +++ b/src/vulkan/Event.zig @@ -19,7 +19,7 @@ pub const VTable = struct { getStatus: *const fn (*Self) VkError!void, reset: *const fn (*Self) VkError!void, signal: *const fn (*Self) VkError!void, - wait: *const fn (*Self, u64) VkError!void, + wait: *const fn (*Self) VkError!void, }; pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.EventCreateInfo) VkError!Self { @@ -47,6 +47,6 @@ pub inline fn signal(self: *Self) VkError!void { try self.vtable.signal(self); } -pub inline fn wait(self: *Self, timeout: u64) VkError!void { - try self.vtable.wait(self, timeout); +pub inline fn wait(self: *Self) VkError!void { + try self.vtable.wait(self); } diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index e7bf69e..d20c34b 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -1705,14 +1705,11 @@ pub export fn strollCmdClearAttachments(p_cmd: vk.CommandBuffer, attachment_coun defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; - _ = attachment_count; - _ = attachments; - _ = rect_count; - _ = rects; + for (attachments[0..], 0..attachment_count) |attachment, _| { + for (rects[0..], 0..rect_count) |rect, _| { + cmd.clearAttachment(attachment, rect) catch |err| return errorLogger(err); + } + } } pub export fn strollCmdClearColorImage(p_cmd: vk.CommandBuffer, p_image: vk.Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, count: u32, ranges: [*]const vk.ImageSubresourceRange) callconv(vk.vulkan_call_conv) void { @@ -2173,18 +2170,18 @@ pub export fn strollCmdWaitEvents( entryPointBeginLogTrace(.vkCmdWaitEvents); defer entryPointEndLogTrace(); - _ = count; - _ = p_events; - _ = src_stage_mask; - _ = dst_stage_mask; - _ = memory_barrier_count; - _ = memory_barriers; - _ = buffer_memory_barrier_count; - _ = buffer_memory_barriers; - _ = image_memory_barrier_count; - _ = image_memory_barriers; const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - _ = cmd; + for (p_events, 0..count) |p_event, _| { + const event = NonDispatchable(Event).fromHandleObject(p_event) catch |err| return errorLogger(err); + cmd.waitEvent( + event, + src_stage_mask, + dst_stage_mask, + memory_barriers[0..memory_barrier_count], + buffer_memory_barriers[0..buffer_memory_barrier_count], + image_memory_barriers[0..image_memory_barrier_count], + ) catch |err| return errorLogger(err); + } } pub export fn strollCmdWriteTimestamp(p_cmd: vk.CommandBuffer, stage: vk.PipelineStageFlags, p_pool: vk.QueryPool, query: u32) callconv(vk.vulkan_call_conv) void {