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
+240
View File
@@ -0,0 +1,240 @@
const std = @import("std");
const vk = @import("vulkan");
const base = @import("base");
const drm = @import("drm.zig");
const common_kmd = @import("../kmd.zig");
const VkError = base.VkError;
const IOCTL = std.os.linux.IOCTL;
const Mapping = struct {
bytes: []align(std.heap.page_size_min) u8,
inline fn slice(self: Mapping, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
const start: usize = @intCast(offset);
const len: usize = @intCast(size);
return self.bytes[start .. start + len];
}
};
pub const Device = struct {
card: base.drm.Card,
pub fn open(io: std.Io, node_path: []const u8) VkError!Device {
return .{
.card = base.drm.Card.open(io, node_path) catch return VkError.InitializationFailed,
};
}
pub fn close(self: *Device, io: std.Io) void {
self.card.close(io);
}
pub fn allocateMemory(self: *Device, io: std.Io, size: vk.DeviceSize) VkError!Memory {
var create = drm.GemCreate{
.size = size,
.handle = 0,
.pad = 0,
};
base.utils.ioctl(self.card.handle, io, drmIoctlIowr(drm.command_base + drm.i915_gem_create, drm.GemCreate), &create) catch return VkError.OutOfDeviceMemory;
var memory = Memory{
.handle = create.handle,
.size = create.size,
.mapping = null,
};
errdefer memory.deinit(self, io);
try memory.setDomain(self, io, drm.i915_gem_domain_cpu, 0);
return memory;
}
pub fn submitBatch(self: *Device, io: std.Io, allocator: std.mem.Allocator, commands: []const u32, relocations: []const common_kmd.Relocation) VkError!void {
const trailer_words = 6;
const batch_size = (commands.len + trailer_words) * @sizeOf(u32);
var batch = try self.allocateMemory(io, batch_size);
defer batch.deinit(self, io);
{
const batch_map = try batch.map(self, io, 0, batch_size);
const batch_words = std.mem.bytesAsSlice(u32, batch_map);
@memcpy(batch_words[0..commands.len], commands);
batch_words[commands.len + 0] = drm.mi_flush_dw;
batch_words[commands.len + 1] = 0;
batch_words[commands.len + 2] = 0;
batch_words[commands.len + 3] = 0;
batch_words[commands.len + 4] = 0;
batch_words[commands.len + 5] = 0x05000000;
batch.unmap();
}
try batch.flushRange(self, io, 0, batch_size);
var objects = std.ArrayList(drm.ExecObject2).empty;
defer objects.deinit(allocator);
var object_handles = std.ArrayList(u32).empty;
defer object_handles.deinit(allocator);
for (relocations) |relocation| {
if (std.mem.indexOfScalar(u32, object_handles.items, relocation.target_handle) == null) {
object_handles.append(allocator, relocation.target_handle) catch return VkError.OutOfHostMemory;
objects.append(allocator, .{
.handle = relocation.target_handle,
.relocation_count = 0,
.relocs_ptr = 0,
.alignment = 0,
.offset = 0,
.flags = if (relocation.write) drm.exec_object_write else 0,
.rsvd1 = 0,
.rsvd2 = 0,
}) catch return VkError.OutOfHostMemory;
} else if (relocation.write) {
const index = std.mem.indexOfScalar(u32, object_handles.items, relocation.target_handle).?;
objects.items[index].flags |= drm.exec_object_write;
}
}
var i915_relocations = std.ArrayList(drm.RelocationEntry).empty;
defer i915_relocations.deinit(allocator);
for (relocations) |relocation| {
i915_relocations.append(allocator, .{
.target_handle = relocation.target_handle,
.delta = relocation.delta,
.offset = relocation.offset,
.presumed_offset = 0,
.read_domains = 0,
.write_domain = 0,
}) catch return VkError.OutOfHostMemory;
}
objects.append(allocator, .{
.handle = batch.handle,
.relocation_count = @intCast(i915_relocations.items.len),
.relocs_ptr = @intFromPtr(i915_relocations.items.ptr),
.alignment = 0,
.offset = 0,
.flags = 0,
.rsvd1 = 0,
.rsvd2 = 0,
}) catch return VkError.OutOfHostMemory;
var execbuffer = drm.ExecBuffer2{
.buffers_ptr = @intFromPtr(objects.items.ptr),
.buffer_count = @intCast(objects.items.len),
.batch_start_offset = 0,
.batch_len = @intCast(batch_size),
.DR1 = 0,
.DR4 = 0,
.num_cliprects = 0,
.cliprects_ptr = 0,
.flags = drm.i915_exec_blt,
.rsvd1 = 0,
.rsvd2 = 0,
};
base.utils.ioctl(self.card.handle, io, drmIoctlIowr(drm.command_base + drm.i915_gem_execbuffer2, drm.ExecBuffer2), &execbuffer) catch return VkError.DeviceLost;
for (object_handles.items) |handle| {
const object = objects.items[std.mem.indexOfScalar(u32, object_handles.items, handle).?];
if (object.flags & drm.exec_object_write == 0) continue;
var wait = drm.GemWait{
.bo_handle = handle,
.flags = 0,
.timeout_ns = -1,
};
base.utils.ioctl(self.card.handle, io, drmIoctlIowr(drm.command_base + drm.i915_gem_wait, drm.GemWait), &wait) catch return VkError.DeviceLost;
}
}
};
pub const Memory = struct {
handle: u32,
size: vk.DeviceSize,
mapping: ?Mapping,
pub fn deinit(self: *Memory, device: *Device, io: std.Io) void {
self.unmap();
var close = drm.GemClose{
.handle = self.handle,
.pad = 0,
};
base.utils.ioctl(device.card.handle, io, drmIoctlIow(drm.gem_close, drm.GemClose), &close) catch {};
self.* = undefined;
}
pub fn map(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
if (offset > self.size) return VkError.MemoryMapFailed;
const available = self.size - offset;
const map_size = if (size == vk.WHOLE_SIZE) available else size;
if (map_size > available) return VkError.MemoryMapFailed;
if (map_size > std.math.maxInt(usize)) return VkError.MemoryMapFailed;
if (self.mapping) |mapping| {
return mapping.slice(offset, map_size);
}
var mmap_offset = drm.GemMmapOffset{
.handle = self.handle,
.pad = 0,
.offset = 0,
.flags = drm.i915_mmap_offset_wb,
.extensions = 0,
};
base.utils.ioctl(device.card.handle, io, drmIoctlIowr(drm.command_base + drm.i915_gem_mmap_gtt, drm.GemMmapOffset), &mmap_offset) catch return VkError.MemoryMapFailed;
if (self.size > std.math.maxInt(usize)) return VkError.MemoryMapFailed;
const full_size: usize = @intCast(self.size);
const bytes = std.posix.mmap(
null,
full_size,
.{ .READ = true, .WRITE = true },
.{ .TYPE = .SHARED },
device.card.handle.handle,
@intCast(mmap_offset.offset),
) catch return VkError.MemoryMapFailed;
self.mapping = .{ .bytes = bytes };
return self.mapping.?.slice(offset, map_size);
}
pub fn unmap(self: *Memory) void {
if (self.mapping) |mapping| {
std.posix.munmap(mapping.bytes);
self.mapping = null;
}
}
pub fn flushRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
_ = offset;
_ = size;
try self.setDomain(device, io, drm.i915_gem_domain_cpu, 0);
}
pub fn invalidateRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
_ = offset;
_ = size;
try self.setDomain(device, io, drm.i915_gem_domain_cpu, 0);
}
fn setDomain(self: *Memory, device: *Device, io: std.Io, read_domains: u32, write_domain: u32) VkError!void {
var domain = drm.GemSetDomain{
.handle = self.handle,
.read_domains = read_domains,
.write_domain = write_domain,
};
base.utils.ioctl(device.card.handle, io, drmIoctlIow(drm.command_base + drm.i915_gem_set_domain, drm.GemSetDomain), &domain) catch return VkError.DeviceLost;
}
};
inline fn drmIoctlIow(nr: u8, comptime T: type) u32 {
return IOCTL.IOW('d', nr, T);
}
inline fn drmIoctlIowr(nr: u8, comptime T: type) u32 {
return IOCTL.IOWR('d', nr, T);
}