diff --git a/README.md b/README.md index 1dbd8f1..446b1a3 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ It does not seek to produce a performant or production-worthy driver. \ ## Soft [software implementation] -Soft be a software implementation of the Vulkan specification, abiding within this driver’s own codebase.\ -It maketh use of a bespoke SPIR-V interpreter and renderer, by whose workings its labours are carried forth. +Soft be a software implementation of the Vulkan specification, abiding within this driver's own codebase.\ +It maketh use of a bespoke [SPIR-V interpreter](https://git.kbz8.me/kbz_8/SPIRV-Interpreter) and renderer, by whose workings its labours are carried forth. ### Build diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index 3bac8ea..d4fe1ae 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -788,6 +788,11 @@ pub fn endRenderPass(interface: *Interface) VkError!void { const CommandImpl = struct { pub fn execute(_: *anyopaque, device: *ExecutionDevice) VkError!void { + const framebuffer = device.renderer.framebuffer orelse return; + const render_pass = device.renderer.render_pass orelse return; + + try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index); + device.renderer.render_pass = null; device.renderer.framebuffer = null; } @@ -856,6 +861,11 @@ pub fn nextSubpass(interface: *Interface, _: vk.SubpassContents) VkError!void { const Impl = @This(); pub fn execute(_: *anyopaque, device: *ExecutionDevice) VkError!void { + const framebuffer = device.renderer.framebuffer orelse return; + const render_pass = device.renderer.render_pass orelse return; + + try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index); + device.renderer.subpass_index += 1; } }; diff --git a/src/soft/SoftFramebuffer.zig b/src/soft/SoftFramebuffer.zig index 3129654..9682c2d 100644 --- a/src/soft/SoftFramebuffer.zig +++ b/src/soft/SoftFramebuffer.zig @@ -5,6 +5,11 @@ const base = @import("base"); const VkError = base.VkError; const Device = base.Device; +const blitter = @import("device/blitter.zig"); + +const SoftImage = @import("SoftImage.zig"); +const SoftRenderPass = @import("SoftRenderPass.zig"); + const Self = @This(); pub const Interface = base.Framebuffer; @@ -30,3 +35,39 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); allocator.destroy(self); } + +pub fn resolveAttachments(self: *Self, render_pass: *SoftRenderPass, subpass_index: usize) VkError!void { + const subpass = render_pass.interface.subpasses[subpass_index]; + + if (subpass.resolve_attachments) |resolve_attachments| { + if (subpass.color_attachments) |color_attachments| { + for (color_attachments[0..], resolve_attachments[0..]) |color, resolve| { + if (resolve.attachment != vk.ATTACHMENT_UNUSED) { + const src_image_view = self.interface.attachments[color.attachment]; + const src_image: *SoftImage = @alignCast(@fieldParentPtr("interface", src_image_view.image)); + + const dst_image_view = self.interface.attachments[resolve.attachment]; + const dst_image: *SoftImage = @alignCast(@fieldParentPtr("interface", dst_image_view.image)); + + try blitter.resolve(src_image, dst_image, .{ + .src_subresource = .{ + .aspect_mask = src_image_view.subresource_range.aspect_mask, + .base_array_layer = src_image_view.subresource_range.base_array_layer, + .layer_count = src_image_view.subresource_range.layer_count, + .mip_level = src_image_view.subresource_range.base_mip_level, + }, + .src_offset = .{ .x = 0, .y = 0, .z = 0 }, + .dst_subresource = .{ + .aspect_mask = dst_image_view.subresource_range.aspect_mask, + .base_array_layer = dst_image_view.subresource_range.base_array_layer, + .layer_count = dst_image_view.subresource_range.layer_count, + .mip_level = dst_image_view.subresource_range.base_mip_level, + }, + .dst_offset = .{ .x = 0, .y = 0, .z = 0 }, + .extent = src_image.getMipLevelExtent(src_image_view.subresource_range.base_mip_level), + }); + } + } + } + } +}