forked from mirror/vulkan-zig
Remove declaration resolving (just merge enums), fixup wrong bitmasks
This commit is contained in:
@@ -6,6 +6,8 @@ A Vulkan binding generator for Zig.
|
|||||||
|
|
||||||
vulkan-zig attempts to provide a better experience to programming Vulkan applications in Zig, by providing features such as integration of vulkan errors with Zig's error system, function pointer loading, renaming fields to standard Zig style, better bitfield handling, turning out parameters into return values and more.
|
vulkan-zig attempts to provide a better experience to programming Vulkan applications in Zig, by providing features such as integration of vulkan errors with Zig's error system, function pointer loading, renaming fields to standard Zig style, better bitfield handling, turning out parameters into return values and more.
|
||||||
|
|
||||||
|
vulkan-zig has been tested with vk.xml version 1.2.141 and 1.2.143.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
### Generation from build.zig
|
### Generation from build.zig
|
||||||
Vulkan bindings can be generated directly from the [Vulkan XML registry](https://github.com/KhronosGroup/Vulkan-Docs/blob/master/xml) build.zig at compiletime, by using the provided
|
Vulkan bindings can be generated directly from the [Vulkan XML registry](https://github.com/KhronosGroup/Vulkan-Docs/blob/master/xml) build.zig at compiletime, by using the provided
|
||||||
|
|||||||
@@ -8,63 +8,53 @@ const mem = std.mem;
|
|||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const FeatureLevel = reg.FeatureLevel;
|
const FeatureLevel = reg.FeatureLevel;
|
||||||
|
|
||||||
const DeclarationResolver = struct {
|
const EnumFieldMerger = struct {
|
||||||
const DeclarationSet = std.StringHashMap(void);
|
const EnumExtensionMap = std.StringHashMap(std.ArrayListUnmanaged(reg.Enum.Field));
|
||||||
const EnumExtensionMap = std.StringHashMap(std.ArrayList(reg.Enum.Field));
|
|
||||||
const FieldSet = std.StringHashMap(void);
|
const FieldSet = std.StringHashMap(void);
|
||||||
|
|
||||||
gpa: *Allocator,
|
gpa: *Allocator,
|
||||||
reg_arena: *Allocator,
|
reg_arena: *Allocator,
|
||||||
registry: *reg.Registry,
|
registry: *reg.Registry,
|
||||||
declarations: DeclarationSet,
|
|
||||||
enum_extensions: EnumExtensionMap,
|
enum_extensions: EnumExtensionMap,
|
||||||
field_set: FieldSet,
|
field_set: FieldSet,
|
||||||
|
|
||||||
fn init(gpa: *Allocator, reg_arena: *Allocator, registry: *reg.Registry) DeclarationResolver {
|
fn init(gpa: *Allocator, reg_arena: *Allocator, registry: *reg.Registry) EnumFieldMerger {
|
||||||
return .{
|
return .{
|
||||||
.gpa = gpa,
|
.gpa = gpa,
|
||||||
.reg_arena = reg_arena,
|
.reg_arena = reg_arena,
|
||||||
.registry = registry,
|
.registry = registry,
|
||||||
.declarations = DeclarationSet.init(gpa),
|
|
||||||
.enum_extensions = EnumExtensionMap.init(gpa),
|
.enum_extensions = EnumExtensionMap.init(gpa),
|
||||||
.field_set = FieldSet.init(gpa),
|
.field_set = FieldSet.init(gpa),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *DeclarationResolver) void {
|
fn deinit(self: *EnumFieldMerger) void {
|
||||||
for (self.enum_extensions.items()) |entry| {
|
for (self.enum_extensions.items()) |*entry| {
|
||||||
entry.value.deinit();
|
entry.value.deinit(self.gpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.field_set.deinit();
|
self.field_set.deinit();
|
||||||
self.enum_extensions.deinit();
|
self.enum_extensions.deinit();
|
||||||
self.declarations.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn putEnumExtension(self: *DeclarationResolver, 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(enum_name);
|
||||||
if (!res.found_existing) {
|
if (!res.found_existing) {
|
||||||
res.entry.value = std.ArrayList(reg.Enum.Field).init(self.gpa);
|
res.entry.value = std.ArrayListUnmanaged(reg.Enum.Field){};
|
||||||
}
|
}
|
||||||
|
|
||||||
try res.entry.value.append(field);
|
try res.entry.value.append(self.gpa, field);
|
||||||
}
|
|
||||||
|
|
||||||
fn addRequire(self: *DeclarationResolver, req: reg.Require) !void {
|
|
||||||
for (req.types) |type_name| {
|
|
||||||
_ = try self.declarations.put(type_name, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (req.commands) |command| {
|
|
||||||
_ = try self.declarations.put(command, {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addRequires(self: *EnumFieldMerger, reqs: []const reg.Require) !void {
|
||||||
|
for (reqs) |req| {
|
||||||
for (req.extends) |enum_ext| {
|
for (req.extends) |enum_ext| {
|
||||||
try self.putEnumExtension(enum_ext.extends, enum_ext.field);
|
try self.putEnumExtension(enum_ext.extends, enum_ext.field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn mergeEnumFields(self: *DeclarationResolver, name: []const u8, base_enum: *reg.Enum) !void {
|
fn mergeEnumFields(self: *EnumFieldMerger, name: []const u8, base_enum: *reg.Enum) !void {
|
||||||
// If there are no extensions for this enum, assume its valid.
|
// If there are no extensions for this enum, assume its valid.
|
||||||
const extensions = self.enum_extensions.get(name) orelse return;
|
const extensions = self.enum_extensions.get(name) orelse return;
|
||||||
|
|
||||||
@@ -96,17 +86,13 @@ const DeclarationResolver = struct {
|
|||||||
base_enum.fields = self.reg_arena.shrink(new_fields, i);
|
base_enum.fields = self.reg_arena.shrink(new_fields, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve(self: *DeclarationResolver) !void {
|
fn merge(self: *EnumFieldMerger) !void {
|
||||||
for (self.registry.features) |feature| {
|
for (self.registry.features) |feature| {
|
||||||
for (feature.requires) |req| {
|
try self.addRequires(feature.requires);
|
||||||
try self.addRequire(req);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.registry.extensions) |ext| {
|
for (self.registry.extensions) |ext| {
|
||||||
for (ext.requires) |req| {
|
try self.addRequires(ext.requires);
|
||||||
try self.addRequire(req);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge all the enum fields.
|
// Merge all the enum fields.
|
||||||
@@ -116,24 +102,6 @@ const DeclarationResolver = struct {
|
|||||||
try self.mergeEnumFields(decl.name, &decl.decl_type.enumeration);
|
try self.mergeEnumFields(decl.name, &decl.decl_type.enumeration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all declarations that are not required.
|
|
||||||
// Some declarations may exist in `self.declarations` that do not exit in
|
|
||||||
// `self.registry.decls`, these are mostly macros and other stuff not pa
|
|
||||||
var read_index: usize = 0;
|
|
||||||
var write_index: usize = 0;
|
|
||||||
while (read_index < self.registry.decls.len) {
|
|
||||||
const decl = self.registry.decls[read_index];
|
|
||||||
const is_required = self.declarations.contains(decl.name);
|
|
||||||
if (decl.decl_type == .foreign or is_required) {
|
|
||||||
self.registry.decls[write_index] = decl;
|
|
||||||
write_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.registry.decls = self.reg_arena.shrink(self.registry.decls, write_index);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -292,11 +260,49 @@ pub const Generator = struct {
|
|||||||
self.registry.extensions.len = write_index;
|
self.registry.extensions.len = write_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn stripFlagBits(self: Generator, name: []const u8) []const u8 {
|
||||||
|
const tagless = util.stripAuthorTag(name, self.registry.tags);
|
||||||
|
return tagless[0 .. tagless.len - "FlagBits".len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stripFlags(self: Generator, name: []const u8) []const u8 {
|
||||||
|
const tagless = util.stripAuthorTag(name, self.registry.tags);
|
||||||
|
return tagless[0 .. tagless.len - "Flags".len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fixupBitmasks(self: *Generator) !void {
|
||||||
|
var bits = std.StringHashMap([]const u8).init(self.gpa);
|
||||||
|
defer bits.deinit();
|
||||||
|
|
||||||
|
for (self.registry.decls) |decl| {
|
||||||
|
if (decl.decl_type == .enumeration and decl.decl_type.enumeration.is_bitmask) {
|
||||||
|
try bits.put(self.stripFlagBits(decl.name), decl.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.registry.decls) |*decl| {
|
||||||
|
switch (decl.decl_type) {
|
||||||
|
.bitmask => |*bitmask| {
|
||||||
|
const base_name = self.stripFlags(decl.name);
|
||||||
|
|
||||||
|
if (bitmask.bits_enum) |bits_enum| {
|
||||||
|
if (bits.get(base_name) == null) {
|
||||||
|
bitmask.bits_enum = null;
|
||||||
|
}
|
||||||
|
} else if (bits.get(base_name)) |bits_enum| {
|
||||||
|
bitmask.bits_enum = bits_enum;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Solve `registry.declarations` according to `registry.extensions` and `registry.features`.
|
// Solve `registry.declarations` according to `registry.extensions` and `registry.features`.
|
||||||
fn resolveDeclarations(self: *Generator) !void {
|
fn mergeEnumFields(self: *Generator) !void {
|
||||||
var resolver = DeclarationResolver.init(self.gpa, &self.reg_arena.allocator, &self.registry);
|
var merger = EnumFieldMerger.init(self.gpa, &self.reg_arena.allocator, &self.registry);
|
||||||
defer resolver.deinit();
|
defer merger.deinit();
|
||||||
try resolver.resolve();
|
try merger.merge();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fixupTags(self: *Generator) !void {
|
fn fixupTags(self: *Generator) !void {
|
||||||
@@ -322,7 +328,8 @@ pub fn generate(allocator: *Allocator, spec_xml: []const u8, writer: var) !void
|
|||||||
defer gen.deinit();
|
defer gen.deinit();
|
||||||
|
|
||||||
gen.removePromotedExtensions();
|
gen.removePromotedExtensions();
|
||||||
try gen.resolveDeclarations();
|
try gen.mergeEnumFields();
|
||||||
|
try gen.fixupBitmasks();
|
||||||
try gen.fixupTags();
|
try gen.fixupTags();
|
||||||
try gen.render(writer);
|
try gen.render(writer);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user