From 38f802b29460b341a27b85668e8c50b511717571 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Tue, 16 Jun 2026 05:06:20 +0200 Subject: [PATCH] adding base for intel backend --- build.zig | 26 + src/intel/IntelBinarySemaphore.zig | 44 ++ src/intel/IntelBuffer.zig | 40 ++ src/intel/IntelBufferView.zig | 32 + src/intel/IntelCommandBuffer.zig | 392 +++++++++++ src/intel/IntelCommandPool.zig | 48 ++ src/intel/IntelDescriptorPool.zig | 57 ++ src/intel/IntelDescriptorSet.zig | 47 ++ src/intel/IntelDescriptorSetLayout.zig | 32 + src/intel/IntelDevice.zig | 208 ++++++ src/intel/IntelDeviceMemory.zig | 59 ++ src/intel/IntelEvent.zig | 56 ++ src/intel/IntelFence.zig | 57 ++ src/intel/IntelFramebuffer.zig | 27 + src/intel/IntelImage.zig | 79 +++ src/intel/IntelImageView.zig | 32 + src/intel/IntelInstance.zig | 75 +++ src/intel/IntelPhysicalDevice.zig | 873 +++++++++++++++++++++++++ src/intel/IntelPipeline.zig | 37 ++ src/intel/IntelPipelineCache.zig | 26 + src/intel/IntelPipelineLayout.zig | 32 + src/intel/IntelQueryPool.zig | 33 + src/intel/IntelQueue.zig | 64 ++ src/intel/IntelRenderPass.zig | 40 ++ src/intel/IntelSampler.zig | 26 + src/intel/IntelShaderModule.zig | 44 ++ src/intel/lib.zig | 84 +++ 27 files changed, 2570 insertions(+) create mode 100644 src/intel/IntelBinarySemaphore.zig create mode 100644 src/intel/IntelBuffer.zig create mode 100644 src/intel/IntelBufferView.zig create mode 100644 src/intel/IntelCommandBuffer.zig create mode 100644 src/intel/IntelCommandPool.zig create mode 100644 src/intel/IntelDescriptorPool.zig create mode 100644 src/intel/IntelDescriptorSet.zig create mode 100644 src/intel/IntelDescriptorSetLayout.zig create mode 100644 src/intel/IntelDevice.zig create mode 100644 src/intel/IntelDeviceMemory.zig create mode 100644 src/intel/IntelEvent.zig create mode 100644 src/intel/IntelFence.zig create mode 100644 src/intel/IntelFramebuffer.zig create mode 100644 src/intel/IntelImage.zig create mode 100644 src/intel/IntelImageView.zig create mode 100644 src/intel/IntelInstance.zig create mode 100644 src/intel/IntelPhysicalDevice.zig create mode 100644 src/intel/IntelPipeline.zig create mode 100644 src/intel/IntelPipelineCache.zig create mode 100644 src/intel/IntelPipelineLayout.zig create mode 100644 src/intel/IntelQueryPool.zig create mode 100644 src/intel/IntelQueue.zig create mode 100644 src/intel/IntelRenderPass.zig create mode 100644 src/intel/IntelSampler.zig create mode 100644 src/intel/IntelShaderModule.zig create mode 100644 src/intel/lib.zig diff --git a/build.zig b/build.zig index 0b55f62..c399efb 100644 --- a/build.zig +++ b/build.zig @@ -38,6 +38,13 @@ const implementations = [_]ImplementationDesc{ .custom = customSoft, .options = optionsSoft, }, + .{ + .name = "intel", + .root_source_file = "src/intel/lib.zig", + .vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 }, + .custom = customIntel, + .options = optionsIntel, + }, }; const RunningMode = enum { @@ -270,6 +277,25 @@ fn optionsSoft(b: *std.Build, options: *Step.Options) !void { options.addOption(bool, "soft_approximates_rgb", approxiamte_rgb_option); } +fn customIntel( + _: *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("intel_c", base_c_mod); +} + +fn optionsIntel(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/intel/IntelBinarySemaphore.zig b/src/intel/IntelBinarySemaphore.zig new file mode 100644 index 0000000..421d048 --- /dev/null +++ b/src/intel/IntelBinarySemaphore.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/intel/IntelBuffer.zig b/src/intel/IntelBuffer.zig new file mode 100644 index 0000000..07e1df8 --- /dev/null +++ b/src/intel/IntelBuffer.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/intel/IntelBufferView.zig b/src/intel/IntelBufferView.zig new file mode 100644 index 0000000..046a07a --- /dev/null +++ b/src/intel/IntelBufferView.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/intel/IntelCommandBuffer.zig b/src/intel/IntelCommandBuffer.zig new file mode 100644 index 0000000..9f919d1 --- /dev/null +++ b/src/intel/IntelCommandBuffer.zig @@ -0,0 +1,392 @@ +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, + .setDeviceMask = setDeviceMask, + .setScissor = setScissor, + .setStencilCompareMask = setStencilCompareMask, + .setStencilReference = setStencilReference, + .setStencilWriteMask = setStencilWriteMask, + .setViewport = setViewport, + .updateBuffer = updateBuffer, + .waitEvent = waitEvent, + }; + + 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 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; +} diff --git a/src/intel/IntelCommandPool.zig b/src/intel/IntelCommandPool.zig new file mode 100644 index 0000000..bf5b86d --- /dev/null +++ b/src/intel/IntelCommandPool.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 IntelCommandBuffer = @import("IntelCommandBuffer.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 IntelCommandBuffer.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/intel/IntelDescriptorPool.zig b/src/intel/IntelDescriptorPool.zig new file mode 100644 index 0000000..8369e0d --- /dev/null +++ b/src/intel/IntelDescriptorPool.zig @@ -0,0 +1,57 @@ +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 IntelDescriptorSet = @import("IntelDescriptorSet.zig"); + +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/intel/IntelDescriptorSet.zig b/src/intel/IntelDescriptorSet.zig new file mode 100644 index 0000000..42c3e06 --- /dev/null +++ b/src/intel/IntelDescriptorSet.zig @@ -0,0 +1,47 @@ +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.free(self.heap); + 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/intel/IntelDescriptorSetLayout.zig b/src/intel/IntelDescriptorSetLayout.zig new file mode 100644 index 0000000..b2d706e --- /dev/null +++ b/src/intel/IntelDescriptorSetLayout.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/intel/IntelDevice.zig b/src/intel/IntelDevice.zig new file mode 100644 index 0000000..8fd68ed --- /dev/null +++ b/src/intel/IntelDevice.zig @@ -0,0 +1,208 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const IntelQueue = @import("IntelQueue.zig"); + +pub const IntelBinarySemaphore = @import("IntelBinarySemaphore.zig"); +pub const IntelBuffer = @import("IntelBuffer.zig"); +pub const IntelBufferView = @import("IntelBufferView.zig"); +pub const IntelCommandBuffer = @import("IntelCommandBuffer.zig"); +pub const IntelCommandPool = @import("IntelCommandPool.zig"); +pub const IntelDescriptorPool = @import("IntelDescriptorPool.zig"); +pub const IntelDescriptorSetLayout = @import("IntelDescriptorSetLayout.zig"); +pub const IntelDeviceMemory = @import("IntelDeviceMemory.zig"); +pub const IntelEvent = @import("IntelEvent.zig"); +pub const IntelFence = @import("IntelFence.zig"); +pub const IntelFramebuffer = @import("IntelFramebuffer.zig"); +pub const IntelImage = @import("IntelImage.zig"); +pub const IntelInstance = @import("IntelInstance.zig"); +pub const IntelImageView = @import("IntelImageView.zig"); +pub const IntelPipeline = @import("IntelPipeline.zig"); +pub const IntelPipelineCache = @import("IntelPipelineCache.zig"); +pub const IntelPipelineLayout = @import("IntelPipelineLayout.zig"); +pub const IntelQueryPool = @import("IntelQueryPool.zig"); +pub const IntelRenderPass = @import("IntelRenderPass.zig"); +pub const IntelSampler = @import("IntelSampler.zig"); +pub const IntelShaderModule = @import("IntelShaderModule.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 = IntelQueue.create, + .destroyQueue = IntelQueue.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 IntelDeviceMemory.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 IntelBuffer.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 IntelDescriptorPool.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 IntelDescriptorSetLayout.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 IntelFence.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 IntelCommandPool.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 IntelImage.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 IntelImageView.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 IntelBufferView.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 IntelPipeline.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 IntelEvent.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 IntelFramebuffer.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 IntelPipeline.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 IntelPipelineCache.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 IntelPipelineLayout.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 IntelQueryPool.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 IntelRenderPass.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 IntelSampler.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 IntelBinarySemaphore.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 IntelShaderModule.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/intel/IntelDeviceMemory.zig b/src/intel/IntelDeviceMemory.zig new file mode 100644 index 0000000..89d8f22 --- /dev/null +++ b/src/intel/IntelDeviceMemory.zig @@ -0,0 +1,59 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const IntelDevice = @import("IntelDevice.zig"); +const base = @import("base"); +const lib = @import("lib.zig"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.DeviceMemory; + +interface: Interface, + +pub fn create(device: *IntelDevice, 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/intel/IntelEvent.zig b/src/intel/IntelEvent.zig new file mode 100644 index 0000000..68b9b0e --- /dev/null +++ b/src/intel/IntelEvent.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/intel/IntelFence.zig b/src/intel/IntelFence.zig new file mode 100644 index 0000000..440a251 --- /dev/null +++ b/src/intel/IntelFence.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/intel/IntelFramebuffer.zig b/src/intel/IntelFramebuffer.zig new file mode 100644 index 0000000..ac43a94 --- /dev/null +++ b/src/intel/IntelFramebuffer.zig @@ -0,0 +1,27 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const IntelRenderPass = @import("IntelRenderPass.zig"); + +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/intel/IntelImage.zig b/src/intel/IntelImage.zig new file mode 100644 index 0000000..57624e2 --- /dev/null +++ b/src/intel/IntelImage.zig @@ -0,0 +1,79 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const lib = @import("lib.zig"); + +const VkError = base.VkError; +const IntelBuffer = @import("IntelBuffer.zig"); + +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.alignment = lib.MEMORY_REQUIREMENTS_IMAGE_ALIGNMENT; +} + +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/intel/IntelImageView.zig b/src/intel/IntelImageView.zig new file mode 100644 index 0000000..db0956b --- /dev/null +++ b/src/intel/IntelImageView.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/intel/IntelInstance.zig b/src/intel/IntelInstance.zig new file mode 100644 index 0000000..c813713 --- /dev/null +++ b/src/intel/IntelInstance.zig @@ -0,0 +1,75 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const IntelPhysicalDevice = @import("IntelPhysicalDevice.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 = if (comptime base.config.intel_single_threaded) .init_single_threaded else 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) VkError!void { + _ = interface; + _ = allocator; +} + +fn releasePhysicalDevices(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + _ = interface; + _ = allocator; +} + +fn io(interface: *Interface) std.Io { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + return self.io_impl; +} diff --git a/src/intel/IntelPhysicalDevice.zig b/src/intel/IntelPhysicalDevice.zig new file mode 100644 index 0000000..bcfd7da --- /dev/null +++ b/src/intel/IntelPhysicalDevice.zig @@ -0,0 +1,873 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const vk = @import("vulkan"); +const base = @import("base"); +const lib = @import("lib.zig"); + +const IntelDevice = @import("IntelDevice.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) 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.driver_version = @bitCast(base.DRIVER_VERSION); + interface.props.device_id = lib.DEVICE_ID; + interface.props.device_type = .cpu; + interface.props.pipeline_cache_uuid = lib.PIPELINE_CACHE_UUID; + 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 IntelDevice.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, + flags: vk.ImageCreateFlags, +) VkError!vk.ImageFormatProperties { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + if (!try self.isFormatSupported(format, image_type, tiling, usage)) + return VkError.FormatNotSupported; + + var properties: vk.ImageFormatProperties = .{ + .max_extent = .{ .width = 0, .height = 0, .depth = 1 }, + .max_mip_levels = 1, + .max_array_layers = lib.MAX_IMAGE_ARRAY_LAYERS, + .sample_counts = .{ .@"1_bit" = true }, + .max_resource_size = std.math.maxInt(u32), + }; + + switch (image_type) { + .@"1d" => { + properties.max_mip_levels = lib.MAX_IMAGE_LEVELS_1D; + properties.max_extent.width = 1 << (lib.MAX_IMAGE_LEVELS_1D - 1); + properties.max_extent.height = 1; + }, + .@"2d" => { + if (flags.cube_compatible_bit) { + properties.max_mip_levels = lib.MAX_IMAGE_LEVELS_CUBE; + properties.max_extent.width = 1 << (lib.MAX_IMAGE_LEVELS_CUBE - 1); + properties.max_extent.height = 1 << (lib.MAX_IMAGE_LEVELS_CUBE - 1); + } else { + properties.max_mip_levels = lib.MAX_IMAGE_LEVELS_2D; + properties.max_extent.width = 1 << (lib.MAX_IMAGE_LEVELS_2D - 1); + properties.max_extent.height = 1 << (lib.MAX_IMAGE_LEVELS_2D - 1); + + const format_properties = try interface.getFormatProperties(format); + const format_features = if (tiling == .linear) format_properties.linear_tiling_features else format_properties.optimal_tiling_features; + if (format_features.color_attachment_bit or format_features.depth_stencil_attachment_bit) { + properties.sample_counts = .{ .@"1_bit" = true, .@"4_bit" = true }; + } + } + }, + .@"3d" => { + properties.max_mip_levels = lib.MAX_IMAGE_LEVELS_3D; + properties.max_extent.width = 1 << (lib.MAX_IMAGE_LEVELS_3D - 1); + properties.max_extent.height = 1 << (lib.MAX_IMAGE_LEVELS_3D - 1); + properties.max_extent.depth = 1 << (lib.MAX_IMAGE_LEVELS_3D - 1); + properties.max_array_layers = 1; + }, + else => return VkError.FormatNotSupported, + } + + if (tiling == .linear) { + properties.max_mip_levels = 1; + properties.max_array_layers = 1; + properties.sample_counts = .{ .@"1_bit" = true }; + } + + return properties; +} + +/// Intel 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; +} + +/// Intel 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/intel/IntelPipeline.zig b/src/intel/IntelPipeline.zig new file mode 100644 index 0000000..a61048b --- /dev/null +++ b/src/intel/IntelPipeline.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/intel/IntelPipelineCache.zig b/src/intel/IntelPipelineCache.zig new file mode 100644 index 0000000..ca02598 --- /dev/null +++ b/src/intel/IntelPipelineCache.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/intel/IntelPipelineLayout.zig b/src/intel/IntelPipelineLayout.zig new file mode 100644 index 0000000..3f0bfc7 --- /dev/null +++ b/src/intel/IntelPipelineLayout.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/intel/IntelQueryPool.zig b/src/intel/IntelQueryPool.zig new file mode 100644 index 0000000..eca39ba --- /dev/null +++ b/src/intel/IntelQueryPool.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/intel/IntelQueue.zig b/src/intel/IntelQueue.zig new file mode 100644 index 0000000..26c0fbc --- /dev/null +++ b/src/intel/IntelQueue.zig @@ -0,0 +1,64 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const IntelCommandBuffer = @import("IntelCommandBuffer.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: *IntelCommandBuffer = @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/intel/IntelRenderPass.zig b/src/intel/IntelRenderPass.zig new file mode 100644 index 0000000..cf56459 --- /dev/null +++ b/src/intel/IntelRenderPass.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/intel/IntelSampler.zig b/src/intel/IntelSampler.zig new file mode 100644 index 0000000..3b22902 --- /dev/null +++ b/src/intel/IntelSampler.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/intel/IntelShaderModule.zig b/src/intel/IntelShaderModule.zig new file mode 100644 index 0000000..c91d96a --- /dev/null +++ b/src/intel/IntelShaderModule.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/intel/lib.zig b/src/intel/lib.zig new file mode 100644 index 0000000..a0795fe --- /dev/null +++ b/src/intel/lib.zig @@ -0,0 +1,84 @@ +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 IntelInstance = @import("IntelInstance.zig"); +pub const IntelDevice = @import("IntelDevice.zig"); +pub const IntelPhysicalDevice = @import("IntelPhysicalDevice.zig"); +pub const IntelQueue = @import("IntelQueue.zig"); + +pub const IntelBinarySemaphore = @import("IntelBinarySemaphore.zig"); +pub const IntelBuffer = @import("IntelBuffer.zig"); +pub const IntelBufferView = @import("IntelBufferView.zig"); +pub const IntelCommandBuffer = @import("IntelCommandBuffer.zig"); +pub const IntelCommandPool = @import("IntelCommandPool.zig"); +pub const IntelDescriptorPool = @import("IntelDescriptorPool.zig"); +pub const IntelDescriptorSet = @import("IntelDescriptorSet.zig"); +pub const IntelDescriptorSetLayout = @import("IntelDescriptorSetLayout.zig"); +pub const IntelDeviceMemory = @import("IntelDeviceMemory.zig"); +pub const IntelEvent = @import("IntelEvent.zig"); +pub const IntelFence = @import("IntelFence.zig"); +pub const IntelFramebuffer = @import("IntelFramebuffer.zig"); +pub const IntelImage = @import("IntelImage.zig"); +pub const IntelImageView = @import("IntelImageView.zig"); +pub const IntelPipeline = @import("IntelPipeline.zig"); +pub const IntelPipelineCache = @import("IntelPipelineCache.zig"); +pub const IntelPipelineLayout = @import("IntelPipelineLayout.zig"); +pub const IntelQueryPool = @import("IntelQueryPool.zig"); +pub const IntelRenderPass = @import("IntelRenderPass.zig"); +pub const IntelSampler = @import("IntelSampler.zig"); +pub const IntelShaderModule = @import("IntelShaderModule.zig"); + +pub const Instance = IntelInstance; + +pub const DRIVER_NAME = "Intel"; + +pub const VULKAN_VERSION = vk.makeApiVersion( + 0, + config.intel_vulkan_version.major, + config.intel_vulkan_version.minor, + config.intel_vulkan_version.patch, +); + +pub const DEVICE_ID = 0x00000000; +pub const PIPELINE_CACHE_UUID: [vk.UUID_SIZE]u8 = "ApeIntelCacheUUI".*; + +pub const PHYSICAL_DEVICE_DEFAULT_NAME = "Ape Intel device"; + +pub const std_options = base.std_options; + +comptime { + _ = base; +} + +test { + std.testing.refAllDecls(IntelBinarySemaphore); + std.testing.refAllDecls(IntelBuffer); + std.testing.refAllDecls(IntelBufferView); + std.testing.refAllDecls(IntelCommandBuffer); + std.testing.refAllDecls(IntelCommandPool); + std.testing.refAllDecls(IntelDescriptorPool); + std.testing.refAllDecls(IntelDescriptorSet); + std.testing.refAllDecls(IntelDescriptorSetLayout); + std.testing.refAllDecls(IntelDevice); + std.testing.refAllDecls(IntelDeviceMemory); + std.testing.refAllDecls(IntelEvent); + std.testing.refAllDecls(IntelFence); + std.testing.refAllDecls(IntelFramebuffer); + std.testing.refAllDecls(IntelImage); + std.testing.refAllDecls(IntelImageView); + std.testing.refAllDecls(IntelInstance); + std.testing.refAllDecls(IntelPhysicalDevice); + std.testing.refAllDecls(IntelPipeline); + std.testing.refAllDecls(IntelPipelineCache); + std.testing.refAllDecls(IntelPipelineLayout); + std.testing.refAllDecls(IntelQueryPool); + std.testing.refAllDecls(IntelQueue); + std.testing.refAllDecls(IntelRenderPass); + std.testing.refAllDecls(IntelSampler); + std.testing.refAllDecls(IntelShaderModule); + std.testing.refAllDecls(base); +}