Remove declaration resolving (just merge enums), fixup wrong bitmasks

This commit is contained in:
Robin Voetter
2020-07-10 04:00:55 +02:00
parent 0e52eec5c5
commit b344d97f98
2 changed files with 64 additions and 55 deletions

View File

@@ -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

View File

@@ -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 { fn addRequires(self: *EnumFieldMerger, reqs: []const reg.Require) !void {
for (req.types) |type_name| { for (reqs) |req| {
_ = try self.declarations.put(type_name, {}); for (req.extends) |enum_ext| {
} try self.putEnumExtension(enum_ext.extends, enum_ext.field);
}
for (req.commands) |command| {
_ = try self.declarations.put(command, {});
}
for (req.extends) |enum_ext| {
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);
} }