From 0873a353924fc1a46a369f3e71ef0cf2a37f3eed Mon Sep 17 00:00:00 2001 From: ashpil Date: Sat, 28 Jan 2023 19:29:25 -0500 Subject: [PATCH] provide defaults for struct fields vulkan considers optional --- generator/vulkan/c_parse.zig | 1 + generator/vulkan/parse.zig | 28 +++++++++++++++++++++------- generator/vulkan/registry.zig | 1 + generator/vulkan/render.zig | 32 +++++++++++++++++++++++++++----- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/generator/vulkan/c_parse.zig b/generator/vulkan/c_parse.zig index dd85b24..4b34ca9 100644 --- a/generator/vulkan/c_parse.zig +++ b/generator/vulkan/c_parse.zig @@ -263,6 +263,7 @@ pub fn parseMember(allocator: Allocator, xctok: *XmlCTokenizer, ptrs_optional: b .field_type = decl.decl_type, .bits = null, .is_buffer_len = false, + .is_optional = false, }; if (try xctok.peek()) |tok| { diff --git a/generator/vulkan/parse.zig b/generator/vulkan/parse.zig index d369444..46e8188 100644 --- a/generator/vulkan/parse.zig +++ b/generator/vulkan/parse.zig @@ -199,6 +199,15 @@ fn parseContainer(allocator: Allocator, ty: *xml.Element, is_union: bool) !regis } } + if (member.getAttribute("optional")) |optionals| { + var optional_it = mem.split(u8, optionals, ","); + if (optional_it.next()) |first_optional| { + members[i].is_optional = mem.eql(u8, first_optional, "true"); + } else { + // Optional is empty, probably incorrect. + return error.InvalidRegistry; + } + } i += 1; } @@ -245,7 +254,7 @@ fn parseFuncPointer(allocator: Allocator, ty: *xml.Element) !registry.Declaratio return try cparse.parseTypedef(allocator, &xctok, true); } -// For some reason, the DeclarationType cannot be passed to lenToPointerSize, as +// For some reason, the DeclarationType cannot be passed to lenToPointer, as // that causes the Zig compiler to generate invalid code for the function. Using a // dedicated enum fixes the issue... const Fields = union(enum) { @@ -253,13 +262,14 @@ const Fields = union(enum) { container: []registry.Container.Field, }; -fn lenToPointerSize(fields: Fields, len: []const u8) registry.Pointer.PointerSize { +// returns .{ size, nullable } +fn lenToPointer(fields: Fields, len: []const u8) std.meta.Tuple(&.{ registry.Pointer.PointerSize, bool }) { switch (fields) { .command => |params| { for (params) |*param| { if (mem.eql(u8, param.name, len)) { param.is_buffer_len = true; - return .{ .other_field = param.name }; + return .{ .{ .other_field = param.name }, false }; } } }, @@ -267,16 +277,16 @@ fn lenToPointerSize(fields: Fields, len: []const u8) registry.Pointer.PointerSiz for (members) |*member| { if (mem.eql(u8, member.name, len)) { member.is_buffer_len = true; - return .{ .other_field = member.name }; + return .{ .{ .other_field = member.name }, member.is_optional }; } } }, } if (mem.eql(u8, len, "null-terminated")) { - return .zero_terminated; + return .{ .zero_terminated, false }; } else { - return .many; + return .{ .many, false }; } } @@ -286,7 +296,11 @@ fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.El var current_type_info = type_info; while (current_type_info.* == .pointer) { // TODO: Check altlen - const size = if (it.next()) |len_str| lenToPointerSize(fields, len_str) else .many; + const size = if (it.next()) |len_str| blk: { + const size_optional = lenToPointer(fields, len_str); + current_type_info.pointer.is_optional = size_optional[1]; + break :blk size_optional[0]; + } else .many; current_type_info.pointer.size = size; current_type_info = current_type_info.pointer.child; } diff --git a/generator/vulkan/registry.zig b/generator/vulkan/registry.zig index 70c779e..dfaac2c 100644 --- a/generator/vulkan/registry.zig +++ b/generator/vulkan/registry.zig @@ -61,6 +61,7 @@ pub const Container = struct { field_type: TypeInfo, bits: ?usize, is_buffer_len: bool, + is_optional: bool, }; stype: ?[]const u8, diff --git a/generator/vulkan/render.zig b/generator/vulkan/render.zig index 51a72a1..39e0978 100644 --- a/generator/vulkan/render.zig +++ b/generator/vulkan/render.zig @@ -749,7 +749,9 @@ fn Renderer(comptime WriterType: type) type { } } else { try self.renderTypeInfo(field.field_type); - try self.renderContainerDefaultField(name, container, field); + if (!container.is_union) { + try self.renderContainerDefaultField(name, container, field); + } try self.writer.writeAll(", "); } } @@ -758,9 +760,7 @@ fn Renderer(comptime WriterType: type) type { } fn renderContainerDefaultField(self: *Self, name: []const u8, container: reg.Container, field: reg.Container.Field) !void { - if (mem.eql(u8, field.name, "pNext")) { - try self.writer.writeAll(" = null"); - } else if (mem.eql(u8, field.name, "sType")) { + if (mem.eql(u8, field.name, "sType")) { if (container.stype == null) { return; } @@ -776,8 +776,30 @@ fn Renderer(comptime WriterType: type) type { try self.writer.writeAll(" = ."); 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)) { + } else if (field.field_type == .name and mem.eql(u8, "VkBool32", field.field_type.name) and isFeatureStruct(name, container.extends)) { try self.writer.writeAll(" = FALSE"); + } else if (field.is_optional) { + if (field.field_type == .name) { + const field_type_name = field.field_type.name; + if (self.resolveDeclaration(field_type_name)) |decl_type| { + if (decl_type == .handle) { + try self.writer.writeAll(" = .null_handle"); + } else if (decl_type == .bitmask) { + try self.writer.writeAll(" = .{}"); + } else if (decl_type == .typedef and decl_type.typedef == .command_ptr) { + try self.writer.writeAll(" = null"); + } else if ((decl_type == .typedef and builtin_types.has(decl_type.typedef.name)) or + (decl_type == .foreign and builtin_types.has(field_type_name))) + { + try self.writer.writeAll(" = 0"); + } + } + } else if (field.field_type == .pointer) { + try self.writer.writeAll(" = null"); + } + } else if (field.field_type == .pointer and field.field_type.pointer.is_optional) { + // pointer nullability could be here or above + try self.writer.writeAll(" = null"); } }