Skip to content

Commit 7d5eb15

Browse files
committed
working on commands
1 parent 8a641ad commit 7d5eb15

10 files changed

Lines changed: 169 additions & 23 deletions

File tree

src/soft/SoftCommandBuffer.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
2525
.clearColorImage = clearColorImage,
2626
.copyBuffer = copyBuffer,
2727
.copyImage = copyImage,
28+
.copyImageToBuffer = copyImageToBuffer,
2829
.end = end,
2930
.fillBuffer = fillBuffer,
3031
.reset = reset,
@@ -99,6 +100,15 @@ pub fn copyImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLa
99100
_ = regions;
100101
}
101102

103+
pub fn copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Buffer, regions: []const vk.BufferImageCopy) VkError!void {
104+
// No-op
105+
_ = interface;
106+
_ = src;
107+
_ = src_layout;
108+
_ = dst;
109+
_ = regions;
110+
}
111+
102112
pub fn resetEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void {
103113
// No-op
104114
_ = interface;

src/soft/SoftImage.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequ
4141
requirements.alignment = lib.MEMORY_REQUIREMENTS_IMAGE_ALIGNMENT;
4242
}
4343

44-
inline fn clear(self: *Self, pixel: *const anyopaque, format: vk.Format, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
44+
inline fn clear(self: *Self, pixel: vk.ClearValue, format: vk.Format, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
4545
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", self.interface.owner));
4646
soft_device.blitter.clear(pixel, format, self, view_format, range, area);
4747
}
@@ -55,5 +55,5 @@ pub fn clearRange(self: *Self, color: vk.ClearColorValue, range: vk.ImageSubreso
5555
.r32g32b32a32_uint
5656
else
5757
.r32g32b32a32_sfloat;
58-
self.clear(@ptrCast(&color.float_32), clear_format, self.interface.format, range, null);
58+
self.clear(.{ .color = color }, clear_format, self.interface.format, range, null);
5959
}

src/soft/SoftQueue.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const base = @import("base");
44

55
const RefCounter = base.RefCounter;
66

7-
const Executor = @import("Executor.zig");
7+
const Device = @import("device/Device.zig");
88
const Dispatchable = base.Dispatchable;
99

1010
const CommandBuffer = base.CommandBuffer;
@@ -97,13 +97,13 @@ fn taskRunner(self: *Self, info: Interface.SubmitInfo, p_fence: ?*base.Fence, ru
9797
command_buffers.deinit(soft_device.device_allocator.allocator());
9898
}
9999

100-
var executor = Executor.init();
101-
defer executor.deinit();
100+
var device = Device.init();
101+
defer device.deinit();
102102

103103
loop: for (info.command_buffers.items) |command_buffer| {
104104
command_buffer.submit() catch continue :loop;
105105
for (command_buffer.commands.items) |command| {
106-
executor.dispatch(&command) catch |err| base.errors.errorLoggerContext(err, "the software command dispatcher");
106+
device.dispatch(&command) catch |err| base.errors.errorLoggerContext(err, "the software command dispatcher");
107107
}
108108
}
109109

src/soft/device/Blitter.zig

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! This software blitter is highly inspired by SwiftShaders one
2+
13
const std = @import("std");
24
const vk = @import("vulkan");
35
const base = @import("base");
@@ -13,15 +15,90 @@ pub const init: Self = .{
1315
.blit_mutex = .{},
1416
};
1517

16-
pub fn clear(self: *Self, pixel: *const anyopaque, format: vk.Format, dest: *SoftImage, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
18+
pub fn clear(self: *Self, pixel: vk.ClearValue, format: vk.Format, dest: *SoftImage, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
1719
const dst_format = base.Image.formatFromAspect(view_format, range.aspect_mask);
1820
if (dst_format == .undefined) {
1921
return;
2022
}
2123

24+
const view_format_value: c_uint = @intCast(@intFromEnum(view_format));
25+
26+
var clamped_pixel: vk.ClearValue = pixel;
27+
if (base.vku.vkuFormatIsSINT(view_format_value) or base.vku.vkuFormatIsUINT(view_format_value)) {
28+
const min_value: f32 = if (base.vku.vkuFormatIsSNORM(view_format_value)) -1.0 else 0.0;
29+
30+
if (range.aspect_mask.color_bit) {
31+
clamped_pixel.color.float_32[0] = std.math.clamp(pixel.color.float_32[0], min_value, 1.0);
32+
clamped_pixel.color.float_32[1] = std.math.clamp(pixel.color.float_32[1], min_value, 1.0);
33+
clamped_pixel.color.float_32[2] = std.math.clamp(pixel.color.float_32[2], min_value, 1.0);
34+
clamped_pixel.color.float_32[3] = std.math.clamp(pixel.color.float_32[3], min_value, 1.0);
35+
}
36+
37+
// Stencil never requires clamping, so we can check for Depth only
38+
if (range.aspect_mask.depth_bit) {
39+
clamped_pixel.depth_stencil.depth = std.math.clamp(pixel.depth_stencil.depth, min_value, 1.0);
40+
}
41+
}
42+
43+
if (self.fastClear(clamped_pixel, format, dest, dst_format, range, area)) {
44+
return;
45+
}
46+
base.logger.fixme("implement slow clear", .{});
47+
}
48+
49+
fn fastClear(self: *Self, clear_value: vk.ClearValue, clear_format: vk.Format, dest: *SoftImage, view_format: vk.Format, range: vk.ImageSubresourceRange, render_area: ?vk.Rect2D) bool {
2250
_ = self;
23-
_ = pixel;
24-
_ = format;
25-
_ = dest;
26-
_ = area;
51+
_ = render_area;
52+
_ = range;
53+
54+
if (clear_format != .r32g32b32a32_sfloat and clear_format != .d32_sfloat and clear_format != .s8_uint) {
55+
return false;
56+
}
57+
58+
const ClearValue = union {
59+
rgba: struct { r: f32, g: f32, b: f32, a: f32 },
60+
rgb: [3]f32,
61+
d: f32,
62+
d_as_u32: u32,
63+
s: u32,
64+
};
65+
66+
const c: *const ClearValue = @ptrCast(&clear_value);
67+
68+
var pack: u32 = 0;
69+
switch (view_format) {
70+
.r5g6b5_unorm_pack16 => pack = @as(u16, @intFromFloat(31.0 * c.rgba.b + 0.5)) | (@as(u16, @intFromFloat(63.0 * c.rgba.g + 0.5)) << 5) | (@as(u16, @intFromFloat(31.0 * c.rgba.r + 0.5)) << 11),
71+
.b5g6r5_unorm_pack16 => pack = @as(u16, @intFromFloat(31.0 * c.rgba.r + 0.5)) | (@as(u16, @intFromFloat(63.0 * c.rgba.g + 0.5)) << 5) | (@as(u16, @intFromFloat(31.0 * c.rgba.b + 0.5)) << 11),
72+
73+
.a8b8g8r8_uint_pack32,
74+
.a8b8g8r8_unorm_pack32,
75+
.r8g8b8a8_unorm,
76+
=> pack = (@as(u32, @intFromFloat(255.0 * c.rgba.a + 0.5)) << 24) | (@as(u32, @intFromFloat(255.0 * c.rgba.b + 0.5)) << 16) | (@as(u32, @intFromFloat(255.0 * c.rgba.g + 0.5)) << 8) | @as(u32, @intFromFloat(255.0 * c.rgba.r + 0.5)),
77+
78+
.b8g8r8a8_unorm => pack = (@as(u32, @intFromFloat(255.0 * c.rgba.a + 0.5)) << 24) | (@as(u32, @intFromFloat(255.0 * c.rgba.r + 0.5)) << 16) | (@as(u32, @intFromFloat(255.0 * c.rgba.g + 0.5)) << 8) | @as(u32, @intFromFloat(255.0 * c.rgba.b + 0.5)),
79+
//.b10g11r11_ufloat_pack32 => pack = R11G11B10F(c.rgb),
80+
//.e5b9g9r9_ufloat_pack32 => pack = RGB9E5(c.rgb),
81+
.d32_sfloat => {
82+
std.debug.assert(clear_format == .d32_sfloat);
83+
pack = c.d_as_u32; // float reinterpreted as uint32
84+
},
85+
.s8_uint => {
86+
std.debug.assert(clear_format == .s8_uint);
87+
pack = @as(u8, @intCast(c.s));
88+
},
89+
else => return false,
90+
}
91+
92+
if (dest.interface.memory) |memory| {
93+
const image_size = dest.interface.getTotalSize();
94+
const memory_map = memory.map(dest.interface.memory_offset, image_size) catch return false;
95+
defer memory.unmap();
96+
97+
const memory_map_as_u32: []u32 = @as([*]u32, @ptrCast(@alignCast(memory_map)))[0..@divExact(image_size, 4)];
98+
99+
@memset(memory_map_as_u32, pack);
100+
101+
return true;
102+
}
103+
return false;
27104
}
Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const std = @import("std");
22
const vk = @import("vulkan");
33
const base = @import("base");
44

5-
const SoftImage = @import("SoftImage.zig");
5+
const SoftImage = @import("../SoftImage.zig");
66

77
const cmd = base.commands;
88
const VkError = base.VkError;
@@ -23,6 +23,7 @@ pub fn dispatch(self: *Self, command: *const cmd.Command) VkError!void {
2323
.ClearColorImage => |data| try clearColorImage(&data),
2424
.CopyBuffer => |data| try copyBuffer(&data),
2525
.CopyImage => |data| try copyImage(&data),
26+
.CopyImageToBuffer => |data| try copyImageToBuffer(&data),
2627
.FillBuffer => |data| try fillBuffer(&data),
2728
else => {},
2829
}
@@ -53,6 +54,42 @@ fn copyImage(data: *const cmd.CommandCopyImage) VkError!void {
5354
std.log.scoped(.commandExecutor).warn("FIXME: implement image to image copy", .{});
5455
}
5556

57+
fn copyImageToBuffer(data: *const cmd.CommandCopyImageToBuffer) VkError!void {
58+
for (data.regions) |region| {
59+
const src_memory = if (data.src.memory) |memory| memory else return VkError.ValidationFailed;
60+
const dst_memory = if (data.dst.memory) |memory| memory else return VkError.ValidationFailed;
61+
62+
const pixel_size: u32 = @intCast(data.src.getPixelSize());
63+
const image_row_pitch: u32 = data.src.extent.width * pixel_size;
64+
const image_size: u32 = @intCast(data.src.getTotalSize());
65+
66+
const buffer_row_length: u32 = if (region.buffer_row_length != 0) region.buffer_row_length else region.image_extent.width;
67+
const buffer_row_pitch: u32 = buffer_row_length * pixel_size;
68+
const buffer_size: u32 = buffer_row_pitch * region.image_extent.height * region.image_extent.depth;
69+
70+
const src_map: []u8 = @as([*]u8, @ptrCast(try src_memory.map(0, image_size)))[0..image_size];
71+
const dst_map: []u8 = @as([*]u8, @ptrCast(try dst_memory.map(region.buffer_offset, buffer_size)))[0..buffer_size];
72+
73+
const row_size = region.image_extent.width * pixel_size;
74+
for (0..data.src.extent.depth) |z| {
75+
for (0..data.src.extent.height) |y| {
76+
const z_as_u32: u32 = @intCast(z);
77+
const y_as_u32: u32 = @intCast(y);
78+
79+
const src_offset = ((@as(u32, @intCast(region.image_offset.z)) + z_as_u32) * data.src.extent.height + @as(u32, @intCast(region.image_offset.y)) + y_as_u32) * image_row_pitch + @as(u32, @intCast(region.image_offset.x)) * pixel_size;
80+
const dst_offset = (z_as_u32 * buffer_row_length * region.image_extent.height + y_as_u32 * buffer_row_length) * pixel_size;
81+
82+
const src_slice = src_map[src_offset..(src_offset + row_size)];
83+
const dst_slice = dst_map[dst_offset..(dst_offset + row_size)];
84+
@memcpy(dst_slice, src_slice);
85+
}
86+
}
87+
88+
src_memory.unmap();
89+
dst_memory.unmap();
90+
}
91+
}
92+
5693
fn fillBuffer(data: *const cmd.CommandFillBuffer) VkError!void {
5794
const memory = if (data.buffer.memory) |memory| memory else return VkError.ValidationFailed;
5895
var memory_map: []u32 = @as([*]u32, @ptrCast(@alignCast(try memory.map(data.offset, data.size))))[0..data.size];

src/soft/lib.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const std = @import("std");
22
const vk = @import("vulkan");
33
pub const base = @import("base");
44

5-
pub const Executor = @import("Executor.zig");
5+
pub const Device = @import("device/Device.zig");
66

77
pub const SoftInstance = @import("SoftInstance.zig");
88
pub const SoftDevice = @import("SoftDevice.zig");
@@ -62,7 +62,7 @@ comptime {
6262
}
6363

6464
test {
65-
std.testing.refAllDecls(Executor);
65+
std.testing.refAllDecls(Device);
6666
std.testing.refAllDecls(SoftBinarySemaphore);
6767
std.testing.refAllDecls(SoftBuffer);
6868
std.testing.refAllDecls(SoftBufferView);

src/vulkan/CommandBuffer.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub const DispatchTable = struct {
4343
clearColorImage: *const fn (*Self, *Image, vk.ImageLayout, *const vk.ClearColorValue, vk.ImageSubresourceRange) VkError!void,
4444
copyBuffer: *const fn (*Self, *Buffer, *Buffer, []const vk.BufferCopy) VkError!void,
4545
copyImage: *const fn (*Self, *Image, vk.ImageLayout, *Image, vk.ImageLayout, []const vk.ImageCopy) VkError!void,
46+
copyImageToBuffer: *const fn (*Self, *Image, vk.ImageLayout, *Buffer, []const vk.BufferImageCopy) VkError!void,
4647
end: *const fn (*Self) VkError!void,
4748
fillBuffer: *const fn (*Self, *Buffer, vk.DeviceSize, vk.DeviceSize, u32) VkError!void,
4849
reset: *const fn (*Self, vk.CommandBufferResetFlags) VkError!void,
@@ -124,6 +125,7 @@ fn cleanCommandList(self: *Self) void {
124125
switch (command) {
125126
.CopyBuffer => |data| allocator.free(data.regions),
126127
.CopyImage => |data| allocator.free(data.regions),
128+
.CopyImageToBuffer => |data| allocator.free(data.regions),
127129
else => {},
128130
}
129131
}
@@ -166,6 +168,17 @@ pub inline fn copyImage(self: *Self, src: *Image, src_layout: vk.ImageLayout, ds
166168
try self.dispatch_table.copyImage(self, src, src_layout, dst, dst_layout, regions);
167169
}
168170

171+
pub inline fn copyImageToBuffer(self: *Self, src: *Image, src_layout: vk.ImageLayout, dst: *Buffer, regions: []const vk.BufferImageCopy) VkError!void {
172+
const allocator = self.host_allocator.allocator();
173+
self.commands.append(allocator, .{ .CopyImageToBuffer = .{
174+
.src = src,
175+
.src_layout = src_layout,
176+
.dst = dst,
177+
.regions = allocator.dupe(vk.BufferImageCopy, regions) catch return VkError.OutOfHostMemory,
178+
} }) catch return VkError.OutOfHostMemory;
179+
try self.dispatch_table.copyImageToBuffer(self, src, src_layout, dst, regions);
180+
}
181+
169182
pub inline fn fillBuffer(self: *Self, buffer: *Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void {
170183
const allocator = self.host_allocator.allocator();
171184
self.commands.append(allocator, .{ .FillBuffer = .{

src/vulkan/Image.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ pub inline fn getTotalSize(self: *Self) usize {
8888
return self.extent.width * self.extent.height * self.extent.depth * pixel_size;
8989
}
9090

91+
pub inline fn getFormatPixelSize(format: vk.Format) usize {
92+
return lib.vku.vkuFormatTexelBlockSize(@intCast(@intFromEnum(format)));
93+
}
94+
95+
pub inline fn getFormatTotalSize(self: *Self, format: vk.Format) usize {
96+
const pixel_size = self.getFormatPixelSize(format);
97+
return self.extent.width * self.extent.height * self.extent.depth * pixel_size;
98+
}
99+
91100
pub fn formatSupportsColorAttachemendBlend(format: vk.Format) bool {
92101
return switch (format) {
93102
// Vulkan 1.1 mandatory

src/vulkan/commands.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub const CommandType = enum {
1010
ClearColorImage,
1111
CopyBuffer,
1212
CopyImage,
13+
CopyImageToBuffer,
1314
Draw,
1415
DrawIndexed,
1516
DrawIndexedIndirect,
@@ -43,6 +44,12 @@ pub const CommandCopyImage = struct {
4344
dst_layout: vk.ImageLayout,
4445
regions: []const vk.ImageCopy,
4546
};
47+
pub const CommandCopyImageToBuffer = struct {
48+
src: *Image,
49+
src_layout: vk.ImageLayout,
50+
dst: *Buffer,
51+
regions: []const vk.BufferImageCopy,
52+
};
4653
pub const CommandDraw = struct {
4754
vertex_count: u32,
4855
instance_count: u32,
@@ -81,6 +88,7 @@ pub const Command = union(CommandType) {
8188
ClearColorImage: CommandClearColorImage,
8289
CopyBuffer: CommandCopyBuffer,
8390
CopyImage: CommandCopyImage,
91+
CopyImageToBuffer: CommandCopyImageToBuffer,
8492
Draw: CommandDraw,
8593
DrawIndexed: CommandDrawIndexed,
8694
DrawIndexedIndirect: CommandDrawIndexedIndirect,

src/vulkan/lib_vulkan.zig

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,15 +1839,7 @@ pub export fn strollCmdCopyImageToBuffer(p_cmd: vk.CommandBuffer, p_src: vk.Imag
18391839
const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err);
18401840
const src = NonDispatchable(Image).fromHandleObject(p_src) catch |err| return errorLogger(err);
18411841
const dst = NonDispatchable(Buffer).fromHandleObject(p_dst) catch |err| return errorLogger(err);
1842-
1843-
notImplementedWarning();
1844-
1845-
_ = cmd;
1846-
_ = src;
1847-
_ = dst;
1848-
_ = layout;
1849-
_ = count;
1850-
_ = regions;
1842+
cmd.copyImageToBuffer(src, layout, dst, regions[0..count]) catch |err| return errorLogger(err);
18511843
}
18521844

18531845
pub export fn strollCmdCopyQueryPoolResults(p_cmd: vk.CommandBuffer, p_pool: vk.QueryPool, first: u32, count: u32, p_dst: vk.Buffer, offset: vk.DeviceSize, stride: vk.DeviceSize, flags: vk.QueryResultFlags) callconv(vk.vulkan_call_conv) void {

0 commit comments

Comments
 (0)