forked from mirror/vulkan-zig
Update parser for VulkanSC changes
The update that added the VulkanSC changes to vk.xml broke vulkan-zig previously.
This commit is contained in:
@@ -33,7 +33,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// remaindure of the script is for local testing
|
// remainder of the script is for local testing
|
||||||
|
|
||||||
const triangle_exe = b.addExecutable(.{
|
const triangle_exe = b.addExecutable(.{
|
||||||
.name = "triangle",
|
.name = "triangle",
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const generate = @import("vulkan/generator.zig").generate;
|
const generator = @import("vulkan/generator.zig");
|
||||||
|
|
||||||
const usage = "Usage: {s} [-h|--help] <spec xml path> <output zig source>\n";
|
const usage =
|
||||||
|
\\Usage: {s} [options] <spec xml path> <output zig source>
|
||||||
|
\\Options:
|
||||||
|
\\-h --help show this message and exit.
|
||||||
|
\\-a --api <api> Generate API for 'vulkan' or 'vulkansc'. Defaults to 'vulkan'.
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const stderr = std.io.getStdErr();
|
const stderr = std.io.getStdErr();
|
||||||
@@ -15,6 +21,7 @@ pub fn main() !void {
|
|||||||
|
|
||||||
var maybe_xml_path: ?[]const u8 = null;
|
var maybe_xml_path: ?[]const u8 = null;
|
||||||
var maybe_out_path: ?[]const u8 = null;
|
var maybe_out_path: ?[]const u8 = null;
|
||||||
|
var api = generator.Api.vulkan;
|
||||||
|
|
||||||
while (args.next()) |arg| {
|
while (args.next()) |arg| {
|
||||||
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
|
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
|
||||||
@@ -32,12 +39,22 @@ pub fn main() !void {
|
|||||||
.{prog_name},
|
.{prog_name},
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
} else if (std.mem.eql(u8, arg, "-a") or std.mem.eql(u8, arg, "--api")) {
|
||||||
|
const api_str = args.next() orelse {
|
||||||
|
try stderr.writer().print("Error: {s} expects argument <api>\n", .{arg});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
api = std.meta.stringToEnum(generator.Api, api_str) orelse {
|
||||||
|
try stderr.writer().print("Error: Invalid api '{s}'", .{api_str});
|
||||||
|
return;
|
||||||
|
};
|
||||||
} else if (maybe_xml_path == null) {
|
} else if (maybe_xml_path == null) {
|
||||||
maybe_xml_path = arg;
|
maybe_xml_path = arg;
|
||||||
} else if (maybe_out_path == null) {
|
} else if (maybe_out_path == null) {
|
||||||
maybe_out_path = arg;
|
maybe_out_path = arg;
|
||||||
} else {
|
} else {
|
||||||
try stderr.writer().print("Error: Superficial argument '{s}'\n", .{arg});
|
try stderr.writer().print("Error: Superficial argument '{s}'\n", .{arg});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +75,7 @@ pub fn main() !void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var out_buffer = std.ArrayList(u8).init(allocator);
|
var out_buffer = std.ArrayList(u8).init(allocator);
|
||||||
try generate(allocator, xml_src, out_buffer.writer());
|
try generator.generate(allocator, api, xml_src, out_buffer.writer());
|
||||||
try out_buffer.append(0);
|
try out_buffer.append(0);
|
||||||
|
|
||||||
const src = out_buffer.items[0 .. out_buffer.items.len - 1 :0];
|
const src = out_buffer.items[0 .. out_buffer.items.len - 1 :0];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const generate = @import("generator.zig").generate;
|
const generator = @import("generator.zig");
|
||||||
const path = std.fs.path;
|
const path = std.fs.path;
|
||||||
const Build = std.Build;
|
const Build = std.Build;
|
||||||
const Step = Build.Step;
|
const Step = Build.Step;
|
||||||
@@ -14,6 +14,10 @@ pub const GenerateStep = struct {
|
|||||||
generated_file: std.build.GeneratedFile,
|
generated_file: std.build.GeneratedFile,
|
||||||
/// The path to vk.xml
|
/// The path to vk.xml
|
||||||
spec_path: []const u8,
|
spec_path: []const u8,
|
||||||
|
/// The API to generate for.
|
||||||
|
/// Defaults to Vulkan.
|
||||||
|
// Note: VulkanSC is experimental.
|
||||||
|
api: generator.Api = .vulkan,
|
||||||
|
|
||||||
/// Initialize a Vulkan generation step, for `builder`. `spec_path` is the path to
|
/// Initialize a Vulkan generation step, for `builder`. `spec_path` is the path to
|
||||||
/// vk.xml, relative to the project root. The generated bindings will be placed at
|
/// vk.xml, relative to the project root. The generated bindings will be placed at
|
||||||
@@ -44,6 +48,11 @@ pub const GenerateStep = struct {
|
|||||||
return create(builder, spec_path, output_name);
|
return create(builder, spec_path, output_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the API to generate for.
|
||||||
|
pub fn setApi(self: *GenerateStep, api_to_generate: generator.Api) void {
|
||||||
|
self.api = api_to_generate;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the module with the generated budings, with name `module_name`.
|
/// Returns the module with the generated budings, with name `module_name`.
|
||||||
pub fn getModule(self: *GenerateStep) *std.build.Module {
|
pub fn getModule(self: *GenerateStep) *std.build.Module {
|
||||||
return self.builder.createModule(.{
|
return self.builder.createModule(.{
|
||||||
@@ -87,7 +96,7 @@ pub const GenerateStep = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var out_buffer = std.ArrayList(u8).init(self.builder.allocator);
|
var out_buffer = std.ArrayList(u8).init(self.builder.allocator);
|
||||||
generate(self.builder.allocator, spec, out_buffer.writer()) catch |err| switch (err) {
|
generator.generate(self.builder.allocator, self.api, spec, out_buffer.writer()) catch |err| switch (err) {
|
||||||
error.InvalidXml => {
|
error.InvalidXml => {
|
||||||
std.log.err("invalid vulkan registry - invalid xml", .{});
|
std.log.err("invalid vulkan registry - invalid xml", .{});
|
||||||
std.log.err("please check that the correct vk.xml file is passed", .{});
|
std.log.err("please check that the correct vk.xml file is passed", .{});
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ pub const Generator = struct {
|
|||||||
registry: reg.Registry,
|
registry: reg.Registry,
|
||||||
id_renderer: IdRenderer,
|
id_renderer: IdRenderer,
|
||||||
|
|
||||||
fn init(allocator: Allocator, spec: *xml.Element) !Generator {
|
fn init(allocator: Allocator, spec: *xml.Element, api: reg.Api) !Generator {
|
||||||
const result = try parseXml(allocator, spec);
|
const result = try parseXml(allocator, spec, api);
|
||||||
|
|
||||||
const tags = try allocator.alloc([]const u8, result.registry.tags.len);
|
const tags = try allocator.alloc([]const u8, result.registry.tags.len);
|
||||||
for (tags, result.registry.tags) |*tag, registry_tag| tag.* = registry_tag.name;
|
for (tags, result.registry.tags) |*tag, registry_tag| tag.* = registry_tag.name;
|
||||||
@@ -170,11 +170,15 @@ pub const Generator = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The vulkan registry contains the specification for multiple APIs: Vulkan and VulkanSC. This enum
|
||||||
|
/// describes applicable APIs.
|
||||||
|
pub const Api = reg.Api;
|
||||||
|
|
||||||
/// Main function for generating the Vulkan bindings. vk.xml is to be provided via `spec_xml`,
|
/// Main function for generating the Vulkan bindings. vk.xml is to be provided via `spec_xml`,
|
||||||
/// and the resulting binding is written to `writer`. `allocator` will be used to allocate temporary
|
/// and the resulting binding is written to `writer`. `allocator` will be used to allocate temporary
|
||||||
/// internal datastructures - mostly via an ArenaAllocator, but sometimes a hashmap uses this allocator
|
/// internal datastructures - mostly via an ArenaAllocator, but sometimes a hashmap uses this allocator
|
||||||
/// directly.
|
/// directly. `api` is the API to generate the bindings for, usually `.vulkan`.
|
||||||
pub fn generate(allocator: Allocator, spec_xml: []const u8, writer: anytype) !void {
|
pub fn generate(allocator: Allocator, api: Api, spec_xml: []const u8, writer: anytype) !void {
|
||||||
const spec = xml.parse(allocator, spec_xml) catch |err| switch (err) {
|
const spec = xml.parse(allocator, spec_xml) catch |err| switch (err) {
|
||||||
error.InvalidDocument,
|
error.InvalidDocument,
|
||||||
error.UnexpectedEof,
|
error.UnexpectedEof,
|
||||||
@@ -191,7 +195,7 @@ pub fn generate(allocator: Allocator, spec_xml: []const u8, writer: anytype) !vo
|
|||||||
};
|
};
|
||||||
defer spec.deinit();
|
defer spec.deinit();
|
||||||
|
|
||||||
var gen = Generator.init(allocator, spec.root) catch |err| switch (err) {
|
var gen = Generator.init(allocator, spec.root, api) catch |err| switch (err) {
|
||||||
error.InvalidXml,
|
error.InvalidXml,
|
||||||
error.InvalidCharacter,
|
error.InvalidCharacter,
|
||||||
error.Overflow,
|
error.Overflow,
|
||||||
|
|||||||
@@ -17,18 +17,18 @@ pub const ParseResult = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parseXml(backing_allocator: Allocator, root: *xml.Element) !ParseResult {
|
pub fn parseXml(backing_allocator: Allocator, root: *xml.Element, api: registry.Api) !ParseResult {
|
||||||
var arena = ArenaAllocator.init(backing_allocator);
|
var arena = ArenaAllocator.init(backing_allocator);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
|
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
var reg = registry.Registry{
|
var reg = registry.Registry{
|
||||||
.decls = try parseDeclarations(allocator, root),
|
.decls = try parseDeclarations(allocator, root, api),
|
||||||
.api_constants = try parseApiConstants(allocator, root),
|
.api_constants = try parseApiConstants(allocator, root, api),
|
||||||
.tags = try parseTags(allocator, root),
|
.tags = try parseTags(allocator, root),
|
||||||
.features = try parseFeatures(allocator, root),
|
.features = try parseFeatures(allocator, root, api),
|
||||||
.extensions = try parseExtensions(allocator, root),
|
.extensions = try parseExtensions(allocator, root, api),
|
||||||
};
|
};
|
||||||
|
|
||||||
return ParseResult{
|
return ParseResult{
|
||||||
@@ -37,7 +37,7 @@ pub fn parseXml(backing_allocator: Allocator, root: *xml.Element) !ParseResult {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseDeclarations(allocator: Allocator, root: *xml.Element) ![]registry.Declaration {
|
fn parseDeclarations(allocator: Allocator, root: *xml.Element, api: registry.Api) ![]registry.Declaration {
|
||||||
var types_elem = root.findChildByTag("types") orelse return error.InvalidRegistry;
|
var types_elem = root.findChildByTag("types") orelse return error.InvalidRegistry;
|
||||||
var commands_elem = root.findChildByTag("commands") orelse return error.InvalidRegistry;
|
var commands_elem = root.findChildByTag("commands") orelse return error.InvalidRegistry;
|
||||||
|
|
||||||
@@ -45,17 +45,20 @@ fn parseDeclarations(allocator: Allocator, root: *xml.Element) ![]registry.Decla
|
|||||||
const decls = try allocator.alloc(registry.Declaration, decl_upper_bound);
|
const decls = try allocator.alloc(registry.Declaration, decl_upper_bound);
|
||||||
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
count += try parseTypes(allocator, decls, types_elem);
|
count += try parseTypes(allocator, decls, types_elem, api);
|
||||||
count += try parseEnums(allocator, decls[count..], root);
|
count += try parseEnums(allocator, decls[count..], root, api);
|
||||||
count += try parseCommands(allocator, decls[count..], commands_elem);
|
count += try parseCommands(allocator, decls[count..], commands_elem, api);
|
||||||
return decls[0..count];
|
return decls[0..count];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseTypes(allocator: Allocator, out: []registry.Declaration, types_elem: *xml.Element) !usize {
|
fn parseTypes(allocator: Allocator, out: []registry.Declaration, types_elem: *xml.Element, api: registry.Api) !usize {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = types_elem.findChildrenByTag("type");
|
var it = types_elem.findChildrenByTag("type");
|
||||||
while (it.next()) |ty| {
|
while (it.next()) |ty| {
|
||||||
out[i] = blk: {
|
out[i] = blk: {
|
||||||
|
if (!requiredByApi(ty, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
const category = ty.getAttribute("category") orelse {
|
const category = ty.getAttribute("category") orelse {
|
||||||
break :blk try parseForeigntype(ty);
|
break :blk try parseForeigntype(ty);
|
||||||
};
|
};
|
||||||
@@ -67,9 +70,9 @@ fn parseTypes(allocator: Allocator, out: []registry.Declaration, types_elem: *xm
|
|||||||
} else if (mem.eql(u8, category, "basetype")) {
|
} else if (mem.eql(u8, category, "basetype")) {
|
||||||
break :blk try parseBaseType(allocator, ty);
|
break :blk try parseBaseType(allocator, ty);
|
||||||
} else if (mem.eql(u8, category, "struct")) {
|
} else if (mem.eql(u8, category, "struct")) {
|
||||||
break :blk try parseContainer(allocator, ty, false);
|
break :blk try parseContainer(allocator, ty, false, api);
|
||||||
} else if (mem.eql(u8, category, "union")) {
|
} else if (mem.eql(u8, category, "union")) {
|
||||||
break :blk try parseContainer(allocator, ty, true);
|
break :blk try parseContainer(allocator, ty, true, api);
|
||||||
} else if (mem.eql(u8, category, "funcpointer")) {
|
} else if (mem.eql(u8, category, "funcpointer")) {
|
||||||
break :blk try parseFuncPointer(allocator, ty);
|
break :blk try parseFuncPointer(allocator, ty);
|
||||||
} else if (mem.eql(u8, category, "enum")) {
|
} else if (mem.eql(u8, category, "enum")) {
|
||||||
@@ -173,7 +176,7 @@ fn parseBaseType(allocator: Allocator, ty: *xml.Element) !registry.Declaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseContainer(allocator: Allocator, ty: *xml.Element, is_union: bool) !registry.Declaration {
|
fn parseContainer(allocator: Allocator, ty: *xml.Element, is_union: bool, api: registry.Api) !registry.Declaration {
|
||||||
const name = ty.getAttribute("name") orelse return error.InvalidRegistry;
|
const name = ty.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
|
|
||||||
if (ty.getAttribute("alias")) |alias| {
|
if (ty.getAttribute("alias")) |alias| {
|
||||||
@@ -191,6 +194,9 @@ fn parseContainer(allocator: Allocator, ty: *xml.Element, is_union: bool) !regis
|
|||||||
var it = ty.findChildrenByTag("member");
|
var it = ty.findChildrenByTag("member");
|
||||||
var maybe_stype: ?[]const u8 = null;
|
var maybe_stype: ?[]const u8 = null;
|
||||||
while (it.next()) |member| {
|
while (it.next()) |member| {
|
||||||
|
if (!requiredByApi(member, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
var xctok = cparse.XmlCTokenizer.init(member);
|
var xctok = cparse.XmlCTokenizer.init(member);
|
||||||
members[i] = try cparse.parseMember(allocator, &xctok, false);
|
members[i] = try cparse.parseMember(allocator, &xctok, false);
|
||||||
if (mem.eql(u8, members[i].name, "sType")) {
|
if (mem.eql(u8, members[i].name, "sType")) {
|
||||||
@@ -227,7 +233,10 @@ fn parseContainer(allocator: Allocator, ty: *xml.Element, is_union: bool) !regis
|
|||||||
|
|
||||||
it = ty.findChildrenByTag("member");
|
it = ty.findChildrenByTag("member");
|
||||||
for (members) |*member| {
|
for (members) |*member| {
|
||||||
const member_elem = it.next().?;
|
const member_elem = while (it.next()) |elem| {
|
||||||
|
if (requiredByApi(elem, api)) break elem;
|
||||||
|
} else unreachable;
|
||||||
|
|
||||||
try parsePointerMeta(.{ .container = members }, &member.field_type, member_elem);
|
try parsePointerMeta(.{ .container = members }, &member.field_type, member_elem);
|
||||||
|
|
||||||
// pNext isn't always properly marked as optional, so just manually override it,
|
// pNext isn't always properly marked as optional, so just manually override it,
|
||||||
@@ -308,6 +317,7 @@ fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.El
|
|||||||
if (it.next()) |_| {
|
if (it.next()) |_| {
|
||||||
// There are more elements in the `len` attribute than there are pointers
|
// There are more elements in the `len` attribute than there are pointers
|
||||||
// Something probably went wrong
|
// Something probably went wrong
|
||||||
|
std.log.err("len: {s}", .{lens});
|
||||||
return error.InvalidRegistry;
|
return error.InvalidRegistry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,18 +352,18 @@ fn parseEnumAlias(elem: *xml.Element) !?registry.Declaration {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseEnums(allocator: Allocator, out: []registry.Declaration, root: *xml.Element) !usize {
|
fn parseEnums(allocator: Allocator, out: []registry.Declaration, root: *xml.Element, api: registry.Api) !usize {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = root.findChildrenByTag("enums");
|
var it = root.findChildrenByTag("enums");
|
||||||
while (it.next()) |enums| {
|
while (it.next()) |enums| {
|
||||||
const name = enums.getAttribute("name") orelse return error.InvalidRegistry;
|
const name = enums.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
if (mem.eql(u8, name, api_constants_name)) {
|
if (mem.eql(u8, name, api_constants_name) or !requiredByApi(enums, api)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
out[i] = .{
|
out[i] = .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.decl_type = .{ .enumeration = try parseEnumFields(allocator, enums) },
|
.decl_type = .{ .enumeration = try parseEnumFields(allocator, enums, api) },
|
||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@@ -361,7 +371,7 @@ fn parseEnums(allocator: Allocator, out: []registry.Declaration, root: *xml.Elem
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseEnumFields(allocator: Allocator, elem: *xml.Element) !registry.Enum {
|
fn parseEnumFields(allocator: Allocator, elem: *xml.Element, api: registry.Api) !registry.Enum {
|
||||||
// TODO: `type` was added recently, fall back to checking endswith FlagBits for older versions?
|
// TODO: `type` was added recently, fall back to checking endswith FlagBits for older versions?
|
||||||
const enum_type = elem.getAttribute("type") orelse return error.InvalidRegistry;
|
const enum_type = elem.getAttribute("type") orelse return error.InvalidRegistry;
|
||||||
const is_bitmask = mem.eql(u8, enum_type, "bitmask");
|
const is_bitmask = mem.eql(u8, enum_type, "bitmask");
|
||||||
@@ -379,6 +389,9 @@ fn parseEnumFields(allocator: Allocator, elem: *xml.Element) !registry.Enum {
|
|||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = elem.findChildrenByTag("enum");
|
var it = elem.findChildrenByTag("enum");
|
||||||
while (it.next()) |field| {
|
while (it.next()) |field| {
|
||||||
|
if (!requiredByApi(field, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
fields[i] = try parseEnumField(field);
|
fields[i] = try parseEnumField(field);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@@ -428,11 +441,14 @@ fn parseEnumField(field: *xml.Element) !registry.Enum.Field {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseCommands(allocator: Allocator, out: []registry.Declaration, commands_elem: *xml.Element) !usize {
|
fn parseCommands(allocator: Allocator, out: []registry.Declaration, commands_elem: *xml.Element, api: registry.Api) !usize {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = commands_elem.findChildrenByTag("command");
|
var it = commands_elem.findChildrenByTag("command");
|
||||||
while (it.next()) |elem| {
|
while (it.next()) |elem| {
|
||||||
out[i] = try parseCommand(allocator, elem);
|
if (!requiredByApi(elem, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
out[i] = try parseCommand(allocator, elem, api);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +470,7 @@ fn splitCommaAlloc(allocator: Allocator, text: []const u8) ![][]const u8 {
|
|||||||
return codes;
|
return codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseCommand(allocator: Allocator, elem: *xml.Element) !registry.Declaration {
|
fn parseCommand(allocator: Allocator, elem: *xml.Element, api: registry.Api) !registry.Declaration {
|
||||||
if (elem.getAttribute("alias")) |alias| {
|
if (elem.getAttribute("alias")) |alias| {
|
||||||
const name = elem.getAttribute("name") orelse return error.InvalidRegistry;
|
const name = elem.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
return registry.Declaration{
|
return registry.Declaration{
|
||||||
@@ -474,6 +490,9 @@ fn parseCommand(allocator: Allocator, elem: *xml.Element) !registry.Declaration
|
|||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = elem.findChildrenByTag("param");
|
var it = elem.findChildrenByTag("param");
|
||||||
while (it.next()) |param| {
|
while (it.next()) |param| {
|
||||||
|
if (!requiredByApi(param, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
var xctok = cparse.XmlCTokenizer.init(param);
|
var xctok = cparse.XmlCTokenizer.init(param);
|
||||||
const decl = try cparse.parseParamOrProto(allocator, &xctok, false);
|
const decl = try cparse.parseParamOrProto(allocator, &xctok, false);
|
||||||
params[i] = .{
|
params[i] = .{
|
||||||
@@ -501,7 +520,10 @@ fn parseCommand(allocator: Allocator, elem: *xml.Element) !registry.Declaration
|
|||||||
|
|
||||||
it = elem.findChildrenByTag("param");
|
it = elem.findChildrenByTag("param");
|
||||||
for (params) |*param| {
|
for (params) |*param| {
|
||||||
const param_elem = it.next().?;
|
const param_elem = while (it.next()) |param_elem| {
|
||||||
|
if (requiredByApi(param_elem, api)) break param_elem;
|
||||||
|
} else unreachable;
|
||||||
|
|
||||||
try parsePointerMeta(.{ .command = params }, ¶m.param_type, param_elem);
|
try parsePointerMeta(.{ .command = params }, ¶m.param_type, param_elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,7 +540,7 @@ fn parseCommand(allocator: Allocator, elem: *xml.Element) !registry.Declaration
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseApiConstants(allocator: Allocator, root: *xml.Element) ![]registry.ApiConstant {
|
fn parseApiConstants(allocator: Allocator, root: *xml.Element, api: registry.Api) ![]registry.ApiConstant {
|
||||||
var enums = blk: {
|
var enums = blk: {
|
||||||
var it = root.findChildrenByTag("enums");
|
var it = root.findChildrenByTag("enums");
|
||||||
while (it.next()) |child| {
|
while (it.next()) |child| {
|
||||||
@@ -550,6 +572,9 @@ fn parseApiConstants(allocator: Allocator, root: *xml.Element) ![]registry.ApiCo
|
|||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = enums.findChildrenByTag("enum");
|
var it = enums.findChildrenByTag("enum");
|
||||||
while (it.next()) |constant| {
|
while (it.next()) |constant| {
|
||||||
|
if (!requiredByApi(constant, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
const expr = if (constant.getAttribute("value")) |expr|
|
const expr = if (constant.getAttribute("value")) |expr|
|
||||||
expr
|
expr
|
||||||
else if (constant.getAttribute("alias")) |alias|
|
else if (constant.getAttribute("alias")) |alias|
|
||||||
@@ -565,21 +590,24 @@ fn parseApiConstants(allocator: Allocator, root: *xml.Element) ![]registry.ApiCo
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i += try parseDefines(types, constants[i..]);
|
i += try parseDefines(types, constants[i..], api);
|
||||||
return constants[0..i];
|
return constants[0..i];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseDefines(types: *xml.Element, out: []registry.ApiConstant) !usize {
|
fn parseDefines(types: *xml.Element, out: []registry.ApiConstant, api: registry.Api) !usize {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = types.findChildrenByTag("type");
|
var it = types.findChildrenByTag("type");
|
||||||
while (it.next()) |ty| {
|
while (it.next()) |ty| {
|
||||||
|
if (!requiredByApi(ty, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
const category = ty.getAttribute("category") orelse continue;
|
const category = ty.getAttribute("category") orelse continue;
|
||||||
if (!mem.eql(u8, category, "define")) {
|
if (!mem.eql(u8, category, "define")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = ty.getCharData("name") orelse continue;
|
const name = ty.getCharData("name") orelse continue;
|
||||||
if (mem.eql(u8, name, "VK_HEADER_VERSION")) {
|
if (mem.eql(u8, name, "VK_HEADER_VERSION") or mem.eql(u8, name, "VKSC_API_VARIANT")) {
|
||||||
out[i] = .{
|
out[i] = .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.value = .{ .expr = mem.trim(u8, ty.children[2].char_data, " ") },
|
.value = .{ .expr = mem.trim(u8, ty.children[2].char_data, " ") },
|
||||||
@@ -615,7 +643,7 @@ fn parseTags(allocator: Allocator, root: *xml.Element) ![]registry.Tag {
|
|||||||
return tags[0..i];
|
return tags[0..i];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFeatures(allocator: Allocator, root: *xml.Element) ![]registry.Feature {
|
fn parseFeatures(allocator: Allocator, root: *xml.Element, api: registry.Api) ![]registry.Feature {
|
||||||
var it = root.findChildrenByTag("feature");
|
var it = root.findChildrenByTag("feature");
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (it.next()) |_| count += 1;
|
while (it.next()) |_| count += 1;
|
||||||
@@ -624,14 +652,17 @@ fn parseFeatures(allocator: Allocator, root: *xml.Element) ![]registry.Feature {
|
|||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
it = root.findChildrenByTag("feature");
|
it = root.findChildrenByTag("feature");
|
||||||
while (it.next()) |feature| {
|
while (it.next()) |feature| {
|
||||||
features[i] = try parseFeature(allocator, feature);
|
if (!requiredByApi(feature, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
features[i] = try parseFeature(allocator, feature, api);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return features;
|
return features[0..i];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFeature(allocator: Allocator, feature: *xml.Element) !registry.Feature {
|
fn parseFeature(allocator: Allocator, feature: *xml.Element, api: registry.Api) !registry.Feature {
|
||||||
const name = feature.getAttribute("name") orelse return error.InvalidRegistry;
|
const name = feature.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
const feature_level = blk: {
|
const feature_level = blk: {
|
||||||
const number = feature.getAttribute("number") orelse return error.InvalidRegistry;
|
const number = feature.getAttribute("number") orelse return error.InvalidRegistry;
|
||||||
@@ -642,7 +673,10 @@ fn parseFeature(allocator: Allocator, feature: *xml.Element) !registry.Feature {
|
|||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = feature.findChildrenByTag("require");
|
var it = feature.findChildrenByTag("require");
|
||||||
while (it.next()) |require| {
|
while (it.next()) |require| {
|
||||||
requires[i] = try parseRequire(allocator, require, null);
|
if (!requiredByApi(require, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
requires[i] = try parseRequire(allocator, require, null, api);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,7 +736,7 @@ fn enumExtOffsetToValue(extnumber: u31, offset: u31) u31 {
|
|||||||
return extension_value_base + (extnumber - 1) * extension_block + offset;
|
return extension_value_base + (extnumber - 1) * extension_block + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseRequire(allocator: Allocator, require: *xml.Element, extnumber: ?u31) !registry.Require {
|
fn parseRequire(allocator: Allocator, require: *xml.Element, extnumber: ?u31, api: registry.Api) !registry.Require {
|
||||||
var n_extends: usize = 0;
|
var n_extends: usize = 0;
|
||||||
var n_types: usize = 0;
|
var n_types: usize = 0;
|
||||||
var n_commands: usize = 0;
|
var n_commands: usize = 0;
|
||||||
@@ -728,6 +762,9 @@ fn parseRequire(allocator: Allocator, require: *xml.Element, extnumber: ?u31) !r
|
|||||||
|
|
||||||
it = require.elements();
|
it = require.elements();
|
||||||
while (it.next()) |elem| {
|
while (it.next()) |elem| {
|
||||||
|
if (!requiredByApi(elem, api))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (mem.eql(u8, elem.tag, "enum")) {
|
if (mem.eql(u8, elem.tag, "enum")) {
|
||||||
if (try parseEnumExtension(elem, extnumber)) |ext| {
|
if (try parseEnumExtension(elem, extnumber)) |ext| {
|
||||||
extends[i_extends] = ext;
|
extends[i_extends] = ext;
|
||||||
@@ -753,20 +790,22 @@ fn parseRequire(allocator: Allocator, require: *xml.Element, extnumber: ?u31) !r
|
|||||||
|
|
||||||
return registry.Require{
|
return registry.Require{
|
||||||
.extends = extends[0..i_extends],
|
.extends = extends[0..i_extends],
|
||||||
.types = types,
|
.types = types[0..i_types],
|
||||||
.commands = commands,
|
.commands = commands[0..i_commands],
|
||||||
.required_feature_level = required_feature_level,
|
.required_feature_level = required_feature_level,
|
||||||
.required_extension = require.getAttribute("extension"),
|
.required_extension = require.getAttribute("extension"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseExtensions(allocator: Allocator, root: *xml.Element) ![]registry.Extension {
|
fn parseExtensions(allocator: Allocator, root: *xml.Element, api: registry.Api) ![]registry.Extension {
|
||||||
const extensions_elem = root.findChildByTag("extensions") orelse return error.InvalidRegistry;
|
const extensions_elem = root.findChildByTag("extensions") orelse return error.InvalidRegistry;
|
||||||
|
|
||||||
const extensions = try allocator.alloc(registry.Extension, extensions_elem.children.len);
|
const extensions = try allocator.alloc(registry.Extension, extensions_elem.children.len);
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = extensions_elem.findChildrenByTag("extension");
|
var it = extensions_elem.findChildrenByTag("extension");
|
||||||
while (it.next()) |extension| {
|
while (it.next()) |extension| {
|
||||||
|
if (!requiredByApi(extension, api))
|
||||||
|
continue;
|
||||||
// Some extensions (in particular 94) are disabled, so just skip them
|
// Some extensions (in particular 94) are disabled, so just skip them
|
||||||
if (extension.getAttribute("supported")) |supported| {
|
if (extension.getAttribute("supported")) |supported| {
|
||||||
if (mem.eql(u8, supported, "disabled")) {
|
if (mem.eql(u8, supported, "disabled")) {
|
||||||
@@ -774,7 +813,7 @@ fn parseExtensions(allocator: Allocator, root: *xml.Element) ![]registry.Extensi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extensions[i] = try parseExtension(allocator, extension);
|
extensions[i] = try parseExtension(allocator, extension, api);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,7 +836,7 @@ fn findExtVersion(extension: *xml.Element) !u32 {
|
|||||||
return error.InvalidRegistry;
|
return error.InvalidRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseExtension(allocator: Allocator, extension: *xml.Element) !registry.Extension {
|
fn parseExtension(allocator: Allocator, extension: *xml.Element, api: registry.Api) !registry.Extension {
|
||||||
const name = extension.getAttribute("name") orelse return error.InvalidRegistry;
|
const name = extension.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
const platform = extension.getAttribute("platform");
|
const platform = extension.getAttribute("platform");
|
||||||
const version = try findExtVersion(extension);
|
const version = try findExtVersion(extension);
|
||||||
@@ -845,7 +884,9 @@ fn parseExtension(allocator: Allocator, extension: *xml.Element) !registry.Exten
|
|||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = extension.findChildrenByTag("require");
|
var it = extension.findChildrenByTag("require");
|
||||||
while (it.next()) |require| {
|
while (it.next()) |require| {
|
||||||
requires[i] = try parseRequire(allocator, require, number);
|
if (!requiredByApi(require, api))
|
||||||
|
continue;
|
||||||
|
requires[i] = try parseRequire(allocator, require, number, api);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -876,3 +917,14 @@ fn splitFeatureLevel(ver: []const u8, split: []const u8) !registry.FeatureLevel
|
|||||||
.minor = try std.fmt.parseInt(u32, minor, 10),
|
.minor = try std.fmt.parseInt(u32, minor, 10),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn requiredByApi(elem: *xml.Element, api: registry.Api) bool {
|
||||||
|
const apis = elem.getAttribute("api") orelse return true; // If the 'api' element is not present, assume required.
|
||||||
|
|
||||||
|
var it = mem.split(u8, apis, ",");
|
||||||
|
while (it.next()) |required_by_api| {
|
||||||
|
if (std.mem.eql(u8, @tagName(api), required_by_api)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
pub const Api = enum {
|
||||||
|
vulkan,
|
||||||
|
vulkansc,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Registry = struct {
|
pub const Registry = struct {
|
||||||
decls: []Declaration,
|
decls: []Declaration,
|
||||||
api_constants: []ApiConstant,
|
api_constants: []ApiConstant,
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
for (registry.decls) |*decl| {
|
for (registry.decls) |*decl| {
|
||||||
const result = try declarations_by_name.getOrPut(decl.name);
|
const result = try declarations_by_name.getOrPut(decl.name);
|
||||||
if (result.found_existing) {
|
if (result.found_existing) {
|
||||||
|
std.log.err("duplicate registry entry '{s}'", .{decl.name});
|
||||||
return error.InvalidRegistry;
|
return error.InvalidRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user