diff --git a/examples/graphics_context.zig b/examples/graphics_context.zig index fdfae55..faf9baf 100644 --- a/examples/graphics_context.zig +++ b/examples/graphics_context.zig @@ -5,78 +5,29 @@ const Allocator = std.mem.Allocator; const required_device_extensions = [_][*:0]const u8{vk.extension_info.khr_swapchain.name}; -const BaseDispatch = vk.BaseWrapper(.{ - .createInstance = true, - .getInstanceProcAddr = true, +const BaseDispatch = vk.BaseWrapper(blk: { + var commands = vk.feature_info.version_1_0.base_functions; + commands = vk.BaseCommandFlags.merge(commands, vk.feature_info.version_1_1.base_functions); + commands = vk.BaseCommandFlags.merge(commands, vk.feature_info.version_1_2.base_functions); + break :blk commands; }); -const InstanceDispatch = vk.InstanceWrapper(.{ - .destroyInstance = true, - .createDevice = true, - .destroySurfaceKHR = true, - .enumeratePhysicalDevices = true, - .getPhysicalDeviceProperties = true, - .enumerateDeviceExtensionProperties = true, - .getPhysicalDeviceSurfaceFormatsKHR = true, - .getPhysicalDeviceSurfacePresentModesKHR = true, - .getPhysicalDeviceSurfaceCapabilitiesKHR = true, - .getPhysicalDeviceQueueFamilyProperties = true, - .getPhysicalDeviceSurfaceSupportKHR = true, - .getPhysicalDeviceMemoryProperties = true, - .getDeviceProcAddr = true, +const InstanceDispatch = vk.InstanceWrapper(blk: { + var commands = vk.feature_info.version_1_0.instance_functions; + commands = vk.InstanceCommandFlags.merge(commands, vk.feature_info.version_1_1.instance_functions); + commands = vk.InstanceCommandFlags.merge(commands, vk.feature_info.version_1_2.instance_functions); + commands = vk.InstanceCommandFlags.merge(commands, vk.extension_info.khr_surface.instance_functions); + commands = vk.InstanceCommandFlags.merge(commands, vk.extension_info.khr_swapchain.instance_functions); + break :blk commands; }); -const DeviceDispatch = vk.DeviceWrapper(.{ - .destroyDevice = true, - .getDeviceQueue = true, - .createSemaphore = true, - .createFence = true, - .createImageView = true, - .destroyImageView = true, - .destroySemaphore = true, - .destroyFence = true, - .getSwapchainImagesKHR = true, - .createSwapchainKHR = true, - .destroySwapchainKHR = true, - .acquireNextImageKHR = true, - .deviceWaitIdle = true, - .waitForFences = true, - .resetFences = true, - .queueSubmit = true, - .queuePresentKHR = true, - .createCommandPool = true, - .destroyCommandPool = true, - .allocateCommandBuffers = true, - .freeCommandBuffers = true, - .queueWaitIdle = true, - .createShaderModule = true, - .destroyShaderModule = true, - .createPipelineLayout = true, - .destroyPipelineLayout = true, - .createRenderPass = true, - .destroyRenderPass = true, - .createGraphicsPipelines = true, - .destroyPipeline = true, - .createFramebuffer = true, - .destroyFramebuffer = true, - .beginCommandBuffer = true, - .endCommandBuffer = true, - .allocateMemory = true, - .freeMemory = true, - .createBuffer = true, - .destroyBuffer = true, - .getBufferMemoryRequirements = true, - .mapMemory = true, - .unmapMemory = true, - .bindBufferMemory = true, - .cmdBeginRenderPass = true, - .cmdEndRenderPass = true, - .cmdBindPipeline = true, - .cmdDraw = true, - .cmdSetViewport = true, - .cmdSetScissor = true, - .cmdBindVertexBuffers = true, - .cmdCopyBuffer = true, +const DeviceDispatch = vk.DeviceWrapper(blk: { + var commands = vk.feature_info.version_1_0.device_functions; + commands = vk.DeviceCommandFlags.merge(commands, vk.feature_info.version_1_1.device_functions); + commands = vk.DeviceCommandFlags.merge(commands, vk.feature_info.version_1_2.device_functions); + commands = vk.DeviceCommandFlags.merge(commands, vk.extension_info.khr_surface.device_functions); + commands = vk.DeviceCommandFlags.merge(commands, vk.extension_info.khr_swapchain.device_functions); + break :blk commands; }); pub const GraphicsContext = struct { diff --git a/generator/vulkan/render.zig b/generator/vulkan/render.zig index 9911730..7989d28 100644 --- a/generator/vulkan/render.zig +++ b/generator/vulkan/render.zig @@ -62,6 +62,7 @@ const preamble = \\ ) !void { \\ try writer.writeAll(@typeName(FlagsType) ++ "{"); \\ var first = true; + \\ @setEvalBranchQuota(10_000); \\ inline for (comptime std.meta.fieldNames(FlagsType)) |name| { \\ if (name[0] == '_') continue; \\ if (@field(self, name)) { @@ -469,6 +470,7 @@ fn Renderer(comptime WriterType: type) type { try self.renderCommandPtrs(); try self.renderExtensionInfo(); + try self.renderFeatureInfo(); try self.renderWrappers(); } @@ -1035,24 +1037,141 @@ fn Renderer(comptime WriterType: type) type { \\ const Info = struct { \\ name: [:0]const u8, \\ version: u32, + \\ instance_functions: InstanceCommandFlags, + \\ device_functions: DeviceCommandFlags, \\ }; ); + // The commands in an extension are not pre-sorted based on if they are instance or device functions. + var instance_commands = std.BufSet.init(self.allocator); + defer instance_commands.deinit(); + var device_commands = std.BufSet.init(self.allocator); + defer device_commands.deinit(); for (self.registry.extensions) |ext| { try self.writer.writeAll("pub const "); try self.writeIdentifierWithCase(.snake, trimVkNamespace(ext.name)); try self.writer.writeAll("= Info {\n"); try self.writer.print(".name = \"{s}\", .version = {},", .{ ext.name, ext.version }); + // collect extension functions + for (ext.requires) |require| { + for (require.commands) |command_name| { + const decl = self.resolveDeclaration(command_name) orelse continue; + // If the target type does not exist, it was likely an empty enum - + // assume spec is correct and that this was not a function alias. + const decl_type = self.resolveAlias(decl) catch continue; + const command = switch (decl_type) { + .command => |cmd| cmd, + else => continue, + }; + const class = classifyCommandDispatch(command_name, command); + switch (class) { + // Vulkan extensions cannot add base functions. + .base => return error.InvalidRegistry, + .instance => { + try instance_commands.insert(command_name); + }, + .device => { + try device_commands.insert(command_name); + }, + } + } + } + // and write them out + try self.writer.writeAll(".instance_functions = "); + try self.renderCommandFlags(&instance_commands); + instance_commands.hash_map.clearRetainingCapacity(); + + try self.writer.writeAll(".device_functions = "); + try self.renderCommandFlags(&device_commands); + device_commands.hash_map.clearRetainingCapacity(); + try self.writer.writeAll("};\n"); } try self.writer.writeAll("};\n"); } + fn renderFeatureInfo(self: *Self) !void { + try self.writer.writeAll( + \\pub const feature_info = struct { + \\ const Info = struct { + \\ base_functions: BaseCommandFlags, + \\ instance_functions: InstanceCommandFlags, + \\ device_functions: DeviceCommandFlags, + \\ }; + ); + // The commands in a feature level are not pre-sorted based on if they are instance or device functions. + var base_commands = std.BufSet.init(self.allocator); + defer base_commands.deinit(); + var instance_commands = std.BufSet.init(self.allocator); + defer instance_commands.deinit(); + var device_commands = std.BufSet.init(self.allocator); + defer device_commands.deinit(); + for (self.registry.features) |feature| { + try self.writer.writeAll("pub const "); + try self.writeIdentifierWithCase(.snake, trimVkNamespace(feature.name)); + try self.writer.writeAll("= Info {\n"); + // collect feature information + for (feature.requires) |require| { + for (require.commands) |command_name| { + const decl = self.resolveDeclaration(command_name) orelse continue; + // If the target type does not exist, it was likely an empty enum - + // assume spec is correct and that this was not a function alias. + const decl_type = self.resolveAlias(decl) catch continue; + const command = switch (decl_type) { + .command => |cmd| cmd, + else => continue, + }; + const class = classifyCommandDispatch(command_name, command); + switch (class) { + .base => { + try base_commands.insert(command_name); + }, + .instance => { + try instance_commands.insert(command_name); + }, + .device => { + try device_commands.insert(command_name); + }, + } + } + } + // and write them out + // clear command lists for next iteration + try self.writer.writeAll(".base_functions = "); + try self.renderCommandFlags(&base_commands); + base_commands.hash_map.clearRetainingCapacity(); + + try self.writer.writeAll(".instance_functions = "); + try self.renderCommandFlags(&instance_commands); + instance_commands.hash_map.clearRetainingCapacity(); + + try self.writer.writeAll(".device_functions = "); + try self.renderCommandFlags(&device_commands); + device_commands.hash_map.clearRetainingCapacity(); + + try self.writer.writeAll("};\n"); + } + + try self.writer.writeAll("};\n"); + } + + fn renderCommandFlags(self: *Self, commands: *const std.BufSet) !void { + try self.writer.writeAll(".{\n"); + var iterator = commands.iterator(); + while (iterator.next()) |command_name| { + try self.writer.writeAll("."); + try self.writeIdentifierWithCase(.camel, trimVkNamespace(command_name.*)); + try self.writer.writeAll(" = true, \n"); + } + try self.writer.writeAll("},\n"); + } + fn renderWrappers(self: *Self) !void { try self.writer.writeAll( \\pub fn CommandFlagsMixin(comptime CommandFlags: type) type { \\ return struct { \\ pub fn merge(lhs: CommandFlags, rhs: CommandFlags) CommandFlags { \\ var result: CommandFlags = .{}; + \\ @setEvalBranchQuota(10_000); \\ inline for (@typeInfo(CommandFlags).Struct.fields) |field| { \\ @field(result, field.name) = @field(lhs, field.name) or @field(rhs, field.name); \\ } @@ -1060,6 +1179,7 @@ fn Renderer(comptime WriterType: type) type { \\ } \\ pub fn intersect(lhs: CommandFlags, rhs: CommandFlags) CommandFlags { \\ var result: CommandFlags = .{}; + \\ @setEvalBranchQuota(10_000); \\ inline for (@typeInfo(CommandFlags).Struct.fields) |field| { \\ @field(result, field.name) = @field(lhs, field.name) and @field(rhs, field.name); \\ } @@ -1067,6 +1187,7 @@ fn Renderer(comptime WriterType: type) type { \\ } \\ pub fn complement(self: CommandFlags) CommandFlags { \\ var result: CommandFlags = .{}; + \\ @setEvalBranchQuota(10_000); \\ inline for (@typeInfo(CommandFlags).Struct.fields) |field| { \\ @field(result, field.name) = !@field(self, field.name); \\ } @@ -1074,12 +1195,14 @@ fn Renderer(comptime WriterType: type) type { \\ } \\ pub fn subtract(lhs: CommandFlags, rhs: CommandFlags) CommandFlags { \\ var result: CommandFlags = .{}; + \\ @setEvalBranchQuota(10_000); \\ inline for (@typeInfo(CommandFlags).Struct.fields) |field| { \\ @field(result, field.name) = @field(lhs, field.name) and !@field(rhs, field.name); \\ } \\ return result; \\ } \\ pub fn contains(lhs: CommandFlags, rhs: CommandFlags) bool { + \\ @setEvalBranchQuota(10_000); \\ inline for (@typeInfo(CommandFlags).Struct.fields) |field| { \\ if (!@field(lhs, field.name) and @field(rhs, field.name)) { \\ return false;