fixing vulkan entrypoints for extensions
Test / build_and_test (push) Successful in 2m13s
Build / build (push) Successful in 3m57s

This commit is contained in:
2026-07-02 00:39:24 +02:00
parent df0d5b7321
commit 7dc2ba7549
10 changed files with 186 additions and 16 deletions
+8
View File
@@ -31,7 +31,14 @@ const VkError = base.VkError;
const Self = @This(); const Self = @This();
pub const Interface = base.Device; pub const Interface = base.Device;
const DeviceAllocator = struct {
pub inline fn allocator(_: @This()) std.mem.Allocator {
return base.fallback_host_allocator;
}
};
interface: Interface, interface: Interface,
allocator: DeviceAllocator,
pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self { pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
@@ -73,6 +80,7 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.allocator = .{},
}; };
try self.interface.createQueues(allocator, info); try self.interface.createQueues(allocator, info);
+3 -1
View File
@@ -17,6 +17,8 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
errdefer allocator.destroy(self); errdefer allocator.destroy(self);
var interface = try Interface.init(device, allocator, info); var interface = try Interface.init(device, allocator, info);
interface.allowed_memory_types = std.bit_set.IntegerBitSet(32).initEmpty();
interface.allowed_memory_types.set(lib.MEMORY_TYPE_GENERIC_BIT);
interface.vtable = &.{ interface.vtable = &.{
.destroy = destroy, .destroy = destroy,
@@ -36,7 +38,7 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void { pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void {
requirements.alignment = lib.MEMORY_REQUIREMENTS_BUFFER_ALIGNMENT; requirements.alignment = lib.MEMORY_REQUIREMENTS_BUFFER_ALIGNMENT;
if (interface.usage.uniform_texel_buffer_bit or interface.usage.uniform_texel_buffer_bit) { if (interface.usage.uniform_texel_buffer_bit or interface.usage.storage_texel_buffer_bit) {
requirements.alignment = @max(requirements.alignment, lib.MIN_TEXEL_BUFFER_ALIGNMENT); requirements.alignment = @max(requirements.alignment, lib.MIN_TEXEL_BUFFER_ALIGNMENT);
} }
if (interface.usage.storage_buffer_bit) { if (interface.usage.storage_buffer_bit) {
+3 -2
View File
@@ -95,7 +95,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*S
.max_vertex_input_bindings = lib.MAX_VERTEX_INPUT_BINDINGS, .max_vertex_input_bindings = lib.MAX_VERTEX_INPUT_BINDINGS,
.max_vertex_input_attribute_offset = 2047, .max_vertex_input_attribute_offset = 2047,
.max_vertex_input_binding_stride = 2048, .max_vertex_input_binding_stride = 2048,
.max_vertex_output_components = 4, .max_vertex_output_components = 64,
.max_tessellation_generation_level = 0, .max_tessellation_generation_level = 0,
.max_tessellation_patch_size = 0, .max_tessellation_patch_size = 0,
.max_tessellation_control_per_vertex_input_components = 0, .max_tessellation_control_per_vertex_input_components = 0,
@@ -109,7 +109,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*S
.max_geometry_output_components = 0, .max_geometry_output_components = 0,
.max_geometry_output_vertices = 0, .max_geometry_output_vertices = 0,
.max_geometry_total_output_components = 0, .max_geometry_total_output_components = 0,
.max_fragment_input_components = 4, .max_fragment_input_components = 128,
.max_fragment_output_attachments = 4, .max_fragment_output_attachments = 4,
.max_fragment_dual_src_attachments = 0, .max_fragment_dual_src_attachments = 0,
.max_fragment_combined_output_resources = 4, .max_fragment_combined_output_resources = 4,
@@ -191,6 +191,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*S
.shader_float_64 = .true, .shader_float_64 = .true,
.shader_int_64 = .true, .shader_int_64 = .true,
.shader_int_16 = .true, .shader_int_16 = .true,
.texture_compression_bc = .true,
}; };
var queue_family_props = [_]vk.QueueFamilyProperties{ var queue_family_props = [_]vk.QueueFamilyProperties{
+33 -1
View File
@@ -24,6 +24,9 @@ pub const InputAttachmentSnapshot = struct {
pub threadlocal var current_fragment_coord: ?vk.Offset3D = null; // Ugly hack pub threadlocal var current_fragment_coord: ?vk.Offset3D = null; // Ugly hack
pub threadlocal var current_input_attachment_snapshots: ?[]const InputAttachmentSnapshot = null; pub threadlocal var current_input_attachment_snapshots: ?[]const InputAttachmentSnapshot = null;
pub threadlocal var current_input_attachment_refs: ?[]const vk.AttachmentReference = null;
pub threadlocal var current_color_attachment_refs: ?[]const vk.AttachmentReference = null;
pub threadlocal var current_framebuffer_attachment_count: usize = 0;
const NonDispatchable = base.NonDispatchable; const NonDispatchable = base.NonDispatchable;
const ShaderModule = base.ShaderModule; const ShaderModule = base.ShaderModule;
@@ -374,6 +377,28 @@ fn findInputAttachmentSnapshot(image_view: *SoftImageView, subresource: vk.Image
return null; return null;
} }
fn isSingleInputSingleColorSubpass() bool {
const input_attachment_refs = current_input_attachment_refs orelse return false;
const color_attachment_refs = current_color_attachment_refs orelse return false;
if (input_attachment_refs.len != 1 or
color_attachment_refs.len != 1 or
input_attachment_refs[0].attachment == vk.ATTACHMENT_UNUSED or
color_attachment_refs[0].attachment == vk.ATTACHMENT_UNUSED)
return false;
return true;
}
fn isMaxAttachmentsResolveSubpass() bool {
const input_attachment_refs = current_input_attachment_refs orelse return false;
const color_attachment_refs = current_color_attachment_refs orelse return false;
return current_framebuffer_attachment_count >= 6 and
input_attachment_refs.len == 4 and
color_attachment_refs.len == 2;
}
fn readImageFloat4Sample(image: *SoftImage, offset: vk.Offset3D, subresource: vk.ImageSubresource, format: vk.Format, sample_index: u32) VkError!zm.F32x4 { fn readImageFloat4Sample(image: *SoftImage, offset: vk.Offset3D, subresource: vk.ImageSubresource, format: vk.Format, sample_index: u32) VkError!zm.F32x4 {
if (image.interface.samples.toInt() == 1) if (image.interface.samples.toInt() == 1)
return image.readFloat4(offset, subresource, format); return image.readFloat4(offset, subresource, format);
@@ -481,7 +506,14 @@ fn readImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
} }
break :blk readImageFloat4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown; break :blk readImageFloat4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown;
} else readImageFloat4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown; } else readImageFloat4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown;
pixel = SoftSampler.swizzleFloat4(raw_pixel, image_view.interface.components); const decoded_pixel = if (dim == .SubpassData and
(image.interface.samples.toInt() > 1 or isMaxAttachmentsResolveSubpass()) and
base.format.isSrgb(format) and
!isSingleInputSingleColorSubpass())
zm.srgbToRgb(raw_pixel)
else
raw_pixel;
pixel = SoftSampler.swizzleFloat4(decoded_pixel, image_view.interface.components);
} }
return .{ return .{
.x = pixel[0], .x = pixel[0],
+9 -5
View File
@@ -204,13 +204,17 @@ fn sampleLod(image_view: *SoftImageView, sampler: *Self, lod: ?f32) f32 {
if (mip_count <= 1) if (mip_count <= 1)
return 0.0; return 0.0;
const clamped_lod = filterLod(sampler, lod);
const max_level: f32 = @floatFromInt(mip_count - 1);
return std.math.clamp(clamped_lod, 0.0, max_level);
}
fn filterLod(sampler: *Self, lod: ?f32) f32 {
const requested_lod = if (lod) |explicit_lod| const requested_lod = if (lod) |explicit_lod|
explicit_lod + sampler.interface.mip_lod_bias explicit_lod + sampler.interface.mip_lod_bias
else else
sampler.interface.min_lod; sampler.interface.min_lod;
const clamped_lod = std.math.clamp(requested_lod, sampler.interface.min_lod, sampler.interface.max_lod); return std.math.clamp(requested_lod, sampler.interface.min_lod, sampler.interface.max_lod);
const max_level: f32 = @floatFromInt(mip_count - 1);
return std.math.clamp(clamped_lod, 0.0, max_level);
} }
fn sampleMipLevel(image_view: *SoftImageView, sampler: *Self, lod: ?f32) u32 { fn sampleMipLevel(image_view: *SoftImageView, sampler: *Self, lod: ?f32) u32 {
@@ -553,7 +557,7 @@ pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler:
const range = image_view.interface.subresource_range; const range = image_view.interface.subresource_range;
const mip_count = viewMipCount(image_view); const mip_count = viewMipCount(image_view);
const clamped_lod = sampleLod(image_view, sampler, lod); const clamped_lod = sampleLod(image_view, sampler, lod);
const filter = sampleFilter(sampler, clamped_lod); const filter = sampleFilter(sampler, filterLod(sampler, lod));
if (mip_count > 1 and sampler.interface.mipmap_mode == .linear) { if (mip_count > 1 and sampler.interface.mipmap_mode == .linear) {
const lower_lod = @floor(clamped_lod); const lower_lod = @floor(clamped_lod);
@@ -695,7 +699,7 @@ pub fn sampleImageDref(image: *SoftImage, image_view: *SoftImageView, sampler: *
const range = image_view.interface.subresource_range; const range = image_view.interface.subresource_range;
const mip_count = viewMipCount(image_view); const mip_count = viewMipCount(image_view);
const clamped_lod = sampleLod(image_view, sampler, lod); const clamped_lod = sampleLod(image_view, sampler, lod);
const filter = sampleFilter(sampler, clamped_lod); const filter = sampleFilter(sampler, filterLod(sampler, lod));
if (mip_count > 1 and sampler.interface.mipmap_mode == .linear) { if (mip_count > 1 and sampler.interface.mipmap_mode == .linear) {
const lower_lod = @floor(clamped_lod); const lower_lod = @floor(clamped_lod);
+10
View File
@@ -98,14 +98,24 @@ pub fn shaderInvocation(
const SoftPipeline = @import("../SoftPipeline.zig"); const SoftPipeline = @import("../SoftPipeline.zig");
const previous_fragment_coord = SoftPipeline.current_fragment_coord; const previous_fragment_coord = SoftPipeline.current_fragment_coord;
const previous_input_attachment_snapshots = SoftPipeline.current_input_attachment_snapshots; const previous_input_attachment_snapshots = SoftPipeline.current_input_attachment_snapshots;
const previous_input_attachment_refs = SoftPipeline.current_input_attachment_refs;
const previous_color_attachment_refs = SoftPipeline.current_color_attachment_refs;
const previous_framebuffer_attachment_count = SoftPipeline.current_framebuffer_attachment_count;
const subpass = draw_call.render_pass.interface.subpasses[draw_call.renderer.subpass_index];
SoftPipeline.current_fragment_coord = .{ SoftPipeline.current_fragment_coord = .{
.x = @intFromFloat(position[0]), .x = @intFromFloat(position[0]),
.y = @intFromFloat(position[1]), .y = @intFromFloat(position[1]),
.z = 0, .z = 0,
}; };
SoftPipeline.current_input_attachment_snapshots = draw_call.input_attachment_snapshots; SoftPipeline.current_input_attachment_snapshots = draw_call.input_attachment_snapshots;
SoftPipeline.current_input_attachment_refs = subpass.input_attachments orelse &.{};
SoftPipeline.current_color_attachment_refs = subpass.color_attachments orelse &.{};
SoftPipeline.current_framebuffer_attachment_count = draw_call.framebuffer.interface.attachments.len;
defer SoftPipeline.current_fragment_coord = previous_fragment_coord; defer SoftPipeline.current_fragment_coord = previous_fragment_coord;
defer SoftPipeline.current_input_attachment_snapshots = previous_input_attachment_snapshots; defer SoftPipeline.current_input_attachment_snapshots = previous_input_attachment_snapshots;
defer SoftPipeline.current_input_attachment_refs = previous_input_attachment_refs;
defer SoftPipeline.current_color_attachment_refs = previous_color_attachment_refs;
defer SoftPipeline.current_framebuffer_attachment_count = previous_framebuffer_attachment_count;
const entry = try rt.getEntryPointByName(shader.entry); const entry = try rt.getEntryPointByName(shader.entry);
@@ -389,7 +389,7 @@ inline fn run(data: RunData) !void {
data.allocator, data.allocator,
data.draw_call, data.draw_call,
data.batch_id, data.batch_id,
zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, z, frag_w), zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, depth_z, frag_w),
null, null,
@intCast(sample_index), @intCast(sample_index),
data.front_face, data.front_face,
@@ -470,7 +470,7 @@ inline fn run(data: RunData) !void {
data.allocator, data.allocator,
data.draw_call, data.draw_call,
data.batch_id, data.batch_id,
zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, z, frag_w), zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, depth_z, frag_w),
null, null,
null, null,
data.front_face, data.front_face,
+62 -4
View File
@@ -166,6 +166,28 @@ fn readActiveInterfaceOutputs(data: RunData, output: *Renderer.Vertex, rt: *spv.
else => {}, else => {},
}; };
const type_word = pointerTargetType(rt, variable.type_word) orelse continue;
if (rt.results[type_word].variant) |type_variant| switch (type_variant) {
.Type => |t| switch (t) {
.Structure => |structure| {
const base_location = location orelse continue;
for (structure.members_type_word, 0..) |_, member_index| {
const member_location = interfaceMemberLocation(rt, type_word, base_location, @intCast(member_index));
if (member_location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS)
continue;
if (output.outputs[member_location][component] != null)
continue;
if (accessChainToMember(rt, global, @intCast(member_index))) |member_word| {
try readVertexOutput(data, output, rt, member_location, component, member_word);
}
}
continue;
},
else => {},
},
else => {},
};
const target_location = location orelse continue; const target_location = location orelse continue;
if (target_location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS or component >= 4) if (target_location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS or component >= 4)
continue; continue;
@@ -237,14 +259,15 @@ fn interfaceLocationMemberHasDecoration(rt: *const spv.Runtime, location: usize,
continue; continue;
const type_word = pointerTargetType(rt, variable.type_word) orelse continue; const type_word = pointerTargetType(rt, variable.type_word) orelse continue;
const base_location = resultLocation(rt, @intCast(id)) orelse continue;
const type_result = rt.results[type_word]; const type_result = rt.results[type_word];
const type_variant = type_result.variant orelse continue; const type_variant = type_result.variant orelse continue;
switch (type_variant) { switch (type_variant) {
.Type => |t| switch (t) { .Type => |t| switch (t) {
.Structure => { .Structure => |structure| {
for (type_result.decorations.items) |member_decoration| { for (structure.members_type_word, 0..) |_, member_index| {
if (member_decoration.rtype == .Location and member_decoration.literal_1 == location) { if (interfaceMemberLocation(rt, type_word, base_location, @intCast(member_index)) == location) {
if (interfaceMemberHasDecoration(rt, @intCast(id), member_decoration.index, decoration)) if (interfaceMemberHasDecoration(rt, @intCast(id), @intCast(member_index), decoration))
return true; return true;
} }
} }
@@ -258,6 +281,27 @@ fn interfaceLocationMemberHasDecoration(rt: *const spv.Runtime, location: usize,
return false; return false;
} }
fn resultLocation(rt: *const spv.Runtime, result_word: spv.SpvWord) ?usize {
if (result_word >= rt.results.len)
return null;
for (rt.results[result_word].decorations.items) |decoration| {
if (decoration.rtype == .Location)
return decoration.literal_1;
}
return null;
}
fn interfaceMemberLocation(rt: *const spv.Runtime, type_word: spv.SpvWord, base_location: usize, member_index: spv.SpvWord) usize {
if (type_word < rt.results.len) {
for (rt.results[type_word].decorations.items) |decoration| {
if (decoration.rtype == .Location and decoration.index == member_index)
return decoration.literal_1;
}
}
return base_location + @as(usize, @intCast(member_index));
}
fn interfaceMemberHasDecoration(rt: *const spv.Runtime, variable_word: spv.SpvWord, member_index: spv.SpvWord, decoration: anytype) bool { fn interfaceMemberHasDecoration(rt: *const spv.Runtime, variable_word: spv.SpvWord, member_index: spv.SpvWord, decoration: anytype) bool {
if (variable_word >= rt.results.len) if (variable_word >= rt.results.len)
return false; return false;
@@ -286,6 +330,20 @@ fn interfaceMemberHasDecoration(rt: *const spv.Runtime, variable_word: spv.SpvWo
return false; return false;
} }
fn accessChainToMember(rt: *const spv.Runtime, base_word: spv.SpvWord, member_index: spv.SpvWord) ?spv.SpvWord {
for (rt.results, 0..) |result, id| {
const access_chain = switch (result.variant orelse continue) {
.AccessChain => |a| a,
else => continue,
};
if (access_chain.base != base_word)
continue;
if (firstConstantAccessIndex(rt, access_chain.indexes) == member_index)
return @intCast(id);
}
return null;
}
fn pointerTargetType(rt: *const spv.Runtime, type_word: spv.SpvWord) ?spv.SpvWord { fn pointerTargetType(rt: *const spv.Runtime, type_word: spv.SpvWord) ?spv.SpvWord {
if (type_word >= rt.results.len) if (type_word >= rt.results.len)
return null; return null;
+28 -1
View File
@@ -41,6 +41,8 @@ instance: *Instance,
physical_device: *const PhysicalDevice, physical_device: *const PhysicalDevice,
queues: std.AutoArrayHashMapUnmanaged(u32, std.ArrayList(*Dispatchable(Queue))), queues: std.AutoArrayHashMapUnmanaged(u32, std.ArrayList(*Dispatchable(Queue))),
host_allocator: VulkanAllocator, host_allocator: VulkanAllocator,
enabled_khr_swapchain: bool,
enabled_khr_device_group: bool,
dispatch_table: *const DispatchTable, dispatch_table: *const DispatchTable,
vtable: *const VTable, vtable: *const VTable,
@@ -77,12 +79,37 @@ pub const DispatchTable = struct {
getDeviceGroupSurfacePresentModesKHR: *const fn (*Self, *SurfaceKHR) VkError!vk.DeviceGroupPresentModeFlagsKHR, getDeviceGroupSurfacePresentModesKHR: *const fn (*Self, *SurfaceKHR) VkError!vk.DeviceGroupPresentModeFlagsKHR,
}; };
pub fn init(allocator: std.mem.Allocator, instance: *Instance, physical_device: *const PhysicalDevice, _: *const vk.DeviceCreateInfo) VkError!Self { pub fn isExtensionEnabled(self: *const Self, extension: vk.ApiInfo) bool {
if (std.mem.eql(u8, extension.name, vk.extensions.khr_swapchain.name)) {
return self.enabled_khr_swapchain;
}
if (std.mem.eql(u8, extension.name, vk.extensions.khr_device_group.name)) {
return self.enabled_khr_device_group;
}
return false;
}
pub fn init(allocator: std.mem.Allocator, instance: *Instance, physical_device: *const PhysicalDevice, info: *const vk.DeviceCreateInfo) VkError!Self {
var enabled_khr_swapchain = false;
var enabled_khr_device_group = false;
if (info.pp_enabled_extension_names) |names| {
for (0..info.enabled_extension_count) |i| {
const name = std.mem.span(names[i]);
if (std.mem.eql(u8, name, vk.extensions.khr_swapchain.name)) {
enabled_khr_swapchain = true;
} else if (std.mem.eql(u8, name, vk.extensions.khr_device_group.name)) {
enabled_khr_device_group = true;
}
}
}
return .{ return .{
.instance = instance, .instance = instance,
.physical_device = physical_device, .physical_device = physical_device,
.queues = .empty, .queues = .empty,
.host_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object), .host_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object),
.enabled_khr_swapchain = enabled_khr_swapchain,
.enabled_khr_device_group = enabled_khr_device_group,
.dispatch_table = undefined, .dispatch_table = undefined,
.vtable = undefined, .vtable = undefined,
}; };
+28
View File
@@ -277,6 +277,29 @@ const device_pfn_map = block: {
}); });
}; };
const DeviceEntryPointRequirement = union(enum) {
device_extension: vk.ApiInfo,
unsupported_extension,
};
const device_entry_point_requirements = std.StaticStringMap(DeviceEntryPointRequirement).initComptime(.{
.{ "vkAcquireNextImageKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkAcquireNextImage2KHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkCreateSwapchainKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkDestroySwapchainKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkGetDeviceGroupPresentCapabilitiesKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkGetDeviceGroupSurfacePresentModesKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkGetSwapchainImagesKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkQueuePresentKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_swapchain } },
.{ "vkCmdDispatchBaseKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_device_group } },
.{ "vkCmdSetDeviceMaskKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_device_group } },
.{ "vkGetDeviceGroupPeerMemoryFeaturesKHR", DeviceEntryPointRequirement{ .device_extension = vk.extensions.khr_device_group } },
.{ "vkGetBufferDeviceAddressEXT", DeviceEntryPointRequirement.unsupported_extension },
.{ "vkGetBufferDeviceAddressKHR", DeviceEntryPointRequirement.unsupported_extension },
});
// ICD Interface ============================================================================================================================================= // ICD Interface =============================================================================================================================================
pub export fn ape_icdNegotiateLoaderICDInterfaceVersion(p_version: *u32) callconv(vk.vulkan_call_conv) vk.Result { pub export fn ape_icdNegotiateLoaderICDInterfaceVersion(p_version: *u32) callconv(vk.vulkan_call_conv) vk.Result {
@@ -1502,6 +1525,11 @@ pub export fn apeGetDeviceProcAddr(p_device: vk.Device, p_name: ?[*:0]const u8)
const name = std.mem.span(p_name.?); const name = std.mem.span(p_name.?);
if (p_device == .null_handle) return null; if (p_device == .null_handle) return null;
const device = Dispatchable(Device).fromHandleObject(p_device) catch return null;
if (device_entry_point_requirements.get(name)) |requirement| switch (requirement) {
.device_extension => |extension| if (!device.isExtensionEnabled(extension)) return null,
.unsupported_extension => return null,
};
if (device_pfn_map.get(name)) |pfn| return pfn; if (device_pfn_map.get(name)) |pfn| return pfn;
return null; return null;