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
+201 -2
View File
@@ -247,6 +247,205 @@ The same rites apply as for the Soft build.
⚠️ Implemented, yet perchance not fully tested nor proven conformant, but rather working in a manner most general to thee and thine.\ ⚠️ Implemented, yet perchance not fully tested nor proven conformant, but rather working in a manner most general to thee and thine.\
Assume thou that functions lacking in this array are, for now, not intended to be wrought. Assume thou that functions lacking in this array are, for now, not intended to be wrought.
Name | Status
-------------------------------------------------|--------
vkAcquireNextImage2KHR | ⚙️ WIP
vkAcquireNextImageKHR | ⚙️ WIP
vkAllocateCommandBuffers | ✅ Implemented
vkAllocateDescriptorSets | ⚙️ WIP
vkAllocateMemory | ✅ Implemented
vkBeginCommandBuffer | ✅ Implemented
vkBindBufferMemory | ⚙️ WIP
vkBindImageMemory | ⚙️ WIP
vkCmdBeginQuery | ⚙️ WIP
vkCmdBeginRenderPass | ⚙️ WIP
vkCmdBindDescriptorSets | ⚙️ WIP
vkCmdBindIndexBuffer | ⚙️ WIP
vkCmdBindPipeline | ⚙️ WIP
vkCmdBindVertexBuffers | ⚙️ WIP
vkCmdBlitImage | ⚙️ WIP
vkCmdClearAttachments | ⚙️ WIP
vkCmdClearColorImage | ⚙️ WIP
vkCmdClearDepthStencilImage | ⚙️ WIP
vkCmdCopyBuffer | ✅ Implemented
vkCmdCopyBufferToImage | ⚙️ WIP
vkCmdCopyImage | ⚙️ WIP
vkCmdCopyImageToBuffer | ⚙️ WIP
vkCmdCopyQueryPoolResults | ⚙️ WIP
vkCmdDispatch | ⚙️ WIP
vkCmdDispatchBaseKHR | ⚙️ WIP
vkCmdDispatchIndirect | ⚙️ WIP
vkCmdDraw | ⚙️ WIP
vkCmdDrawIndexed | ⚙️ WIP
vkCmdDrawIndexedIndirect | ⚙️ WIP
vkCmdDrawIndirect | ⚙️ WIP
vkCmdEndQuery | ⚙️ WIP
vkCmdEndRenderPass | ⚙️ WIP
vkCmdExecuteCommands | ⚙️ WIP
vkCmdFillBuffer | ✅ Implemented
vkCmdNextSubpass | ⚙️ WIP
vkCmdPipelineBarrier | ⚙️ WIP
vkCmdPushConstants | ⚙️ WIP
vkCmdResetEvent | ⚙️ WIP
vkCmdResetQueryPool | ⚙️ WIP
vkCmdResolveImage | ⚙️ WIP
vkCmdSetBlendConstants | ⚙️ WIP
vkCmdSetDepthBias | ⚙️ WIP
vkCmdSetDepthBounds | ⚙️ WIP
vkCmdSetDeviceMaskKHR | ⚙️ WIP
vkCmdSetEvent | ⚙️ WIP
vkCmdSetLineWidth | ⚙️ WIP
vkCmdSetScissor | ⚙️ WIP
vkCmdSetStencilCompareMask | ⚙️ WIP
vkCmdSetStencilReference | ⚙️ WIP
vkCmdSetStencilWriteMask | ⚙️ WIP
vkCmdSetViewport | ⚙️ WIP
vkCmdUpdateBuffer | ⚙️ WIP
vkCmdWaitEvents | ⚙️ WIP
vkCmdWriteTimestamp | ⚙️ WIP
vkCreateBuffer | ⚙️ WIP
vkCreateBufferView | ⚙️ WIP
vkCreateCommandPool | ✅ Implemented
vkCreateComputePipelines | ⚙️ WIP
vkCreateDescriptorPool | ⚙️ WIP
vkCreateDescriptorSetLayout | ⚙️ WIP
vkCreateDevice | ✅ Implemented
vkCreateEvent | ⚙️ WIP
vkCreateFence | ⚙️ WIP
vkCreateFramebuffer | ⚙️ WIP
vkCreateGraphicsPipelines | ⚙️ WIP
vkCreateImage | ⚙️ WIP
vkCreateImageView | ⚙️ WIP
vkCreateInstance | ✅ Implemented
vkCreatePipelineCache | ⚙️ WIP
vkCreatePipelineLayout | ⚙️ WIP
vkCreateQueryPool | ⚙️ WIP
vkCreateRenderPass | ⚙️ WIP
vkCreateSampler | ⚙️ WIP
vkCreateSemaphore | ⚙️ WIP
vkCreateShaderModule | ⚙️ WIP
vkCreateSwapchainKHR | ⚙️ WIP
vkCreateWaylandSurfaceKHR | ⚙️ WIP
vkCreateWin32SurfaceKHR | ⚙️ WIP
vkCreateXcbSurfaceKHR | ⚙️ WIP
vkCreateXlibSurfaceKHR | ⚙️ WIP
vkDestroyBuffer | ⚙️ WIP
vkDestroyBufferView | ⚙️ WIP
vkDestroyCommandPool | ✅ Implemented
vkDestroyDescriptorPool | ⚙️ WIP
vkDestroyDescriptorSetLayout | ⚙️ WIP
vkDestroyDevice | ✅ Implemented
vkDestroyEvent | ⚙️ WIP
vkDestroyFence | ⚙️ WIP
vkDestroyFramebuffer | ⚙️ WIP
vkDestroyImage | ⚙️ WIP
vkDestroyImageView | ⚙️ WIP
vkDestroyInstance | ✅ Implemented
vkDestroyPipeline | ⚙️ WIP
vkDestroyPipelineCache | ⚙️ WIP
vkDestroyPipelineLayout | ⚙️ WIP
vkDestroyQueryPool | ⚙️ WIP
vkDestroyRenderPass | ⚙️ WIP
vkDestroySampler | ⚙️ WIP
vkDestroySemaphore | ⚙️ WIP
vkDestroyShaderModule | ⚙️ WIP
vkDestroySurfaceKHR | ⚙️ WIP
vkDestroySwapchainKHR | ⚙️ WIP
vkDeviceWaitIdle | ⚙️ WIP
vkEndCommandBuffer | ✅ Implemented
vkEnumerateDeviceExtensionProperties | ⚙️ WIP
vkEnumerateDeviceLayerProperties | ⚙️ WIP
vkEnumerateInstanceExtensionProperties | ⚙️ WIP
vkEnumerateInstanceLayerProperties | ⚙️ WIP
vkEnumeratePhysicalDeviceGroupsKHR | ⚙️ WIP
vkEnumeratePhysicalDevices | ✅ Implemented
vkFlushMappedMemoryRanges | ⚙️ WIP
vkFreeCommandBuffers | ⚙️ WIP
vkFreeDescriptorSets | ⚙️ WIP
vkFreeMemory | ✅ Implemented
vkGetBufferDeviceAddress | ⚙️ WIP
vkGetBufferDeviceAddressEXT | ⚙️ WIP
vkGetBufferDeviceAddressKHR | ⚙️ WIP
vkGetBufferMemoryRequirements | ⚙️ WIP
vkGetDeviceGroupPeerMemoryFeaturesKHR | ⚙️ WIP
vkGetDeviceGroupPresentCapabilitiesKHR | ⚙️ WIP
vkGetDeviceGroupSurfacePresentModesKHR | ⚙️ WIP
vkGetDeviceMemoryCommitment | ⚙️ WIP
vkGetDeviceProcAddr | ⚙️ WIP
vkGetDeviceQueue | ⚙️ WIP
vkGetEventStatus | ⚙️ WIP
vkGetFenceStatus | ⚙️ WIP
vkGetImageMemoryRequirements | ⚙️ WIP
vkGetImageSparseMemoryRequirements | ⚙️ WIP
vkGetImageSubresourceLayout | ⚙️ WIP
vkGetInstanceProcAddr | ⚙️ WIP
vkGetPhysicalDeviceFeatures | ✅ Implemented
vkGetPhysicalDeviceFormatProperties | ⚙️ WIP
vkGetPhysicalDeviceImageFormatProperties | ⚙️ WIP
vkGetPhysicalDeviceMemoryProperties | ✅ Implemented
vkGetPhysicalDeviceProperties | ✅ Implemented
vkGetPhysicalDeviceQueueFamilyProperties | ⚙️ WIP
vkGetPhysicalDeviceSparseImageFormatProperties | ⚙️ WIP
vkGetPhysicalDeviceSurfaceCapabilitiesKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfaceFormatsKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfacePresentModesKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfaceSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceWaylandPresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceWin32PresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceXcbPresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceXlibPresentationSupportKHR | ⚙️ WIP
vkGetPipelineCacheData | ⚙️ WIP
vkGetQueryPoolResults | ⚙️ WIP
vkGetRenderAreaGranularity | ⚙️ WIP
vkGetSwapchainImagesKHR | ⚙️ WIP
vkInvalidateMappedMemoryRanges | ⚙️ WIP
vkMapMemory | ⚙️ WIP
vkMergePipelineCaches | ⚙️ WIP
vkQueueBindSparse | ⚙️ WIP
vkQueuePresentKHR | ⚙️ WIP
vkQueueSubmit | ✅ Implemented
vkQueueWaitIdle | ⚙️ WIP
vkResetCommandBuffer | ⚙️ WIP
vkResetCommandPool | ✅ Implemented
vkResetDescriptorPool | ⚙️ WIP
vkResetEvent | ⚙️ WIP
vkResetFences | ⚙️ WIP
vkResetQueryPool | ⚙️ WIP
vkSetEvent | ⚙️ WIP
vkUnmapMemory | ⚙️ WIP
vkUpdateDescriptorSets | ⚙️ WIP
vkWaitForFences | ⚙️ WIP
</details>
## Flint [Intel(R)]
Flint be an implementation of the Vulkan specification, fashioned for the elder Intel iGPUs of generations 9 through 11.
Whether Haswell and those that followed-even the Xe kindred-shall one day partake of its workings remaineth unwritten.
### Build
If thou art truly determined:
```
zig build flint --release=[fast|safe|small]
```
And should thou seek additional build options with:
```
zig build --help
```
The same rites apply as for the Soft and Phi build.
#### Vulkan 1.0 specification
<details>
<summary>
Here standeth the present reckoning of thy Vulkan 1.0 implementation
</summary>
\
⚠️ Implemented, yet perchance not fully tested nor proven conformant, but rather working in a manner most general to thee and thine.\
Assume thou that functions lacking in this array are, for now, not intended to be wrought.
Name | Status Name | Status
-------------------------------------------------|-------- -------------------------------------------------|--------
vkAcquireNextImage2KHR | ⚙️ WIP vkAcquireNextImage2KHR | ⚙️ WIP
@@ -399,7 +598,7 @@ vkGetQueryPoolResults | ⚙️ WIP
vkGetRenderAreaGranularity | ⚙️ WIP vkGetRenderAreaGranularity | ⚙️ WIP
vkGetSwapchainImagesKHR | ⚙️ WIP vkGetSwapchainImagesKHR | ⚙️ WIP
vkInvalidateMappedMemoryRanges | ⚙️ WIP vkInvalidateMappedMemoryRanges | ⚙️ WIP
vkMapMemory | ⚙️ WIP vkMapMemory | ✅ Implemented
vkMergePipelineCaches | ⚙️ WIP vkMergePipelineCaches | ⚙️ WIP
vkQueueBindSparse | ⚙️ WIP vkQueueBindSparse | ⚙️ WIP
vkQueuePresentKHR | ⚙️ WIP vkQueuePresentKHR | ⚙️ WIP
@@ -412,7 +611,7 @@ vkResetEvent | ⚙️ WIP
vkResetFences | ⚙️ WIP vkResetFences | ⚙️ WIP
vkResetQueryPool | ⚙️ WIP vkResetQueryPool | ⚙️ WIP
vkSetEvent | ⚙️ WIP vkSetEvent | ⚙️ WIP
vkUnmapMemory | ⚙️ WIP vkUnmapMemory | ✅ Implemented
vkUpdateDescriptorSets | ⚙️ WIP vkUpdateDescriptorSets | ⚙️ WIP
vkWaitForFences | ⚙️ WIP vkWaitForFences | ⚙️ WIP
</details> </details>
+12 -2
View File
@@ -17,6 +17,8 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
errdefer allocator.destroy(self); errdefer allocator.destroy(self);
var interface = try Interface.init(device, allocator, info); var interface = try Interface.init(device, allocator, info);
interface.allowed_memory_types = std.bit_set.IntegerBitSet(32).initEmpty();
interface.allowed_memory_types.set(0);
interface.vtable = &.{ interface.vtable = &.{
.destroy = destroy, .destroy = destroy,
@@ -35,6 +37,14 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
} }
pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void { pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void {
_ = interface; requirements.alignment = 16;
_ = requirements; if (interface.usage.uniform_texel_buffer_bit or interface.usage.storage_texel_buffer_bit) {
requirements.alignment = @max(requirements.alignment, interface.owner.physical_device.props.limits.min_texel_buffer_offset_alignment);
}
if (interface.usage.storage_buffer_bit) {
requirements.alignment = @max(requirements.alignment, interface.owner.physical_device.props.limits.min_storage_buffer_offset_alignment);
}
if (interface.usage.uniform_buffer_bit) {
requirements.alignment = @max(requirements.alignment, interface.owner.physical_device.props.limits.min_uniform_buffer_offset_alignment);
}
} }
+139 -16
View File
@@ -3,11 +3,39 @@ const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const VkError = base.VkError; const VkError = base.VkError;
const FlintDevice = @import("FlintDevice.zig");
const FlintDeviceMemory = @import("FlintDeviceMemory.zig");
const kmd = @import("kmd.zig");
const Self = @This(); const Self = @This();
pub const Interface = base.CommandBuffer; 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, 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 { 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; 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, .writeTimestamp = writeTimestamp,
}; };
self.* = .{ .interface = interface }; self.* = .{
.interface = interface,
.batch = .empty,
.relocations = .empty,
};
return self; return self;
} }
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); 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); allocator.destroy(self);
} }
pub fn execute(self: *Self) VkError!void { pub fn submitGpuBatch(self: *Self) VkError!void {
try self.interface.submit(); 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 { 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 { pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!void {
_ = interface; const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = flags; 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 { 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 { pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, regions: []const vk.BufferCopy) VkError!void {
_ = interface; const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = src;
_ = dst; for (regions) |region| {
_ = regions; 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 { 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 { pub fn executeCommands(interface: *Interface, commands: *Interface) VkError!void {
_ = interface; const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = commands; 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 { pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void {
_ = interface; const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = buffer; const dst_range = try fillRange(buffer, offset, size);
_ = offset;
_ = size; var filled: vk.DeviceSize = 0;
_ = data; 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 { pub fn updateBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, data: []const u8) VkError!void {
+8
View File
@@ -3,6 +3,8 @@ const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const FlintQueue = @import("FlintQueue.zig"); const FlintQueue = @import("FlintQueue.zig");
const FlintPhysicalDevice = @import("FlintPhysicalDevice.zig");
const Kmd = @import("kmd.zig");
pub const FlintBinarySemaphore = @import("FlintBinarySemaphore.zig"); pub const FlintBinarySemaphore = @import("FlintBinarySemaphore.zig");
pub const FlintBuffer = @import("FlintBuffer.zig"); pub const FlintBuffer = @import("FlintBuffer.zig");
@@ -32,12 +34,16 @@ const Self = @This();
pub const Interface = base.Device; pub const Interface = base.Device;
interface: Interface, interface: Interface,
kmd: Kmd.Device,
pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self { pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
errdefer allocator.destroy(self); errdefer allocator.destroy(self);
var interface = try Interface.init(allocator, instance, physical_device, info); var interface = try Interface.init(allocator, instance, physical_device, info);
const flint_physical_device: *const FlintPhysicalDevice = @alignCast(@fieldParentPtr("interface", physical_device));
var kmd_device = try Kmd.Device.open(instance.io(), flint_physical_device);
errdefer kmd_device.close(instance.io());
interface.vtable = &.{ interface.vtable = &.{
.createQueue = FlintQueue.create, .createQueue = FlintQueue.create,
@@ -73,6 +79,7 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.kmd = kmd_device,
}; };
try self.interface.createQueues(allocator, info); try self.interface.createQueues(allocator, info);
@@ -81,6 +88,7 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
self.kmd.close(interface.io());
allocator.destroy(self); allocator.destroy(self);
} }
+28 -12
View File
@@ -1,9 +1,9 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const lib = @import("lib.zig");
const FlintDevice = @import("FlintDevice.zig"); const FlintDevice = @import("FlintDevice.zig");
const Kmd = @import("kmd.zig");
const VkError = base.VkError; const VkError = base.VkError;
@@ -11,12 +11,19 @@ const Self = @This();
pub const Interface = base.DeviceMemory; pub const Interface = base.DeviceMemory;
interface: Interface, interface: Interface,
allocation: Kmd.Memory,
pub fn create(device: *FlintDevice, allocator: std.mem.Allocator, size: vk.DeviceSize, memory_type_index: u32) VkError!*Self { pub fn create(device: *FlintDevice, allocator: std.mem.Allocator, size: vk.DeviceSize, memory_type_index: u32) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
errdefer allocator.destroy(self); errdefer allocator.destroy(self);
if (memory_type_index >= device.interface.physical_device.mem_props.memory_type_count) {
return VkError.ValidationFailed;
}
var interface = try Interface.init(&device.interface, size, memory_type_index); var interface = try Interface.init(&device.interface, size, memory_type_index);
var allocation = try device.kmd.allocateMemory(device.interface.io(), size);
errdefer allocation.deinit(&device.kmd, device.interface.io());
interface.vtable = &.{ interface.vtable = &.{
.destroy = destroy, .destroy = destroy,
@@ -28,33 +35,42 @@ pub fn create(device: *FlintDevice, allocator: std.mem.Allocator, size: vk.Devic
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.allocation = allocation,
}; };
return self; return self;
} }
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
self.allocation.deinit(&device.kmd, interface.owner.io());
allocator.destroy(self); allocator.destroy(self);
} }
pub fn flushRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { pub fn flushRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
_ = interface; const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = offset; const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
_ = size; try self.allocation.flushRange(&device.kmd, interface.owner.io(), offset, size);
} }
pub fn invalidateRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { pub fn invalidateRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
_ = interface; const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = offset; const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
_ = size; try self.allocation.invalidateRange(&device.kmd, interface.owner.io(), offset, size);
} }
pub fn map(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 { pub fn map(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = self; if (interface.is_mapped) return VkError.MemoryMapFailed;
_ = offset;
_ = size; const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
return VkError.Unknown; const data = try self.allocation.map(&device.kmd, interface.owner.io(), offset, size);
interface.is_mapped = true;
return data;
} }
pub fn unmap(_: *Interface) void {} pub fn unmap(interface: *Interface) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
self.allocation.unmap();
interface.is_mapped = false;
}
+8 -1
View File
@@ -25,12 +25,12 @@ fn castExtension(comptime ext: vk.ApiInfo) vk.ExtensionProperties {
} }
pub const EXTENSIONS = [_]vk.ExtensionProperties{ pub const EXTENSIONS = [_]vk.ExtensionProperties{
castExtension(vk.extensions.khr_device_group),
castExtension(vk.extensions.khr_swapchain), castExtension(vk.extensions.khr_swapchain),
}; };
interface: Interface, interface: Interface,
kmd_type: lib.KmdType, kmd_type: lib.KmdType,
node_path: [base.drm.max_node_name:0]u8,
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device: *const base.drm.Device, kmd_type: lib.KmdType) VkError!*Self { pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device: *const base.drm.Device, kmd_type: lib.KmdType) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
@@ -225,11 +225,18 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.kmd_type = kmd_type, .kmd_type = kmd_type,
.node_path = @splat(0),
}; };
const node_path = drm_device.nodePath();
@memcpy(self.node_path[0..node_path.len], node_path);
return self; return self;
} }
pub fn getNodePath(self: *const Self) [:0]const u8 {
return std.mem.sliceTo(&self.node_path, 0);
}
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
allocator.destroy(self); allocator.destroy(self);
+1 -1
View File
@@ -47,7 +47,7 @@ pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*bas
for (info.command_buffers.items) |command_buffer| { for (info.command_buffers.items) |command_buffer| {
const intel_command_buffer: *FlintCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); const intel_command_buffer: *FlintCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer));
_ = intel_command_buffer; try intel_command_buffer.submitGpuBatch();
} }
for (info.signal_semaphores.items) |semaphore| { for (info.signal_semaphores.items) |semaphore| {
+81
View File
@@ -0,0 +1,81 @@
const vk = @import("vulkan");
pub const command_base = 0x40;
pub const i915_gem_create = 0x1b;
pub const i915_gem_mmap_gtt = 0x24;
pub const i915_gem_set_domain = 0x1f;
pub const i915_gem_execbuffer2 = 0x29;
pub const i915_gem_wait = 0x2c;
pub const gem_close = 0x09;
pub const i915_mmap_offset_wb = 2;
pub const i915_gem_domain_cpu = 0x00000001;
pub const i915_gem_domain_gtt = 0x00000040;
pub const i915_exec_blt = 3 << 0;
pub const exec_object_write = 1 << 2;
pub const mi_flush_dw: u32 = (0x26 << 23) | 3;
pub const GemCreate = extern struct {
size: u64,
handle: u32,
pad: u32,
};
pub const GemMmapOffset = extern struct {
handle: u32,
pad: u32,
offset: u64,
flags: u64,
extensions: u64,
};
pub const GemClose = extern struct {
handle: u32,
pad: u32,
};
pub const GemSetDomain = extern struct {
handle: u32,
read_domains: u32,
write_domain: u32,
};
pub const RelocationEntry = extern struct {
target_handle: u32,
delta: u32,
offset: u64,
presumed_offset: u64,
read_domains: u32,
write_domain: u32,
};
pub const ExecObject2 = extern struct {
handle: u32,
relocation_count: u32,
relocs_ptr: u64,
alignment: u64,
offset: u64,
flags: u64,
rsvd1: u64,
rsvd2: u64,
};
pub const ExecBuffer2 = extern struct {
buffers_ptr: u64,
buffer_count: u32,
batch_start_offset: u32,
batch_len: u32,
DR1: u32,
DR4: u32,
num_cliprects: u32,
cliprects_ptr: u64,
flags: u64,
rsvd1: u64,
rsvd2: u64,
};
pub const GemWait = extern struct {
bo_handle: u32,
flags: u32,
timeout_ns: i64,
};
+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);
}
+144
View File
@@ -0,0 +1,144 @@
const std = @import("std");
const vk = @import("vulkan");
const base = @import("base");
const lib = @import("lib.zig");
const FlintPhysicalDevice = @import("FlintPhysicalDevice.zig");
const i915_kmd = @import("i915/kmd.zig");
const xe = @import("xe/kmd.zig");
const VkError = base.VkError;
pub const xy_src_copy_blt: u32 = (2 << 29) | (0x53 << 22) | 8;
pub const xy_blt_write_alpha: u32 = 1 << 21;
pub const xy_blt_write_rgb: u32 = 1 << 20;
pub const mi_store_data_imm_dword: u32 = (0x20 << 23) | 2;
pub const blt_depth_8: u32 = 0 << 24;
pub const rop_source_copy: u32 = 0xcc << 16;
pub const max_blt_span: vk.DeviceSize = 32 * 1024 - 1;
pub const Relocation = struct {
target_handle: u32,
offset: u64,
delta: u32,
read: bool = false,
write: bool = false,
};
pub const Device = union(lib.KmdType) {
Invalid: void,
I915: i915_kmd.Device,
Xe: xe.Device,
pub fn open(io: std.Io, physical_device: *const FlintPhysicalDevice) VkError!Device {
return switch (physical_device.kmd_type) {
.I915 => .{ .I915 = try i915_kmd.Device.open(io, physical_device.getNodePath()) },
.Xe => .{ .Xe = try xe.Device.open(io, physical_device.getNodePath()) },
.Invalid => VkError.InitializationFailed,
};
}
pub fn close(self: *Device, io: std.Io) void {
switch (self.*) {
.I915 => |*device| device.close(io),
.Xe => |*device| device.close(io),
.Invalid => {},
}
self.* = .{ .Invalid = {} };
}
pub fn allocateMemory(self: *Device, io: std.Io, size: vk.DeviceSize) VkError!Memory {
return switch (self.*) {
.I915 => |*device| .{ .I915 = try device.allocateMemory(io, size) },
.Xe => |*device| .{ .Xe = try device.allocateMemory(io, size) },
.Invalid => VkError.OutOfDeviceMemory,
};
}
pub fn submitBatch(self: *Device, io: std.Io, allocator: std.mem.Allocator, commands: []const u32, relocations: []const Relocation) VkError!void {
return switch (self.*) {
.I915 => |*device| device.submitBatch(io, allocator, commands, relocations),
.Xe => |*device| device.submitBatch(io, allocator, commands, relocations),
.Invalid => VkError.DeviceLost,
};
}
};
pub const Memory = union(lib.KmdType) {
Invalid: void,
I915: i915_kmd.Memory,
Xe: xe.Memory,
pub fn deinit(self: *Memory, device: *Device, io: std.Io) void {
switch (self.*) {
.I915 => |*memory| switch (device.*) {
.I915 => |*adapter| memory.deinit(adapter, io),
else => {},
},
.Xe => |*memory| switch (device.*) {
.Xe => |*adapter| memory.deinit(adapter, io),
else => {},
},
.Invalid => {},
}
self.* = .{ .Invalid = {} };
}
pub fn map(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
return switch (self.*) {
.I915 => |*memory| switch (device.*) {
.I915 => |*adapter| memory.map(adapter, io, offset, size),
else => VkError.MemoryMapFailed,
},
.Xe => |*memory| switch (device.*) {
.Xe => |*adapter| memory.map(adapter, io, offset, size),
else => VkError.MemoryMapFailed,
},
.Invalid => VkError.MemoryMapFailed,
};
}
pub fn unmap(self: *Memory) void {
switch (self.*) {
.I915 => |*memory| memory.unmap(),
.Xe => |*memory| memory.unmap(),
.Invalid => {},
}
}
pub fn flushRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
return switch (self.*) {
.I915 => |*memory| switch (device.*) {
.I915 => |*adapter| memory.flushRange(adapter, io, offset, size),
else => VkError.InvalidDeviceMemoryDrv,
},
.Xe => |*memory| switch (device.*) {
.Xe => |*adapter| memory.flushRange(adapter, io, offset, size),
else => VkError.InvalidDeviceMemoryDrv,
},
.Invalid => VkError.InvalidDeviceMemoryDrv,
};
}
pub fn invalidateRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
return switch (self.*) {
.I915 => |*memory| switch (device.*) {
.I915 => |*adapter| memory.invalidateRange(adapter, io, offset, size),
else => VkError.InvalidDeviceMemoryDrv,
},
.Xe => |*memory| switch (device.*) {
.Xe => |*adapter| memory.invalidateRange(adapter, io, offset, size),
else => VkError.InvalidDeviceMemoryDrv,
},
.Invalid => VkError.InvalidDeviceMemoryDrv,
};
}
pub fn handle(self: *const Memory) VkError!u32 {
return switch (self.*) {
.I915 => |*memory| memory.handle,
.Xe => VkError.FeatureNotPresent,
.Invalid => VkError.InvalidDeviceMemoryDrv,
};
}
};
+2
View File
@@ -9,6 +9,7 @@ pub const FlintInstance = @import("FlintInstance.zig");
pub const FlintDevice = @import("FlintDevice.zig"); pub const FlintDevice = @import("FlintDevice.zig");
pub const FlintPhysicalDevice = @import("FlintPhysicalDevice.zig"); pub const FlintPhysicalDevice = @import("FlintPhysicalDevice.zig");
pub const FlintQueue = @import("FlintQueue.zig"); pub const FlintQueue = @import("FlintQueue.zig");
pub const kmd = @import("kmd.zig");
pub const FlintBinarySemaphore = @import("FlintBinarySemaphore.zig"); pub const FlintBinarySemaphore = @import("FlintBinarySemaphore.zig");
pub const FlintBuffer = @import("FlintBuffer.zig"); pub const FlintBuffer = @import("FlintBuffer.zig");
@@ -85,5 +86,6 @@ test {
std.testing.refAllDecls(FlintRenderPass); std.testing.refAllDecls(FlintRenderPass);
std.testing.refAllDecls(FlintSampler); std.testing.refAllDecls(FlintSampler);
std.testing.refAllDecls(FlintShaderModule); std.testing.refAllDecls(FlintShaderModule);
std.testing.refAllDecls(kmd);
std.testing.refAllDecls(base); std.testing.refAllDecls(base);
} }
+49
View File
@@ -0,0 +1,49 @@
const std = @import("std");
const vk = @import("vulkan");
const base = @import("base");
const VkError = base.VkError;
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(_: *Device, _: std.Io, _: vk.DeviceSize) VkError!Memory {
return VkError.OutOfDeviceMemory;
}
pub fn submitBatch(_: *Device, _: std.Io, _: std.mem.Allocator, _: []const u32, _: []const @import("../kmd.zig").Relocation) VkError!void {
return VkError.FeatureNotPresent;
}
};
pub const Memory = struct {
pub fn deinit(_: *Memory, _: *Device, _: std.Io) void {}
pub fn map(_: *Memory, _: *Device, _: std.Io, _: vk.DeviceSize, _: vk.DeviceSize) VkError![]u8 {
return VkError.MemoryMapFailed;
}
pub fn unmap(_: *Memory) void {}
pub fn flushRange(_: *Memory, _: *Device, _: std.Io, _: vk.DeviceSize, _: vk.DeviceSize) VkError!void {
return VkError.FeatureNotPresent;
}
pub fn invalidateRange(_: *Memory, _: *Device, _: std.Io, _: vk.DeviceSize, _: vk.DeviceSize) VkError!void {
return VkError.FeatureNotPresent;
}
};
test {
std.testing.refAllDecls(@This());
}
+4 -4
View File
@@ -39,21 +39,21 @@ pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void {
self.vtable.destroy(self, allocator); self.vtable.destroy(self, allocator);
} }
pub inline fn bindMemory(self: *Self, memory: *DeviceMemory, offset: vk.DeviceSize) VkError!void { pub fn bindMemory(self: *Self, memory: *DeviceMemory, offset: vk.DeviceSize) VkError!void {
if (offset > memory.size or !self.allowed_memory_types.isSet(memory.memory_type_index)) { if (offset > memory.size or self.size > memory.size - offset or !self.allowed_memory_types.isSet(memory.memory_type_index)) {
return VkError.ValidationFailed; return VkError.ValidationFailed;
} }
self.memory = memory; self.memory = memory;
self.offset = offset; self.offset = offset;
} }
pub inline fn getMemoryRequirements(self: *Self, requirements: *vk.MemoryRequirements) void { pub fn getMemoryRequirements(self: *Self, requirements: *vk.MemoryRequirements) void {
requirements.size = self.size; requirements.size = self.size;
requirements.memory_type_bits = self.allowed_memory_types.mask; requirements.memory_type_bits = self.allowed_memory_types.mask;
self.vtable.getMemoryRequirements(self, requirements); self.vtable.getMemoryRequirements(self, requirements);
} }
pub inline fn getDeviceAddress(self: *Self) VkError!vk.DeviceAddress { pub fn getDeviceAddress(self: *Self) VkError!vk.DeviceAddress {
const memory = self.memory orelse return 0; const memory = self.memory orelse return 0;
const map = try memory.map(self.offset, self.size); const map = try memory.map(self.offset, self.size);
return @intCast(@intFromPtr(map.ptr)); return @intCast(@intFromPtr(map.ptr));
+18
View File
@@ -28,3 +28,21 @@ pub fn writePacked(comptime T: type, bytes: []u8, value: T) void {
const raw: [@sizeOf(T)]u8 = @bitCast(value); const raw: [@sizeOf(T)]u8 = @bitCast(value);
@memcpy(bytes[0..@sizeOf(T)], raw[0..]); @memcpy(bytes[0..@sizeOf(T)], raw[0..]);
} }
pub fn ioctl(file: std.Io.File, io: std.Io, request: u32, arg: ?*anyopaque) (std.Io.Cancelable || std.posix.UnexpectedError)!void {
const result = try io.operate(.{ .device_io_control = .{
.file = file,
.code = request,
.arg = arg,
} });
const rc = if (@import("builtin").link_libc)
@as(c_int, @intCast(result.device_io_control))
else
@as(usize, @bitCast(@as(isize, @intCast(result.device_io_control))));
return switch (std.posix.errno(rc)) {
.SUCCESS => {},
else => |e| std.posix.unexpectedErrno(e),
};
}