implementing device creation, device memory, basic buffers copy and buffers fill in Flint
This commit is contained in:
@@ -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.\
|
||||
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
|
||||
-------------------------------------------------|--------
|
||||
vkAcquireNextImage2KHR | ⚙️ WIP
|
||||
@@ -399,7 +598,7 @@ vkGetQueryPoolResults | ⚙️ WIP
|
||||
vkGetRenderAreaGranularity | ⚙️ WIP
|
||||
vkGetSwapchainImagesKHR | ⚙️ WIP
|
||||
vkInvalidateMappedMemoryRanges | ⚙️ WIP
|
||||
vkMapMemory | ⚙️ WIP
|
||||
vkMapMemory | ✅ Implemented
|
||||
vkMergePipelineCaches | ⚙️ WIP
|
||||
vkQueueBindSparse | ⚙️ WIP
|
||||
vkQueuePresentKHR | ⚙️ WIP
|
||||
@@ -412,7 +611,7 @@ vkResetEvent | ⚙️ WIP
|
||||
vkResetFences | ⚙️ WIP
|
||||
vkResetQueryPool | ⚙️ WIP
|
||||
vkSetEvent | ⚙️ WIP
|
||||
vkUnmapMemory | ⚙️ WIP
|
||||
vkUnmapMemory | ✅ Implemented
|
||||
vkUpdateDescriptorSets | ⚙️ WIP
|
||||
vkWaitForFences | ⚙️ WIP
|
||||
</details>
|
||||
|
||||
@@ -17,6 +17,8 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
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 = &.{
|
||||
.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 {
|
||||
_ = interface;
|
||||
_ = requirements;
|
||||
requirements.alignment = 16;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -3,6 +3,8 @@ const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
|
||||
const FlintQueue = @import("FlintQueue.zig");
|
||||
const FlintPhysicalDevice = @import("FlintPhysicalDevice.zig");
|
||||
const Kmd = @import("kmd.zig");
|
||||
|
||||
pub const FlintBinarySemaphore = @import("FlintBinarySemaphore.zig");
|
||||
pub const FlintBuffer = @import("FlintBuffer.zig");
|
||||
@@ -32,12 +34,16 @@ const Self = @This();
|
||||
pub const Interface = base.Device;
|
||||
|
||||
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 {
|
||||
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
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 = &.{
|
||||
.createQueue = FlintQueue.create,
|
||||
@@ -73,6 +79,7 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
|
||||
|
||||
self.* = .{
|
||||
.interface = interface,
|
||||
.kmd = kmd_device,
|
||||
};
|
||||
|
||||
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 {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
self.kmd.close(interface.io());
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const lib = @import("lib.zig");
|
||||
|
||||
const FlintDevice = @import("FlintDevice.zig");
|
||||
const Kmd = @import("kmd.zig");
|
||||
|
||||
const VkError = base.VkError;
|
||||
|
||||
@@ -11,12 +11,19 @@ const Self = @This();
|
||||
pub const Interface = base.DeviceMemory;
|
||||
|
||||
interface: Interface,
|
||||
allocation: Kmd.Memory,
|
||||
|
||||
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;
|
||||
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 allocation = try device.kmd.allocateMemory(device.interface.io(), size);
|
||||
errdefer allocation.deinit(&device.kmd, device.interface.io());
|
||||
|
||||
interface.vtable = &.{
|
||||
.destroy = destroy,
|
||||
@@ -28,33 +35,42 @@ pub fn create(device: *FlintDevice, allocator: std.mem.Allocator, size: vk.Devic
|
||||
|
||||
self.* = .{
|
||||
.interface = interface,
|
||||
.allocation = allocation,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn flushRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
|
||||
_ = interface;
|
||||
_ = offset;
|
||||
_ = size;
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
|
||||
try self.allocation.flushRange(&device.kmd, interface.owner.io(), offset, size);
|
||||
}
|
||||
|
||||
pub fn invalidateRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void {
|
||||
_ = interface;
|
||||
_ = offset;
|
||||
_ = size;
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
|
||||
try self.allocation.invalidateRange(&device.kmd, interface.owner.io(), offset, size);
|
||||
}
|
||||
|
||||
pub fn map(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
_ = self;
|
||||
_ = offset;
|
||||
_ = size;
|
||||
return VkError.Unknown;
|
||||
if (interface.is_mapped) return VkError.MemoryMapFailed;
|
||||
|
||||
const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -25,12 +25,12 @@ fn castExtension(comptime ext: vk.ApiInfo) vk.ExtensionProperties {
|
||||
}
|
||||
|
||||
pub const EXTENSIONS = [_]vk.ExtensionProperties{
|
||||
castExtension(vk.extensions.khr_device_group),
|
||||
castExtension(vk.extensions.khr_swapchain),
|
||||
};
|
||||
|
||||
interface: Interface,
|
||||
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 {
|
||||
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.* = .{
|
||||
.interface = interface,
|
||||
.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;
|
||||
}
|
||||
|
||||
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 {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
allocator.destroy(self);
|
||||
|
||||
@@ -47,7 +47,7 @@ pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*bas
|
||||
|
||||
for (info.command_buffers.items) |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| {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -9,6 +9,7 @@ pub const FlintInstance = @import("FlintInstance.zig");
|
||||
pub const FlintDevice = @import("FlintDevice.zig");
|
||||
pub const FlintPhysicalDevice = @import("FlintPhysicalDevice.zig");
|
||||
pub const FlintQueue = @import("FlintQueue.zig");
|
||||
pub const kmd = @import("kmd.zig");
|
||||
|
||||
pub const FlintBinarySemaphore = @import("FlintBinarySemaphore.zig");
|
||||
pub const FlintBuffer = @import("FlintBuffer.zig");
|
||||
@@ -85,5 +86,6 @@ test {
|
||||
std.testing.refAllDecls(FlintRenderPass);
|
||||
std.testing.refAllDecls(FlintSampler);
|
||||
std.testing.refAllDecls(FlintShaderModule);
|
||||
std.testing.refAllDecls(kmd);
|
||||
std.testing.refAllDecls(base);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -39,21 +39,21 @@ pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void {
|
||||
self.vtable.destroy(self, allocator);
|
||||
}
|
||||
|
||||
pub inline 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)) {
|
||||
pub fn bindMemory(self: *Self, memory: *DeviceMemory, offset: vk.DeviceSize) VkError!void {
|
||||
if (offset > memory.size or self.size > memory.size - offset or !self.allowed_memory_types.isSet(memory.memory_type_index)) {
|
||||
return VkError.ValidationFailed;
|
||||
}
|
||||
self.memory = memory;
|
||||
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.memory_type_bits = self.allowed_memory_types.mask;
|
||||
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 map = try memory.map(self.offset, self.size);
|
||||
return @intCast(@intFromPtr(map.ptr));
|
||||
|
||||
@@ -28,3 +28,21 @@ pub fn writePacked(comptime T: type, bytes: []u8, value: T) void {
|
||||
const raw: [@sizeOf(T)]u8 = @bitCast(value);
|
||||
@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),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user