forked from mirror/vulkan-zig
Compare commits
15 Commits
zig-0.8.0-
...
zig-0.7.1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34d30d0e64 | ||
|
|
efb63a5cac | ||
|
|
fb5ca7cf90 | ||
|
|
272c1160eb | ||
|
|
2064c912aa | ||
|
|
954ca65ed9 | ||
|
|
9321da3426 | ||
|
|
bda8c7213a | ||
|
|
9aae495eab | ||
|
|
01a64c1f9c | ||
|
|
ffb9e9ff3e | ||
|
|
8e48a8aa03 | ||
|
|
50177211cb | ||
|
|
9eac24ee39 | ||
|
|
2cb1fcc354 |
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@@ -2,9 +2,9 @@ name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ zig-0.8.0-compat ]
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ zig-0.8.0-compat ]
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '0 6 * * *'
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Setup Zig
|
||||
uses: goto-bus-stop/setup-zig@v1.3.0
|
||||
with:
|
||||
version: 0.8.0
|
||||
version: master
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
- name: Fetch Vulkan SDK
|
||||
run: |
|
||||
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.162-focal.list https://packages.lunarg.com/vulkan/1.2.162/lunarg-vulkan-1.2.162-focal.list
|
||||
sudo apt update
|
||||
sudo apt install shaderc libglfw3 libglfw3-dev
|
||||
|
||||
@@ -38,9 +38,3 @@ jobs:
|
||||
- name: Build with latest zig & vk.xml
|
||||
run: |
|
||||
zig build -Dvulkan-registry=./vk.xml
|
||||
|
||||
- name: Archive vk.xml
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: vk.zig
|
||||
path: zig-cache/vk.zig
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1 @@
|
||||
zig-cache/
|
||||
zig-out/
|
||||
|
||||
40
README.md
40
README.md
@@ -12,7 +12,7 @@ vulkan-zig is automatically tested daily against the latest vk.xml and zig, and
|
||||
|
||||
### Zig versions
|
||||
|
||||
vulkan-zig aims to be always compatible with the ever-changing Zig master branch (however, development may lag a few days behind). Sometimes, the Zig master branch breaks a bunch of functionality however, which may make the latest version vulkan-zig incompatible with older releases of Zig. This repository aims to have a version compatible for both the latest Zig master, and the latest Zig release. The `master` branch is compatible with the `master` branch of Zig, and versions for older versions of Zig are maintained in the `zig-<version>-compat` branch.
|
||||
vulkan-zig aims to be always compatible with the ever-changing Zig master branch (however, development may lag a few days behind). Sometimes, the Zig master branch breaks a bunch of functionality however, which may make the latest version vulkan-zig incompatible with older releases of Zig. Versions compatible with older versions of zig are marked with the tag `zig-<version>`.
|
||||
|
||||
## Features
|
||||
### CLI-interface
|
||||
@@ -67,22 +67,23 @@ For each function, a wrapper is generated into one of three structs:
|
||||
* InstanceWrapper. This contains wrappers for functions which are otherwise loaded by `vkGetInstanceProcAddr`.
|
||||
* DeviceWrapper. This contains wrappers for functions which are loaded by `vkGetDeviceProcAddr`.
|
||||
|
||||
Each wrapper struct can be called with an array of the appropriate enums:
|
||||
Each wrapper struct is to be used as a mixin on a struct containing **just** function pointers as members:
|
||||
```zig
|
||||
const vk = @import("vulkan");
|
||||
const BaseDispatch = vk.BaseWrapper(.{
|
||||
.CreateInstance,
|
||||
});
|
||||
const BaseDispatch = struct {
|
||||
vkCreateInstance: vk.PfnCreateInstance,
|
||||
usingnamespace vk.BaseWrapper(@This());
|
||||
};
|
||||
```
|
||||
The wrapper struct then provides wrapper functions for each function pointer in the dispatch struct:
|
||||
```zig
|
||||
pub const BaseWrapper(comptime cmds: anytype) type {
|
||||
...
|
||||
const Dispatch = CreateDispatchStruct(cmds);
|
||||
pub const BaseWrapper(comptime Self: type) type {
|
||||
return struct {
|
||||
dispatch: Dispatch,
|
||||
|
||||
pub const CreateInstanceError = error{
|
||||
pub fn createInstance(
|
||||
self: Self,
|
||||
create_info: InstanceCreateInfo,
|
||||
p_allocator: ?*const AllocationCallbacks,
|
||||
) error{
|
||||
OutOfHostMemory,
|
||||
OutOfDeviceMemory,
|
||||
InitializationFailed,
|
||||
@@ -90,14 +91,9 @@ pub const BaseWrapper(comptime cmds: anytype) type {
|
||||
ExtensionNotPresent,
|
||||
IncompatibleDriver,
|
||||
Unknown,
|
||||
};
|
||||
pub fn createInstance(
|
||||
self: Self,
|
||||
create_info: InstanceCreateInfo,
|
||||
p_allocator: ?*const AllocationCallbacks,
|
||||
) CreateInstanceError!Instance {
|
||||
}!Instance {
|
||||
var instance: Instance = undefined;
|
||||
const result = self.dispatch.vkCreateInstance(
|
||||
const result = self.vkCreateInstance(
|
||||
&create_info,
|
||||
p_allocator,
|
||||
&instance,
|
||||
@@ -129,11 +125,9 @@ Wrappers are generated according to the following rules:
|
||||
* As of yet, there is no specific handling of enumeration style commands or other commands which accept slices.
|
||||
|
||||
Furthermore, each wrapper contains a function to load each function pointer member when passed either `PfnGetInstanceProcAddr` or `PfnGetDeviceProcAddr`, which attempts to load each member as function pointer and casts it to the appropriate type. These functions are loaded literally, and any wrongly named member or member with a wrong function pointer type will result in problems.
|
||||
* For `BaseWrapper`, this function has signature `fn load(loader: anytype) !Self`, where the type of `loader` must resemble `PfnGetInstanceProcAddr` (with optionally having a different calling convention).
|
||||
* For `InstanceWrapper`, this function has signature `fn load(instance: Instance, loader: anytype) !Self`, where the type of `loader` must resemble `PfnGetInstanceProcAddr`.
|
||||
* For `DeviceWrapper`, this function has signature `fn load(device: Device, loader: anytype) !Self`, where the type of `loader` must resemble `PfnGetDeviceProcAddr`.
|
||||
|
||||
One can access the underlying unwrapped C functions by doing `wrapper.dispatch.vkFuncYouWant(..)`.
|
||||
* For `BaseWrapper`, this function has signature `fn load(loader: PfnGetInstanceProcAddr) !Self`.
|
||||
* For `InstanceWrapper`, this function has signature `fn load(instance: Instance, loader: PfnGetInstanceProcAddr) !Self`.
|
||||
* For `DeviceWrapper`, this function has signature `fn load(device: Device, loader: PfnGetDeviceProcAddr) !Self`.
|
||||
|
||||
### Bitflags
|
||||
Packed structs of bools are used for bit flags in vulkan-zig, instead of both a `FlagBits` and `Flags` variant. Places where either of these variants are used are both replaced by this packed struct instead. This means that even in places where just one flag would normally be accepted, the packed struct is accepted. The programmer is responsible for only enabling a single bit.
|
||||
|
||||
@@ -34,7 +34,7 @@ pub const ResourceGenStep = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
fn renderPath(path: []const u8, writer: anytype) void {
|
||||
fn renderPath(self: *ResourceGenStep, path: []const u8, writer: anytype) void {
|
||||
const separators = &[_]u8{ std.fs.path.sep_windows, std.fs.path.sep_posix };
|
||||
var i: usize = 0;
|
||||
while (std.mem.indexOfAnyPos(u8, path, i, separators)) |j| {
|
||||
@@ -42,7 +42,7 @@ pub const ResourceGenStep = struct {
|
||||
switch (std.fs.path.sep) {
|
||||
std.fs.path.sep_windows => writer.writeAll("\\\\") catch unreachable,
|
||||
std.fs.path.sep_posix => writer.writeByte(std.fs.path.sep_posix) catch unreachable,
|
||||
else => unreachable,
|
||||
else => unreachable
|
||||
}
|
||||
|
||||
i = j + 1;
|
||||
@@ -55,7 +55,7 @@ pub const ResourceGenStep = struct {
|
||||
var writer = self.resources.writer();
|
||||
|
||||
writer.print("pub const {s} = @embedFile(\"", .{ name }) catch unreachable;
|
||||
renderPath(shader_out_path, writer);
|
||||
self.renderPath(shader_out_path, writer);
|
||||
writer.writeAll("\");\n") catch unreachable;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,80 +3,85 @@ const vk = @import("vulkan");
|
||||
const c = @import("c.zig");
|
||||
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(.{
|
||||
.CreateInstance,
|
||||
});
|
||||
const BaseDispatch = struct {
|
||||
vkCreateInstance: vk.PfnCreateInstance,
|
||||
usingnamespace vk.BaseWrapper(@This());
|
||||
};
|
||||
|
||||
const InstanceDispatch = vk.InstanceWrapper(.{
|
||||
.DestroyInstance,
|
||||
.CreateDevice,
|
||||
.DestroySurfaceKHR,
|
||||
.EnumeratePhysicalDevices,
|
||||
.GetPhysicalDeviceProperties,
|
||||
.EnumerateDeviceExtensionProperties,
|
||||
.GetPhysicalDeviceSurfaceFormatsKHR,
|
||||
.GetPhysicalDeviceSurfacePresentModesKHR,
|
||||
.GetPhysicalDeviceSurfaceCapabilitiesKHR,
|
||||
.GetPhysicalDeviceQueueFamilyProperties,
|
||||
.GetPhysicalDeviceSurfaceSupportKHR,
|
||||
.GetPhysicalDeviceMemoryProperties,
|
||||
.GetDeviceProcAddr,
|
||||
});
|
||||
const InstanceDispatch = struct {
|
||||
vkDestroyInstance: vk.PfnDestroyInstance,
|
||||
vkCreateDevice: vk.PfnCreateDevice,
|
||||
vkDestroySurfaceKHR: vk.PfnDestroySurfaceKHR,
|
||||
vkEnumeratePhysicalDevices: vk.PfnEnumeratePhysicalDevices,
|
||||
vkGetPhysicalDeviceProperties: vk.PfnGetPhysicalDeviceProperties,
|
||||
vkEnumerateDeviceExtensionProperties: vk.PfnEnumerateDeviceExtensionProperties,
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR: vk.PfnGetPhysicalDeviceSurfaceFormatsKHR,
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR: vk.PfnGetPhysicalDeviceSurfacePresentModesKHR,
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR: vk.PfnGetPhysicalDeviceSurfaceCapabilitiesKHR,
|
||||
vkGetPhysicalDeviceQueueFamilyProperties: vk.PfnGetPhysicalDeviceQueueFamilyProperties,
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR: vk.PfnGetPhysicalDeviceSurfaceSupportKHR,
|
||||
vkGetPhysicalDeviceMemoryProperties: vk.PfnGetPhysicalDeviceMemoryProperties,
|
||||
vkGetDeviceProcAddr: vk.PfnGetDeviceProcAddr,
|
||||
usingnamespace vk.InstanceWrapper(@This());
|
||||
};
|
||||
|
||||
const DeviceDispatch = vk.DeviceWrapper(.{
|
||||
.DestroyDevice,
|
||||
.GetDeviceQueue,
|
||||
.CreateSemaphore,
|
||||
.CreateFence,
|
||||
.CreateImageView,
|
||||
.DestroyImageView,
|
||||
.DestroySemaphore,
|
||||
.DestroyFence,
|
||||
.GetSwapchainImagesKHR,
|
||||
.CreateSwapchainKHR,
|
||||
.DestroySwapchainKHR,
|
||||
.AcquireNextImageKHR,
|
||||
.DeviceWaitIdle,
|
||||
.WaitForFences,
|
||||
.ResetFences,
|
||||
.QueueSubmit,
|
||||
.QueuePresentKHR,
|
||||
.CreateCommandPool,
|
||||
.DestroyCommandPool,
|
||||
.AllocateCommandBuffers,
|
||||
.FreeCommandBuffers,
|
||||
.QueueWaitIdle,
|
||||
.CreateShaderModule,
|
||||
.DestroyShaderModule,
|
||||
.CreatePipelineLayout,
|
||||
.DestroyPipelineLayout,
|
||||
.CreateRenderPass,
|
||||
.DestroyRenderPass,
|
||||
.CreateGraphicsPipelines,
|
||||
.DestroyPipeline,
|
||||
.CreateFramebuffer,
|
||||
.DestroyFramebuffer,
|
||||
.BeginCommandBuffer,
|
||||
.EndCommandBuffer,
|
||||
.AllocateMemory,
|
||||
.FreeMemory,
|
||||
.CreateBuffer,
|
||||
.DestroyBuffer,
|
||||
.GetBufferMemoryRequirements,
|
||||
.MapMemory,
|
||||
.UnmapMemory,
|
||||
.BindBufferMemory,
|
||||
.CmdBeginRenderPass,
|
||||
.CmdEndRenderPass,
|
||||
.CmdBindPipeline,
|
||||
.CmdDraw,
|
||||
.CmdSetViewport,
|
||||
.CmdSetScissor,
|
||||
.CmdBindVertexBuffers,
|
||||
.CmdCopyBuffer,
|
||||
});
|
||||
const DeviceDispatch = struct {
|
||||
vkDestroyDevice: vk.PfnDestroyDevice,
|
||||
vkGetDeviceQueue: vk.PfnGetDeviceQueue,
|
||||
vkCreateSemaphore: vk.PfnCreateSemaphore,
|
||||
vkCreateFence: vk.PfnCreateFence,
|
||||
vkCreateImageView: vk.PfnCreateImageView,
|
||||
vkDestroyImageView: vk.PfnDestroyImageView,
|
||||
vkDestroySemaphore: vk.PfnDestroySemaphore,
|
||||
vkDestroyFence: vk.PfnDestroyFence,
|
||||
vkGetSwapchainImagesKHR: vk.PfnGetSwapchainImagesKHR,
|
||||
vkCreateSwapchainKHR: vk.PfnCreateSwapchainKHR,
|
||||
vkDestroySwapchainKHR: vk.PfnDestroySwapchainKHR,
|
||||
vkAcquireNextImageKHR: vk.PfnAcquireNextImageKHR,
|
||||
vkDeviceWaitIdle: vk.PfnDeviceWaitIdle,
|
||||
vkWaitForFences: vk.PfnWaitForFences,
|
||||
vkResetFences: vk.PfnResetFences,
|
||||
vkQueueSubmit: vk.PfnQueueSubmit,
|
||||
vkQueuePresentKHR: vk.PfnQueuePresentKHR,
|
||||
vkCreateCommandPool: vk.PfnCreateCommandPool,
|
||||
vkDestroyCommandPool: vk.PfnDestroyCommandPool,
|
||||
vkAllocateCommandBuffers: vk.PfnAllocateCommandBuffers,
|
||||
vkFreeCommandBuffers: vk.PfnFreeCommandBuffers,
|
||||
vkQueueWaitIdle: vk.PfnQueueWaitIdle,
|
||||
vkCreateShaderModule: vk.PfnCreateShaderModule,
|
||||
vkDestroyShaderModule: vk.PfnDestroyShaderModule,
|
||||
vkCreatePipelineLayout: vk.PfnCreatePipelineLayout,
|
||||
vkDestroyPipelineLayout: vk.PfnDestroyPipelineLayout,
|
||||
vkCreateRenderPass: vk.PfnCreateRenderPass,
|
||||
vkDestroyRenderPass: vk.PfnDestroyRenderPass,
|
||||
vkCreateGraphicsPipelines: vk.PfnCreateGraphicsPipelines,
|
||||
vkDestroyPipeline: vk.PfnDestroyPipeline,
|
||||
vkCreateFramebuffer: vk.PfnCreateFramebuffer,
|
||||
vkDestroyFramebuffer: vk.PfnDestroyFramebuffer,
|
||||
vkBeginCommandBuffer: vk.PfnBeginCommandBuffer,
|
||||
vkEndCommandBuffer: vk.PfnEndCommandBuffer,
|
||||
vkAllocateMemory: vk.PfnAllocateMemory,
|
||||
vkFreeMemory: vk.PfnFreeMemory,
|
||||
vkCreateBuffer: vk.PfnCreateBuffer,
|
||||
vkDestroyBuffer: vk.PfnDestroyBuffer,
|
||||
vkGetBufferMemoryRequirements: vk.PfnGetBufferMemoryRequirements,
|
||||
vkMapMemory: vk.PfnMapMemory,
|
||||
vkUnmapMemory: vk.PfnUnmapMemory,
|
||||
vkBindBufferMemory: vk.PfnBindBufferMemory,
|
||||
vkCmdBeginRenderPass: vk.PfnCmdBeginRenderPass,
|
||||
vkCmdEndRenderPass: vk.PfnCmdEndRenderPass,
|
||||
vkCmdBindPipeline: vk.PfnCmdBindPipeline,
|
||||
vkCmdDraw: vk.PfnCmdDraw,
|
||||
vkCmdSetViewport: vk.PfnCmdSetViewport,
|
||||
vkCmdSetScissor: vk.PfnCmdSetScissor,
|
||||
vkCmdBindVertexBuffers: vk.PfnCmdBindVertexBuffers,
|
||||
vkCmdCopyBuffer: vk.PfnCmdCopyBuffer,
|
||||
usingnamespace vk.DeviceWrapper(@This());
|
||||
};
|
||||
|
||||
pub const GraphicsContext = struct {
|
||||
vkb: BaseDispatch,
|
||||
@@ -120,14 +125,14 @@ pub const GraphicsContext = struct {
|
||||
self.vki = try InstanceDispatch.load(self.instance, c.glfwGetInstanceProcAddress);
|
||||
errdefer self.vki.destroyInstance(self.instance, null);
|
||||
|
||||
self.surface = try createSurface(self.instance, window);
|
||||
self.surface = try createSurface(self.vki, self.instance, window);
|
||||
errdefer self.vki.destroySurfaceKHR(self.instance, self.surface, null);
|
||||
|
||||
const candidate = try pickPhysicalDevice(self.vki, self.instance, allocator, self.surface);
|
||||
self.pdev = candidate.pdev;
|
||||
self.props = candidate.props;
|
||||
self.dev = try initializeCandidate(self.vki, candidate);
|
||||
self.vkd = try DeviceDispatch.load(self.dev, self.vki.dispatch.vkGetDeviceProcAddr);
|
||||
self.vkd = try DeviceDispatch.load(self.dev, self.vki.vkGetDeviceProcAddr);
|
||||
errdefer self.vkd.destroyDevice(self.dev, null);
|
||||
|
||||
self.graphics_queue = Queue.init(self.vkd, self.dev, candidate.queues.graphics_family);
|
||||
@@ -179,7 +184,7 @@ pub const Queue = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn createSurface(instance: vk.Instance, window: *c.GLFWwindow) !vk.SurfaceKHR {
|
||||
fn createSurface(vki: InstanceDispatch, instance: vk.Instance, window: *c.GLFWwindow) !vk.SurfaceKHR {
|
||||
var surface: vk.SurfaceKHR = undefined;
|
||||
if (c.glfwCreateWindowSurface(instance, window, null, &surface) != .success) {
|
||||
return error.SurfaceInitFailed;
|
||||
@@ -202,7 +207,7 @@ fn initializeCandidate(vki: InstanceDispatch, candidate: DeviceCandidate) !vk.De
|
||||
.queue_family_index = candidate.queues.present_family,
|
||||
.queue_count = 1,
|
||||
.p_queue_priorities = &priority,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const queue_count: u32 = if (candidate.queues.graphics_family == candidate.queues.present_family)
|
||||
@@ -276,14 +281,19 @@ fn checkSuitable(
|
||||
return DeviceCandidate{
|
||||
.pdev = pdev,
|
||||
.props = props,
|
||||
.queues = allocation,
|
||||
.queues = allocation
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn allocateQueues(vki: InstanceDispatch, pdev: vk.PhysicalDevice, allocator: *Allocator, surface: vk.SurfaceKHR) !?QueueAllocation {
|
||||
fn allocateQueues(
|
||||
vki: InstanceDispatch,
|
||||
pdev: vk.PhysicalDevice,
|
||||
allocator: *Allocator,
|
||||
surface: vk.SurfaceKHR
|
||||
) !?QueueAllocation {
|
||||
var family_count: u32 = undefined;
|
||||
vki.getPhysicalDeviceQueueFamilyProperties(pdev, &family_count, null);
|
||||
|
||||
@@ -297,7 +307,7 @@ fn allocateQueues(vki: InstanceDispatch, pdev: vk.PhysicalDevice, allocator: *Al
|
||||
for (families) |properties, i| {
|
||||
const family = @intCast(u32, i);
|
||||
|
||||
if (graphics_family == null and properties.queue_flags.graphics_bit) {
|
||||
if (graphics_family == null and properties.queue_flags.contains(.{.graphics_bit = true})) {
|
||||
graphics_family = family;
|
||||
}
|
||||
|
||||
@@ -309,7 +319,7 @@ fn allocateQueues(vki: InstanceDispatch, pdev: vk.PhysicalDevice, allocator: *Al
|
||||
if (graphics_family != null and present_family != null) {
|
||||
return QueueAllocation{
|
||||
.graphics_family = graphics_family.?,
|
||||
.present_family = present_family.?,
|
||||
.present_family = present_family.?
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ pub fn main() !void {
|
||||
@intCast(c_int, extent.height),
|
||||
app_name,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
) orelse return error.WindowInitFailed;
|
||||
defer c.glfwDestroyWindow(window);
|
||||
|
||||
@@ -78,7 +78,7 @@ pub fn main() !void {
|
||||
const render_pass = try createRenderPass(&gc, swapchain);
|
||||
defer gc.vkd.destroyRenderPass(gc.dev, render_pass, null);
|
||||
|
||||
var pipeline = try createPipeline(&gc, pipeline_layout, render_pass);
|
||||
var pipeline = try createPipeline(&gc, extent, pipeline_layout, render_pass);
|
||||
defer gc.vkd.destroyPipeline(gc.dev, pipeline, null);
|
||||
|
||||
var framebuffers = try createFramebuffers(&gc, allocator, render_pass, swapchain);
|
||||
@@ -104,7 +104,7 @@ pub fn main() !void {
|
||||
defer gc.vkd.freeMemory(gc.dev, memory, null);
|
||||
try gc.vkd.bindBufferMemory(gc.dev, buffer, memory, 0);
|
||||
|
||||
try uploadVertices(&gc, pool, buffer);
|
||||
try uploadVertices(&gc, pool, buffer, memory);
|
||||
|
||||
var cmdbufs = try createCommandBuffers(
|
||||
&gc,
|
||||
@@ -114,7 +114,7 @@ pub fn main() !void {
|
||||
swapchain.extent,
|
||||
render_pass,
|
||||
pipeline,
|
||||
framebuffers,
|
||||
framebuffers
|
||||
);
|
||||
defer destroyCommandBuffers(&gc, pool, allocator, cmdbufs);
|
||||
|
||||
@@ -146,18 +146,19 @@ pub fn main() !void {
|
||||
swapchain.extent,
|
||||
render_pass,
|
||||
pipeline,
|
||||
framebuffers,
|
||||
framebuffers
|
||||
);
|
||||
}
|
||||
|
||||
c.glfwSwapBuffers(window);
|
||||
c.glfwPollEvents();
|
||||
|
||||
}
|
||||
|
||||
try swapchain.waitForAllFences();
|
||||
}
|
||||
|
||||
fn uploadVertices(gc: *const GraphicsContext, pool: vk.CommandPool, buffer: vk.Buffer) !void {
|
||||
fn uploadVertices(gc: *const GraphicsContext, pool: vk.CommandPool, buffer: vk.Buffer, memory: vk.DeviceMemory) !void {
|
||||
const staging_buffer = try gc.vkd.createBuffer(gc.dev, .{
|
||||
.flags = .{},
|
||||
.size = @sizeOf(@TypeOf(vertices)),
|
||||
@@ -296,7 +297,12 @@ fn destroyCommandBuffers(gc: *const GraphicsContext, pool: vk.CommandPool, alloc
|
||||
allocator.free(cmdbufs);
|
||||
}
|
||||
|
||||
fn createFramebuffers(gc: *const GraphicsContext, allocator: *Allocator, render_pass: vk.RenderPass, swapchain: Swapchain) ![]vk.Framebuffer {
|
||||
fn createFramebuffers(
|
||||
gc: *const GraphicsContext,
|
||||
allocator: *Allocator,
|
||||
render_pass: vk.RenderPass,
|
||||
swapchain: Swapchain
|
||||
) ![]vk.Framebuffer {
|
||||
const framebuffers = try allocator.alloc(vk.Framebuffer, swapchain.swap_images.len);
|
||||
errdefer allocator.free(framebuffers);
|
||||
|
||||
@@ -368,6 +374,7 @@ fn createRenderPass(gc: *const GraphicsContext, swapchain: Swapchain) !vk.Render
|
||||
|
||||
fn createPipeline(
|
||||
gc: *const GraphicsContext,
|
||||
extent: vk.Extent2D,
|
||||
layout: vk.PipelineLayout,
|
||||
render_pass: vk.RenderPass,
|
||||
) !vk.Pipeline {
|
||||
@@ -499,8 +506,7 @@ fn createPipeline(
|
||||
_ = try gc.vkd.createGraphicsPipelines(
|
||||
gc.dev,
|
||||
.null_handle,
|
||||
1,
|
||||
@ptrCast([*]const vk.GraphicsPipelineCreateInfo, &gpci),
|
||||
1, @ptrCast([*]const vk.GraphicsPipelineCreateInfo, &gpci),
|
||||
null,
|
||||
@ptrCast([*]vk.Pipeline, &pipeline),
|
||||
);
|
||||
|
||||
2080
examples/vk.xml
2080
examples/vk.xml
File diff suppressed because it is too large
Load Diff
@@ -2,64 +2,6 @@ const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
pub fn isZigPrimitiveType(name: []const u8) bool {
|
||||
if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {
|
||||
for (name[1..]) |c| {
|
||||
switch (c) {
|
||||
'0'...'9' => {},
|
||||
else => return false,
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const primitives = [_][]const u8{
|
||||
"void",
|
||||
"comptime_float",
|
||||
"comptime_int",
|
||||
"bool",
|
||||
"isize",
|
||||
"usize",
|
||||
"f16",
|
||||
"f32",
|
||||
"f64",
|
||||
"f128",
|
||||
"c_longdouble",
|
||||
"noreturn",
|
||||
"type",
|
||||
"anyerror",
|
||||
"c_short",
|
||||
"c_ushort",
|
||||
"c_int",
|
||||
"c_uint",
|
||||
"c_long",
|
||||
"c_ulong",
|
||||
"c_longlong",
|
||||
"c_ulonglong",
|
||||
};
|
||||
|
||||
for (primitives) |reserved| {
|
||||
if (mem.eql(u8, reserved, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn needZigEscape(name: []const u8) bool {
|
||||
return !std.zig.fmt.isValidId(name) or isZigPrimitiveType(name);
|
||||
}
|
||||
|
||||
pub fn writeIdentifier(out: anytype, id: []const u8) !void {
|
||||
// https://github.com/ziglang/zig/issues/2897
|
||||
if (isZigPrimitiveType(id)) {
|
||||
try out.print("{s}_", .{id});
|
||||
} else {
|
||||
try out.print("{}", .{std.zig.fmtId(id)});
|
||||
}
|
||||
}
|
||||
|
||||
pub const CaseStyle = enum {
|
||||
snake,
|
||||
screaming_snake,
|
||||
@@ -196,10 +138,14 @@ pub const IdRenderer = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(self: IdRenderer, out: anytype, id: []const u8) !void {
|
||||
try out.print("{z}", .{ id });
|
||||
}
|
||||
|
||||
pub fn renderFmt(self: *IdRenderer, out: anytype, comptime fmt: []const u8, args: anytype) !void {
|
||||
self.text_cache.items.len = 0;
|
||||
try std.fmt.format(self.text_cache.writer(), fmt, args);
|
||||
try writeIdentifier(out, self.text_cache.items);
|
||||
try out.print("{z}", .{ self.text_cache.items });
|
||||
}
|
||||
|
||||
pub fn renderWithCase(self: *IdRenderer, out: anytype, case_style: CaseStyle, id: []const u8) !void {
|
||||
@@ -216,7 +162,7 @@ pub const IdRenderer = struct {
|
||||
.camel => try self.renderCamel(false, adjusted_id, tag),
|
||||
}
|
||||
|
||||
try writeIdentifier(out, self.text_cache.items);
|
||||
try out.print("{z}", .{ self.text_cache.items });
|
||||
}
|
||||
|
||||
pub fn getAuthorTag(self: IdRenderer, id: []const u8) ?[]const u8 {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub const generateVk = @import("vulkan/generator.zig").generate;
|
||||
pub const VkGenerateStep = @import("vulkan/build_integration.zig").GenerateStep;
|
||||
pub const generateSpirv = @import("spirv/generator.zig").generate;
|
||||
pub const ShaderCompileStep = @import("build_integration.zig").ShaderCompileStep;
|
||||
|
||||
test "main" {
|
||||
|
||||
@@ -5,6 +5,7 @@ const usage = "Usage: {s} [-h|--help] <spec xml path> <output zig source>\n";
|
||||
|
||||
pub fn main() !void {
|
||||
const stderr = std.io.getStdErr();
|
||||
const stdout = std.io.getStdOut();
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
@@ -59,22 +60,15 @@ pub fn main() !void {
|
||||
return;
|
||||
};
|
||||
|
||||
const out_file = cwd.createFile(out_path, .{}) catch |err| {
|
||||
try stderr.writer().print("Error: Failed to create output file '{s}' ({s})\n", .{ out_path, @errorName(err) });
|
||||
return;
|
||||
};
|
||||
defer out_file.close();
|
||||
|
||||
var out_buffer = std.ArrayList(u8).init(allocator);
|
||||
try generate(allocator, xml_src, out_buffer.writer());
|
||||
|
||||
const tree = try std.zig.parse(allocator, out_buffer.items);
|
||||
const formatted = try tree.render(allocator);
|
||||
defer allocator.free(formatted);
|
||||
|
||||
if (std.fs.path.dirname(out_path)) |dir| {
|
||||
cwd.makePath(dir) catch |err| {
|
||||
try stderr.writer().print("Error: Failed to create output directory '{s}' ({s})\n", .{ dir, @errorName(err) });
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
cwd.writeFile(out_path, formatted) catch |err| {
|
||||
try stderr.writer().print("Error: Failed to write to output file '{s}' ({s})\n", .{ out_path, @errorName(err) });
|
||||
return;
|
||||
};
|
||||
_ = try std.zig.render(allocator, out_file.writer(), tree);
|
||||
}
|
||||
|
||||
@@ -65,18 +65,16 @@ pub const GenerateStep = struct {
|
||||
fn make(step: *Step) !void {
|
||||
const self = @fieldParentPtr(GenerateStep, "step", step);
|
||||
const cwd = std.fs.cwd();
|
||||
|
||||
const spec = try cwd.readFileAlloc(self.builder.allocator, self.spec_path, std.math.maxInt(usize));
|
||||
|
||||
var out_buffer = std.ArrayList(u8).init(self.builder.allocator);
|
||||
const spec = try cwd.readFileAlloc(self.builder.allocator, self.spec_path, std.math.maxInt(usize));
|
||||
try generate(self.builder.allocator, spec, out_buffer.writer());
|
||||
|
||||
const tree = try std.zig.parse(self.builder.allocator, out_buffer.items);
|
||||
|
||||
var formatted = try tree.render(self.builder.allocator);
|
||||
|
||||
const dir = path.dirname(self.package.path).?;
|
||||
try cwd.makePath(dir);
|
||||
try cwd.writeFile(self.package.path, formatted);
|
||||
const output_file = cwd.createFile(self.package.path, .{}) catch unreachable;
|
||||
defer output_file.close();
|
||||
_ = try std.zig.render(self.builder.allocator, output_file.writer(), tree);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -143,12 +143,15 @@ pub const CTokenizer = struct {
|
||||
']' => kind = .rbracket,
|
||||
'(' => kind = .lparen,
|
||||
')' => kind = .rparen,
|
||||
else => return error.UnexpectedCharacter,
|
||||
else => return error.UnexpectedCharacter
|
||||
}
|
||||
|
||||
const start = self.offset;
|
||||
_ = self.consumeNoEof();
|
||||
return Token{ .kind = kind, .text = self.source[start..self.offset] };
|
||||
return Token{
|
||||
.kind = kind,
|
||||
.text = self.source[start .. self.offset]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -362,7 +365,7 @@ fn parseDeclaration(allocator: *Allocator, xctok: *XmlCTokenizer) ParseError!Dec
|
||||
.array = .{
|
||||
.size = array_size,
|
||||
.child = child,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// update the inner_type pointer so it points to the proper
|
||||
@@ -400,8 +403,8 @@ fn parseFnPtrSuffix(allocator: *Allocator, xctok: *XmlCTokenizer, return_type: T
|
||||
.return_type = return_type_heap,
|
||||
.success_codes = &[_][]const u8{},
|
||||
.error_codes = &[_][]const u8{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const first_param = try parseDeclaration(allocator, xctok);
|
||||
@@ -497,10 +500,10 @@ fn parseArrayDeclarator(xctok: *XmlCTokenizer) !?ArraySize {
|
||||
.int = std.fmt.parseInt(usize, size_tok.text, 10) catch |err| switch (err) {
|
||||
error.Overflow => return error.Overflow,
|
||||
error.InvalidCharacter => unreachable,
|
||||
},
|
||||
}
|
||||
},
|
||||
.enum_name => .{.alias = size_tok.text},
|
||||
else => return error.InvalidSyntax,
|
||||
else => return error.InvalidSyntax
|
||||
};
|
||||
|
||||
_ = try xctok.expect(.rbracket);
|
||||
@@ -514,7 +517,7 @@ pub fn parseVersion(xctok: *XmlCTokenizer) ![4][]const u8 {
|
||||
return error.InvalidVersion;
|
||||
}
|
||||
|
||||
_ = try xctok.expect(.name);
|
||||
const name = try xctok.expect(.name);
|
||||
const vk_make_version = try xctok.expect(.type_name);
|
||||
if (!mem.eql(u8, vk_make_version.text, "VK_MAKE_API_VERSION")) {
|
||||
return error.NotVersion;
|
||||
@@ -537,20 +540,24 @@ pub fn parseVersion(xctok: *XmlCTokenizer) ![4][]const u8 {
|
||||
return version;
|
||||
}
|
||||
|
||||
fn testTokenizer(tokenizer: anytype, expected_tokens: []const Token) !void {
|
||||
fn testTokenizer(tokenizer: anytype, expected_tokens: []const Token) void {
|
||||
for (expected_tokens) |expected| {
|
||||
const tok = (tokenizer.next() catch unreachable).?;
|
||||
try testing.expectEqual(expected.kind, tok.kind);
|
||||
try testing.expectEqualSlices(u8, expected.text, tok.text);
|
||||
testing.expectEqual(expected.kind, tok.kind);
|
||||
testing.expectEqualSlices(u8, expected.text, tok.text);
|
||||
}
|
||||
|
||||
if (tokenizer.next() catch unreachable) |_| unreachable;
|
||||
}
|
||||
|
||||
test "CTokenizer" {
|
||||
var ctok = CTokenizer{ .source = "typedef ([const)]** VKAPI_PTR 123,;aaaa" };
|
||||
var ctok = CTokenizer {
|
||||
.source = \\typedef ([const)]** VKAPI_PTR 123,;aaaa
|
||||
};
|
||||
|
||||
try testTokenizer(&ctok, &[_]Token{
|
||||
testTokenizer(
|
||||
&ctok,
|
||||
&[_]Token{
|
||||
.{.kind = .kw_typedef, .text = "typedef"},
|
||||
.{.kind = .lparen, .text = "("},
|
||||
.{.kind = .lbracket, .text = "["},
|
||||
@@ -564,11 +571,13 @@ test "CTokenizer" {
|
||||
.{.kind = .comma, .text = ","},
|
||||
.{.kind = .semicolon, .text = ";"},
|
||||
.{.kind = .id, .text = "aaaa"},
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
test "XmlCTokenizer" {
|
||||
const document = try xml.parse(testing.allocator,
|
||||
const document = try xml.parse(
|
||||
testing.allocator,
|
||||
\\<root>// comment <name>commented name</name> <type>commented type</type> trailing
|
||||
\\ typedef void (VKAPI_PTR *<name>PFN_vkVoidFunction</name>)(void);
|
||||
\\</root>
|
||||
@@ -577,7 +586,9 @@ test "XmlCTokenizer" {
|
||||
|
||||
var xctok = XmlCTokenizer.init(document.root);
|
||||
|
||||
try testTokenizer(&xctok, &[_]Token{
|
||||
testTokenizer(
|
||||
&xctok,
|
||||
&[_]Token{
|
||||
.{.kind = .kw_typedef, .text = "typedef"},
|
||||
.{.kind = .id, .text = "void"},
|
||||
.{.kind = .lparen, .text = "("},
|
||||
@@ -589,11 +600,13 @@ test "XmlCTokenizer" {
|
||||
.{.kind = .id, .text = "void"},
|
||||
.{.kind = .rparen, .text = ")"},
|
||||
.{.kind = .semicolon, .text = ";"},
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
test "parseTypedef" {
|
||||
const document = try xml.parse(testing.allocator,
|
||||
const document = try xml.parse(
|
||||
testing.allocator,
|
||||
\\<root> // comment <name>commented name</name> trailing
|
||||
\\ typedef const struct <type>Python</type>* pythons[4];
|
||||
\\ // more comments
|
||||
@@ -608,10 +621,10 @@ test "parseTypedef" {
|
||||
var xctok = XmlCTokenizer.init(document.root);
|
||||
const decl = try parseTypedef(&arena.allocator, &xctok);
|
||||
|
||||
try testing.expectEqualSlices(u8, "pythons", decl.name);
|
||||
testing.expectEqualSlices(u8, "pythons", decl.name);
|
||||
const array = decl.decl_type.typedef.array;
|
||||
try testing.expectEqual(ArraySize{ .int = 4 }, array.size);
|
||||
testing.expectEqual(ArraySize{.int = 4}, array.size);
|
||||
const ptr = array.child.pointer;
|
||||
try testing.expectEqual(true, ptr.is_const);
|
||||
try testing.expectEqualSlices(u8, "Python", ptr.child.name);
|
||||
testing.expectEqual(true, ptr.is_const);
|
||||
testing.expectEqualSlices(u8, "Python", ptr.child.name);
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ const EnumFieldMerger = struct {
|
||||
}
|
||||
|
||||
fn deinit(self: *EnumFieldMerger) void {
|
||||
for (self.enum_extensions.values()) |*value| {
|
||||
value.deinit(self.gpa);
|
||||
for (self.enum_extensions.items()) |*entry| {
|
||||
entry.value.deinit(self.gpa);
|
||||
}
|
||||
|
||||
self.field_set.deinit();
|
||||
@@ -40,10 +40,10 @@ const EnumFieldMerger = struct {
|
||||
fn putEnumExtension(self: *EnumFieldMerger, enum_name: []const u8, field: reg.Enum.Field) !void {
|
||||
const res = try self.enum_extensions.getOrPut(enum_name);
|
||||
if (!res.found_existing) {
|
||||
res.value_ptr.* = std.ArrayListUnmanaged(reg.Enum.Field){};
|
||||
res.entry.value = std.ArrayListUnmanaged(reg.Enum.Field){};
|
||||
}
|
||||
|
||||
try res.value_ptr.append(self.gpa, field);
|
||||
try res.entry.value.append(self.gpa, field);
|
||||
}
|
||||
|
||||
fn addRequires(self: *EnumFieldMerger, reqs: []const reg.Require) !void {
|
||||
@@ -147,37 +147,10 @@ pub const Generator = struct {
|
||||
try merger.merge();
|
||||
}
|
||||
|
||||
// https://github.com/KhronosGroup/Vulkan-Docs/pull/1556
|
||||
fn fixupBitFlags(self: *Generator) !void {
|
||||
var seen_bits = std.StringArrayHashMap(void).init(&self.reg_arena.allocator);
|
||||
defer seen_bits.deinit();
|
||||
|
||||
for (self.registry.decls) |decl| {
|
||||
const bitmask = switch (decl.decl_type) {
|
||||
.bitmask => |bm| bm,
|
||||
else => continue,
|
||||
};
|
||||
|
||||
if (bitmask.bits_enum) |bits_enum| {
|
||||
try seen_bits.put(bits_enum, {});
|
||||
}
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
|
||||
for (self.registry.decls) |decl| {
|
||||
switch (decl.decl_type) {
|
||||
.enumeration => |e| {
|
||||
if (e.is_bitmask and seen_bits.get(decl.name) == null)
|
||||
continue;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
self.registry.decls[i] = decl;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
self.registry.decls.len = i;
|
||||
fn fixupTags(self: *Generator) !void {
|
||||
var fixer_upper = TagFixerUpper.init(self.gpa, &self.registry, &self.id_renderer);
|
||||
defer fixer_upper.deinit();
|
||||
try fixer_upper.fixup();
|
||||
}
|
||||
|
||||
fn render(self: *Generator, writer: anytype) !void {
|
||||
@@ -197,6 +170,5 @@ pub fn generate(allocator: *Allocator, spec_xml: []const u8, writer: anytype) !v
|
||||
defer gen.deinit();
|
||||
|
||||
try gen.mergeEnumFields();
|
||||
try gen.fixupBitFlags();
|
||||
try gen.render(writer);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ fn parseTypes(allocator: *Allocator, out: []registry.Declaration, types_elem: *x
|
||||
} else if (mem.eql(u8, category, "funcpointer")) {
|
||||
break :blk try parseFuncPointer(allocator, ty);
|
||||
} else if (mem.eql(u8, category, "enum")) {
|
||||
break :blk (try parseEnumAlias(ty)) orelse continue;
|
||||
break :blk (try parseEnumAlias(allocator, ty)) orelse continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -118,13 +118,10 @@ fn parseBitmaskType(ty: *xml.Element) !registry.Declaration {
|
||||
|
||||
return registry.Declaration{
|
||||
.name = ty.getCharData("name") orelse return error.InvalidRegistry,
|
||||
.decl_type = .{
|
||||
.bitmask = .{
|
||||
// Who knows why these are different fields
|
||||
.bits_enum = ty.getAttribute("requires") orelse ty.getAttribute("bitvalues"),
|
||||
.decl_type = .{.bitmask = .{
|
||||
.bits_enum = ty.getAttribute("requires") orelse ty.getAttribute("bitvalues"), // Who knows why these are different fields
|
||||
.bitwidth = bitwidth,
|
||||
},
|
||||
},
|
||||
}},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -135,9 +132,7 @@ fn parseHandleType(ty: *xml.Element) !registry.Declaration {
|
||||
const alias = ty.getAttribute("alias") orelse return error.InvalidRegistry;
|
||||
return registry.Declaration{
|
||||
.name = name,
|
||||
.decl_type = .{
|
||||
.alias = .{ .name = alias, .target = .other_type },
|
||||
},
|
||||
.decl_type = .{.alias = .{.name = alias, .target = .other_type}},
|
||||
};
|
||||
} else {
|
||||
const name = ty.getCharData("name") orelse return error.InvalidRegistry;
|
||||
@@ -153,7 +148,7 @@ fn parseHandleType(ty: *xml.Element) !registry.Declaration {
|
||||
.handle = .{
|
||||
.parent = ty.getAttribute("parent"),
|
||||
.is_dispatchable = dispatchable,
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -180,9 +175,7 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
|
||||
if (ty.getAttribute("alias")) |alias| {
|
||||
return registry.Declaration{
|
||||
.name = name,
|
||||
.decl_type = .{
|
||||
.alias = .{ .name = alias, .target = .other_type },
|
||||
},
|
||||
.decl_type = .{.alias = .{.name = alias, .target = .other_type}},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -218,8 +211,8 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
|
||||
.stype = maybe_stype,
|
||||
.fields = members,
|
||||
.is_union = is_union,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -297,14 +290,12 @@ fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.El
|
||||
}
|
||||
}
|
||||
|
||||
fn parseEnumAlias(elem: *xml.Element) !?registry.Declaration {
|
||||
fn parseEnumAlias(allocator: *Allocator, elem: *xml.Element) !?registry.Declaration {
|
||||
if (elem.getAttribute("alias")) |alias| {
|
||||
const name = elem.getAttribute("name") orelse return error.InvalidRegistry;
|
||||
return registry.Declaration{
|
||||
.name = name,
|
||||
.decl_type = .{
|
||||
.alias = .{ .name = alias, .target = .other_type },
|
||||
},
|
||||
.decl_type = .{.alias = .{.name = alias, .target = .other_type}},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -428,9 +419,7 @@ fn parseCommand(allocator: *Allocator, elem: *xml.Element) !registry.Declaration
|
||||
const name = elem.getAttribute("name") orelse return error.InvalidRegistry;
|
||||
return registry.Declaration{
|
||||
.name = name,
|
||||
.decl_type = .{
|
||||
.alias = .{ .name = alias, .target = .other_command },
|
||||
},
|
||||
.decl_type = .{.alias = .{.name = alias, .target = .other_command}}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -482,8 +471,8 @@ fn parseCommand(allocator: *Allocator, elem: *xml.Element) !registry.Declaration
|
||||
.return_type = return_type,
|
||||
.success_codes = success_codes,
|
||||
.error_codes = error_codes,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -557,7 +546,9 @@ fn parseDefines(types: *xml.Element, out: []registry.ApiConstant) !usize {
|
||||
var xctok = cparse.XmlCTokenizer.init(ty);
|
||||
out[i] = .{
|
||||
.name = name,
|
||||
.value = .{ .version = cparse.parseVersion(&xctok) catch continue },
|
||||
.value = .{
|
||||
.version = cparse.parseVersion(&xctok) catch continue
|
||||
},
|
||||
};
|
||||
}
|
||||
i += 1;
|
||||
@@ -618,7 +609,7 @@ fn parseFeature(allocator: *Allocator, feature: *xml.Element) !registry.Feature
|
||||
return registry.Feature{
|
||||
.name = name,
|
||||
.level = feature_level,
|
||||
.requires = allocator.shrink(requires, i),
|
||||
.requires = allocator.shrink(requires, i)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -651,10 +642,7 @@ fn parseEnumExtension(elem: *xml.Element, parent_extnumber: ?u31) !?registry.Req
|
||||
return registry.Require.EnumExtension{
|
||||
.extends = extends,
|
||||
.extnumber = actual_extnumber,
|
||||
.field = .{
|
||||
.name = name,
|
||||
.value = .{ .int = value },
|
||||
},
|
||||
.field = .{.name = name, .value = .{.int = value}},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -783,6 +771,7 @@ fn parseExtension(allocator: *Allocator, extension: *xml.Element) !registry.Exte
|
||||
const promotedto = extension.getAttribute("promotedto") orelse break :blk .none;
|
||||
if (mem.startsWith(u8, promotedto, "VK_VERSION_")) {
|
||||
const feature_level = try splitFeatureLevel(promotedto["VK_VERSION_".len ..], "_");
|
||||
|
||||
break :blk .{.feature = feature_level};
|
||||
}
|
||||
|
||||
@@ -827,7 +816,7 @@ fn parseExtension(allocator: *Allocator, extension: *xml.Element) !registry.Exte
|
||||
.promoted_to = promoted_to,
|
||||
.platform = platform,
|
||||
.required_feature_level = requires_core,
|
||||
.requires = allocator.shrink(requires, i),
|
||||
.requires = allocator.shrink(requires, i)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ pub const Enum = struct {
|
||||
alias: struct {
|
||||
name: []const u8,
|
||||
is_compat_alias: bool,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
pub const Field = struct {
|
||||
@@ -118,7 +118,7 @@ pub const Pointer = struct {
|
||||
one,
|
||||
many, // The length is given by some complex expression, possibly involving another field
|
||||
other_field: []const u8, // The length is given by some other field or parameter
|
||||
zero_terminated,
|
||||
zero_terminated
|
||||
};
|
||||
|
||||
is_const: bool,
|
||||
|
||||
@@ -9,17 +9,14 @@ const IdRenderer = id_render.IdRenderer;
|
||||
|
||||
const preamble =
|
||||
\\
|
||||
\\// This file is generated from the Khronos Vulkan XML API registry by vulkan-zig.
|
||||
\\// This file is generated from the Khronos Vulkan XML API registry
|
||||
\\
|
||||
\\const std = @import("std");
|
||||
\\const builtin = @import("builtin");
|
||||
\\const root = @import("root");
|
||||
\\
|
||||
\\const GlobalScope = @This();
|
||||
\\
|
||||
\\pub const vulkan_call_conv: std.builtin.CallingConvention = if (builtin.os.tag == .windows and builtin.cpu.arch == .i386)
|
||||
\\pub const vulkan_call_conv: builtin.CallingConvention = if (builtin.os.tag == .windows and builtin.cpu.arch == .i386)
|
||||
\\ .Stdcall
|
||||
\\ else if (builtin.abi == .android and (builtin.cpu.arch.isARM() or builtin.cpu.arch.isThumb()) and std.Target.arm.featureSetHas(builtin.cpu.features, .has_v7) and builtin.cpu.arch.ptrBitWidth() == 32)
|
||||
\\ else if (builtin.abi == .android and (builtin.cpu.arch.isARM() or builtin.cpu.arch.isThumb()) and builtin.Target.arm.featureSetHas(builtin.cpu.features, .has_v7) and builtin.cpu.arch.ptrBitWidth() == 32)
|
||||
\\ // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
|
||||
\\ // calling convention, i.e. float parameters are passed in registers. This
|
||||
\\ // is true even if the rest of the application passes floats on the stack,
|
||||
@@ -43,7 +40,7 @@ const preamble =
|
||||
\\ return fromInt(toInt(lhs) & toInt(rhs));
|
||||
\\ }
|
||||
\\ pub fn complement(self: FlagsType) FlagsType {
|
||||
\\ return fromInt(~toInt(self));
|
||||
\\ return fromInt(~toInt(lhs));
|
||||
\\ }
|
||||
\\ pub fn subtract(lhs: FlagsType, rhs: FlagsType) FlagsType {
|
||||
\\ return fromInt(toInt(lhs) & toInt(rhs.complement()));
|
||||
@@ -198,7 +195,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
return error.InvalidRegistry;
|
||||
}
|
||||
|
||||
result.value_ptr.* = &decl.decl_type;
|
||||
result.entry.value = &decl.decl_type;
|
||||
}
|
||||
|
||||
return Self{
|
||||
@@ -217,7 +214,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
}
|
||||
|
||||
fn writeIdentifier(self: Self, id: []const u8) !void {
|
||||
try id_render.writeIdentifier(self.writer, id);
|
||||
try self.id_renderer.render(self.writer, id);
|
||||
}
|
||||
|
||||
fn writeIdentifierWithCase(self: *Self, case: CaseStyle, id: []const u8) !void {
|
||||
@@ -245,7 +242,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
}
|
||||
}
|
||||
|
||||
fn extractBitflagFieldName(bitflag_name: BitflagName, field_name: []const u8) ![]const u8 {
|
||||
fn extractBitflagFieldName(self: Self, bitflag_name: BitflagName, field_name: []const u8) ![]const u8 {
|
||||
var flag_it = id_render.SegmentIterator.init(bitflag_name.base_name);
|
||||
var field_it = id_render.SegmentIterator.init(field_name);
|
||||
|
||||
@@ -298,6 +295,16 @@ fn Renderer(comptime WriterType: type) type {
|
||||
return mem.endsWith(u8, base_name, "Flags");
|
||||
}
|
||||
|
||||
fn containerHasField(self: Self, container: *const reg.Container, field_name: []const u8) bool {
|
||||
for (container.fields) |field| {
|
||||
if (mem.eql(u8, field, field_name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn isInOutPointer(self: Self, ptr: reg.Pointer) !bool {
|
||||
if (ptr.child.* != .name) {
|
||||
return false;
|
||||
@@ -366,7 +373,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
}
|
||||
},
|
||||
.name => |name| {
|
||||
if ((try self.extractBitflagName(name)) != null or self.isFlags(name)) {
|
||||
if ((try self.extractBitflagName(param.param_type.name)) != null or self.isFlags(param.param_type.name)) {
|
||||
return .bitflags;
|
||||
}
|
||||
},
|
||||
@@ -380,7 +387,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
return .other;
|
||||
}
|
||||
|
||||
fn classifyCommandDispatch(name: []const u8, command: reg.Command) CommandDispatchType {
|
||||
fn classifyCommandDispatch(self: Self, name: []const u8, command: reg.Command) CommandDispatchType {
|
||||
const device_handles = std.ComptimeStringMap(void, .{
|
||||
.{"VkDevice", {}},
|
||||
.{"VkCommandBuffer", {}},
|
||||
@@ -415,7 +422,6 @@ fn Renderer(comptime WriterType: type) type {
|
||||
fn render(self: *Self) !void {
|
||||
try self.renderCopyright();
|
||||
try self.writer.writeAll(preamble);
|
||||
try self.renderCommandEnums();
|
||||
|
||||
for (self.registry.api_constants) |api_constant| {
|
||||
try self.renderApiConstant(api_constant);
|
||||
@@ -430,37 +436,6 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.renderWrappers();
|
||||
}
|
||||
|
||||
fn renderCommandEnums(self: *Self) !void {
|
||||
try self.renderCommandEnumOfDispatchType(.base);
|
||||
try self.renderCommandEnumOfDispatchType(.instance);
|
||||
try self.renderCommandEnumOfDispatchType(.device);
|
||||
try self.writer.writeAll("\n");
|
||||
}
|
||||
|
||||
fn renderCommandEnumOfDispatchType(self: *Self, dispatch_type: CommandDispatchType) !void {
|
||||
const dispatch_type_name = switch (dispatch_type) {
|
||||
.base => "Base",
|
||||
.instance => "Instance",
|
||||
.device => "Device",
|
||||
};
|
||||
|
||||
try self.writer.print("pub const {s}Command = enum {{\n", .{dispatch_type_name});
|
||||
for (self.registry.decls) |decl| {
|
||||
if (decl.decl_type == .command) {
|
||||
const command = decl.decl_type.command;
|
||||
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
||||
try self.writer.print("{s},\n", .{trimVkNamespace(decl.name)});
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
var it = mem.split(self.registry.copyright, "\n");
|
||||
while (it.next()) |line| {
|
||||
@@ -564,7 +539,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writeIdentifierFmt("{s}Flags{s}{s}", .{
|
||||
trimVkNamespace(bitflag_name.base_name),
|
||||
@as([]const u8, if (bitflag_name.revision) |revision| revision else ""),
|
||||
@as([]const u8, if (bitflag_name.tag) |tag| tag else ""),
|
||||
@as([]const u8, if (bitflag_name.tag) |tag| tag else "")
|
||||
});
|
||||
return;
|
||||
} else if (mem.startsWith(u8, name, "vk")) {
|
||||
@@ -604,7 +579,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writeIdentifierFmt("{s}Flags{s}{s}", .{
|
||||
trimVkNamespace(bitflag_name.base_name),
|
||||
@as([]const u8, if (bitflag_name.revision) |revision| revision else ""),
|
||||
@as([]const u8, if (bitflag_name.tag) |tag| tag else ""),
|
||||
@as([]const u8, if (bitflag_name.tag) |tag| tag else "")
|
||||
});
|
||||
try self.writer.writeAll(".IntType");
|
||||
break :blk;
|
||||
@@ -735,6 +710,37 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writeIdentifierWithCase(.snake, try self.extractEnumFieldName(name, field_name));
|
||||
}
|
||||
|
||||
fn renderEnumerationValue(self: *Self, enum_name: []const u8, enumeration: reg.Enum, value: reg.Enum.Value) !void {
|
||||
var current_value = value;
|
||||
var maybe_alias_of: ?[]const u8 = null;
|
||||
|
||||
while (true) {
|
||||
switch (current_value) {
|
||||
.int => |int| try self.writer.print(" = {}, ", .{int}),
|
||||
.bitpos => |pos| try self.writer.print(" = 1 << {}, ", .{pos}),
|
||||
.bit_vector => |bv| try self.writer.print("= 0x{X}, ", .{bv}),
|
||||
.alias => |alias| {
|
||||
// Find the alias
|
||||
current_value = for (enumeration.fields) |field| {
|
||||
if (mem.eql(u8, field.name, alias.name)) {
|
||||
maybe_alias_of = field.name;
|
||||
break field.value;
|
||||
}
|
||||
} else return error.InvalidRegistry; // There is no alias
|
||||
continue;
|
||||
},
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (maybe_alias_of) |alias_of| {
|
||||
try self.writer.writeAll("// alias of ");
|
||||
try self.renderEnumFieldName(enum_name, alias_of);
|
||||
try self.writer.writeByte('\n');
|
||||
}
|
||||
}
|
||||
|
||||
fn renderEnumeration(self: *Self, name: []const u8, enumeration: reg.Enum) !void {
|
||||
if (enumeration.is_bitmask) {
|
||||
try self.renderBitmaskBits(name, enumeration);
|
||||
@@ -743,37 +749,17 @@ fn Renderer(comptime WriterType: type) type {
|
||||
|
||||
try self.writer.writeAll("pub const ");
|
||||
try self.renderName(name);
|
||||
try self.writer.writeAll(" = enum(c_int) {");
|
||||
try self.writer.writeAll(" = extern enum(i32) {");
|
||||
|
||||
for (enumeration.fields) |field| {
|
||||
if (field.value == .alias)
|
||||
if (field.value == .alias and field.value.alias.is_compat_alias)
|
||||
continue;
|
||||
|
||||
try self.renderEnumFieldName(name, field.name);
|
||||
switch (field.value) {
|
||||
.int => |int| try self.writer.print(" = {}, ", .{int}),
|
||||
.bitpos => |pos| try self.writer.print(" = 1 << {}, ", .{pos}),
|
||||
.bit_vector => |bv| try self.writer.print("= 0x{X}, ", .{bv}),
|
||||
.alias => unreachable,
|
||||
}
|
||||
try self.renderEnumerationValue(name, enumeration, field.value);
|
||||
}
|
||||
|
||||
try self.writer.writeAll("_,");
|
||||
|
||||
for (enumeration.fields) |field| {
|
||||
if (field.value != .alias or field.value.alias.is_compat_alias)
|
||||
continue;
|
||||
|
||||
try self.writer.writeAll("pub const ");
|
||||
try self.renderEnumFieldName(name, field.name);
|
||||
try self.writer.writeAll(" = ");
|
||||
try self.renderName(name);
|
||||
try self.writer.writeByte('.');
|
||||
try self.renderEnumFieldName(name, field.value.alias.name);
|
||||
try self.writer.writeAll(";\n");
|
||||
}
|
||||
|
||||
try self.writer.writeAll("};\n");
|
||||
try self.writer.writeAll("_,};\n");
|
||||
}
|
||||
|
||||
fn bitmaskFlagsType(bitwidth: u8) ![]const u8 {
|
||||
@@ -785,7 +771,12 @@ fn Renderer(comptime WriterType: type) type {
|
||||
}
|
||||
|
||||
fn renderUsingFlagsMixin(self: *Self, name: []const u8, bitwidth: u8) !void {
|
||||
const flags_type = try bitmaskFlagsType(bitwidth);
|
||||
const flags_type = switch (bitwidth) {
|
||||
32 => "Flags",
|
||||
64 => "Flags64",
|
||||
else => return error.InvalidRegistry,
|
||||
};
|
||||
|
||||
try self.writer.writeAll("pub usingnamespace FlagsMixin(");
|
||||
try self.renderName(name);
|
||||
try self.writer.print(", {s});\n", .{ flags_type });
|
||||
@@ -811,7 +802,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
|
||||
for (flags_by_bitpos[0.. bits.bitwidth]) |maybe_flag_name, bitpos| {
|
||||
if (maybe_flag_name) |flag_name| {
|
||||
const field_name = try extractBitflagFieldName(bitflag_name, flag_name);
|
||||
const field_name = try self.extractBitflagFieldName(bitflag_name, flag_name);
|
||||
try self.writeIdentifierWithCase(.snake, field_name);
|
||||
} else {
|
||||
try self.writer.print("_reserved_bit_{}", .{bitpos});
|
||||
@@ -819,7 +810,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
|
||||
try self.writer.writeAll(": bool ");
|
||||
if (bitpos == 0) { // Force alignment to integer boundaries
|
||||
try self.writer.print("align(@alignOf({s})) ", .{flags_type});
|
||||
try self.writer.writeAll("align(@alignOf(Flags)) ");
|
||||
}
|
||||
try self.writer.writeAll("= false, ");
|
||||
}
|
||||
@@ -842,13 +833,15 @@ fn Renderer(comptime WriterType: type) type {
|
||||
\\ = packed struct {{
|
||||
\\_reserved_bits: {s} = 0,
|
||||
\\pub usingnamespace FlagsMixin(
|
||||
, .{flags_type});
|
||||
, .{ flags_type }
|
||||
);
|
||||
try self.renderName(name);
|
||||
try self.writer.print(
|
||||
\\, {s});
|
||||
\\}};
|
||||
\\
|
||||
, .{flags_type});
|
||||
, .{ flags_type }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,7 +850,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
|
||||
try self.writer.writeAll("pub const ");
|
||||
try self.renderName(name);
|
||||
try self.writer.print(" = enum({s}) {{null_handle = 0, _}};\n", .{backing_type});
|
||||
try self.writer.print(" = extern enum({s}) {{null_handle = 0, _}};\n", .{backing_type});
|
||||
}
|
||||
|
||||
fn renderAlias(self: *Self, name: []const u8, alias: reg.Alias) !void {
|
||||
@@ -945,53 +938,25 @@ fn Renderer(comptime WriterType: type) type {
|
||||
}
|
||||
|
||||
fn renderWrappers(self: *Self) !void {
|
||||
try self.renderWrappersOfDispatchType(.base);
|
||||
try self.renderWrappersOfDispatchType(.instance);
|
||||
try self.renderWrappersOfDispatchType(.device);
|
||||
try self.renderWrappersOfDispatchType("BaseWrapper", .base);
|
||||
try self.renderWrappersOfDispatchType("InstanceWrapper", .instance);
|
||||
try self.renderWrappersOfDispatchType("DeviceWrapper", .device);
|
||||
}
|
||||
|
||||
fn renderWrappersOfDispatchType(self: *Self, dispatch_type: CommandDispatchType) !void {
|
||||
const name = switch (dispatch_type) {
|
||||
.base => "Base",
|
||||
.instance => "Instance",
|
||||
.device => "Device",
|
||||
};
|
||||
|
||||
fn renderWrappersOfDispatchType(self: *Self, name: []const u8, dispatch_type: CommandDispatchType) !void {
|
||||
try self.writer.print(
|
||||
\\pub fn {s}Wrapper(comptime cmds: anytype) type {{
|
||||
\\ comptime var fields: [cmds.len]std.builtin.TypeInfo.StructField = undefined;
|
||||
\\ inline for (cmds) |cmd, i| {{
|
||||
\\ const cmd_name = {s}CommandToString(cmd);
|
||||
\\ const cmd_type_name = "Pfn" ++ cmd_name;
|
||||
\\ const cmd_type = @field(GlobalScope, cmd_type_name);
|
||||
\\ fields[i] = .{{
|
||||
\\ .name = "vk" ++ cmd_name,
|
||||
\\ .field_type = cmd_type,
|
||||
\\ .default_value = null,
|
||||
\\ .is_comptime = false,
|
||||
\\ .alignment = @alignOf(*cmd_type),
|
||||
\\ }};
|
||||
\\ }}
|
||||
\\ const Dispatch = @Type(.{{
|
||||
\\ .Struct = .{{
|
||||
\\ .layout = .Auto,
|
||||
\\ .fields = &fields,
|
||||
\\ .decls = &[_]std.builtin.TypeInfo.Declaration{{}},
|
||||
\\ .is_tuple = false,
|
||||
\\ }},
|
||||
\\ }});
|
||||
\\pub fn {s}(comptime Self: type) type {{
|
||||
\\ return struct {{
|
||||
\\ dispatch: Dispatch,
|
||||
\\
|
||||
\\ const Self = @This();
|
||||
, .{ name, name });
|
||||
, .{name}
|
||||
);
|
||||
|
||||
try self.renderWrapperLoader(dispatch_type);
|
||||
|
||||
for (self.registry.decls) |decl| {
|
||||
if (decl.decl_type == .command) {
|
||||
const command = decl.decl_type.command;
|
||||
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
||||
if (self.classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
||||
try self.renderWrapper(decl.name, decl.decl_type.command);
|
||||
}
|
||||
}
|
||||
@@ -1018,15 +983,16 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writer.print(
|
||||
\\pub fn load({s}) !Self {{
|
||||
\\ var self: Self = undefined;
|
||||
\\ inline for (std.meta.fields(Dispatch)) |field| {{
|
||||
\\ inline for (std.meta.fields(Self)) |field| {{
|
||||
\\ const name = @ptrCast([*:0]const u8, field.name ++ "\x00");
|
||||
\\ const cmd_ptr = loader({s}name) orelse return error.CommandLoadFailure;
|
||||
\\ @field(self.dispatch, field.name) = @ptrCast(field.field_type, cmd_ptr);
|
||||
\\ const cmd_ptr = loader({s}name) orelse return error.InvalidCommand;
|
||||
\\ @field(self, field.name) = @ptrCast(field.field_type, cmd_ptr);
|
||||
\\ }}
|
||||
\\ return self;
|
||||
\\}}
|
||||
\\
|
||||
, .{ params, loader_first_param });
|
||||
, .{params, loader_first_param}
|
||||
);
|
||||
}
|
||||
|
||||
fn derefName(name: []const u8) []const u8 {
|
||||
@@ -1055,8 +1021,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
.bitflags, // Special stuff handled in renderWrapperCall
|
||||
.buffer_len,
|
||||
.mut_buffer_len,
|
||||
.other,
|
||||
=> {
|
||||
.other => {
|
||||
try self.writeIdentifierWithCase(.snake, param.name);
|
||||
try self.writer.writeAll(": ");
|
||||
try self.renderTypeInfo(param.param_type);
|
||||
@@ -1068,8 +1033,8 @@ fn Renderer(comptime WriterType: type) type {
|
||||
|
||||
try self.writer.writeAll(") ");
|
||||
|
||||
if (command.error_codes.len > 0) {
|
||||
try self.renderErrorSetName(name);
|
||||
if (command.return_type.* == .name and mem.eql(u8, command.return_type.name, "VkResult")) {
|
||||
try self.renderErrorSet(command.error_codes);
|
||||
try self.writer.writeByte('!');
|
||||
}
|
||||
|
||||
@@ -1083,7 +1048,7 @@ fn Renderer(comptime WriterType: type) type {
|
||||
}
|
||||
|
||||
fn renderWrapperCall(self: *Self, name: []const u8, command: reg.Command, returns: []const ReturnValue) !void {
|
||||
try self.writer.writeAll("self.dispatch.");
|
||||
try self.writer.writeAll("self.");
|
||||
try self.writeIdentifier(name);
|
||||
try self.writer.writeAll("(");
|
||||
|
||||
@@ -1104,7 +1069,10 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writeIdentifierWithCase(.snake, param.name);
|
||||
try self.writer.writeAll(".toInt()");
|
||||
},
|
||||
.in_out_pointer, .buffer_len, .mut_buffer_len, .other => {
|
||||
.in_out_pointer,
|
||||
.buffer_len,
|
||||
.mut_buffer_len,
|
||||
.other => {
|
||||
try self.writeIdentifierWithCase(.snake, param.name);
|
||||
},
|
||||
}
|
||||
@@ -1159,11 +1127,6 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writeIdentifierFmt("{s}Result", .{trimVkNamespace(command_name)});
|
||||
}
|
||||
|
||||
fn renderErrorSetName(self: *Self, name: []const u8) !void {
|
||||
try self.writeIdentifierWithCase(.title, trimVkNamespace(name));
|
||||
try self.writer.writeAll("Error");
|
||||
}
|
||||
|
||||
fn renderReturnStruct(self: *Self, command_name: []const u8, returns: []const ReturnValue) !void {
|
||||
try self.writer.writeAll("pub const ");
|
||||
try self.renderReturnStructName(command_name);
|
||||
@@ -1173,13 +1136,16 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writer.writeAll(": ");
|
||||
try self.renderTypeInfo(ret.return_value_type);
|
||||
try self.writer.writeAll(", ");
|
||||
|
||||
}
|
||||
try self.writer.writeAll("};\n");
|
||||
}
|
||||
|
||||
fn renderWrapper(self: *Self, name: []const u8, command: reg.Command) !void {
|
||||
const returns_vk_result = command.return_type.* == .name and mem.eql(u8, command.return_type.name, "VkResult");
|
||||
const returns_void = command.return_type.* == .name and mem.eql(u8, command.return_type.name, "void");
|
||||
const returns_vk_result = command.return_type.* == .name
|
||||
and mem.eql(u8, command.return_type.name, "VkResult");
|
||||
const returns_void = command.return_type.* == .name
|
||||
and mem.eql(u8, command.return_type.name, "void");
|
||||
|
||||
const returns = try self.extractReturns(command);
|
||||
|
||||
@@ -1187,14 +1153,6 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.renderReturnStruct(name, returns);
|
||||
}
|
||||
|
||||
if (command.error_codes.len > 0) {
|
||||
try self.writer.writeAll("pub const ");
|
||||
try self.renderErrorSetName(name);
|
||||
try self.writer.writeAll(" = ");
|
||||
try self.renderErrorSet(command.error_codes);
|
||||
try self.writer.writeAll(";\n");
|
||||
}
|
||||
|
||||
try self.renderWrapperPrototype(name, command, returns);
|
||||
|
||||
if (returns.len == 1 and returns[0].origin == .inner_return_value) {
|
||||
@@ -1264,13 +1222,13 @@ fn Renderer(comptime WriterType: type) type {
|
||||
try self.writer.writeAll(") {\n");
|
||||
|
||||
for (command.success_codes) |success| {
|
||||
try self.writer.writeAll("Result.");
|
||||
try self.writer.writeByte('.');
|
||||
try self.renderEnumFieldName("VkResult", success);
|
||||
try self.writer.writeAll(" => {},");
|
||||
}
|
||||
|
||||
for (command.error_codes) |err| {
|
||||
try self.writer.writeAll("Result.");
|
||||
try self.writer.writeByte('.');
|
||||
try self.renderEnumFieldName("VkResult", err);
|
||||
try self.writer.writeAll(" => return error.");
|
||||
try self.renderResultAsErrorName(err);
|
||||
|
||||
@@ -7,13 +7,13 @@ const ArrayList = std.ArrayList;
|
||||
|
||||
pub const Attribute = struct {
|
||||
name: []const u8,
|
||||
value: []const u8,
|
||||
value: []const u8
|
||||
};
|
||||
|
||||
pub const Content = union(enum) {
|
||||
CharData: []const u8,
|
||||
Comment: []const u8,
|
||||
Element: *Element,
|
||||
Element: *Element
|
||||
};
|
||||
|
||||
pub const Element = struct {
|
||||
@@ -50,7 +50,7 @@ pub const Element = struct {
|
||||
|
||||
return switch (child.children.items[0]) {
|
||||
.CharData => |char_data| char_data,
|
||||
else => null,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ pub const Element = struct {
|
||||
pub fn findChildrenByTag(self: *Element, tag: []const u8) FindChildrenByTagIterator {
|
||||
return .{
|
||||
.inner = self.elements(),
|
||||
.tag = tag,
|
||||
.tag = tag
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ pub const Element = struct {
|
||||
pub const XmlDecl = struct {
|
||||
version: []const u8,
|
||||
encoding: ?[]const u8,
|
||||
standalone: ?bool,
|
||||
standalone: ?bool
|
||||
};
|
||||
|
||||
pub const Document = struct {
|
||||
@@ -154,7 +154,7 @@ const ParseContext = struct {
|
||||
.source = source,
|
||||
.offset = 0,
|
||||
.line = 0,
|
||||
.column = 0,
|
||||
.column = 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ const ParseContext = struct {
|
||||
ws = true;
|
||||
_ = self.consumeNoEof();
|
||||
},
|
||||
else => break,
|
||||
else => break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,46 +257,46 @@ const ParseContext = struct {
|
||||
test "ParseContext" {
|
||||
{
|
||||
var ctx = ParseContext.init("I like pythons");
|
||||
try testing.expectEqual(@as(?u8, 'I'), ctx.peek());
|
||||
try testing.expectEqual(@as(u8, 'I'), ctx.consumeNoEof());
|
||||
try testing.expectEqual(@as(?u8, ' '), ctx.peek());
|
||||
try testing.expectEqual(@as(u8, ' '), try ctx.consume());
|
||||
testing.expectEqual(@as(?u8, 'I'), ctx.peek());
|
||||
testing.expectEqual(@as(u8, 'I'), ctx.consumeNoEof());
|
||||
testing.expectEqual(@as(?u8, ' '), ctx.peek());
|
||||
testing.expectEqual(@as(u8, ' '), try ctx.consume());
|
||||
|
||||
try testing.expect(ctx.eat('l'));
|
||||
try testing.expectEqual(@as(?u8, 'i'), ctx.peek());
|
||||
try testing.expectEqual(false, ctx.eat('a'));
|
||||
try testing.expectEqual(@as(?u8, 'i'), ctx.peek());
|
||||
testing.expect(ctx.eat('l'));
|
||||
testing.expectEqual(@as(?u8, 'i'), ctx.peek());
|
||||
testing.expectEqual(false, ctx.eat('a'));
|
||||
testing.expectEqual(@as(?u8, 'i'), ctx.peek());
|
||||
|
||||
try ctx.expect('i');
|
||||
try testing.expectEqual(@as(?u8, 'k'), ctx.peek());
|
||||
try testing.expectError(error.UnexpectedCharacter, ctx.expect('a'));
|
||||
try testing.expectEqual(@as(?u8, 'k'), ctx.peek());
|
||||
testing.expectEqual(@as(?u8, 'k'), ctx.peek());
|
||||
testing.expectError(error.UnexpectedCharacter, ctx.expect('a'));
|
||||
testing.expectEqual(@as(?u8, 'k'), ctx.peek());
|
||||
|
||||
try testing.expect(ctx.eatStr("ke"));
|
||||
try testing.expectEqual(@as(?u8, ' '), ctx.peek());
|
||||
testing.expect(ctx.eatStr("ke"));
|
||||
testing.expectEqual(@as(?u8, ' '), ctx.peek());
|
||||
|
||||
try testing.expect(ctx.eatWs());
|
||||
try testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
try testing.expectEqual(false, ctx.eatWs());
|
||||
try testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
testing.expect(ctx.eatWs());
|
||||
testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
testing.expectEqual(false, ctx.eatWs());
|
||||
testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
|
||||
try testing.expectEqual(false, ctx.eatStr("aaaaaaaaa"));
|
||||
try testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
testing.expectEqual(false, ctx.eatStr("aaaaaaaaa"));
|
||||
testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
|
||||
try testing.expectError(error.UnexpectedEof, ctx.expectStr("aaaaaaaaa"));
|
||||
try testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
try testing.expectError(error.UnexpectedCharacter, ctx.expectStr("pytn"));
|
||||
try testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
testing.expectError(error.UnexpectedEof, ctx.expectStr("aaaaaaaaa"));
|
||||
testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
testing.expectError(error.UnexpectedCharacter, ctx.expectStr("pytn"));
|
||||
testing.expectEqual(@as(?u8, 'p'), ctx.peek());
|
||||
try ctx.expectStr("python");
|
||||
try testing.expectEqual(@as(?u8, 's'), ctx.peek());
|
||||
testing.expectEqual(@as(?u8, 's'), ctx.peek());
|
||||
}
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("");
|
||||
try testing.expectEqual(ctx.peek(), null);
|
||||
try testing.expectError(error.UnexpectedEof, ctx.consume());
|
||||
try testing.expectEqual(ctx.eat('p'), false);
|
||||
try testing.expectError(error.UnexpectedEof, ctx.expect('p'));
|
||||
testing.expectEqual(ctx.peek(), null);
|
||||
testing.expectError(error.UnexpectedEof, ctx.consume());
|
||||
testing.expectEqual(ctx.eat('p'), false);
|
||||
testing.expectError(error.UnexpectedEof, ctx.expect('p'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ pub const ParseError = error{
|
||||
InvalidStandaloneValue,
|
||||
NonMatchingClosingTag,
|
||||
InvalidDocument,
|
||||
OutOfMemory,
|
||||
OutOfMemory
|
||||
};
|
||||
|
||||
pub fn parse(backing_allocator: *Allocator, source: []const u8) !Document {
|
||||
@@ -323,7 +323,7 @@ fn parseDocument(ctx: *ParseContext, backing_allocator: *Allocator) !Document {
|
||||
var doc = Document{
|
||||
.arena = ArenaAllocator.init(backing_allocator),
|
||||
.xml_decl = null,
|
||||
.root = undefined,
|
||||
.root = undefined
|
||||
};
|
||||
|
||||
errdefer doc.deinit();
|
||||
@@ -376,7 +376,7 @@ fn parseNameNoDupe(ctx: *ParseContext) ![]const u8 {
|
||||
switch (ch) {
|
||||
' ', '\t', '\n', '\r' => break,
|
||||
'&', '"', '\'', '<', '>', '?', '=', '/' => break,
|
||||
else => _ = ctx.consumeNoEof(),
|
||||
else => _ = ctx.consumeNoEof()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ fn tryParseCharData(ctx: *ParseContext, alloc: *Allocator) !?[]const u8 {
|
||||
while (ctx.peek()) |ch| {
|
||||
switch (ch) {
|
||||
'<' => break,
|
||||
else => _ = ctx.consumeNoEof(),
|
||||
else => _ = ctx.consumeNoEof()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,41 +477,41 @@ test "tryParseElement" {
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("<= a='b'/>");
|
||||
try testing.expectEqual(@as(?*Element, null), try tryParseElement(&ctx, alloc));
|
||||
try testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
||||
testing.expectEqual(@as(?*Element, null), try tryParseElement(&ctx, alloc));
|
||||
testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
||||
}
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("<python size='15' color = \"green\"/>");
|
||||
const elem = try tryParseElement(&ctx, alloc);
|
||||
try testing.expectEqualSlices(u8, elem.?.tag, "python");
|
||||
testing.expectEqualSlices(u8, elem.?.tag, "python");
|
||||
|
||||
const size_attr = elem.?.attributes.items[0];
|
||||
try testing.expectEqualSlices(u8, size_attr.name, "size");
|
||||
try testing.expectEqualSlices(u8, size_attr.value, "15");
|
||||
testing.expectEqualSlices(u8, size_attr.name, "size");
|
||||
testing.expectEqualSlices(u8, size_attr.value, "15");
|
||||
|
||||
const color_attr = elem.?.attributes.items[1];
|
||||
try testing.expectEqualSlices(u8, color_attr.name, "color");
|
||||
try testing.expectEqualSlices(u8, color_attr.value, "green");
|
||||
testing.expectEqualSlices(u8, color_attr.name, "color");
|
||||
testing.expectEqualSlices(u8, color_attr.value, "green");
|
||||
}
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("<python>test</python>");
|
||||
const elem = try tryParseElement(&ctx, alloc);
|
||||
try testing.expectEqualSlices(u8, elem.?.tag, "python");
|
||||
try testing.expectEqualSlices(u8, elem.?.children.items[0].CharData, "test");
|
||||
testing.expectEqualSlices(u8, elem.?.tag, "python");
|
||||
testing.expectEqualSlices(u8, elem.?.children.items[0].CharData, "test");
|
||||
}
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("<a>b<c/>d<e/>f<!--g--></a>");
|
||||
const elem = try tryParseElement(&ctx, alloc);
|
||||
try testing.expectEqualSlices(u8, elem.?.tag, "a");
|
||||
try testing.expectEqualSlices(u8, elem.?.children.items[0].CharData, "b");
|
||||
try testing.expectEqualSlices(u8, elem.?.children.items[1].Element.tag, "c");
|
||||
try testing.expectEqualSlices(u8, elem.?.children.items[2].CharData, "d");
|
||||
try testing.expectEqualSlices(u8, elem.?.children.items[3].Element.tag, "e");
|
||||
try testing.expectEqualSlices(u8, elem.?.children.items[4].CharData, "f");
|
||||
try testing.expectEqualSlices(u8, elem.?.children.items[5].Comment, "g");
|
||||
testing.expectEqualSlices(u8, elem.?.tag, "a");
|
||||
testing.expectEqualSlices(u8, elem.?.children.items[0].CharData, "b");
|
||||
testing.expectEqualSlices(u8, elem.?.children.items[1].Element.tag, "c");
|
||||
testing.expectEqualSlices(u8, elem.?.children.items[2].CharData, "d");
|
||||
testing.expectEqualSlices(u8, elem.?.children.items[3].Element.tag, "e");
|
||||
testing.expectEqualSlices(u8, elem.?.children.items[4].CharData, "f");
|
||||
testing.expectEqualSlices(u8, elem.?.children.items[5].Comment, "g");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,24 +565,24 @@ test "tryParseProlog" {
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("<?xmla version='aa'?>");
|
||||
try testing.expectEqual(@as(?*XmlDecl, null), try tryParseProlog(&ctx, alloc));
|
||||
try testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
||||
testing.expectEqual(@as(?*XmlDecl, null), try tryParseProlog(&ctx, alloc));
|
||||
testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
||||
}
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("<?xml version='aa'?>");
|
||||
const decl = try tryParseProlog(&ctx, alloc);
|
||||
try testing.expectEqualSlices(u8, "aa", decl.?.version);
|
||||
try testing.expectEqual(@as(?[]const u8, null), decl.?.encoding);
|
||||
try testing.expectEqual(@as(?bool, null), decl.?.standalone);
|
||||
testing.expectEqualSlices(u8, "aa", decl.?.version);
|
||||
testing.expectEqual(@as(?[]const u8, null), decl.?.encoding);
|
||||
testing.expectEqual(@as(?bool, null), decl.?.standalone);
|
||||
}
|
||||
|
||||
{
|
||||
var ctx = ParseContext.init("<?xml version=\"aa\" encoding = 'bbb' standalone \t = 'yes'?>");
|
||||
const decl = try tryParseProlog(&ctx, alloc);
|
||||
try testing.expectEqualSlices(u8, "aa", decl.?.version);
|
||||
try testing.expectEqualSlices(u8, "bbb", decl.?.encoding.?);
|
||||
try testing.expectEqual(@as(?bool, true), decl.?.standalone.?);
|
||||
testing.expectEqualSlices(u8, "aa", decl.?.version);
|
||||
testing.expectEqualSlices(u8, "bbb", decl.?.encoding.?);
|
||||
testing.expectEqual(@as(?bool, true), decl.?.standalone.?);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,14 +605,17 @@ fn tryParseComment(ctx: *ParseContext, alloc: *Allocator) !?[]const u8 {
|
||||
}
|
||||
|
||||
fn unescapeEntity(text: []const u8) !u8 {
|
||||
const EntitySubstition = struct { text: []const u8, replacement: u8 };
|
||||
const EntitySubstition = struct {
|
||||
text: []const u8,
|
||||
replacement: u8
|
||||
};
|
||||
|
||||
const entities = [_]EntitySubstition{
|
||||
.{.text = "<", .replacement = '<'},
|
||||
.{.text = ">", .replacement = '>'},
|
||||
.{.text = "&", .replacement = '&'},
|
||||
.{.text = "'", .replacement = '\''},
|
||||
.{ .text = """, .replacement = '"' },
|
||||
.{.text = """, .replacement = '"'}
|
||||
};
|
||||
|
||||
for (entities) |entity| {
|
||||
@@ -646,12 +649,12 @@ test "dupeAndUnescape" {
|
||||
defer arena.deinit();
|
||||
var alloc = &arena.allocator;
|
||||
|
||||
try testing.expectEqualSlices(u8, "test", try dupeAndUnescape(alloc, "test"));
|
||||
try testing.expectEqualSlices(u8, "a<b&c>d\"e'f<", try dupeAndUnescape(alloc, "a<b&c>d"e'f<"));
|
||||
try testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&"));
|
||||
try testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&&"));
|
||||
try testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&test;"));
|
||||
try testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&boa"));
|
||||
testing.expectEqualSlices(u8, "test", try dupeAndUnescape(alloc, "test"));
|
||||
testing.expectEqualSlices(u8, "a<b&c>d\"e'f<", try dupeAndUnescape(alloc, "a<b&c>d"e'f<"));
|
||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&"));
|
||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&&"));
|
||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&test;"));
|
||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&boa"));
|
||||
}
|
||||
|
||||
test "Top level comments" {
|
||||
@@ -660,5 +663,5 @@ test "Top level comments" {
|
||||
var alloc = &arena.allocator;
|
||||
|
||||
const doc = try parse(alloc, "<?xml version='aa'?><!--comment--><python color='green'/><!--another comment-->");
|
||||
try testing.expectEqualSlices(u8, "python", doc.root.tag);
|
||||
testing.expectEqualSlices(u8, "python", doc.root.tag);
|
||||
}
|
||||
Reference in New Issue
Block a user