diff --git a/.gitea/workflows/Build.yml b/.gitea/workflows/Build.yml index 221fb9e..0a527a9 100644 --- a/.gitea/workflows/Build.yml +++ b/.gitea/workflows/Build.yml @@ -27,6 +27,9 @@ jobs: - name: Building Flint run: zig build flint + - name: Building Phi + run: zig build phi + - name: Generating docs run: zig build docs diff --git a/.gitea/workflows/Test.yml b/.gitea/workflows/Test.yml index 9fafbee..1475fe1 100644 --- a/.gitea/workflows/Test.yml +++ b/.gitea/workflows/Test.yml @@ -23,3 +23,6 @@ jobs: - name: Flint Tests run: zig build test-flint + + - name: Phi Tests + run: zig build test-phi diff --git a/build.zig b/build.zig index 95623fe..69a8968 100644 --- a/build.zig +++ b/build.zig @@ -45,6 +45,13 @@ const implementations = [_]ImplementationDesc{ .custom = customFlint, .options = optionsFlint, }, + .{ + .name = "phi", + .root_source_file = "src/phi/lib.zig", + .vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 }, + .custom = customPhi, + .options = optionsPhi, + }, }; const RunningMode = enum { @@ -291,8 +298,6 @@ fn customFlint( _: bool, ) !void { lib_mod.addImport("intel_c", base_c_mod); - - lib_mod.addImport("soft_c", base_c_mod); } fn optionsFlint(b: *std.Build, options: *Step.Options) !void { @@ -300,6 +305,25 @@ fn optionsFlint(b: *std.Build, options: *Step.Options) !void { _ = options; } +fn customPhi( + _: *std.Build, + _: *Step.Compile, + lib_mod: *std.Build.Module, + _: *std.Build.Module, + _: *std.Build.Module, + base_c_mod: *std.Build.Module, + _: std.Build.ResolvedTarget, + _: std.builtin.OptimizeMode, + _: bool, +) !void { + lib_mod.addImport("phi_c", base_c_mod); +} + +fn optionsPhi(b: *std.Build, options: *Step.Options) !void { + _ = b; + _ = options; +} + fn addCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *const ImplementationDesc, impl_lib: *Step.Compile, comptime mode: RunningMode) !*Step { const cts = b.dependency("cts_bin", .{}); diff --git a/src/phi/PhiBinarySemaphore.zig b/src/phi/PhiBinarySemaphore.zig new file mode 100644 index 0000000..421d048 --- /dev/null +++ b/src/phi/PhiBinarySemaphore.zig @@ -0,0 +1,44 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.BinarySemaphore; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.SemaphoreCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + .signal = signal, + .wait = wait, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn signal(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} + +pub fn wait(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} diff --git a/src/phi/PhiBuffer.zig b/src/phi/PhiBuffer.zig new file mode 100644 index 0000000..07e1df8 --- /dev/null +++ b/src/phi/PhiBuffer.zig @@ -0,0 +1,40 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const lib = @import("lib.zig"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.Buffer; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.BufferCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + .getMemoryRequirements = getMemoryRequirements, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void { + _ = interface; + _ = requirements; +} diff --git a/src/phi/PhiBufferView.zig b/src/phi/PhiBufferView.zig new file mode 100644 index 0000000..046a07a --- /dev/null +++ b/src/phi/PhiBufferView.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.BufferView; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.BufferViewCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiCommandBuffer.zig b/src/phi/PhiCommandBuffer.zig new file mode 100644 index 0000000..91c5b4f --- /dev/null +++ b/src/phi/PhiCommandBuffer.zig @@ -0,0 +1,420 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.CommandBuffer; + +interface: Interface, + +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; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + interface.vtable = &.{ .destroy = destroy }; + interface.dispatch_table = &.{ + .begin = begin, + .beginQuery = beginQuery, + .beginRenderPass = beginRenderPass, + .bindDescriptorSets = bindDescriptorSets, + .bindPipeline = bindPipeline, + .bindIndexBuffer = bindIndexBuffer, + .bindVertexBuffer = bindVertexBuffer, + .blitImage = blitImage, + .clearAttachment = clearAttachment, + .clearColorImage = clearColorImage, + .clearDepthStencilImage = clearDepthStencilImage, + .copyBuffer = copyBuffer, + .copyBufferToImage = copyBufferToImage, + .copyImage = copyImage, + .copyImageToBuffer = copyImageToBuffer, + .copyQueryPoolResults = copyQueryPoolResults, + .dispatch = dispatch, + .dispatchBase = dispatchBase, + .dispatchIndirect = dispatchIndirect, + .draw = draw, + .drawIndexed = drawIndexed, + .drawIndexedIndirect = drawIndexedIndirect, + .drawIndirect = drawIndirect, + .end = end, + .endQuery = endQuery, + .endRenderPass = endRenderPass, + .executeCommands = executeCommands, + .fillBuffer = fillBuffer, + .nextSubpass = nextSubpass, + .pipelineBarrier = pipelineBarrier, + .pushConstants = pushConstants, + .reset = reset, + .resetQueryPool = resetQueryPool, + .resetEvent = resetEvent, + .resolveImage = resolveImage, + .setEvent = setEvent, + .setBlendConstants = setBlendConstants, + .setDepthBias = setDepthBias, + .setDepthBounds = setDepthBounds, + .setDeviceMask = setDeviceMask, + .setLineWidth = setLineWidth, + .setScissor = setScissor, + .setStencilCompareMask = setStencilCompareMask, + .setStencilReference = setStencilReference, + .setStencilWriteMask = setStencilWriteMask, + .setViewport = setViewport, + .updateBuffer = updateBuffer, + .waitEvent = waitEvent, + .writeTimestamp = writeTimestamp, + }; + + self.* = .{ .interface = interface }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn execute(self: *Self) VkError!void { + try self.interface.submit(); + self.interface.finish() catch {}; +} + +pub fn begin(interface: *Interface, info: *const vk.CommandBufferBeginInfo) VkError!void { + _ = interface; + _ = info; +} + +pub fn end(interface: *Interface) VkError!void { + _ = interface; +} + +pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!void { + _ = interface; + _ = flags; +} + +pub fn beginQuery(interface: *Interface, pool: *base.QueryPool, query: u32, flags: vk.QueryControlFlags) VkError!void { + _ = interface; + _ = flags; + try pool.begin(query); +} + +pub fn endQuery(interface: *Interface, pool: *base.QueryPool, query: u32) VkError!void { + _ = interface; + try pool.end(query); +} + +pub fn resetQueryPool(interface: *Interface, pool: *base.QueryPool, first: u32, count: u32) VkError!void { + _ = interface; + try pool.reset(first, count); +} + +pub fn beginRenderPass(interface: *Interface, render_pass: *base.RenderPass, framebuffer: *base.Framebuffer, render_area: vk.Rect2D, clear_values: ?[]const vk.ClearValue) VkError!void { + _ = interface; + _ = render_pass; + _ = framebuffer; + _ = render_area; + _ = clear_values; +} + +pub fn bindDescriptorSets(interface: *Interface, bind_point: vk.PipelineBindPoint, first_set: u32, sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*base.DescriptorSet, dynamic_offsets: []const u32) VkError!void { + _ = interface; + _ = bind_point; + _ = first_set; + _ = sets; + _ = dynamic_offsets; +} + +pub fn bindPipeline(interface: *Interface, bind_point: vk.PipelineBindPoint, pipeline: *base.Pipeline) VkError!void { + _ = interface; + _ = bind_point; + _ = pipeline; +} + +pub fn bindIndexBuffer(interface: *Interface, buffer: *base.Buffer, offset: usize, index_type: vk.IndexType) VkError!void { + _ = interface; + _ = buffer; + _ = offset; + _ = index_type; +} + +pub fn bindVertexBuffer(interface: *Interface, index: usize, buffer: *base.Buffer, offset: usize) VkError!void { + _ = interface; + _ = index; + _ = buffer; + _ = offset; +} + +pub fn blitImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageBlit, filter: vk.Filter) VkError!void { + _ = interface; + _ = src; + _ = src_layout; + _ = dst; + _ = dst_layout; + _ = regions; + _ = filter; +} + +pub fn clearAttachment(interface: *Interface, attachment: vk.ClearAttachment, rect: vk.ClearRect) VkError!void { + _ = interface; + _ = attachment; + _ = rect; +} + +pub fn clearColorImage(interface: *Interface, image: *base.Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, range: vk.ImageSubresourceRange) VkError!void { + _ = interface; + _ = image; + _ = layout; + _ = color; + _ = range; +} + +pub fn clearDepthStencilImage(interface: *Interface, image: *base.Image, layout: vk.ImageLayout, value: *const vk.ClearDepthStencilValue, range: vk.ImageSubresourceRange) VkError!void { + _ = interface; + _ = image; + _ = layout; + _ = value; + _ = range; +} + +pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, regions: []const vk.BufferCopy) VkError!void { + _ = interface; + _ = src; + _ = dst; + _ = regions; +} + +pub fn copyBufferToImage(interface: *Interface, src: *base.Buffer, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.BufferImageCopy) VkError!void { + _ = interface; + _ = src; + _ = dst; + _ = dst_layout; + _ = regions; +} + +pub fn copyImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageCopy) VkError!void { + _ = interface; + _ = src; + _ = src_layout; + _ = dst; + _ = dst_layout; + _ = regions; +} + +pub fn copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Buffer, regions: []const vk.BufferImageCopy) VkError!void { + _ = interface; + _ = src; + _ = src_layout; + _ = dst; + _ = regions; +} + +pub fn copyQueryPoolResults(interface: *Interface, pool: *base.QueryPool, first: u32, count: u32, dst: *base.Buffer, offset: vk.DeviceSize, stride: vk.DeviceSize, flags: vk.QueryResultFlags) VkError!void { + _ = interface; + _ = pool; + _ = first; + _ = count; + _ = dst; + _ = offset; + _ = stride; + _ = flags; +} + +pub fn dispatch(interface: *Interface, group_count_x: u32, group_count_y: u32, group_count_z: u32) VkError!void { + _ = interface; + _ = group_count_x; + _ = group_count_y; + _ = group_count_z; +} + +pub fn dispatchBase(interface: *Interface, base_group_x: u32, base_group_y: u32, base_group_z: u32, group_count_x: u32, group_count_y: u32, group_count_z: u32) VkError!void { + _ = interface; + _ = base_group_x; + _ = base_group_y; + _ = base_group_z; + _ = group_count_x; + _ = group_count_y; + _ = group_count_z; +} + +pub fn setDeviceMask(interface: *Interface, device_mask: u32) VkError!void { + _ = interface; + _ = device_mask; +} + +pub fn dispatchIndirect(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize) VkError!void { + _ = interface; + _ = buffer; + _ = offset; +} + +pub fn draw(interface: *Interface, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void { + _ = interface; + _ = vertex_count; + _ = instance_count; + _ = first_vertex; + _ = first_instance; +} + +pub fn drawIndexed(interface: *Interface, index_count: usize, instance_count: usize, first_index: usize, vertex_offset: i32, first_instance: usize) VkError!void { + _ = interface; + _ = index_count; + _ = instance_count; + _ = first_index; + _ = vertex_offset; + _ = first_instance; +} + +pub fn drawIndexedIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void { + _ = interface; + _ = buffer; + _ = offset; + _ = count; + _ = stride; +} + +pub fn drawIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void { + _ = interface; + _ = buffer; + _ = offset; + _ = count; + _ = stride; +} + +pub fn endRenderPass(interface: *Interface) VkError!void { + _ = interface; +} + +pub fn executeCommands(interface: *Interface, commands: *Interface) VkError!void { + _ = interface; + _ = commands; +} + +pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void { + _ = interface; + _ = buffer; + _ = offset; + _ = size; + _ = data; +} + +pub fn updateBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, data: []const u8) VkError!void { + _ = interface; + _ = buffer; + _ = offset; + _ = data; +} + +pub fn nextSubpass(interface: *Interface, contents: vk.SubpassContents) VkError!void { + _ = interface; + _ = contents; +} + +pub fn pipelineBarrier(interface: *Interface, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, dependency: vk.DependencyFlags, memory: []const vk.MemoryBarrier, buffers: []const vk.BufferMemoryBarrier, images: []const vk.ImageMemoryBarrier) VkError!void { + _ = interface; + _ = src_stage; + _ = dst_stage; + _ = dependency; + _ = memory; + _ = buffers; + _ = images; +} + +pub fn pushConstants(interface: *Interface, stages: vk.ShaderStageFlags, offset: u32, blob: []const u8) VkError!void { + _ = interface; + _ = stages; + _ = offset; + _ = blob; +} + +pub fn resetEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void { + _ = interface; + _ = stage; + try event.reset(); +} + +pub fn resolveImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, region: vk.ImageResolve) VkError!void { + _ = interface; + _ = src; + _ = src_layout; + _ = dst; + _ = dst_layout; + _ = region; +} + +pub fn setEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void { + _ = interface; + _ = stage; + try event.signal(); +} + +pub fn setScissor(interface: *Interface, first: u32, scissor: []const vk.Rect2D) VkError!void { + _ = interface; + _ = first; + _ = scissor; +} + +pub fn setViewport(interface: *Interface, first: u32, viewports: []const vk.Viewport) VkError!void { + _ = interface; + _ = first; + _ = viewports; +} + +pub fn setBlendConstants(interface: *Interface, constants: [4]f32) VkError!void { + _ = interface; + _ = constants; +} + +pub fn setDepthBias(interface: *Interface, constant_factor: f32, clamp: f32, slope_factor: f32) VkError!void { + _ = interface; + _ = constant_factor; + _ = clamp; + _ = slope_factor; +} + +pub fn setDepthBounds(interface: *Interface, min: f32, max: f32) VkError!void { + _ = interface; + _ = min; + _ = max; +} + +pub fn setLineWidth(interface: *Interface, width: f32) VkError!void { + _ = interface; + _ = width; +} + +pub fn setStencilCompareMask(interface: *Interface, face_mask: vk.StencilFaceFlags, compare_mask: u32) VkError!void { + _ = interface; + _ = face_mask; + _ = compare_mask; +} + +pub fn setStencilReference(interface: *Interface, face_mask: vk.StencilFaceFlags, reference: u32) VkError!void { + _ = interface; + _ = face_mask; + _ = reference; +} + +pub fn setStencilWriteMask(interface: *Interface, face_mask: vk.StencilFaceFlags, write_mask: u32) VkError!void { + _ = interface; + _ = face_mask; + _ = write_mask; +} + +pub fn waitEvent(interface: *Interface, event: *base.Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { + _ = interface; + _ = event; + _ = src_stage; + _ = dst_stage; + _ = memory_barriers; + _ = buffer_barriers; + _ = image_barriers; +} + +pub fn writeTimestamp(interface: *Interface, stage: vk.PipelineStageFlags, pool: *base.QueryPool, query: u32) VkError!void { + _ = interface; + _ = stage; + try pool.writeTimestamp(query, 0); +} diff --git a/src/phi/PhiCommandPool.zig b/src/phi/PhiCommandPool.zig new file mode 100644 index 0000000..b70e6e3 --- /dev/null +++ b/src/phi/PhiCommandPool.zig @@ -0,0 +1,48 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const NonDispatchable = base.NonDispatchable; +const VkError = base.VkError; +const Device = base.Device; + +const PhiCommandBuffer = @import("PhiCommandBuffer.zig"); + +const Self = @This(); +pub const Interface = base.CommandPool; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.CommandPoolCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .createCommandBuffer = createCommandBuffer, + .destroy = destroy, + .reset = reset, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn createCommandBuffer(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.CommandBufferAllocateInfo) VkError!*base.CommandBuffer { + const cmd = try PhiCommandBuffer.create(interface.owner, allocator, info); + return &cmd.interface; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn reset(interface: *Interface, flags: vk.CommandPoolResetFlags) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = flags; +} diff --git a/src/phi/PhiDescriptorPool.zig b/src/phi/PhiDescriptorPool.zig new file mode 100644 index 0000000..c390577 --- /dev/null +++ b/src/phi/PhiDescriptorPool.zig @@ -0,0 +1,55 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const VulkanAllocator = base.VulkanAllocator; + +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.DescriptorPool; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.DescriptorPoolCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .allocateDescriptorSet = allocateDescriptorSet, + .destroy = destroy, + .freeDescriptorSet = freeDescriptorSet, + .reset = reset, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn allocateDescriptorSet(interface: *Interface, layout: *base.DescriptorSetLayout) VkError!*base.DescriptorSet { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = layout; + return VkError.Unknown; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn freeDescriptorSet(interface: *Interface, set: *base.DescriptorSet) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = set; +} + +pub fn reset(interface: *Interface, _: vk.DescriptorPoolResetFlags) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} diff --git a/src/phi/PhiDescriptorSet.zig b/src/phi/PhiDescriptorSet.zig new file mode 100644 index 0000000..7472fb9 --- /dev/null +++ b/src/phi/PhiDescriptorSet.zig @@ -0,0 +1,46 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.DescriptorSet; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, layout: *base.DescriptorSetLayout) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, layout); + + interface.vtable = &.{ + .copy = copy, + .destroy = destroy, + .write = write, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn copy(interface: *Interface, src_interface: *const Interface, data: vk.CopyDescriptorSet) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = src_interface; + _ = data; +} + +pub fn write(interface: *Interface, write_data: vk.WriteDescriptorSet) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = write_data; +} diff --git a/src/phi/PhiDescriptorSetLayout.zig b/src/phi/PhiDescriptorSetLayout.zig new file mode 100644 index 0000000..b2d706e --- /dev/null +++ b/src/phi/PhiDescriptorSetLayout.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.DescriptorSetLayout; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.DescriptorSetLayoutCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiDevice.zig b/src/phi/PhiDevice.zig new file mode 100644 index 0000000..2221286 --- /dev/null +++ b/src/phi/PhiDevice.zig @@ -0,0 +1,208 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const PhiQueue = @import("PhiQueue.zig"); + +pub const PhiBinarySemaphore = @import("PhiBinarySemaphore.zig"); +pub const PhiBuffer = @import("PhiBuffer.zig"); +pub const PhiBufferView = @import("PhiBufferView.zig"); +pub const PhiCommandBuffer = @import("PhiCommandBuffer.zig"); +pub const PhiCommandPool = @import("PhiCommandPool.zig"); +pub const PhiDescriptorPool = @import("PhiDescriptorPool.zig"); +pub const PhiDescriptorSetLayout = @import("PhiDescriptorSetLayout.zig"); +pub const PhiDeviceMemory = @import("PhiDeviceMemory.zig"); +pub const PhiEvent = @import("PhiEvent.zig"); +pub const PhiFence = @import("PhiFence.zig"); +pub const PhiFramebuffer = @import("PhiFramebuffer.zig"); +pub const PhiImage = @import("PhiImage.zig"); +pub const PhiInstance = @import("PhiInstance.zig"); +pub const PhiImageView = @import("PhiImageView.zig"); +pub const PhiPipeline = @import("PhiPipeline.zig"); +pub const PhiPipelineCache = @import("PhiPipelineCache.zig"); +pub const PhiPipelineLayout = @import("PhiPipelineLayout.zig"); +pub const PhiQueryPool = @import("PhiQueryPool.zig"); +pub const PhiRenderPass = @import("PhiRenderPass.zig"); +pub const PhiSampler = @import("PhiSampler.zig"); +pub const PhiShaderModule = @import("PhiShaderModule.zig"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Device; + +interface: Interface, + +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); + + interface.vtable = &.{ + .createQueue = PhiQueue.create, + .destroyQueue = PhiQueue.destroy, + }; + + interface.dispatch_table = &.{ + .allocateMemory = allocateMemory, + .createBuffer = createBuffer, + .createBufferView = createBufferView, + .createCommandPool = createCommandPool, + .createComputePipeline = createComputePipeline, + .createDescriptorPool = createDescriptorPool, + .createDescriptorSetLayout = createDescriptorSetLayout, + .createEvent = createEvent, + .createFence = createFence, + .createFramebuffer = createFramebuffer, + .createGraphicsPipeline = createGraphicsPipeline, + .createImage = createImage, + .createImageView = createImageView, + .createPipelineCache = createPipelineCache, + .createPipelineLayout = createPipelineLayout, + .createQueryPool = createQueryPool, + .createRenderPass = createRenderPass, + .createSampler = createSampler, + .createSemaphore = createSemaphore, + .createShaderModule = createShaderModule, + .destroy = destroy, + .getDeviceGroupPeerMemoryFeatures = getDeviceGroupPeerMemoryFeatures, + .getDeviceGroupPresentCapabilitiesKHR = getDeviceGroupPresentCapabilitiesKHR, + .getDeviceGroupSurfacePresentModesKHR = getDeviceGroupSurfacePresentModesKHR, + }; + + self.* = .{ + .interface = interface, + }; + + try self.interface.createQueues(allocator, info); + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn allocateMemory(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.MemoryAllocateInfo) VkError!*base.DeviceMemory { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const device_memory = try PhiDeviceMemory.create(self, allocator, info.allocation_size, info.memory_type_index); + return &device_memory.interface; +} + +pub fn createBuffer(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.BufferCreateInfo) VkError!*base.Buffer { + const buffer = try PhiBuffer.create(interface, allocator, info); + return &buffer.interface; +} + +pub fn createDescriptorPool(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.DescriptorPoolCreateInfo) VkError!*base.DescriptorPool { + const pool = try PhiDescriptorPool.create(interface, allocator, info); + return &pool.interface; +} + +pub fn createDescriptorSetLayout(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.DescriptorSetLayoutCreateInfo) VkError!*base.DescriptorSetLayout { + const layout = try PhiDescriptorSetLayout.create(interface, allocator, info); + return &layout.interface; +} + +pub fn createFence(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!*base.Fence { + const fence = try PhiFence.create(interface, allocator, info); + return &fence.interface; +} + +pub fn createCommandPool(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.CommandPoolCreateInfo) VkError!*base.CommandPool { + const pool = try PhiCommandPool.create(interface, allocator, info); + return &pool.interface; +} + +pub fn createImage(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.ImageCreateInfo) VkError!*base.Image { + const image = try PhiImage.create(interface, allocator, info); + return &image.interface; +} + +pub fn createImageView(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.ImageViewCreateInfo) VkError!*base.ImageView { + const view = try PhiImageView.create(interface, allocator, info); + return &view.interface; +} + +pub fn createBufferView(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.BufferViewCreateInfo) VkError!*base.BufferView { + const view = try PhiBufferView.create(interface, allocator, info); + return &view.interface; +} + +pub fn createComputePipeline(interface: *Interface, allocator: std.mem.Allocator, cache: ?*base.PipelineCache, info: *const vk.ComputePipelineCreateInfo) VkError!*base.Pipeline { + const pipeline = try PhiPipeline.createCompute(interface, allocator, cache, info); + return &pipeline.interface; +} + +pub fn createEvent(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.EventCreateInfo) VkError!*base.Event { + const event = try PhiEvent.create(interface, allocator, info); + return &event.interface; +} + +pub fn createFramebuffer(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.FramebufferCreateInfo) VkError!*base.Framebuffer { + const framebuffer = try PhiFramebuffer.create(interface, allocator, info); + return &framebuffer.interface; +} + +pub fn createGraphicsPipeline(interface: *Interface, allocator: std.mem.Allocator, cache: ?*base.PipelineCache, info: *const vk.GraphicsPipelineCreateInfo) VkError!*base.Pipeline { + const pipeline = try PhiPipeline.createGraphics(interface, allocator, cache, info); + return &pipeline.interface; +} + +pub fn createPipelineCache(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.PipelineCacheCreateInfo) VkError!*base.PipelineCache { + const cache = try PhiPipelineCache.create(interface, allocator, info); + return &cache.interface; +} + +pub fn createPipelineLayout(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.PipelineLayoutCreateInfo) VkError!*base.PipelineLayout { + const layout = try PhiPipelineLayout.create(interface, allocator, info); + return &layout.interface; +} + +pub fn createQueryPool(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.QueryPoolCreateInfo) VkError!*base.QueryPool { + const pool = try PhiQueryPool.create(interface, allocator, info); + return &pool.interface; +} + +pub fn createRenderPass(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.RenderPassCreateInfo) VkError!*base.RenderPass { + const pass = try PhiRenderPass.create(interface, allocator, info); + return &pass.interface; +} + +pub fn createSampler(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.SamplerCreateInfo) VkError!*base.Sampler { + const sampler = try PhiSampler.create(interface, allocator, info); + return &sampler.interface; +} + +pub fn createSemaphore(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.SemaphoreCreateInfo) VkError!*base.BinarySemaphore { + const semaphore = try PhiBinarySemaphore.create(interface, allocator, info); + return &semaphore.interface; +} + +pub fn createShaderModule(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.ShaderModuleCreateInfo) VkError!*base.ShaderModule { + const module = try PhiShaderModule.create(interface, allocator, info); + return &module.interface; +} + +pub fn getDeviceGroupPeerMemoryFeatures(interface: *Interface, heap_index: u32, local_device_index: u32, remote_device_index: u32) VkError!vk.PeerMemoryFeatureFlags { + if (heap_index >= interface.physical_device.mem_props.memory_heap_count) return VkError.ValidationFailed; + if (local_device_index != 0 or remote_device_index != 0) return VkError.ValidationFailed; + + return .{ + .copy_src_bit = true, + .copy_dst_bit = true, + .generic_src_bit = true, + .generic_dst_bit = true, + }; +} + +pub fn getDeviceGroupPresentCapabilitiesKHR(_: *Interface, capabilities: *vk.DeviceGroupPresentCapabilitiesKHR) VkError!void { + capabilities.present_mask = @splat(0); + capabilities.present_mask[0] = 1; + capabilities.modes = .{ .local_bit_khr = true }; +} + +pub fn getDeviceGroupSurfacePresentModesKHR(_: *Interface, _: *base.SurfaceKHR) VkError!vk.DeviceGroupPresentModeFlagsKHR { + return .{ .local_bit_khr = true }; +} diff --git a/src/phi/PhiDeviceMemory.zig b/src/phi/PhiDeviceMemory.zig new file mode 100644 index 0000000..cd24d18 --- /dev/null +++ b/src/phi/PhiDeviceMemory.zig @@ -0,0 +1,60 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const lib = @import("lib.zig"); + +const PhiDevice = @import("PhiDevice.zig"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.DeviceMemory; + +interface: Interface, + +pub fn create(device: *PhiDevice, 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); + + var interface = try Interface.init(&device.interface, size, memory_type_index); + + interface.vtable = &.{ + .destroy = destroy, + .map = map, + .unmap = unmap, + .flushRange = flushRange, + .invalidateRange = invalidateRange, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn flushRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { + _ = interface; + _ = offset; + _ = size; +} + +pub fn invalidateRange(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { + _ = interface; + _ = 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; +} + +pub fn unmap(_: *Interface) void {} diff --git a/src/phi/PhiEvent.zig b/src/phi/PhiEvent.zig new file mode 100644 index 0000000..68b9b0e --- /dev/null +++ b/src/phi/PhiEvent.zig @@ -0,0 +1,56 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.Event; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.EventCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + .getStatus = getStatus, + .reset = reset, + .signal = signal, + .wait = wait, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn getStatus(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} + +pub fn reset(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} + +pub fn signal(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} + +pub fn wait(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} diff --git a/src/phi/PhiFence.zig b/src/phi/PhiFence.zig new file mode 100644 index 0000000..440a251 --- /dev/null +++ b/src/phi/PhiFence.zig @@ -0,0 +1,57 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.Fence; + +interface: Interface, + +pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + .getStatus = getStatus, + .reset = reset, + .signal = signal, + .wait = wait, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn getStatus(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} + +pub fn reset(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} + +pub fn signal(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; +} + +pub fn wait(interface: *Interface, timeout: u64) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = timeout; +} diff --git a/src/phi/PhiFramebuffer.zig b/src/phi/PhiFramebuffer.zig new file mode 100644 index 0000000..7c9e5d3 --- /dev/null +++ b/src/phi/PhiFramebuffer.zig @@ -0,0 +1,26 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Framebuffer; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.FramebufferCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + interface.vtable = &.{ .destroy = destroy }; + + self.* = .{ .interface = interface }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiImage.zig b/src/phi/PhiImage.zig new file mode 100644 index 0000000..4c65234 --- /dev/null +++ b/src/phi/PhiImage.zig @@ -0,0 +1,78 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const lib = @import("lib.zig"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Image; + +pub const F32x4 = @Vector(4, f32); +pub const U32x4 = @Vector(4, u32); + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.ImageCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + interface.vtable = &.{ + .destroy = destroy, + .getMemoryRequirements = getMemoryRequirements, + .getSubresourceLayout = getSubresourceLayout, + .getTotalSizeForAspect = getTotalSizeForAspect, + .getSliceMemSizeForMipLevel = getSliceMemSizeForMipLevel, + .getRowPitchMemSizeForMipLevel = getRowPitchMemSizeForMipLevel, + .copyToMemory = copyToMemory, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn getMemoryRequirements(_: *Interface, requirements: *vk.MemoryRequirements) VkError!void { + _ = requirements; +} + +pub fn copyToMemory(interface: *const Interface, memory: []u8, subresource: vk.ImageSubresourceLayers) VkError!void { + _ = interface; + _ = subresource; + @memset(memory, 0); +} + +pub fn getTotalSizeForAspect(interface: *const Interface, aspect_mask: vk.ImageAspectFlags) VkError!usize { + _ = aspect_mask; + return interface.extent.width * interface.extent.height * interface.extent.depth * base.format.texelSize(interface.format); +} + +pub fn getSubresourceLayout(interface: *const Interface, subresource: vk.ImageSubresource) VkError!vk.SubresourceLayout { + _ = subresource; + return .{ + .offset = 0, + .size = try getTotalSizeForAspect(interface, base.format.toAspect(interface.format)), + .row_pitch = getRowPitchMemSizeForMipLevel(interface, base.format.toAspect(interface.format), 0), + .array_pitch = getSliceMemSizeForMipLevel(interface, base.format.toAspect(interface.format), 0), + .depth_pitch = getSliceMemSizeForMipLevel(interface, base.format.toAspect(interface.format), 0), + }; +} + +pub fn getSliceMemSizeForMipLevel(interface: *const Interface, aspect_mask: vk.ImageAspectFlags, mip_level: u32) usize { + _ = aspect_mask; + _ = mip_level; + return interface.extent.width * interface.extent.height * base.format.texelSize(interface.format); +} + +pub fn getRowPitchMemSizeForMipLevel(interface: *const Interface, aspect_mask: vk.ImageAspectFlags, mip_level: u32) usize { + _ = aspect_mask; + _ = mip_level; + return interface.extent.width * base.format.texelSize(interface.format); +} diff --git a/src/phi/PhiImageView.zig b/src/phi/PhiImageView.zig new file mode 100644 index 0000000..db0956b --- /dev/null +++ b/src/phi/PhiImageView.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.ImageView; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.ImageViewCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiInstance.zig b/src/phi/PhiInstance.zig new file mode 100644 index 0000000..e340c0d --- /dev/null +++ b/src/phi/PhiInstance.zig @@ -0,0 +1,119 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const lib = @import("lib.zig"); + +const PhiPhysicalDevice = @import("PhiPhysicalDevice.zig"); + +const Dispatchable = base.Dispatchable; + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Instance; + +interface: Interface, +threaded: std.Io.Threaded, +io_impl: std.Io, +allocator: std.mem.Allocator, + +fn castExtension(comptime ext: vk.ApiInfo) vk.ExtensionProperties { + var props: vk.ExtensionProperties = .{ + .extension_name = @splat(0), + .spec_version = @bitCast(ext.version), + }; + @memcpy(props.extension_name[0..ext.name.len], ext.name); + return props; +} + +pub const EXTENSIONS = [_]vk.ExtensionProperties{ + castExtension(vk.extensions.khr_device_group_creation), + castExtension(vk.extensions.khr_get_physical_device_properties_2), + castExtension(vk.extensions.khr_surface), + castExtension(vk.extensions.khr_wayland_surface), +}; + +pub fn create(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) VkError!*Interface { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + self.allocator = std.heap.smp_allocator; + self.threaded = std.Io.Threaded.init(self.allocator, .{}); + self.io_impl = self.threaded.io(); + + self.interface = try base.Instance.init(allocator, infos); + self.interface.dispatch_table = &.{ + .destroy = destroy, + }; + + self.interface.vtable = &.{ + .requestPhysicalDevices = requestPhysicalDevices, + .releasePhysicalDevices = releasePhysicalDevices, + .io = io, + }; + + return &self.interface; +} + +fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.threaded.deinit(); + allocator.destroy(self); +} + +fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, devices: []base.drm.Card) VkError!void { + if (interface.physical_devices.items.len != 0) { + return; + } + + const io_var = interface.io(); + + for (devices[0..]) |device| { + const drm_device = device.getDevice(io_var, allocator, .{}) catch continue; + + if (drm_device.node_type != .render or + std.meta.activeTag(drm_device.device_info) != .pci or + drm_device.device_info.pci.vendor_id != lib.INTEL_PCI_VENDOR_ID) + continue; + + const physical_device = try PhiPhysicalDevice.create(allocator, interface, &drm_device); + errdefer physical_device.interface.release(allocator) catch {}; + + const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface); + errdefer dispatchable.destroy(allocator); + + interface.physical_devices.append(allocator, dispatchable) catch return VkError.OutOfHostMemory; + } +} + +fn releasePhysicalDevices(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + var result: ?VkError = null; + + for (interface.physical_devices.items) |physical_device| { + physical_device.object.release(allocator) catch |err| { + if (result == null) { + result = err; + } + }; + physical_device.destroy(allocator); + } + + interface.physical_devices.deinit(allocator); + interface.physical_devices = .empty; + + if (result) |err| { + return err; + } +} + +fn io(interface: *Interface) std.Io { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + return self.io_impl; +} + +fn mapDeviceEnumerationError(err: anyerror) VkError { + return switch (err) { + error.OutOfMemory => VkError.OutOfHostMemory, + else => VkError.InitializationFailed, + }; +} diff --git a/src/phi/PhiPhysicalDevice.zig b/src/phi/PhiPhysicalDevice.zig new file mode 100644 index 0000000..13463d4 --- /dev/null +++ b/src/phi/PhiPhysicalDevice.zig @@ -0,0 +1,854 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const vk = @import("vulkan"); +const base = @import("base"); +const lib = @import("lib.zig"); + +const pci_ids = @import("pci_ids.zig").map; + +const PhiDevice = @import("PhiDevice.zig"); + +const VkError = base.VkError; +const VulkanAllocator = base.VulkanAllocator; +const SurfaceKHR = base.SurfaceKHR; + +const Self = @This(); +pub const Interface = base.PhysicalDevice; + +fn castExtension(comptime ext: vk.ApiInfo) vk.ExtensionProperties { + var props: vk.ExtensionProperties = .{ + .extension_name = @splat(0), + .spec_version = @bitCast(ext.version), + }; + @memcpy(props.extension_name[0..ext.name.len], ext.name); + return props; +} + +pub const EXTENSIONS = [_]vk.ExtensionProperties{ + castExtension(vk.extensions.khr_device_group), + castExtension(vk.extensions.khr_swapchain), +}; + +interface: Interface, + +pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device: *const base.drm.Device) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(allocator, instance); + + interface.dispatch_table = &.{ + .createDevice = createDevice, + .getFormatProperties = getFormatProperties, + .getImageFormatProperties = getImageFormatProperties, + .getSparseImageFormatProperties = getSparseImageFormatProperties, + .enumerateLayerProperties = enumerateLayerProperties, + .enumerateExtensionProperties = enumerateExtensionProperties, + .release = destroy, + + // VK_KHR_get_physical_device_properties_2 + .getSparseImageFormatProperties2 = getSparseImageFormatProperties2, + + // VK_KHR_surface + .getSurfaceSupportKHR = getSurfaceSupportKHR, + }; + + interface.props.api_version = @bitCast(lib.VULKAN_VERSION); + interface.props.vendor_id = lib.INTEL_PCI_VENDOR_ID; + interface.props.driver_version = @bitCast(base.DRIVER_VERSION); + interface.props.device_id = drm_device.device_info.pci.device_id; + interface.props.device_type = .discrete_gpu; + + @memset(interface.props.device_name[0..], 0); + + for (pci_ids[0..]) |pci| { + if (pci.id != drm_device.device_info.pci.device_id) + continue; + + const len = @min(vk.MAX_PHYSICAL_DEVICE_NAME_SIZE, pci.name.len); + @memcpy(interface.props.device_name[0..len], pci.name[0..len]); + + const driver_mark = " [Phi ApeDriver]"; + + @memcpy(interface.props.device_name[len .. len + driver_mark.len], driver_mark); + + break; + } + + interface.props.pipeline_cache_uuid = undefined; + interface.props.limits = .{ + .max_image_dimension_1d = 4096, + .max_image_dimension_2d = 4096, + .max_image_dimension_3d = 256, + .max_image_dimension_cube = 4096, + .max_image_array_layers = 256, + .max_texel_buffer_elements = 65536, + .max_uniform_buffer_range = 16384, + .max_storage_buffer_range = 134217728, + .max_push_constants_size = 256, + .max_memory_allocation_count = 1024, + .max_sampler_allocation_count = 4096, + .buffer_image_granularity = 131072, + .sparse_address_space_size = 0, + .max_bound_descriptor_sets = 8, + .max_per_stage_descriptor_samplers = 16, + .max_per_stage_descriptor_uniform_buffers = 12, + .max_per_stage_descriptor_storage_buffers = 4, + .max_per_stage_descriptor_sampled_images = 16, + .max_per_stage_descriptor_storage_images = 4, + .max_per_stage_descriptor_input_attachments = 4, + .max_per_stage_resources = 128, + .max_descriptor_set_samplers = 96, + .max_descriptor_set_uniform_buffers = 72, + .max_descriptor_set_uniform_buffers_dynamic = 8, + .max_descriptor_set_storage_buffers = 24, + .max_descriptor_set_storage_buffers_dynamic = 4, + .max_descriptor_set_sampled_images = 96, + .max_descriptor_set_storage_images = 24, + .max_descriptor_set_input_attachments = 4, + .max_vertex_input_attributes = 32, + .max_vertex_input_bindings = 32, + .max_vertex_input_attribute_offset = 2047, + .max_vertex_input_binding_stride = 2048, + .max_vertex_output_components = 64, + .max_tessellation_generation_level = 0, + .max_tessellation_patch_size = 0, + .max_tessellation_control_per_vertex_input_components = 0, + .max_tessellation_control_per_vertex_output_components = 0, + .max_tessellation_control_per_patch_output_components = 0, + .max_tessellation_control_total_output_components = 0, + .max_tessellation_evaluation_input_components = 0, + .max_tessellation_evaluation_output_components = 0, + .max_geometry_shader_invocations = 0, + .max_geometry_input_components = 0, + .max_geometry_output_components = 0, + .max_geometry_output_vertices = 0, + .max_geometry_total_output_components = 0, + .max_fragment_input_components = 64, + .max_fragment_output_attachments = 4, + .max_fragment_dual_src_attachments = 0, + .max_fragment_combined_output_resources = 4, + .max_compute_shared_memory_size = 16384, + .max_compute_work_group_count = .{ 65535, 65535, 65535 }, + .max_compute_work_group_invocations = 128, + .max_compute_work_group_size = .{ 128, 128, 64 }, + .sub_pixel_precision_bits = 4, + .sub_texel_precision_bits = 4, + .mipmap_precision_bits = 4, + .max_draw_indexed_index_value = 4294967295, + .max_draw_indirect_count = 65535, + .max_sampler_lod_bias = 2.0, + .max_sampler_anisotropy = 1.0, + .max_viewports = 1, + .max_viewport_dimensions = .{ 4096, 4096 }, + .viewport_bounds_range = .{ -8192.0, 8191.0 }, + .viewport_sub_pixel_bits = 0, + .min_memory_map_alignment = 64, + .min_texel_buffer_offset_alignment = 256, + .min_uniform_buffer_offset_alignment = 256, + .min_storage_buffer_offset_alignment = 256, + .min_texel_offset = -8, + .max_texel_offset = 7, + .min_texel_gather_offset = 0, + .max_texel_gather_offset = 0, + .min_interpolation_offset = 0.0, + .max_interpolation_offset = 0.0, + .sub_pixel_interpolation_offset_bits = 0, + .max_framebuffer_width = 4096, + .max_framebuffer_height = 4096, + .max_framebuffer_layers = 256, + .framebuffer_color_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .framebuffer_depth_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .framebuffer_stencil_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .framebuffer_no_attachments_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .max_color_attachments = 4, + .sampled_image_color_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .sampled_image_integer_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .sampled_image_depth_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .sampled_image_stencil_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .storage_image_sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }, + .max_sample_mask_words = 1, + .timestamp_compute_and_graphics = .false, + .timestamp_period = 1.0, + .max_clip_distances = 0, + .max_cull_distances = 0, + .max_combined_clip_and_cull_distances = 0, + .discrete_queue_priorities = 2, + .point_size_range = .{ 1.0, 1.0 }, + .line_width_range = .{ 1.0, 1.0 }, + .point_size_granularity = 0.0, + .line_width_granularity = 0.0, + .strict_lines = .false, + .standard_sample_locations = .true, + .optimal_buffer_copy_offset_alignment = 1, + .optimal_buffer_copy_row_pitch_alignment = 1, + .non_coherent_atom_size = 256, + }; + + interface.mem_props.memory_type_count = 1; + interface.mem_props.memory_types[0] = .{ + .heap_index = 0, + .property_flags = .{ + .device_local_bit = true, + .host_visible_bit = true, + .host_coherent_bit = true, + .host_cached_bit = true, + }, + }; + interface.mem_props.memory_heap_count = 1; + interface.mem_props.memory_heaps[0] = .{ + .size = std.process.totalSystemMemory() catch 0, + .flags = .{ .device_local_bit = true }, + }; + + interface.features = .{ + .robust_buffer_access = .true, + .shader_float_64 = .true, + .shader_int_64 = .true, + .shader_int_16 = .true, + }; + + var queue_family_props = [_]vk.QueueFamilyProperties{ + .{ + .queue_flags = .{ .graphics_bit = true, .compute_bit = true, .transfer_bit = true }, + .queue_count = 1, + .timestamp_valid_bits = 0, + .min_image_transfer_granularity = .{ .width = 1, .height = 1, .depth = 1 }, + }, + }; + interface.queue_family_props.appendSlice(allocator, queue_family_props[0..]) catch return VkError.OutOfHostMemory; + + self.* = .{ + .interface = interface, + }; + + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn createDevice(interface: *Interface, allocator: std.mem.Allocator, infos: *const vk.DeviceCreateInfo) VkError!*base.Device { + const device = try PhiDevice.create(interface.instance, interface, allocator, infos); + return &device.interface; +} + +pub fn enumerateLayerProperties(_: *const Interface, count: *u32, p_properties: ?[*]vk.LayerProperties) VkError!void { + count.* = 0; + _ = p_properties; +} + +pub fn enumerateExtensionProperties(_: *const Interface, layer_name: ?[]const u8, count: *u32, p_properties: ?[*]vk.ExtensionProperties) VkError!void { + if (layer_name) |_| { + return VkError.LayerNotPresent; + } + + const available = EXTENSIONS.len; + if (p_properties) |properties| { + const write_count = @min(count.*, available); + for (EXTENSIONS[0..write_count], properties[0..write_count]) |ext, *prop| { + prop.* = ext; + } + count.* = @intCast(write_count); + if (write_count < available) return VkError.Incomplete; + } else { + count.* = @intCast(available); + } +} + +pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.FormatProperties { + _ = interface; + var properties: vk.FormatProperties = .{}; + + switch (format) { + // Formats which can be sampled *and* filtered + .r4g4b4a4_unorm_pack16, + .b4g4r4a4_unorm_pack16, + .a4r4g4b4_unorm_pack16, + .a4b4g4r4_unorm_pack16, + .r5g6b5_unorm_pack16, + .b5g6r5_unorm_pack16, + .r5g5b5a1_unorm_pack16, + .b5g5r5a1_unorm_pack16, + .a1r5g5b5_unorm_pack16, + .r8_unorm, + .r8_srgb, + .r8_snorm, + .r8g8_unorm, + .r8g8_srgb, + .r8g8_snorm, + .r8g8b8a8_unorm, + .r8g8b8a8_snorm, + .r8g8b8a8_srgb, + .b8g8r8a8_unorm, + .b8g8r8a8_srgb, + .a8b8g8r8_unorm_pack32, + .a8b8g8r8_snorm_pack32, + .a8b8g8r8_srgb_pack32, + .a2b10g10r10_unorm_pack32, + .a2r10g10b10_unorm_pack32, + .r16_unorm, + .r16_snorm, + .r16_sfloat, + .r16g16_unorm, + .r16g16_snorm, + .r16g16_sfloat, + .r16g16b16a16_unorm, + .r16g16b16a16_snorm, + .r16g16b16a16_sfloat, + .r32_sfloat, + .r32g32_sfloat, + .r32g32b32a32_sfloat, + .b10g11r11_ufloat_pack32, + .e5b9g9r9_ufloat_pack32, + //.bc1_rgb_unorm_block, + //.bc1_rgb_srgb_block, + //.bc1_rgba_unorm_block, + //.bc1_rgba_srgb_block, + //.bc2_unorm_block, + //.bc2_srgb_block, + //.bc3_unorm_block, + //.bc3_srgb_block, + //.bc4_unorm_block, + //.bc4_snorm_block, + //.bc5_unorm_block, + //.bc5_snorm_block, + //.bc6h_ufloat_block, + //.bc6h_sfloat_block, + //.bc7_unorm_block, + //.bc7_srgb_block, + //.etc2_r8g8b8_unorm_block, + //.etc2_r8g8b8_srgb_block, + //.etc2_r8g8b8a1_unorm_block, + //.etc2_r8g8b8a1_srgb_block, + //.etc2_r8g8b8a8_unorm_block, + //.etc2_r8g8b8a8_srgb_block, + //.eac_r11_unorm_block, + //.eac_r11_snorm_block, + //.eac_r11g11_unorm_block, + //.eac_r11g11_snorm_block, + //.astc_4x_4_unorm_block, + //.astc_5x_4_unorm_block, + //.astc_5x_5_unorm_block, + //.astc_6x_5_unorm_block, + //.astc_6x_6_unorm_block, + //.astc_8x_5_unorm_block, + //.astc_8x_6_unorm_block, + //.astc_8x_8_unorm_block, + //.astc_1_0x_5_unorm_block, + //.astc_1_0x_6_unorm_block, + //.astc_1_0x_8_unorm_block, + //.astc_1_0x_10_unorm_block, + //.astc_1_2x_10_unorm_block, + //.astc_1_2x_12_unorm_block, + //.astc_4x_4_srgb_block, + //.astc_5x_4_srgb_block, + //.astc_5x_5_srgb_block, + //.astc_6x_5_srgb_block, + //.astc_6x_6_srgb_block, + //.astc_8x_5_srgb_block, + //.astc_8x_6_srgb_block, + //.astc_8x_8_srgb_block, + //.astc_1_0x_5_srgb_block, + //.astc_1_0x_6_srgb_block, + //.astc_1_0x_8_srgb_block, + //.astc_1_0x_10_srgb_block, + //.astc_1_2x_10_srgb_block, + //.astc_1_2x_12_srgb_block, + .d16_unorm, + .d32_sfloat, + .d32_sfloat_s8_uint, + => { + properties.optimal_tiling_features.blit_src_bit = true; + properties.optimal_tiling_features.sampled_image_bit = true; + properties.optimal_tiling_features.transfer_dst_bit = true; + properties.optimal_tiling_features.transfer_src_bit = true; + properties.optimal_tiling_features.sampled_image_filter_linear_bit = true; + }, + + // Formats which can be sampled, but don't support filtering + .r8_uint, + .r8_sint, + .r8g8_uint, + .r8g8_sint, + .r8g8b8a8_uint, + .r8g8b8a8_sint, + .a8b8g8r8_uint_pack32, + .a8b8g8r8_sint_pack32, + .a2b10g10r10_uint_pack32, + .a2r10g10b10_uint_pack32, + .r16_uint, + .r16_sint, + .r16g16_uint, + .r16g16_sint, + .r16g16b16a16_uint, + .r16g16b16a16_sint, + .r32_uint, + .r32_sint, + .r32g32_uint, + .r32g32_sint, + .r32g32b32a32_uint, + .r32g32b32a32_sint, + .s8_uint, + => { + properties.optimal_tiling_features.blit_src_bit = true; + properties.optimal_tiling_features.sampled_image_bit = true; + properties.optimal_tiling_features.transfer_dst_bit = true; + properties.optimal_tiling_features.transfer_src_bit = true; + }, + + // YCbCr formats + .g8_b8_r8_3plane_420_unorm, + .g8_b8r8_2plane_420_unorm, + .g10x6_b10x6r10x6_2plane_420_unorm_3pack16, + => { + properties.optimal_tiling_features.sampled_image_bit = true; + properties.optimal_tiling_features.sampled_image_filter_linear_bit = true; + properties.optimal_tiling_features.sampled_image_ycbcr_conversion_linear_filter_bit = true; + properties.optimal_tiling_features.transfer_src_bit = true; + properties.optimal_tiling_features.transfer_dst_bit = true; + properties.optimal_tiling_features.cosited_chroma_samples_bit = true; + }, + else => {}, + } + + switch (format) { + // Vulkan 1.0 mandatory storage image formats supporting atomic operations + .r32_uint, + .r32_sint, + => { + properties.buffer_features.storage_texel_buffer_bit = true; + properties.buffer_features.storage_texel_buffer_atomic_bit = true; + properties.optimal_tiling_features.storage_image_bit = true; + properties.optimal_tiling_features.storage_image_atomic_bit = true; + }, + // vulkan 1.0 mandatory storage image formats + .r8g8b8a8_unorm, + .r8g8b8a8_snorm, + .r8g8b8a8_uint, + .r8g8b8a8_sint, + .r16g16b16a16_uint, + .r16g16b16a16_sint, + .r16g16b16a16_sfloat, + .r32_sfloat, + .r32g32_uint, + .r32g32_sint, + .r32g32_sfloat, + .r32g32b32a32_uint, + .r32g32b32a32_sint, + .r32g32b32a32_sfloat, + .a2b10g10r10_unorm_pack32, + .a2b10g10r10_uint_pack32, + // vulkan 1.0 shaderstorageimageextendedformats + .r16g16_sfloat, + .b10g11r11_ufloat_pack32, + .r16_sfloat, + .r16g16b16a16_unorm, + .r16g16_unorm, + .r8g8_unorm, + .r16_unorm, + .r8_unorm, + .r16g16b16a16_snorm, + .r16g16_snorm, + .r8g8_snorm, + .r16_snorm, + .r8_snorm, + .r16g16_sint, + .r8g8_sint, + .r16_sint, + .r8_sint, + .r16g16_uint, + .r8g8_uint, + .r16_uint, + .r8_uint, + // additional formats not listed under "formats without shader storage format" + .a8b8g8r8_unorm_pack32, + .a8b8g8r8_snorm_pack32, + .a8b8g8r8_uint_pack32, + .a8b8g8r8_sint_pack32, + .b8g8r8a8_unorm, + .b8g8r8a8_srgb, + => { + properties.optimal_tiling_features.storage_image_bit = true; + properties.buffer_features.storage_texel_buffer_bit = true; + }, + + else => {}, + } + + switch (format) { + .r5g6b5_unorm_pack16, + .a1r5g5b5_unorm_pack16, + .r4g4b4a4_unorm_pack16, + .b4g4r4a4_unorm_pack16, + .a4r4g4b4_unorm_pack16, + .a4b4g4r4_unorm_pack16, + .b5g6r5_unorm_pack16, + .r5g5b5a1_unorm_pack16, + .b5g5r5a1_unorm_pack16, + .r8_unorm, + .r8g8_unorm, + .r8g8b8a8_unorm, + .r8g8b8a8_srgb, + .b8g8r8a8_unorm, + .b8g8r8a8_srgb, + .a8b8g8r8_unorm_pack32, + .a8b8g8r8_srgb_pack32, + .a2b10g10r10_unorm_pack32, + .a2r10g10b10_unorm_pack32, + .r16_sfloat, + .r16g16_sfloat, + .r16g16b16a16_sfloat, + .r32_sfloat, + .r32g32_sfloat, + .r32g32b32a32_sfloat, + .b10g11r11_ufloat_pack32, + .r8_uint, + .r8_sint, + .r8g8_uint, + .r8g8_sint, + .r8g8b8a8_uint, + .r8g8b8a8_sint, + .a8b8g8r8_uint_pack32, + .a8b8g8r8_sint_pack32, + .a2b10g10r10_uint_pack32, + .a2r10g10b10_uint_pack32, + .r16_unorm, + .r16_uint, + .r16_sint, + .r16g16_unorm, + .r16g16_uint, + .r16g16_sint, + .r16g16b16a16_unorm, + .r16g16b16a16_uint, + .r16g16b16a16_sint, + .r32_uint, + .r32_sint, + .r32g32_uint, + .r32g32_sint, + .r32g32b32a32_uint, + .r32g32b32a32_sint, + => { + properties.optimal_tiling_features.color_attachment_bit = true; + properties.optimal_tiling_features.blit_dst_bit = true; + }, + .s8_uint, + .d16_unorm, + .d32_sfloat, // note: either vk_format_d32_sfloat or vk_format_x8_d24_unorm_pack32 must be supported + .d32_sfloat_s8_uint, + => { // note: either vk_format_d24_unorm_s8_uint or vk_format_d32_sfloat_s8_uint must be supported + properties.optimal_tiling_features.depth_stencil_attachment_bit = true; + }, + + else => {}, + } + + if (base.format.supportsColorAttachemendBlend(format)) { + properties.optimal_tiling_features.color_attachment_blend_bit = true; + } + + switch (format) { + .r8_unorm, + .r8_snorm, + .r8_uscaled, + .r8_sscaled, + .r8_uint, + .r8_sint, + .r8g8_unorm, + .r8g8_snorm, + .r8g8_uscaled, + .r8g8_sscaled, + .r8g8_uint, + .r8g8_sint, + .r8g8b8a8_unorm, + .r8g8b8a8_snorm, + .r8g8b8a8_uscaled, + .r8g8b8a8_sscaled, + .r8g8b8a8_uint, + .r8g8b8a8_sint, + .b8g8r8a8_unorm, + .a8b8g8r8_unorm_pack32, + .a8b8g8r8_snorm_pack32, + .a8b8g8r8_uscaled_pack32, + .a8b8g8r8_sscaled_pack32, + .a8b8g8r8_uint_pack32, + .a8b8g8r8_sint_pack32, + .a2r10g10b10_unorm_pack32, + .a2r10g10b10_snorm_pack32, + .a2r10g10b10_uint_pack32, + .a2r10g10b10_sint_pack32, + .a2b10g10r10_unorm_pack32, + .a2b10g10r10_snorm_pack32, + .a2b10g10r10_uint_pack32, + .a2b10g10r10_sint_pack32, + .r16_unorm, + .r16_snorm, + .r16_uscaled, + .r16_sscaled, + .r16_uint, + .r16_sint, + .r16_sfloat, + .r16g16_unorm, + .r16g16_snorm, + .r16g16_uscaled, + .r16g16_sscaled, + .r16g16_uint, + .r16g16_sint, + .r16g16_sfloat, + .r16g16b16a16_unorm, + .r16g16b16a16_snorm, + .r16g16b16a16_uscaled, + .r16g16b16a16_sscaled, + .r16g16b16a16_uint, + .r16g16b16a16_sint, + .r16g16b16a16_sfloat, + .r32_uint, + .r32_sint, + .r32_sfloat, + .r32g32_uint, + .r32g32_sint, + .r32g32_sfloat, + .r32g32b32_uint, + .r32g32b32_sint, + .r32g32b32_sfloat, + .r32g32b32a32_uint, + .r32g32b32a32_sint, + .r32g32b32a32_sfloat, + => properties.buffer_features.vertex_buffer_bit = true, + else => {}, + } + + switch (format) { + // Vulkan 1.1 mandatory + .r8_unorm, + .r8_snorm, + .r8_uint, + .r8_sint, + .r8g8_unorm, + .r8g8_snorm, + .r8g8_uint, + .r8g8_sint, + .r8g8b8a8_unorm, + .r8g8b8a8_snorm, + .r8g8b8a8_uint, + .r8g8b8a8_sint, + .b8g8r8a8_unorm, + .a8b8g8r8_unorm_pack32, + .a8b8g8r8_snorm_pack32, + .a8b8g8r8_uint_pack32, + .a8b8g8r8_sint_pack32, + .a2b10g10r10_unorm_pack32, + .a2b10g10r10_uint_pack32, + .r16_uint, + .r16_sint, + .r16_sfloat, + .r16g16_uint, + .r16g16_sint, + .r16g16_sfloat, + .r16g16b16a16_uint, + .r16g16b16a16_sint, + .r16g16b16a16_sfloat, + .r32_uint, + .r32_sint, + .r32_sfloat, + .r32g32_uint, + .r32g32_sint, + .r32g32_sfloat, + .r32g32b32a32_uint, + .r32g32b32a32_sint, + .r32g32b32a32_sfloat, + .b10g11r11_ufloat_pack32, + // optional + .a2r10g10b10_unorm_pack32, + .a2r10g10b10_uint_pack32, + => properties.buffer_features.uniform_texel_buffer_bit = true, + else => {}, + } + + if (properties.optimal_tiling_features.toInt() != 0) { + // "Formats that are required to support VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT must also support + // VK_FORMAT_FEATURE_TRANSFER_SRC_BIT and VK_FORMAT_FEATURE_TRANSFER_DST_BIT." + + properties.linear_tiling_features.transfer_src_bit = true; + properties.linear_tiling_features.transfer_dst_bit = true; + } + + return properties; +} + +pub fn getImageFormatProperties( + interface: *Interface, + format: vk.Format, + image_type: vk.ImageType, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, + _: vk.ImageCreateFlags, +) VkError!vk.ImageFormatProperties { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + if (!try self.isFormatSupported(format, image_type, tiling, usage)) + return VkError.FormatNotSupported; + + const properties: vk.ImageFormatProperties = .{ + .max_extent = .{ .width = 0, .height = 0, .depth = 1 }, + .max_mip_levels = 1, + .max_array_layers = 1, + .sample_counts = .{ .@"1_bit" = true }, + .max_resource_size = std.math.maxInt(u32), + }; + + return properties; +} + +/// Phi does not support sparse images. +pub fn getSparseImageFormatProperties( + interface: *Interface, + format: vk.Format, + image_type: vk.ImageType, + samples: vk.SampleCountFlags, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, + properties: ?[*]vk.SparseImageFormatProperties, +) VkError!u32 { + _ = interface; + _ = format; + _ = image_type; + _ = samples; + _ = tiling; + _ = usage; + _ = properties; + return 0; +} + +/// Phi does not support sparse images. +pub fn getSparseImageFormatProperties2( + interface: *Interface, + format: vk.Format, + image_type: vk.ImageType, + samples: vk.SampleCountFlags, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, + properties: ?[*]vk.SparseImageFormatProperties2, +) VkError!u32 { + _ = interface; + _ = format; + _ = image_type; + _ = samples; + _ = tiling; + _ = usage; + _ = properties; + return 0; +} + +fn isFormatSupported( + self: *Self, + format: vk.Format, + image_type: vk.ImageType, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, +) VkError!bool { + const format_properties = try self.interface.getFormatProperties(format); + const format_features = switch (tiling) { + .linear => format_properties.linear_tiling_features, + .optimal => format_properties.optimal_tiling_features, + else => return false, + }; + + if (!checkFormatUsage(usage, format_features)) + return false; + + const all_recognized_usages: vk.ImageUsageFlags = .{ + .sampled_bit = true, + .storage_bit = true, + .color_attachment_bit = true, + .depth_stencil_attachment_bit = true, + .input_attachment_bit = true, + .transfer_src_bit = true, + .transfer_dst_bit = true, + .transient_attachment_bit = true, + }; + + if (usage.subtract(all_recognized_usages).toInt() != 0) + return false; + + if (usage.sampled_bit) { + if (tiling != .linear and !format_features.sampled_image_bit) + return false; + } + + if (tiling == .linear) { + if (image_type != .@"2d") + return false; + if (base.format.isDepth(format) or base.format.isStencil(format)) + return false; + } + + return true; +} + +fn checkFormatUsage(usage: vk.ImageUsageFlags, features: vk.FormatFeatureFlags) bool { + if (usage.sampled_bit and !features.sampled_image_bit) + return false; + if (usage.storage_bit and !features.storage_image_bit) + return false; + if (usage.color_attachment_bit and !features.color_attachment_bit) + return false; + if (usage.depth_stencil_attachment_bit and !features.depth_stencil_attachment_bit) + return false; + if (usage.input_attachment_bit and !(features.color_attachment_bit or features.depth_stencil_attachment_bit)) + return false; + if (usage.transfer_src_bit and !features.transfer_src_bit) + return false; + if (usage.transfer_dst_bit and !features.transfer_dst_bit) + return false; + return true; +} + +pub fn getSurfaceSupportKHR(_: *Interface, _: u32, _: *SurfaceKHR) VkError!bool { + return true; +} + +const CpuidRegs = packed struct { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +}; + +fn cpuid(leaf_id: u32, subleaf_id: u32) CpuidRegs { + comptime { + switch (builtin.cpu.arch) { + .x86, .x86_64 => {}, + else => @compileError("cpuid is only available on x86/x86_64"), + } + } + + var eax: u32 = undefined; + var ebx: u32 = undefined; + var ecx: u32 = undefined; + var edx: u32 = undefined; + + asm volatile ("cpuid" + : [_] "={eax}" (eax), + [_] "={ebx}" (ebx), + [_] "={ecx}" (ecx), + [_] "={edx}" (edx), + : [_] "{eax}" (leaf_id), + [_] "{ecx}" (subleaf_id), + ); + + return .{ + .eax = eax, + .ebx = ebx, + .ecx = ecx, + .edx = edx, + }; +} + +fn writeU32Le(dst: []u8, offset: usize, value: u32) void { + dst[offset + 0] = @truncate(value); + dst[offset + 1] = @truncate(value >> 8); + dst[offset + 2] = @truncate(value >> 16); + dst[offset + 3] = @truncate(value >> 24); +} diff --git a/src/phi/PhiPipeline.zig b/src/phi/PhiPipeline.zig new file mode 100644 index 0000000..a61048b --- /dev/null +++ b/src/phi/PhiPipeline.zig @@ -0,0 +1,37 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Pipeline; + +interface: Interface, + +pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache: ?*base.PipelineCache, info: *const vk.ComputePipelineCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.initCompute(device, allocator, cache, info); + interface.vtable = &.{ .destroy = destroy }; + + self.* = .{ .interface = interface }; + return self; +} + +pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache: ?*base.PipelineCache, info: *const vk.GraphicsPipelineCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.initGraphics(device, allocator, cache, info); + interface.vtable = &.{ .destroy = destroy }; + + self.* = .{ .interface = interface }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiPipelineCache.zig b/src/phi/PhiPipelineCache.zig new file mode 100644 index 0000000..ca02598 --- /dev/null +++ b/src/phi/PhiPipelineCache.zig @@ -0,0 +1,26 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.PipelineCache; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.PipelineCacheCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + interface.vtable = &.{ .destroy = destroy }; + + self.* = .{ .interface = interface }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiPipelineLayout.zig b/src/phi/PhiPipelineLayout.zig new file mode 100644 index 0000000..3f0bfc7 --- /dev/null +++ b/src/phi/PhiPipelineLayout.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.PipelineLayout; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.PipelineLayoutCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiQueryPool.zig b/src/phi/PhiQueryPool.zig new file mode 100644 index 0000000..eca39ba --- /dev/null +++ b/src/phi/PhiQueryPool.zig @@ -0,0 +1,33 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.QueryPool; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.QueryPoolCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.free(interface.queries); + allocator.destroy(self); +} diff --git a/src/phi/PhiQueue.zig b/src/phi/PhiQueue.zig new file mode 100644 index 0000000..163cd53 --- /dev/null +++ b/src/phi/PhiQueue.zig @@ -0,0 +1,64 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const PhiCommandBuffer = @import("PhiCommandBuffer.zig"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Queue; + +interface: Interface, + +pub fn create(allocator: std.mem.Allocator, device: *base.Device, index: u32, family_index: u32, flags: vk.DeviceQueueCreateFlags) VkError!*Interface { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(allocator, device, index, family_index, flags); + interface.dispatch_table = &.{ + .bindSparse = bindSparse, + .submit = submit, + .waitIdle = waitIdle, + }; + + self.* = .{ .interface = interface }; + return &self.interface; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn bindSparse(interface: *Interface, info: []const vk.BindSparseInfo, fence: ?*base.Fence) VkError!void { + _ = interface; + _ = info; + _ = fence; + return VkError.FeatureNotPresent; +} + +pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*base.Fence) VkError!void { + _ = interface; + for (infos) |info| { + for (info.wait_semaphores.items) |semaphore| { + try semaphore.wait(); + } + + for (info.command_buffers.items) |command_buffer| { + const intel_command_buffer: *PhiCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); + _ = intel_command_buffer; + } + + for (info.signal_semaphores.items) |semaphore| { + try semaphore.signal(); + } + } + if (fence) |value| { + try value.signal(); + } +} + +pub fn waitIdle(interface: *Interface) VkError!void { + _ = interface; +} diff --git a/src/phi/PhiRenderPass.zig b/src/phi/PhiRenderPass.zig new file mode 100644 index 0000000..cf56459 --- /dev/null +++ b/src/phi/PhiRenderPass.zig @@ -0,0 +1,40 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.RenderPass; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.RenderPassCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + .getRenderAreaGranularity = getRenderAreaGranularity, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn getRenderAreaGranularity(_: *Interface) vk.Extent2D { + return .{ + .width = 1, + .height = 1, + }; +} diff --git a/src/phi/PhiSampler.zig b/src/phi/PhiSampler.zig new file mode 100644 index 0000000..3b22902 --- /dev/null +++ b/src/phi/PhiSampler.zig @@ -0,0 +1,26 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Sampler; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.SamplerCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + interface.vtable = &.{ .destroy = destroy }; + + self.* = .{ .interface = interface }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/phi/PhiShaderModule.zig b/src/phi/PhiShaderModule.zig new file mode 100644 index 0000000..c91d96a --- /dev/null +++ b/src/phi/PhiShaderModule.zig @@ -0,0 +1,44 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.ShaderModule; + +interface: Interface, +ref_count: std.atomic.Value(usize), + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.ShaderModuleCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + interface.vtable = &.{ .destroy = destroy }; + + self.* = .{ + .interface = interface, + .ref_count = std.atomic.Value(usize).init(1), + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.unref(allocator); +} + +pub fn drop(self: *Self, allocator: std.mem.Allocator) void { + allocator.destroy(self); +} + +pub fn ref(self: *Self) void { + _ = self.ref_count.fetchAdd(1, .monotonic); +} + +pub fn unref(self: *Self, allocator: std.mem.Allocator) void { + if (self.ref_count.fetchSub(1, .release) == 1) { + self.drop(allocator); + } +} diff --git a/src/phi/lib.zig b/src/phi/lib.zig new file mode 100644 index 0000000..b101b46 --- /dev/null +++ b/src/phi/lib.zig @@ -0,0 +1,83 @@ +const std = @import("std"); +const vk = @import("vulkan"); +pub const base = @import("base"); + +pub const c = @import("intel_c"); +pub const config = base.config; + +pub const PhiInstance = @import("PhiInstance.zig"); +pub const PhiDevice = @import("PhiDevice.zig"); +pub const PhiPhysicalDevice = @import("PhiPhysicalDevice.zig"); +pub const PhiQueue = @import("PhiQueue.zig"); + +pub const PhiBinarySemaphore = @import("PhiBinarySemaphore.zig"); +pub const PhiBuffer = @import("PhiBuffer.zig"); +pub const PhiBufferView = @import("PhiBufferView.zig"); +pub const PhiCommandBuffer = @import("PhiCommandBuffer.zig"); +pub const PhiCommandPool = @import("PhiCommandPool.zig"); +pub const PhiDescriptorPool = @import("PhiDescriptorPool.zig"); +pub const PhiDescriptorSet = @import("PhiDescriptorSet.zig"); +pub const PhiDescriptorSetLayout = @import("PhiDescriptorSetLayout.zig"); +pub const PhiDeviceMemory = @import("PhiDeviceMemory.zig"); +pub const PhiEvent = @import("PhiEvent.zig"); +pub const PhiFence = @import("PhiFence.zig"); +pub const PhiFramebuffer = @import("PhiFramebuffer.zig"); +pub const PhiImage = @import("PhiImage.zig"); +pub const PhiImageView = @import("PhiImageView.zig"); +pub const PhiPipeline = @import("PhiPipeline.zig"); +pub const PhiPipelineCache = @import("PhiPipelineCache.zig"); +pub const PhiPipelineLayout = @import("PhiPipelineLayout.zig"); +pub const PhiQueryPool = @import("PhiQueryPool.zig"); +pub const PhiRenderPass = @import("PhiRenderPass.zig"); +pub const PhiSampler = @import("PhiSampler.zig"); +pub const PhiShaderModule = @import("PhiShaderModule.zig"); + +pub const Instance = PhiInstance; + +pub const DRIVER_NAME = "Phi"; + +pub const PHYSICAL_DEVICE_DEFAULT_NAME = "Intel(R) Xeon Phi(TM) Coprocessor"; + +pub const INTEL_PCI_VENDOR_ID = 0x8086; + +pub const VULKAN_VERSION = vk.makeApiVersion( + 0, + config.phi_vulkan_version.major, + config.phi_vulkan_version.minor, + config.phi_vulkan_version.patch, +); + +pub const std_options = base.std_options; + +comptime { + _ = base; +} + +test { + std.testing.refAllDecls(PhiBinarySemaphore); + std.testing.refAllDecls(PhiBuffer); + std.testing.refAllDecls(PhiBufferView); + std.testing.refAllDecls(PhiCommandBuffer); + std.testing.refAllDecls(PhiCommandPool); + std.testing.refAllDecls(PhiDescriptorPool); + std.testing.refAllDecls(PhiDescriptorSet); + std.testing.refAllDecls(PhiDescriptorSetLayout); + std.testing.refAllDecls(PhiDevice); + std.testing.refAllDecls(PhiDeviceMemory); + std.testing.refAllDecls(PhiEvent); + std.testing.refAllDecls(PhiFence); + std.testing.refAllDecls(PhiFramebuffer); + std.testing.refAllDecls(PhiImage); + std.testing.refAllDecls(PhiImageView); + std.testing.refAllDecls(PhiInstance); + std.testing.refAllDecls(PhiPhysicalDevice); + std.testing.refAllDecls(PhiPipeline); + std.testing.refAllDecls(PhiPipelineCache); + std.testing.refAllDecls(PhiPipelineLayout); + std.testing.refAllDecls(PhiQueryPool); + std.testing.refAllDecls(PhiQueue); + std.testing.refAllDecls(PhiRenderPass); + std.testing.refAllDecls(PhiSampler); + std.testing.refAllDecls(PhiShaderModule); + std.testing.refAllDecls(base); +} diff --git a/src/phi/pci_ids.zig b/src/phi/pci_ids.zig new file mode 100644 index 0000000..a40f957 --- /dev/null +++ b/src/phi/pci_ids.zig @@ -0,0 +1,29 @@ +const std = @import("std"); + +const PciInfo = struct { + id: u16, + name: []const u8, +}; + +/// Not a hashmap as they need runtime allocations +pub const map = [_]PciInfo{ + .{ .id = 0x2250, .name = "Intel(R) Xeon Phi(TM) Coprocessor 5100 Series" }, + + .{ .id = 0x2251, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2252, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2253, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2254, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2255, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2256, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2257, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2258, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x2259, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x225a, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + .{ .id = 0x225b, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" }, + + .{ .id = 0x225c, .name = "Intel(R) Xeon Phi(TM) Coprocessor SE10/7120 Series" }, + .{ .id = 0x225d, .name = "Intel(R) Xeon Phi(TM) Coprocessor 3120 Series" }, + .{ .id = 0x225e, .name = "Intel(R) Xeon Phi(TM) Coprocessor 31S1" }, + + .{ .id = 0x2262, .name = "Intel(R) Xeon Phi(TM) Coprocessor 7220" }, +};