implementing device creation, device memory, basic buffers copy and buffers fill in Flint
Test / build_and_test (push) Successful in 4m51s
Build / build (push) Successful in 6m44s

This commit is contained in:
2026-07-10 00:19:29 +02:00
parent 3044bb37a5
commit 0224b5675f
14 changed files with 935 additions and 38 deletions
+139 -16
View File
@@ -3,11 +3,39 @@ const vk = @import("vulkan");
const base = @import("base");
const VkError = base.VkError;
const FlintDevice = @import("FlintDevice.zig");
const FlintDeviceMemory = @import("FlintDeviceMemory.zig");
const kmd = @import("kmd.zig");
const Self = @This();
pub const Interface = base.CommandBuffer;
const BufferRange = struct {
memory: *FlintDeviceMemory,
offset: vk.DeviceSize,
size: vk.DeviceSize,
fn init(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!BufferRange {
const base_memory = buffer.memory orelse return VkError.InvalidDeviceMemoryDrv;
const memory: *FlintDeviceMemory = @alignCast(@fieldParentPtr("interface", base_memory));
const bound, const bound_overflow = @addWithOverflow(offset, size);
if (bound_overflow != 0 or bound > buffer.size) return VkError.ValidationFailed;
const memory_offset, const memory_offset_overflow = @addWithOverflow(buffer.offset, offset);
if (memory_offset_overflow != 0) return VkError.ValidationFailed;
return .{
.memory = memory,
.offset = memory_offset,
.size = size,
};
}
};
interface: Interface,
batch: std.ArrayList(u32),
relocations: std.ArrayList(kmd.Relocation),
pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.CommandBufferAllocateInfo) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
@@ -67,18 +95,64 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
.writeTimestamp = writeTimestamp,
};
self.* = .{ .interface = interface };
self.* = .{
.interface = interface,
.batch = .empty,
.relocations = .empty,
};
return self;
}
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const command_allocator = self.interface.host_allocator.allocator();
self.batch.deinit(command_allocator);
self.relocations.deinit(command_allocator);
allocator.destroy(self);
}
pub fn execute(self: *Self) VkError!void {
pub fn submitGpuBatch(self: *Self) VkError!void {
try self.interface.submit();
self.interface.finish() catch {};
defer self.interface.finish() catch {};
if (self.batch.items.len == 0) return;
const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", self.interface.owner));
const allocator = self.interface.host_allocator.allocator();
try device.kmd.submitBatch(self.interface.owner.io(), allocator, self.batch.items, self.relocations.items);
}
fn emit(self: *Self, dword: u32) VkError!void {
self.batch.append(self.interface.host_allocator.allocator(), dword) catch return VkError.OutOfHostMemory;
}
fn emitRelocatedAddress(self: *Self, range: BufferRange, read: bool, write: bool) VkError!void {
const address_offset = self.batch.items.len * @sizeOf(u32);
try self.emit(@intCast(range.offset));
try self.emit(0);
self.relocations.append(self.interface.host_allocator.allocator(), .{
.target_handle = try range.memory.allocation.handle(),
.offset = @intCast(address_offset),
.delta = @intCast(range.offset),
.read = read,
.write = write,
}) catch return VkError.OutOfHostMemory;
}
fn copyRangeFromRegion(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!BufferRange {
return BufferRange.init(buffer, offset, size);
}
fn fillRange(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!BufferRange {
const resolved_size = if (size == vk.WHOLE_SIZE) blk: {
if (offset > buffer.size) return VkError.ValidationFailed;
break :blk std.mem.alignBackward(vk.DeviceSize, buffer.size - offset, @sizeOf(u32));
} else blk: {
if (size % @sizeOf(u32) != 0) return VkError.ValidationFailed;
break :blk size;
};
return BufferRange.init(buffer, offset, resolved_size);
}
pub fn begin(interface: *Interface, info: *const vk.CommandBufferBeginInfo) VkError!void {
@@ -91,8 +165,15 @@ pub fn end(interface: *Interface) VkError!void {
}
pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!void {
_ = interface;
_ = flags;
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
if (flags.release_resources_bit) {
const command_allocator = self.interface.host_allocator.allocator();
self.batch.clearAndFree(command_allocator);
self.relocations.clearAndFree(command_allocator);
} else {
self.batch.clearRetainingCapacity();
self.relocations.clearRetainingCapacity();
}
}
pub fn beginQuery(interface: *Interface, pool: *base.QueryPool, query: u32, flags: vk.QueryControlFlags) VkError!void {
@@ -180,10 +261,31 @@ pub fn clearDepthStencilImage(interface: *Interface, image: *base.Image, layout:
}
pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, regions: []const vk.BufferCopy) VkError!void {
_ = interface;
_ = src;
_ = dst;
_ = regions;
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
for (regions) |region| {
const src_range = try copyRangeFromRegion(src, region.src_offset, region.size);
const dst_range = try copyRangeFromRegion(dst, region.dst_offset, region.size);
var copied: vk.DeviceSize = 0;
while (copied < src_range.size) {
const chunk = @min(src_range.size - copied, kmd.max_blt_span);
const src_chunk: BufferRange = .{ .memory = src_range.memory, .offset = src_range.offset + copied, .size = chunk };
const dst_chunk: BufferRange = .{ .memory = dst_range.memory, .offset = dst_range.offset + copied, .size = chunk };
const width: u32 = @intCast(chunk);
try self.emit(kmd.xy_src_copy_blt | kmd.xy_blt_write_alpha | kmd.xy_blt_write_rgb);
try self.emit(kmd.blt_depth_8 | kmd.rop_source_copy | width);
try self.emit(0);
try self.emit((1 << 16) | width);
try self.emitRelocatedAddress(dst_chunk, false, true);
try self.emit(0);
try self.emit(width);
try self.emitRelocatedAddress(src_chunk, true, false);
copied += chunk;
}
}
}
pub fn copyBufferToImage(interface: *Interface, src: *base.Buffer, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.BufferImageCopy) VkError!void {
@@ -288,16 +390,37 @@ pub fn endRenderPass(interface: *Interface) VkError!void {
}
pub fn executeCommands(interface: *Interface, commands: *Interface) VkError!void {
_ = interface;
_ = commands;
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const secondary: *Self = @alignCast(@fieldParentPtr("interface", commands));
const allocator = self.interface.host_allocator.allocator();
const relocation_offset = self.batch.items.len * @sizeOf(u32);
self.batch.appendSlice(allocator, secondary.batch.items) catch return VkError.OutOfHostMemory;
for (secondary.relocations.items) |relocation| {
self.relocations.append(allocator, .{
.target_handle = relocation.target_handle,
.offset = relocation.offset + relocation_offset,
.delta = relocation.delta,
.read = relocation.read,
.write = relocation.write,
}) catch return VkError.OutOfHostMemory;
}
}
pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void {
_ = interface;
_ = buffer;
_ = offset;
_ = size;
_ = data;
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const dst_range = try fillRange(buffer, offset, size);
var filled: vk.DeviceSize = 0;
while (filled < dst_range.size) {
const dst_chunk: BufferRange = .{ .memory = dst_range.memory, .offset = dst_range.offset + filled, .size = @sizeOf(u32) };
try self.emit(kmd.mi_store_data_imm_dword);
try self.emitRelocatedAddress(dst_chunk, false, true);
try self.emit(data);
filled += @sizeOf(u32);
}
}
pub fn updateBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, data: []const u8) VkError!void {