14 Commits

Author SHA1 Message Date
Robin Voetter
d87813312e Make Vulkan enums always be 32-bit (fixes #26) 2021-11-08 13:51:35 +01:00
InKryption
e17c3593d1 Update graphics_context.zig 2021-11-08 13:51:24 +01:00
InKryption
9513d33bf8 Replace anytype with explicit []const {s}Command 2021-11-08 13:51:12 +01:00
Robin Voetter
59c5b88d17 Add mach-glfw and mach-glfw-vulkan-example readme links 2021-11-08 13:48:27 +01:00
Stephen Gutekanst
4588c0fcad examples: do not call glfwSwapBuffers
I am porting this example to [mach-glfw](github.com/hexops/mach-glfw), and noticed that no GLFW error handling callback is registered because in my port there are a lot of GLFW errors :)

`glfwSwapBuffers` here is emitting `GLFW_NO_WINDOW_CONTEXT` errors constantly, because calling it without a valid OpenGL context is illegal. It's not needed for Vulkan.
2021-11-08 13:48:03 +01:00
Robin Voetter
f55409f98a Make command enums lower camel case to reflect command function name style 2021-10-25 14:38:00 +02:00
Robin Voetter
cbf06a8d42 CI: Enable CI for zig-0.8.1-compat 2021-10-25 13:59:04 +02:00
Robin Voetter
c5bb254766 Make sure there are no errors after parsing generated Zig 2021-10-25 13:58:44 +02:00
Robin Voetter
5980bac303 CI: Bump vulkan sdk to 189 2021-10-25 13:55:18 +02:00
Robin Voetter
3bfacc7e16 Fix some allocation bugs, replace everything by arena (#18) 2021-10-25 13:54:48 +02:00
Marten Ringwelski
1e594c0f09 examples/swapchain: Fix typo 2021-10-25 13:54:31 +02:00
ashpil
397e663296 adds defaults for previously undetected feature struct 2021-10-25 13:54:12 +02:00
Robin Voetter
933010cfff Update readme with new build.zig usage 2021-10-25 13:53:04 +02:00
ashpil
0eccd593ce implements default for feature structs 2021-10-25 13:46:52 +02:00
10 changed files with 193 additions and 137 deletions

View File

@@ -2,9 +2,9 @@ name: Build
on: on:
push: push:
branches: [ zig-0.8.0-compat ] branches: [ zig-0.8.1-compat ]
pull_request: pull_request:
branches: [ zig-0.8.0-compat ] branches: [ zig-0.8.1-compat ]
schedule: schedule:
- cron: '0 6 * * *' - cron: '0 6 * * *'
@@ -27,7 +27,7 @@ jobs:
- name: Fetch Vulkan SDK - name: Fetch Vulkan SDK
run: | run: |
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add - wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.2.176-focal.list https://packages.lunarg.com/vulkan/1.2.176/lunarg-vulkan-1.2.176-focal.list sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.2.189-focal.list https://packages.lunarg.com/vulkan/1.2.189/lunarg-vulkan-1.2.189-focal.list
sudo apt update sudo apt update
sudo apt install shaderc libglfw3 libglfw3-dev sudo apt install shaderc libglfw3 libglfw3-dev

View File

@@ -36,10 +36,10 @@ pub fn build(b: *Builder) void {
exe.step.dependOn(&gen.step); exe.step.dependOn(&gen.step);
// Add the generated file as package to the final executable // Add the generated file as package to the final executable
exe.addPackagePath("vulkan", gen.full_out_path); exe.addPackage(gen.package);
} }
``` ```
This reads vk.xml, parses its contents, and renders the Vulkan bindings to "vk.zig", which is then formatted and placed in `zig-cache`. The resulting file can then be added to an executable by using `addPackagePath`. This reads vk.xml, parses its contents, and renders the Vulkan bindings to "vk.zig", which is then formatted and placed in `zig-cache`. The resulting file can then be added to an executable by using `addPackage`, after which the bindings will be made available to the executable under the name `vulkan`.
### Function & field renaming ### Function & field renaming
Functions and fields are renamed to be more or less in line with [Zig's standard library style](https://ziglang.org/documentation/master/#Style-Guide): Functions and fields are renamed to be more or less in line with [Zig's standard library style](https://ziglang.org/documentation/master/#Style-Guide):
@@ -231,7 +231,7 @@ pub fn build(b: *Builder) void {
const gen = vkgen.VkGenerateStep(b, "path/to/vk.xml", "vk.zig"); const gen = vkgen.VkGenerateStep(b, "path/to/vk.xml", "vk.zig");
exe.step.dependOn(&gen.step); exe.step.dependOn(&gen.step);
exe.addPackagePath("vulkan", gen.full_out_path); exe.addPackage(gen.package);
const shader_comp = vkgen.ShaderCompileStep.init( const shader_comp = vkgen.ShaderCompileStep.init(
builder, builder,
@@ -252,5 +252,7 @@ Upon compilation, glslc is then invoked to compile each shader, and the result i
A partial implementation of https://vulkan-tutorial.org is implemented in [examples/triangle.zig](examples/triangle.zig). This example can be ran by executing `zig build run-triangle` in vulkan-zig's root. A partial implementation of https://vulkan-tutorial.org is implemented in [examples/triangle.zig](examples/triangle.zig). This example can be ran by executing `zig build run-triangle` in vulkan-zig's root.
## See also ## See also
* Implementation of https://vulkan-tutorial.org: https://github.com/andrewrk/zig-vulkan-triangle. * Implementation of https://vulkan-tutorial.org using `@cImport`'ed bindings: https://github.com/andrewrk/zig-vulkan-triangle.
* Alternative binding generator: https://github.com/SpexGuy/Zig-Vulkan-Headers * Alternative binding generator: https://github.com/SpexGuy/Zig-Vulkan-Headers
* Zig bindings for GLFW: https://github.com/hexops/mach-glfw
* With vulkan-zig integration example: https://github.com/hexops/mach-glfw-vulkan-example

View File

@@ -5,77 +5,77 @@ const Allocator = std.mem.Allocator;
const required_device_extensions = [_][]const u8{vk.extension_info.khr_swapchain.name}; const required_device_extensions = [_][]const u8{vk.extension_info.khr_swapchain.name};
const BaseDispatch = vk.BaseWrapper(.{ const BaseDispatch = vk.BaseWrapper(&.{
.CreateInstance, .createInstance,
}); });
const InstanceDispatch = vk.InstanceWrapper(.{ const InstanceDispatch = vk.InstanceWrapper(&.{
.DestroyInstance, .destroyInstance,
.CreateDevice, .createDevice,
.DestroySurfaceKHR, .destroySurfaceKHR,
.EnumeratePhysicalDevices, .enumeratePhysicalDevices,
.GetPhysicalDeviceProperties, .getPhysicalDeviceProperties,
.EnumerateDeviceExtensionProperties, .enumerateDeviceExtensionProperties,
.GetPhysicalDeviceSurfaceFormatsKHR, .getPhysicalDeviceSurfaceFormatsKHR,
.GetPhysicalDeviceSurfacePresentModesKHR, .getPhysicalDeviceSurfacePresentModesKHR,
.GetPhysicalDeviceSurfaceCapabilitiesKHR, .getPhysicalDeviceSurfaceCapabilitiesKHR,
.GetPhysicalDeviceQueueFamilyProperties, .getPhysicalDeviceQueueFamilyProperties,
.GetPhysicalDeviceSurfaceSupportKHR, .getPhysicalDeviceSurfaceSupportKHR,
.GetPhysicalDeviceMemoryProperties, .getPhysicalDeviceMemoryProperties,
.GetDeviceProcAddr, .getDeviceProcAddr,
}); });
const DeviceDispatch = vk.DeviceWrapper(.{ const DeviceDispatch = vk.DeviceWrapper(&.{
.DestroyDevice, .destroyDevice,
.GetDeviceQueue, .getDeviceQueue,
.CreateSemaphore, .createSemaphore,
.CreateFence, .createFence,
.CreateImageView, .createImageView,
.DestroyImageView, .destroyImageView,
.DestroySemaphore, .destroySemaphore,
.DestroyFence, .destroyFence,
.GetSwapchainImagesKHR, .getSwapchainImagesKHR,
.CreateSwapchainKHR, .createSwapchainKHR,
.DestroySwapchainKHR, .destroySwapchainKHR,
.AcquireNextImageKHR, .acquireNextImageKHR,
.DeviceWaitIdle, .deviceWaitIdle,
.WaitForFences, .waitForFences,
.ResetFences, .resetFences,
.QueueSubmit, .queueSubmit,
.QueuePresentKHR, .queuePresentKHR,
.CreateCommandPool, .createCommandPool,
.DestroyCommandPool, .destroyCommandPool,
.AllocateCommandBuffers, .allocateCommandBuffers,
.FreeCommandBuffers, .freeCommandBuffers,
.QueueWaitIdle, .queueWaitIdle,
.CreateShaderModule, .createShaderModule,
.DestroyShaderModule, .destroyShaderModule,
.CreatePipelineLayout, .createPipelineLayout,
.DestroyPipelineLayout, .destroyPipelineLayout,
.CreateRenderPass, .createRenderPass,
.DestroyRenderPass, .destroyRenderPass,
.CreateGraphicsPipelines, .createGraphicsPipelines,
.DestroyPipeline, .destroyPipeline,
.CreateFramebuffer, .createFramebuffer,
.DestroyFramebuffer, .destroyFramebuffer,
.BeginCommandBuffer, .beginCommandBuffer,
.EndCommandBuffer, .endCommandBuffer,
.AllocateMemory, .allocateMemory,
.FreeMemory, .freeMemory,
.CreateBuffer, .createBuffer,
.DestroyBuffer, .destroyBuffer,
.GetBufferMemoryRequirements, .getBufferMemoryRequirements,
.MapMemory, .mapMemory,
.UnmapMemory, .unmapMemory,
.BindBufferMemory, .bindBufferMemory,
.CmdBeginRenderPass, .cmdBeginRenderPass,
.CmdEndRenderPass, .cmdEndRenderPass,
.CmdBindPipeline, .cmdBindPipeline,
.CmdDraw, .cmdDraw,
.CmdSetViewport, .cmdSetViewport,
.CmdSetScissor, .cmdSetScissor,
.CmdBindVertexBuffers, .cmdBindVertexBuffers,
.CmdCopyBuffer, .cmdCopyBuffer,
}); });
pub const GraphicsContext = struct { pub const GraphicsContext = struct {

View File

@@ -251,7 +251,7 @@ fn initSwapchainImages(gc: *const GraphicsContext, swapchain: vk.SwapchainKHR, f
_ = try gc.vkd.getSwapchainImagesKHR(gc.dev, swapchain, &count, images.ptr); _ = try gc.vkd.getSwapchainImagesKHR(gc.dev, swapchain, &count, images.ptr);
const swap_images = try allocator.alloc(SwapImage, count); const swap_images = try allocator.alloc(SwapImage, count);
errdefer allocator.free(images); errdefer allocator.free(swap_images);
var i: usize = 0; var i: usize = 0;
errdefer for (swap_images[0..i]) |si| si.deinit(gc); errdefer for (swap_images[0..i]) |si| si.deinit(gc);

View File

@@ -150,7 +150,6 @@ pub fn main() !void {
); );
} }
c.glfwSwapBuffers(window);
c.glfwPollEvents(); c.glfwPollEvents();
} }

View File

@@ -72,6 +72,7 @@ pub const GenerateStep = struct {
try generate(self.builder.allocator, spec, out_buffer.writer()); try generate(self.builder.allocator, spec, out_buffer.writer());
const tree = try std.zig.parse(self.builder.allocator, out_buffer.items); const tree = try std.zig.parse(self.builder.allocator, out_buffer.items);
std.debug.assert(tree.errors.len == 0); // If this triggers, vulkan-zig produced invalid code.
var formatted = try tree.render(self.builder.allocator); var formatted = try tree.render(self.builder.allocator);

View File

@@ -9,41 +9,30 @@ const Allocator = mem.Allocator;
const FeatureLevel = reg.FeatureLevel; const FeatureLevel = reg.FeatureLevel;
const EnumFieldMerger = struct { const EnumFieldMerger = struct {
const EnumExtensionMap = std.StringArrayHashMap(std.ArrayListUnmanaged(reg.Enum.Field)); const EnumExtensionMap = std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(reg.Enum.Field));
const FieldSet = std.StringArrayHashMap(void); const FieldSet = std.StringArrayHashMapUnmanaged(void);
gpa: *Allocator, arena: *Allocator,
reg_arena: *Allocator,
registry: *reg.Registry, registry: *reg.Registry,
enum_extensions: EnumExtensionMap, enum_extensions: EnumExtensionMap,
field_set: FieldSet, field_set: FieldSet,
fn init(gpa: *Allocator, reg_arena: *Allocator, registry: *reg.Registry) EnumFieldMerger { fn init(arena: *Allocator, registry: *reg.Registry) EnumFieldMerger {
return .{ return .{
.gpa = gpa, .arena = arena,
.reg_arena = reg_arena,
.registry = registry, .registry = registry,
.enum_extensions = EnumExtensionMap.init(gpa), .enum_extensions = .{},
.field_set = FieldSet.init(gpa), .field_set = .{},
}; };
} }
fn deinit(self: *EnumFieldMerger) void {
for (self.enum_extensions.values()) |*value| {
value.deinit(self.gpa);
}
self.field_set.deinit();
self.enum_extensions.deinit();
}
fn putEnumExtension(self: *EnumFieldMerger, enum_name: []const u8, field: reg.Enum.Field) !void { fn putEnumExtension(self: *EnumFieldMerger, enum_name: []const u8, field: reg.Enum.Field) !void {
const res = try self.enum_extensions.getOrPut(enum_name); const res = try self.enum_extensions.getOrPut(self.arena, enum_name);
if (!res.found_existing) { if (!res.found_existing) {
res.value_ptr.* = std.ArrayListUnmanaged(reg.Enum.Field){}; res.value_ptr.* = std.ArrayListUnmanaged(reg.Enum.Field){};
} }
try res.value_ptr.append(self.gpa, field); try res.value_ptr.append(self.arena, field);
} }
fn addRequires(self: *EnumFieldMerger, reqs: []const reg.Require) !void { fn addRequires(self: *EnumFieldMerger, reqs: []const reg.Require) !void {
@@ -61,11 +50,11 @@ const EnumFieldMerger = struct {
self.field_set.clearRetainingCapacity(); self.field_set.clearRetainingCapacity();
const n_fields_upper_bound = base_enum.fields.len + extensions.items.len; const n_fields_upper_bound = base_enum.fields.len + extensions.items.len;
const new_fields = try self.reg_arena.alloc(reg.Enum.Field, n_fields_upper_bound); const new_fields = try self.arena.alloc(reg.Enum.Field, n_fields_upper_bound);
var i: usize = 0; var i: usize = 0;
for (base_enum.fields) |field| { for (base_enum.fields) |field| {
const res = try self.field_set.getOrPut(field.name); const res = try self.field_set.getOrPut(self.arena, field.name);
if (!res.found_existing) { if (!res.found_existing) {
new_fields[i] = field; new_fields[i] = field;
i += 1; i += 1;
@@ -74,16 +63,16 @@ const EnumFieldMerger = struct {
// Assume that if a field name clobbers, the value is the same // Assume that if a field name clobbers, the value is the same
for (extensions.items) |field| { for (extensions.items) |field| {
const res = try self.field_set.getOrPut(field.name); const res = try self.field_set.getOrPut(self.arena, field.name);
if (!res.found_existing) { if (!res.found_existing) {
new_fields[i] = field; new_fields[i] = field;
i += 1; i += 1;
} }
} }
// Existing base_enum.fields was allocatued by `self.reg_arena`, so // Existing base_enum.fields was allocated by `self.arena`, so
// it gets cleaned up whenever that is deinited. // it gets cleaned up whenever that is deinited.
base_enum.fields = self.reg_arena.shrink(new_fields, i); base_enum.fields = self.arena.shrink(new_fields, i);
} }
fn merge(self: *EnumFieldMerger) !void { fn merge(self: *EnumFieldMerger) !void {
@@ -106,8 +95,7 @@ const EnumFieldMerger = struct {
}; };
pub const Generator = struct { pub const Generator = struct {
gpa: *Allocator, arena: std.heap.ArenaAllocator,
reg_arena: std.heap.ArenaAllocator,
registry: reg.Registry, registry: reg.Registry,
id_renderer: IdRenderer, id_renderer: IdRenderer,
@@ -118,16 +106,14 @@ pub const Generator = struct {
for (tags) |*tag, i| tag.* = result.registry.tags[i].name; for (tags) |*tag, i| tag.* = result.registry.tags[i].name;
return Generator{ return Generator{
.gpa = allocator, .arena = result.arena,
.reg_arena = result.arena,
.registry = result.registry, .registry = result.registry,
.id_renderer = IdRenderer.init(allocator, tags), .id_renderer = IdRenderer.init(allocator, tags),
}; };
} }
fn deinit(self: Generator) void { fn deinit(self: Generator) void {
self.gpa.free(self.id_renderer.tags); self.arena.deinit();
self.reg_arena.deinit();
} }
fn stripFlagBits(self: Generator, name: []const u8) []const u8 { fn stripFlagBits(self: Generator, name: []const u8) []const u8 {
@@ -142,14 +128,13 @@ pub const Generator = struct {
// Solve `registry.declarations` according to `registry.extensions` and `registry.features`. // Solve `registry.declarations` according to `registry.extensions` and `registry.features`.
fn mergeEnumFields(self: *Generator) !void { fn mergeEnumFields(self: *Generator) !void {
var merger = EnumFieldMerger.init(self.gpa, &self.reg_arena.allocator, &self.registry); var merger = EnumFieldMerger.init(&self.arena.allocator, &self.registry);
defer merger.deinit();
try merger.merge(); try merger.merge();
} }
// https://github.com/KhronosGroup/Vulkan-Docs/pull/1556 // https://github.com/KhronosGroup/Vulkan-Docs/pull/1556
fn fixupBitFlags(self: *Generator) !void { fn fixupBitFlags(self: *Generator) !void {
var seen_bits = std.StringArrayHashMap(void).init(&self.reg_arena.allocator); var seen_bits = std.StringArrayHashMap(void).init(&self.arena.allocator);
defer seen_bits.deinit(); defer seen_bits.deinit();
for (self.registry.decls) |decl| { for (self.registry.decls) |decl| {
@@ -181,7 +166,7 @@ pub const Generator = struct {
} }
fn render(self: *Generator, writer: anytype) !void { fn render(self: *Generator, writer: anytype) !void {
try renderRegistry(writer, &self.reg_arena.allocator, &self.registry, &self.id_renderer); try renderRegistry(writer, &self.arena.allocator, &self.registry, &self.id_renderer);
} }
}; };

View File

@@ -205,6 +205,18 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
members = allocator.shrink(members, i); members = allocator.shrink(members, i);
var maybe_extends: ?[][]const u8 = null;
if (ty.getAttribute("structextends")) |extends| {
const n_structs = std.mem.count(u8, extends, ",") + 1;
maybe_extends = try allocator.alloc([]const u8, n_structs);
var struct_extends = std.mem.split(extends, ",");
var j: usize = 0;
while (struct_extends.next()) |struct_extend| {
maybe_extends.?[j] = struct_extend;
j += 1;
}
}
it = ty.findChildrenByTag("member"); it = ty.findChildrenByTag("member");
for (members) |*member| { for (members) |*member| {
const member_elem = it.next().?; const member_elem = it.next().?;
@@ -218,6 +230,7 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
.stype = maybe_stype, .stype = maybe_stype,
.fields = members, .fields = members,
.is_union = is_union, .is_union = is_union,
.extends = maybe_extends,
}, },
}, },
}; };

View File

@@ -65,6 +65,7 @@ pub const Container = struct {
}; };
stype: ?[]const u8, stype: ?[]const u8,
extends: ?[]const []const u8,
fields: []Field, fields: []Field,
is_union: bool, is_union: bool,
}; };

View File

@@ -185,10 +185,6 @@ fn Renderer(comptime WriterType: type) type {
declarations_by_name: std.StringHashMap(*const reg.DeclarationType), declarations_by_name: std.StringHashMap(*const reg.DeclarationType),
fn init(writer: WriterType, allocator: *Allocator, registry: *const reg.Registry, id_renderer: *IdRenderer) !Self { fn init(writer: WriterType, allocator: *Allocator, registry: *const reg.Registry, id_renderer: *IdRenderer) !Self {
const tags = try allocator.alloc([]const u8, registry.tags.len);
errdefer allocator.free(tags);
for (tags) |*tag, i| tag.* = registry.tags[i].name;
var declarations_by_name = std.StringHashMap(*const reg.DeclarationType).init(allocator); var declarations_by_name = std.StringHashMap(*const reg.DeclarationType).init(allocator);
errdefer declarations_by_name.deinit(); errdefer declarations_by_name.deinit();
@@ -212,8 +208,6 @@ fn Renderer(comptime WriterType: type) type {
fn deinit(self: *Self) void { fn deinit(self: *Self) void {
self.declarations_by_name.deinit(); self.declarations_by_name.deinit();
self.allocator.free(self.id_renderer.tags);
self.id_renderer.deinit();
} }
fn writeIdentifier(self: Self, id: []const u8) !void { fn writeIdentifier(self: Self, id: []const u8) !void {
@@ -446,19 +440,70 @@ fn Renderer(comptime WriterType: type) type {
try self.writer.print("pub const {s}Command = enum {{\n", .{dispatch_type_name}); try self.writer.print("pub const {s}Command = enum {{\n", .{dispatch_type_name});
for (self.registry.decls) |decl| { for (self.registry.decls) |decl| {
if (decl.decl_type == .command) { const command = switch (decl.decl_type) {
const command = decl.decl_type.command; .command => |cmd| cmd,
if (classifyCommandDispatch(decl.name, command) == dispatch_type) { else => continue,
try self.writer.print("{s},\n", .{trimVkNamespace(decl.name)}); };
}
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
try self.writeIdentifierWithCase(.camel, trimVkNamespace(decl.name));
try self.writer.writeAll(",\n");
} }
} }
{
try self.writer.print(
\\
\\pub fn symbol(self: {s}Command) [:0]const u8 {{
\\ return switch (self) {{
\\
, .{dispatch_type_name}
);
for (self.registry.decls) |decl| {
const command = switch (decl.decl_type) {
.command => |cmd| cmd,
else => continue,
};
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
try self.writer.writeAll(".");
try self.writeIdentifierWithCase(.camel, trimVkNamespace(decl.name));
try self.writer.print(" => \"{s}\",\n", .{ decl.name });
}
}
try self.writer.writeAll("};\n}\n");
}
{
try self.writer.print(
\\
\\pub fn PfnType(comptime self: {s}Command) type {{
\\ return switch (self) {{
\\
, .{dispatch_type_name}
);
for (self.registry.decls) |decl| {
const command = switch (decl.decl_type) {
.command => |cmd| cmd,
else => continue,
};
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
try self.writer.writeAll(".");
try self.writeIdentifierWithCase(.camel, trimVkNamespace(decl.name));
try self.writer.writeAll(" => ");
try self.renderCommandPtrName(decl.name);
try self.writer.writeAll(",\n");
}
}
try self.writer.writeAll("};\n}\n");
}
try self.writer.writeAll("};\n"); try self.writer.writeAll("};\n");
try self.writer.print(
\\fn {s}CommandToString(cmd: {s}Command) []const u8 {{
\\ return std.meta.tagName(cmd);
\\}}
, .{ dispatch_type_name, dispatch_type_name });
} }
fn renderCopyright(self: *Self) !void { fn renderCopyright(self: *Self) !void {
@@ -705,7 +750,7 @@ fn Renderer(comptime WriterType: type) type {
} }
} else { } else {
try self.renderTypeInfo(field.field_type); try self.renderTypeInfo(field.field_type);
try self.renderContainerDefaultField(container, field); try self.renderContainerDefaultField(name, container, field);
try self.writer.writeAll(", "); try self.writer.writeAll(", ");
} }
} }
@@ -713,7 +758,7 @@ fn Renderer(comptime WriterType: type) type {
try self.writer.writeAll("};\n"); try self.writer.writeAll("};\n");
} }
fn renderContainerDefaultField(self: *Self, container: reg.Container, field: reg.Container.Field) !void { fn renderContainerDefaultField(self: *Self, name: []const u8, container: reg.Container, field: reg.Container.Field) !void {
if (mem.eql(u8, field.name, "pNext")) { if (mem.eql(u8, field.name, "pNext")) {
try self.writer.writeAll(" = null"); try self.writer.writeAll(" = null");
} else if (mem.eql(u8, field.name, "sType")) { } else if (mem.eql(u8, field.name, "sType")) {
@@ -728,9 +773,21 @@ fn Renderer(comptime WriterType: type) type {
try self.writer.writeAll(" = ."); try self.writer.writeAll(" = .");
try self.writeIdentifierWithCase(.snake, stype["VK_STRUCTURE_TYPE_".len..]); try self.writeIdentifierWithCase(.snake, stype["VK_STRUCTURE_TYPE_".len..]);
} else if (field.field_type == .name and !container.is_union and mem.eql(u8, "VkBool32", field.field_type.name) and isFeatureStruct(name, container.extends)) {
try self.writer.writeAll(" = FALSE");
} }
} }
fn isFeatureStruct(name: []const u8, maybe_extends: ?[]const []const u8) bool {
if (std.mem.eql(u8, name, "VkPhysicalDeviceFeatures")) return true;
if (maybe_extends) |extends| {
return for (extends) |extend| {
if (mem.eql(u8, extend, "VkDeviceCreateInfo")) break true;
} else false;
}
return false;
}
fn renderEnumFieldName(self: *Self, name: []const u8, field_name: []const u8) !void { fn renderEnumFieldName(self: *Self, name: []const u8, field_name: []const u8) !void {
try self.writeIdentifierWithCase(.snake, try self.extractEnumFieldName(name, field_name)); try self.writeIdentifierWithCase(.snake, try self.extractEnumFieldName(name, field_name));
} }
@@ -743,7 +800,7 @@ fn Renderer(comptime WriterType: type) type {
try self.writer.writeAll("pub const "); try self.writer.writeAll("pub const ");
try self.renderName(name); try self.renderName(name);
try self.writer.writeAll(" = enum(c_int) {"); try self.writer.writeAll(" = enum(i32) {");
for (enumeration.fields) |field| { for (enumeration.fields) |field| {
if (field.value == .alias) if (field.value == .alias)
@@ -958,18 +1015,16 @@ fn Renderer(comptime WriterType: type) type {
}; };
try self.writer.print( try self.writer.print(
\\pub fn {s}Wrapper(comptime cmds: anytype) type {{ \\pub fn {s}Wrapper(comptime cmds: []const {s}Command) type {{
\\ comptime var fields: [cmds.len]std.builtin.TypeInfo.StructField = undefined; \\ comptime var fields: [cmds.len]std.builtin.TypeInfo.StructField = undefined;
\\ inline for (cmds) |cmd, i| {{ \\ inline for (cmds) |cmd, i| {{
\\ const cmd_name = {s}CommandToString(cmd); \\ const PfnType = cmd.PfnType();
\\ const cmd_type_name = "Pfn" ++ cmd_name;
\\ const cmd_type = @field(GlobalScope, cmd_type_name);
\\ fields[i] = .{{ \\ fields[i] = .{{
\\ .name = "vk" ++ cmd_name, \\ .name = cmd.symbol(),
\\ .field_type = cmd_type, \\ .field_type = PfnType,
\\ .default_value = null, \\ .default_value = null,
\\ .is_comptime = false, \\ .is_comptime = false,
\\ .alignment = @alignOf(*cmd_type), \\ .alignment = @alignOf(PfnType),
\\ }}; \\ }};
\\ }} \\ }}
\\ const Dispatch = @Type(.{{ \\ const Dispatch = @Type(.{{