working on commands

This commit is contained in:
2025-12-22 16:57:41 +01:00
parent 8a641adb8e
commit 7d5eb1553b
10 changed files with 170 additions and 24 deletions

View File

@@ -25,6 +25,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
.clearColorImage = clearColorImage,
.copyBuffer = copyBuffer,
.copyImage = copyImage,
.copyImageToBuffer = copyImageToBuffer,
.end = end,
.fillBuffer = fillBuffer,
.reset = reset,
@@ -99,6 +100,15 @@ pub fn copyImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLa
_ = regions;
}
pub fn copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Buffer, regions: []const vk.BufferImageCopy) VkError!void {
// No-op
_ = interface;
_ = src;
_ = src_layout;
_ = dst;
_ = regions;
}
pub fn resetEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void {
// No-op
_ = interface;

View File

@@ -41,7 +41,7 @@ pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequ
requirements.alignment = lib.MEMORY_REQUIREMENTS_IMAGE_ALIGNMENT;
}
inline fn clear(self: *Self, pixel: *const anyopaque, format: vk.Format, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
inline fn clear(self: *Self, pixel: vk.ClearValue, format: vk.Format, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", self.interface.owner));
soft_device.blitter.clear(pixel, format, self, view_format, range, area);
}
@@ -55,5 +55,5 @@ pub fn clearRange(self: *Self, color: vk.ClearColorValue, range: vk.ImageSubreso
.r32g32b32a32_uint
else
.r32g32b32a32_sfloat;
self.clear(@ptrCast(&color.float_32), clear_format, self.interface.format, range, null);
self.clear(.{ .color = color }, clear_format, self.interface.format, range, null);
}

View File

@@ -4,7 +4,7 @@ const base = @import("base");
const RefCounter = base.RefCounter;
const Executor = @import("Executor.zig");
const Device = @import("device/Device.zig");
const Dispatchable = base.Dispatchable;
const CommandBuffer = base.CommandBuffer;
@@ -97,13 +97,13 @@ fn taskRunner(self: *Self, info: Interface.SubmitInfo, p_fence: ?*base.Fence, ru
command_buffers.deinit(soft_device.device_allocator.allocator());
}
var executor = Executor.init();
defer executor.deinit();
var device = Device.init();
defer device.deinit();
loop: for (info.command_buffers.items) |command_buffer| {
command_buffer.submit() catch continue :loop;
for (command_buffer.commands.items) |command| {
executor.dispatch(&command) catch |err| base.errors.errorLoggerContext(err, "the software command dispatcher");
device.dispatch(&command) catch |err| base.errors.errorLoggerContext(err, "the software command dispatcher");
}
}

View File

@@ -1,3 +1,5 @@
//! This software blitter is highly inspired by SwiftShaders one
const std = @import("std");
const vk = @import("vulkan");
const base = @import("base");
@@ -13,15 +15,90 @@ pub const init: Self = .{
.blit_mutex = .{},
};
pub fn clear(self: *Self, pixel: *const anyopaque, format: vk.Format, dest: *SoftImage, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
pub fn clear(self: *Self, pixel: vk.ClearValue, format: vk.Format, dest: *SoftImage, view_format: vk.Format, range: vk.ImageSubresourceRange, area: ?vk.Rect2D) void {
const dst_format = base.Image.formatFromAspect(view_format, range.aspect_mask);
if (dst_format == .undefined) {
return;
}
_ = self;
_ = pixel;
_ = format;
_ = dest;
_ = area;
const view_format_value: c_uint = @intCast(@intFromEnum(view_format));
var clamped_pixel: vk.ClearValue = pixel;
if (base.vku.vkuFormatIsSINT(view_format_value) or base.vku.vkuFormatIsUINT(view_format_value)) {
const min_value: f32 = if (base.vku.vkuFormatIsSNORM(view_format_value)) -1.0 else 0.0;
if (range.aspect_mask.color_bit) {
clamped_pixel.color.float_32[0] = std.math.clamp(pixel.color.float_32[0], min_value, 1.0);
clamped_pixel.color.float_32[1] = std.math.clamp(pixel.color.float_32[1], min_value, 1.0);
clamped_pixel.color.float_32[2] = std.math.clamp(pixel.color.float_32[2], min_value, 1.0);
clamped_pixel.color.float_32[3] = std.math.clamp(pixel.color.float_32[3], min_value, 1.0);
}
// Stencil never requires clamping, so we can check for Depth only
if (range.aspect_mask.depth_bit) {
clamped_pixel.depth_stencil.depth = std.math.clamp(pixel.depth_stencil.depth, min_value, 1.0);
}
}
if (self.fastClear(clamped_pixel, format, dest, dst_format, range, area)) {
return;
}
base.logger.fixme("implement slow clear", .{});
}
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 {
_ = self;
_ = render_area;
_ = range;
if (clear_format != .r32g32b32a32_sfloat and clear_format != .d32_sfloat and clear_format != .s8_uint) {
return false;
}
const ClearValue = union {
rgba: struct { r: f32, g: f32, b: f32, a: f32 },
rgb: [3]f32,
d: f32,
d_as_u32: u32,
s: u32,
};
const c: *const ClearValue = @ptrCast(&clear_value);
var pack: u32 = 0;
switch (view_format) {
.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),
.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),
.a8b8g8r8_uint_pack32,
.a8b8g8r8_unorm_pack32,
.r8g8b8a8_unorm,
=> 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)),
.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)),
//.b10g11r11_ufloat_pack32 => pack = R11G11B10F(c.rgb),
//.e5b9g9r9_ufloat_pack32 => pack = RGB9E5(c.rgb),
.d32_sfloat => {
std.debug.assert(clear_format == .d32_sfloat);
pack = c.d_as_u32; // float reinterpreted as uint32
},
.s8_uint => {
std.debug.assert(clear_format == .s8_uint);
pack = @as(u8, @intCast(c.s));
},
else => return false,
}
if (dest.interface.memory) |memory| {
const image_size = dest.interface.getTotalSize();
const memory_map = memory.map(dest.interface.memory_offset, image_size) catch return false;
defer memory.unmap();
const memory_map_as_u32: []u32 = @as([*]u32, @ptrCast(@alignCast(memory_map)))[0..@divExact(image_size, 4)];
@memset(memory_map_as_u32, pack);
return true;
}
return false;
}

View File

@@ -2,7 +2,7 @@ const std = @import("std");
const vk = @import("vulkan");
const base = @import("base");
const SoftImage = @import("SoftImage.zig");
const SoftImage = @import("../SoftImage.zig");
const cmd = base.commands;
const VkError = base.VkError;
@@ -23,6 +23,7 @@ pub fn dispatch(self: *Self, command: *const cmd.Command) VkError!void {
.ClearColorImage => |data| try clearColorImage(&data),
.CopyBuffer => |data| try copyBuffer(&data),
.CopyImage => |data| try copyImage(&data),
.CopyImageToBuffer => |data| try copyImageToBuffer(&data),
.FillBuffer => |data| try fillBuffer(&data),
else => {},
}
@@ -53,6 +54,42 @@ fn copyImage(data: *const cmd.CommandCopyImage) VkError!void {
std.log.scoped(.commandExecutor).warn("FIXME: implement image to image copy", .{});
}
fn copyImageToBuffer(data: *const cmd.CommandCopyImageToBuffer) VkError!void {
for (data.regions) |region| {
const src_memory = if (data.src.memory) |memory| memory else return VkError.ValidationFailed;
const dst_memory = if (data.dst.memory) |memory| memory else return VkError.ValidationFailed;
const pixel_size: u32 = @intCast(data.src.getPixelSize());
const image_row_pitch: u32 = data.src.extent.width * pixel_size;
const image_size: u32 = @intCast(data.src.getTotalSize());
const buffer_row_length: u32 = if (region.buffer_row_length != 0) region.buffer_row_length else region.image_extent.width;
const buffer_row_pitch: u32 = buffer_row_length * pixel_size;
const buffer_size: u32 = buffer_row_pitch * region.image_extent.height * region.image_extent.depth;
const src_map: []u8 = @as([*]u8, @ptrCast(try src_memory.map(0, image_size)))[0..image_size];
const dst_map: []u8 = @as([*]u8, @ptrCast(try dst_memory.map(region.buffer_offset, buffer_size)))[0..buffer_size];
const row_size = region.image_extent.width * pixel_size;
for (0..data.src.extent.depth) |z| {
for (0..data.src.extent.height) |y| {
const z_as_u32: u32 = @intCast(z);
const y_as_u32: u32 = @intCast(y);
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;
const dst_offset = (z_as_u32 * buffer_row_length * region.image_extent.height + y_as_u32 * buffer_row_length) * pixel_size;
const src_slice = src_map[src_offset..(src_offset + row_size)];
const dst_slice = dst_map[dst_offset..(dst_offset + row_size)];
@memcpy(dst_slice, src_slice);
}
}
src_memory.unmap();
dst_memory.unmap();
}
}
fn fillBuffer(data: *const cmd.CommandFillBuffer) VkError!void {
const memory = if (data.buffer.memory) |memory| memory else return VkError.ValidationFailed;
var memory_map: []u32 = @as([*]u32, @ptrCast(@alignCast(try memory.map(data.offset, data.size))))[0..data.size];

View File

@@ -2,7 +2,7 @@ const std = @import("std");
const vk = @import("vulkan");
pub const base = @import("base");
pub const Executor = @import("Executor.zig");
pub const Device = @import("device/Device.zig");
pub const SoftInstance = @import("SoftInstance.zig");
pub const SoftDevice = @import("SoftDevice.zig");
@@ -62,7 +62,7 @@ comptime {
}
test {
std.testing.refAllDecls(Executor);
std.testing.refAllDecls(Device);
std.testing.refAllDecls(SoftBinarySemaphore);
std.testing.refAllDecls(SoftBuffer);
std.testing.refAllDecls(SoftBufferView);