forked from mirror/vulkan-zig
Compare commits
24 Commits
zig-0.13-c
...
zig-0.8.1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d87813312e | ||
|
|
e17c3593d1 | ||
|
|
9513d33bf8 | ||
|
|
59c5b88d17 | ||
|
|
4588c0fcad | ||
|
|
f55409f98a | ||
|
|
cbf06a8d42 | ||
|
|
c5bb254766 | ||
|
|
5980bac303 | ||
|
|
3bfacc7e16 | ||
|
|
1e594c0f09 | ||
|
|
397e663296 | ||
|
|
933010cfff | ||
|
|
0eccd593ce | ||
|
|
6a2c379146 | ||
|
|
4429151d9c | ||
|
|
77651872ab | ||
|
|
5a51d18bda | ||
|
|
6feeeac109 | ||
|
|
8f10cec149 | ||
|
|
0e65efd9d6 | ||
|
|
b3c71d69ea | ||
|
|
b63533d95b | ||
|
|
419e541a16 |
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@@ -2,9 +2,9 @@ name: Build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ zig-0.8.1-compat ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ zig-0.8.1-compat ]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 6 * * *'
|
- cron: '0 6 * * *'
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ jobs:
|
|||||||
- name: Setup Zig
|
- name: Setup Zig
|
||||||
uses: goto-bus-stop/setup-zig@v1.3.0
|
uses: goto-bus-stop/setup-zig@v1.3.0
|
||||||
with:
|
with:
|
||||||
version: master
|
version: 0.8.0
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: |
|
||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- name: Fetch Vulkan SDK
|
- name: Fetch Vulkan SDK
|
||||||
run: |
|
run: |
|
||||||
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
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.189-focal.list https://packages.lunarg.com/vulkan/1.2.189/lunarg-vulkan-1.2.189-focal.list
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install shaderc libglfw3 libglfw3-dev
|
sudo apt install shaderc libglfw3 libglfw3-dev
|
||||||
|
|
||||||
@@ -38,3 +38,9 @@ jobs:
|
|||||||
- name: Build with latest zig & vk.xml
|
- name: Build with latest zig & vk.xml
|
||||||
run: |
|
run: |
|
||||||
zig build -Dvulkan-registry=./vk.xml
|
zig build -Dvulkan-registry=./vk.xml
|
||||||
|
|
||||||
|
- name: Archive vk.xml
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: vk.zig
|
||||||
|
path: zig-cache/vk.zig
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -36,10 +36,10 @@ pub fn build(b: *Builder) void {
|
|||||||
exe.step.dependOn(&gen.step);
|
exe.step.dependOn(&gen.step);
|
||||||
|
|
||||||
// Add the generated file as package to the final executable
|
// Add the generated file as package to the final executable
|
||||||
exe.addPackagePath("vulkan", gen.full_out_path);
|
exe.addPackage(gen.package);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
This reads vk.xml, parses its contents, and renders the Vulkan bindings to "vk.zig", which is then formatted and placed in `zig-cache`. The resulting file can then be added to an executable by using `addPackagePath`.
|
This reads vk.xml, parses its contents, and renders the Vulkan bindings to "vk.zig", which is then formatted and placed in `zig-cache`. The resulting file can then be added to an executable by using `addPackage`, after which the bindings will be made available to the executable under the name `vulkan`.
|
||||||
|
|
||||||
### Function & field renaming
|
### Function & field renaming
|
||||||
Functions and fields are renamed to be more or less in line with [Zig's standard library style](https://ziglang.org/documentation/master/#Style-Guide):
|
Functions and fields are renamed to be more or less in line with [Zig's standard library style](https://ziglang.org/documentation/master/#Style-Guide):
|
||||||
@@ -67,23 +67,22 @@ For each function, a wrapper is generated into one of three structs:
|
|||||||
* InstanceWrapper. This contains wrappers for functions which are otherwise loaded by `vkGetInstanceProcAddr`.
|
* InstanceWrapper. This contains wrappers for functions which are otherwise loaded by `vkGetInstanceProcAddr`.
|
||||||
* DeviceWrapper. This contains wrappers for functions which are loaded by `vkGetDeviceProcAddr`.
|
* DeviceWrapper. This contains wrappers for functions which are loaded by `vkGetDeviceProcAddr`.
|
||||||
|
|
||||||
Each wrapper struct is to be used as a mixin on a struct containing **just** function pointers as members:
|
Each wrapper struct can be called with an array of the appropriate enums:
|
||||||
```zig
|
```zig
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
const BaseDispatch = struct {
|
const BaseDispatch = vk.BaseWrapper(.{
|
||||||
vkCreateInstance: vk.PfnCreateInstance,
|
.CreateInstance,
|
||||||
usingnamespace vk.BaseWrapper(@This());
|
});
|
||||||
};
|
|
||||||
```
|
```
|
||||||
The wrapper struct then provides wrapper functions for each function pointer in the dispatch struct:
|
The wrapper struct then provides wrapper functions for each function pointer in the dispatch struct:
|
||||||
```zig
|
```zig
|
||||||
pub const BaseWrapper(comptime Self: type) type {
|
pub const BaseWrapper(comptime cmds: anytype) type {
|
||||||
|
...
|
||||||
|
const Dispatch = CreateDispatchStruct(cmds);
|
||||||
return struct {
|
return struct {
|
||||||
pub fn createInstance(
|
dispatch: Dispatch,
|
||||||
self: Self,
|
|
||||||
create_info: InstanceCreateInfo,
|
pub const CreateInstanceError = error{
|
||||||
p_allocator: ?*const AllocationCallbacks,
|
|
||||||
) error{
|
|
||||||
OutOfHostMemory,
|
OutOfHostMemory,
|
||||||
OutOfDeviceMemory,
|
OutOfDeviceMemory,
|
||||||
InitializationFailed,
|
InitializationFailed,
|
||||||
@@ -91,9 +90,14 @@ pub const BaseWrapper(comptime Self: type) type {
|
|||||||
ExtensionNotPresent,
|
ExtensionNotPresent,
|
||||||
IncompatibleDriver,
|
IncompatibleDriver,
|
||||||
Unknown,
|
Unknown,
|
||||||
}!Instance {
|
};
|
||||||
|
pub fn createInstance(
|
||||||
|
self: Self,
|
||||||
|
create_info: InstanceCreateInfo,
|
||||||
|
p_allocator: ?*const AllocationCallbacks,
|
||||||
|
) CreateInstanceError!Instance {
|
||||||
var instance: Instance = undefined;
|
var instance: Instance = undefined;
|
||||||
const result = self.vkCreateInstance(
|
const result = self.dispatch.vkCreateInstance(
|
||||||
&create_info,
|
&create_info,
|
||||||
p_allocator,
|
p_allocator,
|
||||||
&instance,
|
&instance,
|
||||||
@@ -125,9 +129,11 @@ 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.
|
* 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.
|
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: PfnGetInstanceProcAddr) !Self`.
|
* 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: PfnGetInstanceProcAddr) !Self`.
|
* 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: PfnGetDeviceProcAddr) !Self`.
|
* 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(..)`.
|
||||||
|
|
||||||
### Bitflags
|
### 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.
|
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.
|
||||||
@@ -225,7 +231,7 @@ pub fn build(b: *Builder) void {
|
|||||||
|
|
||||||
const gen = vkgen.VkGenerateStep(b, "path/to/vk.xml", "vk.zig");
|
const gen = vkgen.VkGenerateStep(b, "path/to/vk.xml", "vk.zig");
|
||||||
exe.step.dependOn(&gen.step);
|
exe.step.dependOn(&gen.step);
|
||||||
exe.addPackagePath("vulkan", gen.full_out_path);
|
exe.addPackage(gen.package);
|
||||||
|
|
||||||
const shader_comp = vkgen.ShaderCompileStep.init(
|
const shader_comp = vkgen.ShaderCompileStep.init(
|
||||||
builder,
|
builder,
|
||||||
@@ -246,5 +252,7 @@ Upon compilation, glslc is then invoked to compile each shader, and the result i
|
|||||||
A partial implementation of https://vulkan-tutorial.org is implemented in [examples/triangle.zig](examples/triangle.zig). This example can be ran by executing `zig build run-triangle` in vulkan-zig's root.
|
A partial implementation of https://vulkan-tutorial.org is implemented in [examples/triangle.zig](examples/triangle.zig). This example can be ran by executing `zig build run-triangle` in vulkan-zig's root.
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
* Implementation of https://vulkan-tutorial.org: https://github.com/andrewrk/zig-vulkan-triangle.
|
* Implementation of https://vulkan-tutorial.org using `@cImport`'ed bindings: https://github.com/andrewrk/zig-vulkan-triangle.
|
||||||
* Alternative binding generator: https://github.com/SpexGuy/Zig-Vulkan-Headers
|
* Alternative binding generator: https://github.com/SpexGuy/Zig-Vulkan-Headers
|
||||||
|
* Zig bindings for GLFW: https://github.com/hexops/mach-glfw
|
||||||
|
* With vulkan-zig integration example: https://github.com/hexops/mach-glfw-vulkan-example
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ pub const ResourceGenStep = struct {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderPath(self: *ResourceGenStep, path: []const u8, writer: anytype) void {
|
fn renderPath(path: []const u8, writer: anytype) void {
|
||||||
const separators = &[_]u8{ std.fs.path.sep_windows, std.fs.path.sep_posix };
|
const separators = &[_]u8{ std.fs.path.sep_windows, std.fs.path.sep_posix };
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (std.mem.indexOfAnyPos(u8, path, i, separators)) |j| {
|
while (std.mem.indexOfAnyPos(u8, path, i, separators)) |j| {
|
||||||
@@ -42,7 +42,7 @@ pub const ResourceGenStep = struct {
|
|||||||
switch (std.fs.path.sep) {
|
switch (std.fs.path.sep) {
|
||||||
std.fs.path.sep_windows => writer.writeAll("\\\\") catch unreachable,
|
std.fs.path.sep_windows => writer.writeAll("\\\\") catch unreachable,
|
||||||
std.fs.path.sep_posix => writer.writeByte(std.fs.path.sep_posix) catch unreachable,
|
std.fs.path.sep_posix => writer.writeByte(std.fs.path.sep_posix) catch unreachable,
|
||||||
else => unreachable
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
i = j + 1;
|
i = j + 1;
|
||||||
@@ -55,7 +55,7 @@ pub const ResourceGenStep = struct {
|
|||||||
var writer = self.resources.writer();
|
var writer = self.resources.writer();
|
||||||
|
|
||||||
writer.print("pub const {s} = @embedFile(\"", .{name}) catch unreachable;
|
writer.print("pub const {s} = @embedFile(\"", .{name}) catch unreachable;
|
||||||
self.renderPath(shader_out_path, writer);
|
renderPath(shader_out_path, writer);
|
||||||
writer.writeAll("\");\n") catch unreachable;
|
writer.writeAll("\");\n") catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,85 +3,80 @@ const vk = @import("vulkan");
|
|||||||
const c = @import("c.zig");
|
const c = @import("c.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const required_device_extensions = [_][]const u8{
|
const required_device_extensions = [_][]const u8{vk.extension_info.khr_swapchain.name};
|
||||||
vk.extension_info.khr_swapchain.name
|
|
||||||
};
|
|
||||||
|
|
||||||
const BaseDispatch = struct {
|
const BaseDispatch = vk.BaseWrapper(&.{
|
||||||
vkCreateInstance: vk.PfnCreateInstance,
|
.createInstance,
|
||||||
usingnamespace vk.BaseWrapper(@This());
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const InstanceDispatch = struct {
|
const InstanceDispatch = vk.InstanceWrapper(&.{
|
||||||
vkDestroyInstance: vk.PfnDestroyInstance,
|
.destroyInstance,
|
||||||
vkCreateDevice: vk.PfnCreateDevice,
|
.createDevice,
|
||||||
vkDestroySurfaceKHR: vk.PfnDestroySurfaceKHR,
|
.destroySurfaceKHR,
|
||||||
vkEnumeratePhysicalDevices: vk.PfnEnumeratePhysicalDevices,
|
.enumeratePhysicalDevices,
|
||||||
vkGetPhysicalDeviceProperties: vk.PfnGetPhysicalDeviceProperties,
|
.getPhysicalDeviceProperties,
|
||||||
vkEnumerateDeviceExtensionProperties: vk.PfnEnumerateDeviceExtensionProperties,
|
.enumerateDeviceExtensionProperties,
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR: vk.PfnGetPhysicalDeviceSurfaceFormatsKHR,
|
.getPhysicalDeviceSurfaceFormatsKHR,
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR: vk.PfnGetPhysicalDeviceSurfacePresentModesKHR,
|
.getPhysicalDeviceSurfacePresentModesKHR,
|
||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR: vk.PfnGetPhysicalDeviceSurfaceCapabilitiesKHR,
|
.getPhysicalDeviceSurfaceCapabilitiesKHR,
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties: vk.PfnGetPhysicalDeviceQueueFamilyProperties,
|
.getPhysicalDeviceQueueFamilyProperties,
|
||||||
vkGetPhysicalDeviceSurfaceSupportKHR: vk.PfnGetPhysicalDeviceSurfaceSupportKHR,
|
.getPhysicalDeviceSurfaceSupportKHR,
|
||||||
vkGetPhysicalDeviceMemoryProperties: vk.PfnGetPhysicalDeviceMemoryProperties,
|
.getPhysicalDeviceMemoryProperties,
|
||||||
vkGetDeviceProcAddr: vk.PfnGetDeviceProcAddr,
|
.getDeviceProcAddr,
|
||||||
usingnamespace vk.InstanceWrapper(@This());
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const DeviceDispatch = struct {
|
const DeviceDispatch = vk.DeviceWrapper(&.{
|
||||||
vkDestroyDevice: vk.PfnDestroyDevice,
|
.destroyDevice,
|
||||||
vkGetDeviceQueue: vk.PfnGetDeviceQueue,
|
.getDeviceQueue,
|
||||||
vkCreateSemaphore: vk.PfnCreateSemaphore,
|
.createSemaphore,
|
||||||
vkCreateFence: vk.PfnCreateFence,
|
.createFence,
|
||||||
vkCreateImageView: vk.PfnCreateImageView,
|
.createImageView,
|
||||||
vkDestroyImageView: vk.PfnDestroyImageView,
|
.destroyImageView,
|
||||||
vkDestroySemaphore: vk.PfnDestroySemaphore,
|
.destroySemaphore,
|
||||||
vkDestroyFence: vk.PfnDestroyFence,
|
.destroyFence,
|
||||||
vkGetSwapchainImagesKHR: vk.PfnGetSwapchainImagesKHR,
|
.getSwapchainImagesKHR,
|
||||||
vkCreateSwapchainKHR: vk.PfnCreateSwapchainKHR,
|
.createSwapchainKHR,
|
||||||
vkDestroySwapchainKHR: vk.PfnDestroySwapchainKHR,
|
.destroySwapchainKHR,
|
||||||
vkAcquireNextImageKHR: vk.PfnAcquireNextImageKHR,
|
.acquireNextImageKHR,
|
||||||
vkDeviceWaitIdle: vk.PfnDeviceWaitIdle,
|
.deviceWaitIdle,
|
||||||
vkWaitForFences: vk.PfnWaitForFences,
|
.waitForFences,
|
||||||
vkResetFences: vk.PfnResetFences,
|
.resetFences,
|
||||||
vkQueueSubmit: vk.PfnQueueSubmit,
|
.queueSubmit,
|
||||||
vkQueuePresentKHR: vk.PfnQueuePresentKHR,
|
.queuePresentKHR,
|
||||||
vkCreateCommandPool: vk.PfnCreateCommandPool,
|
.createCommandPool,
|
||||||
vkDestroyCommandPool: vk.PfnDestroyCommandPool,
|
.destroyCommandPool,
|
||||||
vkAllocateCommandBuffers: vk.PfnAllocateCommandBuffers,
|
.allocateCommandBuffers,
|
||||||
vkFreeCommandBuffers: vk.PfnFreeCommandBuffers,
|
.freeCommandBuffers,
|
||||||
vkQueueWaitIdle: vk.PfnQueueWaitIdle,
|
.queueWaitIdle,
|
||||||
vkCreateShaderModule: vk.PfnCreateShaderModule,
|
.createShaderModule,
|
||||||
vkDestroyShaderModule: vk.PfnDestroyShaderModule,
|
.destroyShaderModule,
|
||||||
vkCreatePipelineLayout: vk.PfnCreatePipelineLayout,
|
.createPipelineLayout,
|
||||||
vkDestroyPipelineLayout: vk.PfnDestroyPipelineLayout,
|
.destroyPipelineLayout,
|
||||||
vkCreateRenderPass: vk.PfnCreateRenderPass,
|
.createRenderPass,
|
||||||
vkDestroyRenderPass: vk.PfnDestroyRenderPass,
|
.destroyRenderPass,
|
||||||
vkCreateGraphicsPipelines: vk.PfnCreateGraphicsPipelines,
|
.createGraphicsPipelines,
|
||||||
vkDestroyPipeline: vk.PfnDestroyPipeline,
|
.destroyPipeline,
|
||||||
vkCreateFramebuffer: vk.PfnCreateFramebuffer,
|
.createFramebuffer,
|
||||||
vkDestroyFramebuffer: vk.PfnDestroyFramebuffer,
|
.destroyFramebuffer,
|
||||||
vkBeginCommandBuffer: vk.PfnBeginCommandBuffer,
|
.beginCommandBuffer,
|
||||||
vkEndCommandBuffer: vk.PfnEndCommandBuffer,
|
.endCommandBuffer,
|
||||||
vkAllocateMemory: vk.PfnAllocateMemory,
|
.allocateMemory,
|
||||||
vkFreeMemory: vk.PfnFreeMemory,
|
.freeMemory,
|
||||||
vkCreateBuffer: vk.PfnCreateBuffer,
|
.createBuffer,
|
||||||
vkDestroyBuffer: vk.PfnDestroyBuffer,
|
.destroyBuffer,
|
||||||
vkGetBufferMemoryRequirements: vk.PfnGetBufferMemoryRequirements,
|
.getBufferMemoryRequirements,
|
||||||
vkMapMemory: vk.PfnMapMemory,
|
.mapMemory,
|
||||||
vkUnmapMemory: vk.PfnUnmapMemory,
|
.unmapMemory,
|
||||||
vkBindBufferMemory: vk.PfnBindBufferMemory,
|
.bindBufferMemory,
|
||||||
vkCmdBeginRenderPass: vk.PfnCmdBeginRenderPass,
|
.cmdBeginRenderPass,
|
||||||
vkCmdEndRenderPass: vk.PfnCmdEndRenderPass,
|
.cmdEndRenderPass,
|
||||||
vkCmdBindPipeline: vk.PfnCmdBindPipeline,
|
.cmdBindPipeline,
|
||||||
vkCmdDraw: vk.PfnCmdDraw,
|
.cmdDraw,
|
||||||
vkCmdSetViewport: vk.PfnCmdSetViewport,
|
.cmdSetViewport,
|
||||||
vkCmdSetScissor: vk.PfnCmdSetScissor,
|
.cmdSetScissor,
|
||||||
vkCmdBindVertexBuffers: vk.PfnCmdBindVertexBuffers,
|
.cmdBindVertexBuffers,
|
||||||
vkCmdCopyBuffer: vk.PfnCmdCopyBuffer,
|
.cmdCopyBuffer,
|
||||||
usingnamespace vk.DeviceWrapper(@This());
|
});
|
||||||
};
|
|
||||||
|
|
||||||
pub const GraphicsContext = struct {
|
pub const GraphicsContext = struct {
|
||||||
vkb: BaseDispatch,
|
vkb: BaseDispatch,
|
||||||
@@ -125,14 +120,14 @@ pub const GraphicsContext = struct {
|
|||||||
self.vki = try InstanceDispatch.load(self.instance, c.glfwGetInstanceProcAddress);
|
self.vki = try InstanceDispatch.load(self.instance, c.glfwGetInstanceProcAddress);
|
||||||
errdefer self.vki.destroyInstance(self.instance, null);
|
errdefer self.vki.destroyInstance(self.instance, null);
|
||||||
|
|
||||||
self.surface = try createSurface(self.vki, self.instance, window);
|
self.surface = try createSurface(self.instance, window);
|
||||||
errdefer self.vki.destroySurfaceKHR(self.instance, self.surface, null);
|
errdefer self.vki.destroySurfaceKHR(self.instance, self.surface, null);
|
||||||
|
|
||||||
const candidate = try pickPhysicalDevice(self.vki, self.instance, allocator, self.surface);
|
const candidate = try pickPhysicalDevice(self.vki, self.instance, allocator, self.surface);
|
||||||
self.pdev = candidate.pdev;
|
self.pdev = candidate.pdev;
|
||||||
self.props = candidate.props;
|
self.props = candidate.props;
|
||||||
self.dev = try initializeCandidate(self.vki, candidate);
|
self.dev = try initializeCandidate(self.vki, candidate);
|
||||||
self.vkd = try DeviceDispatch.load(self.dev, self.vki.vkGetDeviceProcAddr);
|
self.vkd = try DeviceDispatch.load(self.dev, self.vki.dispatch.vkGetDeviceProcAddr);
|
||||||
errdefer self.vkd.destroyDevice(self.dev, null);
|
errdefer self.vkd.destroyDevice(self.dev, null);
|
||||||
|
|
||||||
self.graphics_queue = Queue.init(self.vkd, self.dev, candidate.queues.graphics_family);
|
self.graphics_queue = Queue.init(self.vkd, self.dev, candidate.queues.graphics_family);
|
||||||
@@ -184,7 +179,7 @@ pub const Queue = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn createSurface(vki: InstanceDispatch, instance: vk.Instance, window: *c.GLFWwindow) !vk.SurfaceKHR {
|
fn createSurface(instance: vk.Instance, window: *c.GLFWwindow) !vk.SurfaceKHR {
|
||||||
var surface: vk.SurfaceKHR = undefined;
|
var surface: vk.SurfaceKHR = undefined;
|
||||||
if (c.glfwCreateWindowSurface(instance, window, null, &surface) != .success) {
|
if (c.glfwCreateWindowSurface(instance, window, null, &surface) != .success) {
|
||||||
return error.SurfaceInitFailed;
|
return error.SurfaceInitFailed;
|
||||||
@@ -207,7 +202,7 @@ fn initializeCandidate(vki: InstanceDispatch, candidate: DeviceCandidate) !vk.De
|
|||||||
.queue_family_index = candidate.queues.present_family,
|
.queue_family_index = candidate.queues.present_family,
|
||||||
.queue_count = 1,
|
.queue_count = 1,
|
||||||
.p_queue_priorities = &priority,
|
.p_queue_priorities = &priority,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const queue_count: u32 = if (candidate.queues.graphics_family == candidate.queues.present_family)
|
const queue_count: u32 = if (candidate.queues.graphics_family == candidate.queues.present_family)
|
||||||
@@ -281,19 +276,14 @@ fn checkSuitable(
|
|||||||
return DeviceCandidate{
|
return DeviceCandidate{
|
||||||
.pdev = pdev,
|
.pdev = pdev,
|
||||||
.props = props,
|
.props = props,
|
||||||
.queues = allocation
|
.queues = allocation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocateQueues(
|
fn allocateQueues(vki: InstanceDispatch, pdev: vk.PhysicalDevice, allocator: *Allocator, surface: vk.SurfaceKHR) !?QueueAllocation {
|
||||||
vki: InstanceDispatch,
|
|
||||||
pdev: vk.PhysicalDevice,
|
|
||||||
allocator: *Allocator,
|
|
||||||
surface: vk.SurfaceKHR
|
|
||||||
) !?QueueAllocation {
|
|
||||||
var family_count: u32 = undefined;
|
var family_count: u32 = undefined;
|
||||||
vki.getPhysicalDeviceQueueFamilyProperties(pdev, &family_count, null);
|
vki.getPhysicalDeviceQueueFamilyProperties(pdev, &family_count, null);
|
||||||
|
|
||||||
@@ -307,7 +297,7 @@ fn allocateQueues(
|
|||||||
for (families) |properties, i| {
|
for (families) |properties, i| {
|
||||||
const family = @intCast(u32, i);
|
const family = @intCast(u32, i);
|
||||||
|
|
||||||
if (graphics_family == null and properties.queue_flags.contains(.{.graphics_bit = true})) {
|
if (graphics_family == null and properties.queue_flags.graphics_bit) {
|
||||||
graphics_family = family;
|
graphics_family = family;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +309,7 @@ fn allocateQueues(
|
|||||||
if (graphics_family != null and present_family != null) {
|
if (graphics_family != null and present_family != null) {
|
||||||
return QueueAllocation{
|
return QueueAllocation{
|
||||||
.graphics_family = graphics_family.?,
|
.graphics_family = graphics_family.?,
|
||||||
.present_family = present_family.?
|
.present_family = present_family.?,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ fn initSwapchainImages(gc: *const GraphicsContext, swapchain: vk.SwapchainKHR, f
|
|||||||
_ = try gc.vkd.getSwapchainImagesKHR(gc.dev, swapchain, &count, images.ptr);
|
_ = try gc.vkd.getSwapchainImagesKHR(gc.dev, swapchain, &count, images.ptr);
|
||||||
|
|
||||||
const swap_images = try allocator.alloc(SwapImage, count);
|
const swap_images = try allocator.alloc(SwapImage, count);
|
||||||
errdefer allocator.free(images);
|
errdefer allocator.free(swap_images);
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
errdefer for (swap_images[0..i]) |si| si.deinit(gc);
|
errdefer for (swap_images[0..i]) |si| si.deinit(gc);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ pub fn main() !void {
|
|||||||
@intCast(c_int, extent.height),
|
@intCast(c_int, extent.height),
|
||||||
app_name,
|
app_name,
|
||||||
null,
|
null,
|
||||||
null
|
null,
|
||||||
) orelse return error.WindowInitFailed;
|
) orelse return error.WindowInitFailed;
|
||||||
defer c.glfwDestroyWindow(window);
|
defer c.glfwDestroyWindow(window);
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ pub fn main() !void {
|
|||||||
const render_pass = try createRenderPass(&gc, swapchain);
|
const render_pass = try createRenderPass(&gc, swapchain);
|
||||||
defer gc.vkd.destroyRenderPass(gc.dev, render_pass, null);
|
defer gc.vkd.destroyRenderPass(gc.dev, render_pass, null);
|
||||||
|
|
||||||
var pipeline = try createPipeline(&gc, extent, pipeline_layout, render_pass);
|
var pipeline = try createPipeline(&gc, pipeline_layout, render_pass);
|
||||||
defer gc.vkd.destroyPipeline(gc.dev, pipeline, null);
|
defer gc.vkd.destroyPipeline(gc.dev, pipeline, null);
|
||||||
|
|
||||||
var framebuffers = try createFramebuffers(&gc, allocator, render_pass, swapchain);
|
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);
|
defer gc.vkd.freeMemory(gc.dev, memory, null);
|
||||||
try gc.vkd.bindBufferMemory(gc.dev, buffer, memory, 0);
|
try gc.vkd.bindBufferMemory(gc.dev, buffer, memory, 0);
|
||||||
|
|
||||||
try uploadVertices(&gc, pool, buffer, memory);
|
try uploadVertices(&gc, pool, buffer);
|
||||||
|
|
||||||
var cmdbufs = try createCommandBuffers(
|
var cmdbufs = try createCommandBuffers(
|
||||||
&gc,
|
&gc,
|
||||||
@@ -114,7 +114,7 @@ pub fn main() !void {
|
|||||||
swapchain.extent,
|
swapchain.extent,
|
||||||
render_pass,
|
render_pass,
|
||||||
pipeline,
|
pipeline,
|
||||||
framebuffers
|
framebuffers,
|
||||||
);
|
);
|
||||||
defer destroyCommandBuffers(&gc, pool, allocator, cmdbufs);
|
defer destroyCommandBuffers(&gc, pool, allocator, cmdbufs);
|
||||||
|
|
||||||
@@ -146,19 +146,17 @@ pub fn main() !void {
|
|||||||
swapchain.extent,
|
swapchain.extent,
|
||||||
render_pass,
|
render_pass,
|
||||||
pipeline,
|
pipeline,
|
||||||
framebuffers
|
framebuffers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
c.glfwSwapBuffers(window);
|
|
||||||
c.glfwPollEvents();
|
c.glfwPollEvents();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try swapchain.waitForAllFences();
|
try swapchain.waitForAllFences();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uploadVertices(gc: *const GraphicsContext, pool: vk.CommandPool, buffer: vk.Buffer, memory: vk.DeviceMemory) !void {
|
fn uploadVertices(gc: *const GraphicsContext, pool: vk.CommandPool, buffer: vk.Buffer) !void {
|
||||||
const staging_buffer = try gc.vkd.createBuffer(gc.dev, .{
|
const staging_buffer = try gc.vkd.createBuffer(gc.dev, .{
|
||||||
.flags = .{},
|
.flags = .{},
|
||||||
.size = @sizeOf(@TypeOf(vertices)),
|
.size = @sizeOf(@TypeOf(vertices)),
|
||||||
@@ -297,12 +295,7 @@ fn destroyCommandBuffers(gc: *const GraphicsContext, pool: vk.CommandPool, alloc
|
|||||||
allocator.free(cmdbufs);
|
allocator.free(cmdbufs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createFramebuffers(
|
fn createFramebuffers(gc: *const GraphicsContext, allocator: *Allocator, render_pass: vk.RenderPass, swapchain: Swapchain) ![]vk.Framebuffer {
|
||||||
gc: *const GraphicsContext,
|
|
||||||
allocator: *Allocator,
|
|
||||||
render_pass: vk.RenderPass,
|
|
||||||
swapchain: Swapchain
|
|
||||||
) ![]vk.Framebuffer {
|
|
||||||
const framebuffers = try allocator.alloc(vk.Framebuffer, swapchain.swap_images.len);
|
const framebuffers = try allocator.alloc(vk.Framebuffer, swapchain.swap_images.len);
|
||||||
errdefer allocator.free(framebuffers);
|
errdefer allocator.free(framebuffers);
|
||||||
|
|
||||||
@@ -374,7 +367,6 @@ fn createRenderPass(gc: *const GraphicsContext, swapchain: Swapchain) !vk.Render
|
|||||||
|
|
||||||
fn createPipeline(
|
fn createPipeline(
|
||||||
gc: *const GraphicsContext,
|
gc: *const GraphicsContext,
|
||||||
extent: vk.Extent2D,
|
|
||||||
layout: vk.PipelineLayout,
|
layout: vk.PipelineLayout,
|
||||||
render_pass: vk.RenderPass,
|
render_pass: vk.RenderPass,
|
||||||
) !vk.Pipeline {
|
) !vk.Pipeline {
|
||||||
@@ -506,7 +498,8 @@ fn createPipeline(
|
|||||||
_ = try gc.vkd.createGraphicsPipelines(
|
_ = try gc.vkd.createGraphicsPipelines(
|
||||||
gc.dev,
|
gc.dev,
|
||||||
.null_handle,
|
.null_handle,
|
||||||
1, @ptrCast([*]const vk.GraphicsPipelineCreateInfo, &gpci),
|
1,
|
||||||
|
@ptrCast([*]const vk.GraphicsPipelineCreateInfo, &gpci),
|
||||||
null,
|
null,
|
||||||
@ptrCast([*]vk.Pipeline, &pipeline),
|
@ptrCast([*]vk.Pipeline, &pipeline),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,6 +2,64 @@ const std = @import("std");
|
|||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
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 {
|
pub const CaseStyle = enum {
|
||||||
snake,
|
snake,
|
||||||
screaming_snake,
|
screaming_snake,
|
||||||
@@ -138,14 +196,10 @@ pub const IdRenderer = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: IdRenderer, out: anytype, id: []const u8) !void {
|
|
||||||
try out.print("{}", .{ std.zig.fmtId(id) });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn renderFmt(self: *IdRenderer, out: anytype, comptime fmt: []const u8, args: anytype) !void {
|
pub fn renderFmt(self: *IdRenderer, out: anytype, comptime fmt: []const u8, args: anytype) !void {
|
||||||
self.text_cache.items.len = 0;
|
self.text_cache.items.len = 0;
|
||||||
try std.fmt.format(self.text_cache.writer(), fmt, args);
|
try std.fmt.format(self.text_cache.writer(), fmt, args);
|
||||||
try out.print("{}", .{ std.zig.fmtId(self.text_cache.items) });
|
try writeIdentifier(out, self.text_cache.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn renderWithCase(self: *IdRenderer, out: anytype, case_style: CaseStyle, id: []const u8) !void {
|
pub fn renderWithCase(self: *IdRenderer, out: anytype, case_style: CaseStyle, id: []const u8) !void {
|
||||||
@@ -162,7 +216,7 @@ pub const IdRenderer = struct {
|
|||||||
.camel => try self.renderCamel(false, adjusted_id, tag),
|
.camel => try self.renderCamel(false, adjusted_id, tag),
|
||||||
}
|
}
|
||||||
|
|
||||||
try out.print("{}", .{ std.zig.fmtId(self.text_cache.items) });
|
try writeIdentifier(out, self.text_cache.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAuthorTag(self: IdRenderer, id: []const u8) ?[]const u8 {
|
pub fn getAuthorTag(self: IdRenderer, id: []const u8) ?[]const u8 {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
pub const generateVk = @import("vulkan/generator.zig").generate;
|
pub const generateVk = @import("vulkan/generator.zig").generate;
|
||||||
pub const VkGenerateStep = @import("vulkan/build_integration.zig").GenerateStep;
|
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;
|
pub const ShaderCompileStep = @import("build_integration.zig").ShaderCompileStep;
|
||||||
|
|
||||||
test "main" {
|
test "main" {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const usage = "Usage: {s} [-h|--help] <spec xml path> <output zig source>\n";
|
|||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const stderr = std.io.getStdErr();
|
const stderr = std.io.getStdErr();
|
||||||
const stdout = std.io.getStdOut();
|
|
||||||
|
|
||||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ pub const GenerateStep = struct {
|
|||||||
try generate(self.builder.allocator, spec, out_buffer.writer());
|
try generate(self.builder.allocator, spec, out_buffer.writer());
|
||||||
|
|
||||||
const tree = try std.zig.parse(self.builder.allocator, out_buffer.items);
|
const tree = try std.zig.parse(self.builder.allocator, out_buffer.items);
|
||||||
|
std.debug.assert(tree.errors.len == 0); // If this triggers, vulkan-zig produced invalid code.
|
||||||
|
|
||||||
var formatted = try tree.render(self.builder.allocator);
|
var formatted = try tree.render(self.builder.allocator);
|
||||||
|
|
||||||
|
|||||||
@@ -143,15 +143,12 @@ pub const CTokenizer = struct {
|
|||||||
']' => kind = .rbracket,
|
']' => kind = .rbracket,
|
||||||
'(' => kind = .lparen,
|
'(' => kind = .lparen,
|
||||||
')' => kind = .rparen,
|
')' => kind = .rparen,
|
||||||
else => return error.UnexpectedCharacter
|
else => return error.UnexpectedCharacter,
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = self.offset;
|
const start = self.offset;
|
||||||
_ = self.consumeNoEof();
|
_ = self.consumeNoEof();
|
||||||
return Token{
|
return Token{ .kind = kind, .text = self.source[start..self.offset] };
|
||||||
.kind = kind,
|
|
||||||
.text = self.source[start .. self.offset]
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -365,7 +362,7 @@ fn parseDeclaration(allocator: *Allocator, xctok: *XmlCTokenizer) ParseError!Dec
|
|||||||
.array = .{
|
.array = .{
|
||||||
.size = array_size,
|
.size = array_size,
|
||||||
.child = child,
|
.child = child,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// update the inner_type pointer so it points to the proper
|
// update the inner_type pointer so it points to the proper
|
||||||
@@ -403,8 +400,8 @@ fn parseFnPtrSuffix(allocator: *Allocator, xctok: *XmlCTokenizer, return_type: T
|
|||||||
.return_type = return_type_heap,
|
.return_type = return_type_heap,
|
||||||
.success_codes = &[_][]const u8{},
|
.success_codes = &[_][]const u8{},
|
||||||
.error_codes = &[_][]const u8{},
|
.error_codes = &[_][]const u8{},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const first_param = try parseDeclaration(allocator, xctok);
|
const first_param = try parseDeclaration(allocator, xctok);
|
||||||
@@ -500,10 +497,10 @@ fn parseArrayDeclarator(xctok: *XmlCTokenizer) !?ArraySize {
|
|||||||
.int = std.fmt.parseInt(usize, size_tok.text, 10) catch |err| switch (err) {
|
.int = std.fmt.parseInt(usize, size_tok.text, 10) catch |err| switch (err) {
|
||||||
error.Overflow => return error.Overflow,
|
error.Overflow => return error.Overflow,
|
||||||
error.InvalidCharacter => unreachable,
|
error.InvalidCharacter => unreachable,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
.enum_name => .{ .alias = size_tok.text },
|
.enum_name => .{ .alias = size_tok.text },
|
||||||
else => return error.InvalidSyntax
|
else => return error.InvalidSyntax,
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = try xctok.expect(.rbracket);
|
_ = try xctok.expect(.rbracket);
|
||||||
@@ -517,7 +514,7 @@ pub fn parseVersion(xctok: *XmlCTokenizer) ![4][]const u8 {
|
|||||||
return error.InvalidVersion;
|
return error.InvalidVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = try xctok.expect(.name);
|
_ = try xctok.expect(.name);
|
||||||
const vk_make_version = try xctok.expect(.type_name);
|
const vk_make_version = try xctok.expect(.type_name);
|
||||||
if (!mem.eql(u8, vk_make_version.text, "VK_MAKE_API_VERSION")) {
|
if (!mem.eql(u8, vk_make_version.text, "VK_MAKE_API_VERSION")) {
|
||||||
return error.NotVersion;
|
return error.NotVersion;
|
||||||
@@ -551,13 +548,9 @@ fn testTokenizer(tokenizer: anytype, expected_tokens: []const Token) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "CTokenizer" {
|
test "CTokenizer" {
|
||||||
var ctok = CTokenizer {
|
var ctok = CTokenizer{ .source = "typedef ([const)]** VKAPI_PTR 123,;aaaa" };
|
||||||
.source = \\typedef ([const)]** VKAPI_PTR 123,;aaaa
|
|
||||||
};
|
|
||||||
|
|
||||||
try testTokenizer(
|
try testTokenizer(&ctok, &[_]Token{
|
||||||
&ctok,
|
|
||||||
&[_]Token{
|
|
||||||
.{ .kind = .kw_typedef, .text = "typedef" },
|
.{ .kind = .kw_typedef, .text = "typedef" },
|
||||||
.{ .kind = .lparen, .text = "(" },
|
.{ .kind = .lparen, .text = "(" },
|
||||||
.{ .kind = .lbracket, .text = "[" },
|
.{ .kind = .lbracket, .text = "[" },
|
||||||
@@ -571,13 +564,11 @@ test "CTokenizer" {
|
|||||||
.{ .kind = .comma, .text = "," },
|
.{ .kind = .comma, .text = "," },
|
||||||
.{ .kind = .semicolon, .text = ";" },
|
.{ .kind = .semicolon, .text = ";" },
|
||||||
.{ .kind = .id, .text = "aaaa" },
|
.{ .kind = .id, .text = "aaaa" },
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "XmlCTokenizer" {
|
test "XmlCTokenizer" {
|
||||||
const document = try xml.parse(
|
const document = try xml.parse(testing.allocator,
|
||||||
testing.allocator,
|
|
||||||
\\<root>// comment <name>commented name</name> <type>commented type</type> trailing
|
\\<root>// comment <name>commented name</name> <type>commented type</type> trailing
|
||||||
\\ typedef void (VKAPI_PTR *<name>PFN_vkVoidFunction</name>)(void);
|
\\ typedef void (VKAPI_PTR *<name>PFN_vkVoidFunction</name>)(void);
|
||||||
\\</root>
|
\\</root>
|
||||||
@@ -586,9 +577,7 @@ test "XmlCTokenizer" {
|
|||||||
|
|
||||||
var xctok = XmlCTokenizer.init(document.root);
|
var xctok = XmlCTokenizer.init(document.root);
|
||||||
|
|
||||||
try testTokenizer(
|
try testTokenizer(&xctok, &[_]Token{
|
||||||
&xctok,
|
|
||||||
&[_]Token{
|
|
||||||
.{ .kind = .kw_typedef, .text = "typedef" },
|
.{ .kind = .kw_typedef, .text = "typedef" },
|
||||||
.{ .kind = .id, .text = "void" },
|
.{ .kind = .id, .text = "void" },
|
||||||
.{ .kind = .lparen, .text = "(" },
|
.{ .kind = .lparen, .text = "(" },
|
||||||
@@ -600,13 +589,11 @@ test "XmlCTokenizer" {
|
|||||||
.{ .kind = .id, .text = "void" },
|
.{ .kind = .id, .text = "void" },
|
||||||
.{ .kind = .rparen, .text = ")" },
|
.{ .kind = .rparen, .text = ")" },
|
||||||
.{ .kind = .semicolon, .text = ";" },
|
.{ .kind = .semicolon, .text = ";" },
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "parseTypedef" {
|
test "parseTypedef" {
|
||||||
const document = try xml.parse(
|
const document = try xml.parse(testing.allocator,
|
||||||
testing.allocator,
|
|
||||||
\\<root> // comment <name>commented name</name> trailing
|
\\<root> // comment <name>commented name</name> trailing
|
||||||
\\ typedef const struct <type>Python</type>* pythons[4];
|
\\ typedef const struct <type>Python</type>* pythons[4];
|
||||||
\\ // more comments
|
\\ // more comments
|
||||||
|
|||||||
@@ -9,41 +9,30 @@ const Allocator = mem.Allocator;
|
|||||||
const FeatureLevel = reg.FeatureLevel;
|
const FeatureLevel = reg.FeatureLevel;
|
||||||
|
|
||||||
const EnumFieldMerger = struct {
|
const EnumFieldMerger = struct {
|
||||||
const EnumExtensionMap = std.StringArrayHashMap(std.ArrayListUnmanaged(reg.Enum.Field));
|
const EnumExtensionMap = std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(reg.Enum.Field));
|
||||||
const FieldSet = std.StringArrayHashMap(void);
|
const FieldSet = std.StringArrayHashMapUnmanaged(void);
|
||||||
|
|
||||||
gpa: *Allocator,
|
arena: *Allocator,
|
||||||
reg_arena: *Allocator,
|
|
||||||
registry: *reg.Registry,
|
registry: *reg.Registry,
|
||||||
enum_extensions: EnumExtensionMap,
|
enum_extensions: EnumExtensionMap,
|
||||||
field_set: FieldSet,
|
field_set: FieldSet,
|
||||||
|
|
||||||
fn init(gpa: *Allocator, reg_arena: *Allocator, registry: *reg.Registry) EnumFieldMerger {
|
fn init(arena: *Allocator, registry: *reg.Registry) EnumFieldMerger {
|
||||||
return .{
|
return .{
|
||||||
.gpa = gpa,
|
.arena = arena,
|
||||||
.reg_arena = reg_arena,
|
|
||||||
.registry = registry,
|
.registry = registry,
|
||||||
.enum_extensions = EnumExtensionMap.init(gpa),
|
.enum_extensions = .{},
|
||||||
.field_set = FieldSet.init(gpa),
|
.field_set = .{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *EnumFieldMerger) void {
|
|
||||||
for (self.enum_extensions.values()) |*value| {
|
|
||||||
value.deinit(self.gpa);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.field_set.deinit();
|
|
||||||
self.enum_extensions.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn putEnumExtension(self: *EnumFieldMerger, enum_name: []const u8, field: reg.Enum.Field) !void {
|
fn putEnumExtension(self: *EnumFieldMerger, enum_name: []const u8, field: reg.Enum.Field) !void {
|
||||||
const res = try self.enum_extensions.getOrPut(enum_name);
|
const res = try self.enum_extensions.getOrPut(self.arena, enum_name);
|
||||||
if (!res.found_existing) {
|
if (!res.found_existing) {
|
||||||
res.value_ptr.* = std.ArrayListUnmanaged(reg.Enum.Field){};
|
res.value_ptr.* = std.ArrayListUnmanaged(reg.Enum.Field){};
|
||||||
}
|
}
|
||||||
|
|
||||||
try res.value_ptr.append(self.gpa, field);
|
try res.value_ptr.append(self.arena, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addRequires(self: *EnumFieldMerger, reqs: []const reg.Require) !void {
|
fn addRequires(self: *EnumFieldMerger, reqs: []const reg.Require) !void {
|
||||||
@@ -61,11 +50,11 @@ const EnumFieldMerger = struct {
|
|||||||
self.field_set.clearRetainingCapacity();
|
self.field_set.clearRetainingCapacity();
|
||||||
|
|
||||||
const n_fields_upper_bound = base_enum.fields.len + extensions.items.len;
|
const n_fields_upper_bound = base_enum.fields.len + extensions.items.len;
|
||||||
const new_fields = try self.reg_arena.alloc(reg.Enum.Field, n_fields_upper_bound);
|
const new_fields = try self.arena.alloc(reg.Enum.Field, n_fields_upper_bound);
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
|
|
||||||
for (base_enum.fields) |field| {
|
for (base_enum.fields) |field| {
|
||||||
const res = try self.field_set.getOrPut(field.name);
|
const res = try self.field_set.getOrPut(self.arena, field.name);
|
||||||
if (!res.found_existing) {
|
if (!res.found_existing) {
|
||||||
new_fields[i] = field;
|
new_fields[i] = field;
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -74,16 +63,16 @@ const EnumFieldMerger = struct {
|
|||||||
|
|
||||||
// Assume that if a field name clobbers, the value is the same
|
// Assume that if a field name clobbers, the value is the same
|
||||||
for (extensions.items) |field| {
|
for (extensions.items) |field| {
|
||||||
const res = try self.field_set.getOrPut(field.name);
|
const res = try self.field_set.getOrPut(self.arena, field.name);
|
||||||
if (!res.found_existing) {
|
if (!res.found_existing) {
|
||||||
new_fields[i] = field;
|
new_fields[i] = field;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Existing base_enum.fields was allocatued by `self.reg_arena`, so
|
// Existing base_enum.fields was allocated by `self.arena`, so
|
||||||
// it gets cleaned up whenever that is deinited.
|
// it gets cleaned up whenever that is deinited.
|
||||||
base_enum.fields = self.reg_arena.shrink(new_fields, i);
|
base_enum.fields = self.arena.shrink(new_fields, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge(self: *EnumFieldMerger) !void {
|
fn merge(self: *EnumFieldMerger) !void {
|
||||||
@@ -106,8 +95,7 @@ const EnumFieldMerger = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Generator = struct {
|
pub const Generator = struct {
|
||||||
gpa: *Allocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
reg_arena: std.heap.ArenaAllocator,
|
|
||||||
registry: reg.Registry,
|
registry: reg.Registry,
|
||||||
id_renderer: IdRenderer,
|
id_renderer: IdRenderer,
|
||||||
|
|
||||||
@@ -118,16 +106,14 @@ pub const Generator = struct {
|
|||||||
for (tags) |*tag, i| tag.* = result.registry.tags[i].name;
|
for (tags) |*tag, i| tag.* = result.registry.tags[i].name;
|
||||||
|
|
||||||
return Generator{
|
return Generator{
|
||||||
.gpa = allocator,
|
.arena = result.arena,
|
||||||
.reg_arena = result.arena,
|
|
||||||
.registry = result.registry,
|
.registry = result.registry,
|
||||||
.id_renderer = IdRenderer.init(allocator, tags),
|
.id_renderer = IdRenderer.init(allocator, tags),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: Generator) void {
|
fn deinit(self: Generator) void {
|
||||||
self.gpa.free(self.id_renderer.tags);
|
self.arena.deinit();
|
||||||
self.reg_arena.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stripFlagBits(self: Generator, name: []const u8) []const u8 {
|
fn stripFlagBits(self: Generator, name: []const u8) []const u8 {
|
||||||
@@ -142,19 +128,45 @@ pub const Generator = struct {
|
|||||||
|
|
||||||
// Solve `registry.declarations` according to `registry.extensions` and `registry.features`.
|
// Solve `registry.declarations` according to `registry.extensions` and `registry.features`.
|
||||||
fn mergeEnumFields(self: *Generator) !void {
|
fn mergeEnumFields(self: *Generator) !void {
|
||||||
var merger = EnumFieldMerger.init(self.gpa, &self.reg_arena.allocator, &self.registry);
|
var merger = EnumFieldMerger.init(&self.arena.allocator, &self.registry);
|
||||||
defer merger.deinit();
|
|
||||||
try merger.merge();
|
try merger.merge();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fixupTags(self: *Generator) !void {
|
// https://github.com/KhronosGroup/Vulkan-Docs/pull/1556
|
||||||
var fixer_upper = TagFixerUpper.init(self.gpa, &self.registry, &self.id_renderer);
|
fn fixupBitFlags(self: *Generator) !void {
|
||||||
defer fixer_upper.deinit();
|
var seen_bits = std.StringArrayHashMap(void).init(&self.arena.allocator);
|
||||||
try fixer_upper.fixup();
|
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 render(self: *Generator, writer: anytype) !void {
|
fn render(self: *Generator, writer: anytype) !void {
|
||||||
try renderRegistry(writer, &self.reg_arena.allocator, &self.registry, &self.id_renderer);
|
try renderRegistry(writer, &self.arena.allocator, &self.registry, &self.id_renderer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,5 +182,6 @@ pub fn generate(allocator: *Allocator, spec_xml: []const u8, writer: anytype) !v
|
|||||||
defer gen.deinit();
|
defer gen.deinit();
|
||||||
|
|
||||||
try gen.mergeEnumFields();
|
try gen.mergeEnumFields();
|
||||||
|
try gen.fixupBitFlags();
|
||||||
try gen.render(writer);
|
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")) {
|
} 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")) {
|
||||||
break :blk (try parseEnumAlias(allocator, ty)) orelse continue;
|
break :blk (try parseEnumAlias(ty)) orelse continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -118,10 +118,13 @@ fn parseBitmaskType(ty: *xml.Element) !registry.Declaration {
|
|||||||
|
|
||||||
return registry.Declaration{
|
return registry.Declaration{
|
||||||
.name = ty.getCharData("name") orelse return error.InvalidRegistry,
|
.name = ty.getCharData("name") orelse return error.InvalidRegistry,
|
||||||
.decl_type = .{.bitmask = .{
|
.decl_type = .{
|
||||||
.bits_enum = ty.getAttribute("requires") orelse ty.getAttribute("bitvalues"), // Who knows why these are different fields
|
.bitmask = .{
|
||||||
|
// Who knows why these are different fields
|
||||||
|
.bits_enum = ty.getAttribute("requires") orelse ty.getAttribute("bitvalues"),
|
||||||
.bitwidth = bitwidth,
|
.bitwidth = bitwidth,
|
||||||
}},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,7 +135,9 @@ fn parseHandleType(ty: *xml.Element) !registry.Declaration {
|
|||||||
const alias = ty.getAttribute("alias") orelse return error.InvalidRegistry;
|
const alias = ty.getAttribute("alias") orelse return error.InvalidRegistry;
|
||||||
return registry.Declaration{
|
return registry.Declaration{
|
||||||
.name = name,
|
.name = name,
|
||||||
.decl_type = .{.alias = .{.name = alias, .target = .other_type}},
|
.decl_type = .{
|
||||||
|
.alias = .{ .name = alias, .target = .other_type },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const name = ty.getCharData("name") orelse return error.InvalidRegistry;
|
const name = ty.getCharData("name") orelse return error.InvalidRegistry;
|
||||||
@@ -148,7 +153,7 @@ fn parseHandleType(ty: *xml.Element) !registry.Declaration {
|
|||||||
.handle = .{
|
.handle = .{
|
||||||
.parent = ty.getAttribute("parent"),
|
.parent = ty.getAttribute("parent"),
|
||||||
.is_dispatchable = dispatchable,
|
.is_dispatchable = dispatchable,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -175,7 +180,9 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
|
|||||||
if (ty.getAttribute("alias")) |alias| {
|
if (ty.getAttribute("alias")) |alias| {
|
||||||
return registry.Declaration{
|
return registry.Declaration{
|
||||||
.name = name,
|
.name = name,
|
||||||
.decl_type = .{.alias = .{.name = alias, .target = .other_type}},
|
.decl_type = .{
|
||||||
|
.alias = .{ .name = alias, .target = .other_type },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +205,18 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
|
|||||||
|
|
||||||
members = allocator.shrink(members, i);
|
members = allocator.shrink(members, i);
|
||||||
|
|
||||||
|
var maybe_extends: ?[][]const u8 = null;
|
||||||
|
if (ty.getAttribute("structextends")) |extends| {
|
||||||
|
const n_structs = std.mem.count(u8, extends, ",") + 1;
|
||||||
|
maybe_extends = try allocator.alloc([]const u8, n_structs);
|
||||||
|
var struct_extends = std.mem.split(extends, ",");
|
||||||
|
var j: usize = 0;
|
||||||
|
while (struct_extends.next()) |struct_extend| {
|
||||||
|
maybe_extends.?[j] = struct_extend;
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
it = ty.findChildrenByTag("member");
|
it = ty.findChildrenByTag("member");
|
||||||
for (members) |*member| {
|
for (members) |*member| {
|
||||||
const member_elem = it.next().?;
|
const member_elem = it.next().?;
|
||||||
@@ -211,8 +230,9 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
|
|||||||
.stype = maybe_stype,
|
.stype = maybe_stype,
|
||||||
.fields = members,
|
.fields = members,
|
||||||
.is_union = is_union,
|
.is_union = is_union,
|
||||||
}
|
.extends = maybe_extends,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,12 +310,14 @@ fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.El
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseEnumAlias(allocator: *Allocator, elem: *xml.Element) !?registry.Declaration {
|
fn parseEnumAlias(elem: *xml.Element) !?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{
|
||||||
.name = name,
|
.name = name,
|
||||||
.decl_type = .{.alias = .{.name = alias, .target = .other_type}},
|
.decl_type = .{
|
||||||
|
.alias = .{ .name = alias, .target = .other_type },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +441,9 @@ fn parseCommand(allocator: *Allocator, elem: *xml.Element) !registry.Declaration
|
|||||||
const name = elem.getAttribute("name") orelse return error.InvalidRegistry;
|
const name = elem.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
return registry.Declaration{
|
return registry.Declaration{
|
||||||
.name = name,
|
.name = name,
|
||||||
.decl_type = .{.alias = .{.name = alias, .target = .other_command}}
|
.decl_type = .{
|
||||||
|
.alias = .{ .name = alias, .target = .other_command },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,8 +495,8 @@ fn parseCommand(allocator: *Allocator, elem: *xml.Element) !registry.Declaration
|
|||||||
.return_type = return_type,
|
.return_type = return_type,
|
||||||
.success_codes = success_codes,
|
.success_codes = success_codes,
|
||||||
.error_codes = error_codes,
|
.error_codes = error_codes,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,9 +570,7 @@ fn parseDefines(types: *xml.Element, out: []registry.ApiConstant) !usize {
|
|||||||
var xctok = cparse.XmlCTokenizer.init(ty);
|
var xctok = cparse.XmlCTokenizer.init(ty);
|
||||||
out[i] = .{
|
out[i] = .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.value = .{
|
.value = .{ .version = cparse.parseVersion(&xctok) catch continue },
|
||||||
.version = cparse.parseVersion(&xctok) catch continue
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -609,7 +631,7 @@ fn parseFeature(allocator: *Allocator, feature: *xml.Element) !registry.Feature
|
|||||||
return registry.Feature{
|
return registry.Feature{
|
||||||
.name = name,
|
.name = name,
|
||||||
.level = feature_level,
|
.level = feature_level,
|
||||||
.requires = allocator.shrink(requires, i)
|
.requires = allocator.shrink(requires, i),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,7 +664,10 @@ fn parseEnumExtension(elem: *xml.Element, parent_extnumber: ?u31) !?registry.Req
|
|||||||
return registry.Require.EnumExtension{
|
return registry.Require.EnumExtension{
|
||||||
.extends = extends,
|
.extends = extends,
|
||||||
.extnumber = actual_extnumber,
|
.extnumber = actual_extnumber,
|
||||||
.field = .{.name = name, .value = .{.int = value}},
|
.field = .{
|
||||||
|
.name = name,
|
||||||
|
.value = .{ .int = value },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,7 +796,6 @@ fn parseExtension(allocator: *Allocator, extension: *xml.Element) !registry.Exte
|
|||||||
const promotedto = extension.getAttribute("promotedto") orelse break :blk .none;
|
const promotedto = extension.getAttribute("promotedto") orelse break :blk .none;
|
||||||
if (mem.startsWith(u8, promotedto, "VK_VERSION_")) {
|
if (mem.startsWith(u8, promotedto, "VK_VERSION_")) {
|
||||||
const feature_level = try splitFeatureLevel(promotedto["VK_VERSION_".len..], "_");
|
const feature_level = try splitFeatureLevel(promotedto["VK_VERSION_".len..], "_");
|
||||||
|
|
||||||
break :blk .{ .feature = feature_level };
|
break :blk .{ .feature = feature_level };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,7 +840,7 @@ fn parseExtension(allocator: *Allocator, extension: *xml.Element) !registry.Exte
|
|||||||
.promoted_to = promoted_to,
|
.promoted_to = promoted_to,
|
||||||
.platform = platform,
|
.platform = platform,
|
||||||
.required_feature_level = requires_core,
|
.required_feature_level = requires_core,
|
||||||
.requires = allocator.shrink(requires, i)
|
.requires = allocator.shrink(requires, i),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ pub const Container = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
stype: ?[]const u8,
|
stype: ?[]const u8,
|
||||||
|
extends: ?[]const []const u8,
|
||||||
fields: []Field,
|
fields: []Field,
|
||||||
is_union: bool,
|
is_union: bool,
|
||||||
};
|
};
|
||||||
@@ -77,7 +78,7 @@ pub const Enum = struct {
|
|||||||
alias: struct {
|
alias: struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
is_compat_alias: bool,
|
is_compat_alias: bool,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Field = struct {
|
pub const Field = struct {
|
||||||
@@ -118,7 +119,7 @@ pub const Pointer = struct {
|
|||||||
one,
|
one,
|
||||||
many, // The length is given by some complex expression, possibly involving another field
|
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
|
other_field: []const u8, // The length is given by some other field or parameter
|
||||||
zero_terminated
|
zero_terminated,
|
||||||
};
|
};
|
||||||
|
|
||||||
is_const: bool,
|
is_const: bool,
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ const IdRenderer = id_render.IdRenderer;
|
|||||||
|
|
||||||
const preamble =
|
const preamble =
|
||||||
\\
|
\\
|
||||||
\\// This file is generated from the Khronos Vulkan XML API registry
|
\\// This file is generated from the Khronos Vulkan XML API registry by vulkan-zig.
|
||||||
\\
|
\\
|
||||||
\\const std = @import("std");
|
\\const std = @import("std");
|
||||||
\\const builtin = @import("builtin");
|
\\const builtin = @import("builtin");
|
||||||
\\const root = @import("root");
|
\\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: std.builtin.CallingConvention = if (builtin.os.tag == .windows and builtin.cpu.arch == .i386)
|
||||||
\\ .Stdcall
|
\\ .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 std.Target.arm.featureSetHas(builtin.cpu.features, .has_v7) and builtin.cpu.arch.ptrBitWidth() == 32)
|
||||||
@@ -40,7 +43,7 @@ const preamble =
|
|||||||
\\ return fromInt(toInt(lhs) & toInt(rhs));
|
\\ return fromInt(toInt(lhs) & toInt(rhs));
|
||||||
\\ }
|
\\ }
|
||||||
\\ pub fn complement(self: FlagsType) FlagsType {
|
\\ pub fn complement(self: FlagsType) FlagsType {
|
||||||
\\ return fromInt(~toInt(lhs));
|
\\ return fromInt(~toInt(self));
|
||||||
\\ }
|
\\ }
|
||||||
\\ pub fn subtract(lhs: FlagsType, rhs: FlagsType) FlagsType {
|
\\ pub fn subtract(lhs: FlagsType, rhs: FlagsType) FlagsType {
|
||||||
\\ return fromInt(toInt(lhs) & toInt(rhs.complement()));
|
\\ return fromInt(toInt(lhs) & toInt(rhs.complement()));
|
||||||
@@ -182,10 +185,6 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
declarations_by_name: std.StringHashMap(*const reg.DeclarationType),
|
declarations_by_name: std.StringHashMap(*const reg.DeclarationType),
|
||||||
|
|
||||||
fn init(writer: WriterType, allocator: *Allocator, registry: *const reg.Registry, id_renderer: *IdRenderer) !Self {
|
fn init(writer: WriterType, allocator: *Allocator, registry: *const reg.Registry, id_renderer: *IdRenderer) !Self {
|
||||||
const tags = try allocator.alloc([]const u8, registry.tags.len);
|
|
||||||
errdefer allocator.free(tags);
|
|
||||||
for (tags) |*tag, i| tag.* = registry.tags[i].name;
|
|
||||||
|
|
||||||
var declarations_by_name = std.StringHashMap(*const reg.DeclarationType).init(allocator);
|
var declarations_by_name = std.StringHashMap(*const reg.DeclarationType).init(allocator);
|
||||||
errdefer declarations_by_name.deinit();
|
errdefer declarations_by_name.deinit();
|
||||||
|
|
||||||
@@ -209,12 +208,10 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
|
|
||||||
fn deinit(self: *Self) void {
|
fn deinit(self: *Self) void {
|
||||||
self.declarations_by_name.deinit();
|
self.declarations_by_name.deinit();
|
||||||
self.allocator.free(self.id_renderer.tags);
|
|
||||||
self.id_renderer.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeIdentifier(self: Self, id: []const u8) !void {
|
fn writeIdentifier(self: Self, id: []const u8) !void {
|
||||||
try self.id_renderer.render(self.writer, id);
|
try id_render.writeIdentifier(self.writer, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeIdentifierWithCase(self: *Self, case: CaseStyle, id: []const u8) !void {
|
fn writeIdentifierWithCase(self: *Self, case: CaseStyle, id: []const u8) !void {
|
||||||
@@ -242,7 +239,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extractBitflagFieldName(self: Self, bitflag_name: BitflagName, field_name: []const u8) ![]const u8 {
|
fn extractBitflagFieldName(bitflag_name: BitflagName, field_name: []const u8) ![]const u8 {
|
||||||
var flag_it = id_render.SegmentIterator.init(bitflag_name.base_name);
|
var flag_it = id_render.SegmentIterator.init(bitflag_name.base_name);
|
||||||
var field_it = id_render.SegmentIterator.init(field_name);
|
var field_it = id_render.SegmentIterator.init(field_name);
|
||||||
|
|
||||||
@@ -295,16 +292,6 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
return mem.endsWith(u8, base_name, "Flags");
|
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 {
|
fn isInOutPointer(self: Self, ptr: reg.Pointer) !bool {
|
||||||
if (ptr.child.* != .name) {
|
if (ptr.child.* != .name) {
|
||||||
return false;
|
return false;
|
||||||
@@ -373,7 +360,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.name => |name| {
|
.name => |name| {
|
||||||
if ((try self.extractBitflagName(param.param_type.name)) != null or self.isFlags(param.param_type.name)) {
|
if ((try self.extractBitflagName(name)) != null or self.isFlags(name)) {
|
||||||
return .bitflags;
|
return .bitflags;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -387,7 +374,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
return .other;
|
return .other;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classifyCommandDispatch(self: Self, name: []const u8, command: reg.Command) CommandDispatchType {
|
fn classifyCommandDispatch(name: []const u8, command: reg.Command) CommandDispatchType {
|
||||||
const device_handles = std.ComptimeStringMap(void, .{
|
const device_handles = std.ComptimeStringMap(void, .{
|
||||||
.{ "VkDevice", {} },
|
.{ "VkDevice", {} },
|
||||||
.{ "VkCommandBuffer", {} },
|
.{ "VkCommandBuffer", {} },
|
||||||
@@ -422,6 +409,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
fn render(self: *Self) !void {
|
fn render(self: *Self) !void {
|
||||||
try self.renderCopyright();
|
try self.renderCopyright();
|
||||||
try self.writer.writeAll(preamble);
|
try self.writer.writeAll(preamble);
|
||||||
|
try self.renderCommandEnums();
|
||||||
|
|
||||||
for (self.registry.api_constants) |api_constant| {
|
for (self.registry.api_constants) |api_constant| {
|
||||||
try self.renderApiConstant(api_constant);
|
try self.renderApiConstant(api_constant);
|
||||||
@@ -436,6 +424,88 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.renderWrappers();
|
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| {
|
||||||
|
const command = switch (decl.decl_type) {
|
||||||
|
.command => |cmd| cmd,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
||||||
|
try self.writeIdentifierWithCase(.camel, trimVkNamespace(decl.name));
|
||||||
|
try self.writer.writeAll(",\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
try self.writer.print(
|
||||||
|
\\
|
||||||
|
\\pub fn symbol(self: {s}Command) [:0]const u8 {{
|
||||||
|
\\ return switch (self) {{
|
||||||
|
\\
|
||||||
|
, .{dispatch_type_name}
|
||||||
|
);
|
||||||
|
|
||||||
|
for (self.registry.decls) |decl| {
|
||||||
|
const command = switch (decl.decl_type) {
|
||||||
|
.command => |cmd| cmd,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
||||||
|
try self.writer.writeAll(".");
|
||||||
|
try self.writeIdentifierWithCase(.camel, trimVkNamespace(decl.name));
|
||||||
|
try self.writer.print(" => \"{s}\",\n", .{ decl.name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.writer.writeAll("};\n}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
try self.writer.print(
|
||||||
|
\\
|
||||||
|
\\pub fn PfnType(comptime self: {s}Command) type {{
|
||||||
|
\\ return switch (self) {{
|
||||||
|
\\
|
||||||
|
, .{dispatch_type_name}
|
||||||
|
);
|
||||||
|
|
||||||
|
for (self.registry.decls) |decl| {
|
||||||
|
const command = switch (decl.decl_type) {
|
||||||
|
.command => |cmd| cmd,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
||||||
|
try self.writer.writeAll(".");
|
||||||
|
try self.writeIdentifierWithCase(.camel, trimVkNamespace(decl.name));
|
||||||
|
try self.writer.writeAll(" => ");
|
||||||
|
try self.renderCommandPtrName(decl.name);
|
||||||
|
try self.writer.writeAll(",\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.writer.writeAll("};\n}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.writer.writeAll("};\n");
|
||||||
|
}
|
||||||
|
|
||||||
fn renderCopyright(self: *Self) !void {
|
fn renderCopyright(self: *Self) !void {
|
||||||
var it = mem.split(self.registry.copyright, "\n");
|
var it = mem.split(self.registry.copyright, "\n");
|
||||||
while (it.next()) |line| {
|
while (it.next()) |line| {
|
||||||
@@ -539,7 +609,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writeIdentifierFmt("{s}Flags{s}{s}", .{
|
try self.writeIdentifierFmt("{s}Flags{s}{s}", .{
|
||||||
trimVkNamespace(bitflag_name.base_name),
|
trimVkNamespace(bitflag_name.base_name),
|
||||||
@as([]const u8, if (bitflag_name.revision) |revision| revision else ""),
|
@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;
|
return;
|
||||||
} else if (mem.startsWith(u8, name, "vk")) {
|
} else if (mem.startsWith(u8, name, "vk")) {
|
||||||
@@ -579,7 +649,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writeIdentifierFmt("{s}Flags{s}{s}", .{
|
try self.writeIdentifierFmt("{s}Flags{s}{s}", .{
|
||||||
trimVkNamespace(bitflag_name.base_name),
|
trimVkNamespace(bitflag_name.base_name),
|
||||||
@as([]const u8, if (bitflag_name.revision) |revision| revision else ""),
|
@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");
|
try self.writer.writeAll(".IntType");
|
||||||
break :blk;
|
break :blk;
|
||||||
@@ -680,7 +750,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try self.renderTypeInfo(field.field_type);
|
try self.renderTypeInfo(field.field_type);
|
||||||
try self.renderContainerDefaultField(container, field);
|
try self.renderContainerDefaultField(name, container, field);
|
||||||
try self.writer.writeAll(", ");
|
try self.writer.writeAll(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -688,7 +758,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writer.writeAll("};\n");
|
try self.writer.writeAll("};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderContainerDefaultField(self: *Self, container: reg.Container, field: reg.Container.Field) !void {
|
fn renderContainerDefaultField(self: *Self, name: []const u8, container: reg.Container, field: reg.Container.Field) !void {
|
||||||
if (mem.eql(u8, field.name, "pNext")) {
|
if (mem.eql(u8, field.name, "pNext")) {
|
||||||
try self.writer.writeAll(" = null");
|
try self.writer.writeAll(" = null");
|
||||||
} else if (mem.eql(u8, field.name, "sType")) {
|
} else if (mem.eql(u8, field.name, "sType")) {
|
||||||
@@ -703,44 +773,25 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
|
|
||||||
try self.writer.writeAll(" = .");
|
try self.writer.writeAll(" = .");
|
||||||
try self.writeIdentifierWithCase(.snake, stype["VK_STRUCTURE_TYPE_".len..]);
|
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)) {
|
||||||
|
try self.writer.writeAll(" = FALSE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn isFeatureStruct(name: []const u8, maybe_extends: ?[]const []const u8) bool {
|
||||||
|
if (std.mem.eql(u8, name, "VkPhysicalDeviceFeatures")) return true;
|
||||||
|
if (maybe_extends) |extends| {
|
||||||
|
return for (extends) |extend| {
|
||||||
|
if (mem.eql(u8, extend, "VkDeviceCreateInfo")) break true;
|
||||||
|
} else false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
fn renderEnumFieldName(self: *Self, name: []const u8, field_name: []const u8) !void {
|
fn renderEnumFieldName(self: *Self, name: []const u8, field_name: []const u8) !void {
|
||||||
try self.writeIdentifierWithCase(.snake, try self.extractEnumFieldName(name, field_name));
|
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 {
|
fn renderEnumeration(self: *Self, name: []const u8, enumeration: reg.Enum) !void {
|
||||||
if (enumeration.is_bitmask) {
|
if (enumeration.is_bitmask) {
|
||||||
try self.renderBitmaskBits(name, enumeration);
|
try self.renderBitmaskBits(name, enumeration);
|
||||||
@@ -749,17 +800,37 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
|
|
||||||
try self.writer.writeAll("pub const ");
|
try self.writer.writeAll("pub const ");
|
||||||
try self.renderName(name);
|
try self.renderName(name);
|
||||||
try self.writer.writeAll(" = extern enum(i32) {");
|
try self.writer.writeAll(" = enum(i32) {");
|
||||||
|
|
||||||
for (enumeration.fields) |field| {
|
for (enumeration.fields) |field| {
|
||||||
if (field.value == .alias and field.value.alias.is_compat_alias)
|
if (field.value == .alias)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
try self.renderEnumFieldName(name, field.name);
|
try self.renderEnumFieldName(name, field.name);
|
||||||
try self.renderEnumerationValue(name, enumeration, field.value);
|
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.writer.writeAll("_,};\n");
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bitmaskFlagsType(bitwidth: u8) ![]const u8 {
|
fn bitmaskFlagsType(bitwidth: u8) ![]const u8 {
|
||||||
@@ -797,7 +868,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
|
|
||||||
for (flags_by_bitpos[0..bits.bitwidth]) |maybe_flag_name, bitpos| {
|
for (flags_by_bitpos[0..bits.bitwidth]) |maybe_flag_name, bitpos| {
|
||||||
if (maybe_flag_name) |flag_name| {
|
if (maybe_flag_name) |flag_name| {
|
||||||
const field_name = try self.extractBitflagFieldName(bitflag_name, flag_name);
|
const field_name = try extractBitflagFieldName(bitflag_name, flag_name);
|
||||||
try self.writeIdentifierWithCase(.snake, field_name);
|
try self.writeIdentifierWithCase(.snake, field_name);
|
||||||
} else {
|
} else {
|
||||||
try self.writer.print("_reserved_bit_{}", .{bitpos});
|
try self.writer.print("_reserved_bit_{}", .{bitpos});
|
||||||
@@ -828,15 +899,13 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
\\ = packed struct {{
|
\\ = packed struct {{
|
||||||
\\_reserved_bits: {s} = 0,
|
\\_reserved_bits: {s} = 0,
|
||||||
\\pub usingnamespace FlagsMixin(
|
\\pub usingnamespace FlagsMixin(
|
||||||
, .{ flags_type }
|
, .{flags_type});
|
||||||
);
|
|
||||||
try self.renderName(name);
|
try self.renderName(name);
|
||||||
try self.writer.print(
|
try self.writer.print(
|
||||||
\\, {s});
|
\\, {s});
|
||||||
\\}};
|
\\}};
|
||||||
\\
|
\\
|
||||||
, .{ flags_type }
|
, .{flags_type});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,7 +914,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
|
|
||||||
try self.writer.writeAll("pub const ");
|
try self.writer.writeAll("pub const ");
|
||||||
try self.renderName(name);
|
try self.renderName(name);
|
||||||
try self.writer.print(" = extern enum({s}) {{null_handle = 0, _}};\n", .{backing_type});
|
try self.writer.print(" = enum({s}) {{null_handle = 0, _}};\n", .{backing_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderAlias(self: *Self, name: []const u8, alias: reg.Alias) !void {
|
fn renderAlias(self: *Self, name: []const u8, alias: reg.Alias) !void {
|
||||||
@@ -933,25 +1002,51 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn renderWrappers(self: *Self) !void {
|
fn renderWrappers(self: *Self) !void {
|
||||||
try self.renderWrappersOfDispatchType("BaseWrapper", .base);
|
try self.renderWrappersOfDispatchType(.base);
|
||||||
try self.renderWrappersOfDispatchType("InstanceWrapper", .instance);
|
try self.renderWrappersOfDispatchType(.instance);
|
||||||
try self.renderWrappersOfDispatchType("DeviceWrapper", .device);
|
try self.renderWrappersOfDispatchType(.device);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderWrappersOfDispatchType(self: *Self, name: []const u8, dispatch_type: CommandDispatchType) !void {
|
fn renderWrappersOfDispatchType(self: *Self, dispatch_type: CommandDispatchType) !void {
|
||||||
|
const name = switch (dispatch_type) {
|
||||||
|
.base => "Base",
|
||||||
|
.instance => "Instance",
|
||||||
|
.device => "Device",
|
||||||
|
};
|
||||||
|
|
||||||
try self.writer.print(
|
try self.writer.print(
|
||||||
\\pub fn {s}(comptime Self: type) type {{
|
\\pub fn {s}Wrapper(comptime cmds: []const {s}Command) type {{
|
||||||
|
\\ comptime var fields: [cmds.len]std.builtin.TypeInfo.StructField = undefined;
|
||||||
|
\\ inline for (cmds) |cmd, i| {{
|
||||||
|
\\ const PfnType = cmd.PfnType();
|
||||||
|
\\ fields[i] = .{{
|
||||||
|
\\ .name = cmd.symbol(),
|
||||||
|
\\ .field_type = PfnType,
|
||||||
|
\\ .default_value = null,
|
||||||
|
\\ .is_comptime = false,
|
||||||
|
\\ .alignment = @alignOf(PfnType),
|
||||||
|
\\ }};
|
||||||
|
\\ }}
|
||||||
|
\\ const Dispatch = @Type(.{{
|
||||||
|
\\ .Struct = .{{
|
||||||
|
\\ .layout = .Auto,
|
||||||
|
\\ .fields = &fields,
|
||||||
|
\\ .decls = &[_]std.builtin.TypeInfo.Declaration{{}},
|
||||||
|
\\ .is_tuple = false,
|
||||||
|
\\ }},
|
||||||
|
\\ }});
|
||||||
\\ return struct {{
|
\\ return struct {{
|
||||||
|
\\ dispatch: Dispatch,
|
||||||
\\
|
\\
|
||||||
, .{name}
|
\\ const Self = @This();
|
||||||
);
|
, .{ name, name });
|
||||||
|
|
||||||
try self.renderWrapperLoader(dispatch_type);
|
try self.renderWrapperLoader(dispatch_type);
|
||||||
|
|
||||||
for (self.registry.decls) |decl| {
|
for (self.registry.decls) |decl| {
|
||||||
if (decl.decl_type == .command) {
|
if (decl.decl_type == .command) {
|
||||||
const command = decl.decl_type.command;
|
const command = decl.decl_type.command;
|
||||||
if (self.classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
if (classifyCommandDispatch(decl.name, command) == dispatch_type) {
|
||||||
try self.renderWrapper(decl.name, decl.decl_type.command);
|
try self.renderWrapper(decl.name, decl.decl_type.command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -978,16 +1073,15 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writer.print(
|
try self.writer.print(
|
||||||
\\pub fn load({s}) !Self {{
|
\\pub fn load({s}) !Self {{
|
||||||
\\ var self: Self = undefined;
|
\\ var self: Self = undefined;
|
||||||
\\ inline for (std.meta.fields(Self)) |field| {{
|
\\ inline for (std.meta.fields(Dispatch)) |field| {{
|
||||||
\\ const name = @ptrCast([*:0]const u8, field.name ++ "\x00");
|
\\ const name = @ptrCast([*:0]const u8, field.name ++ "\x00");
|
||||||
\\ const cmd_ptr = loader({s}name) orelse return error.InvalidCommand;
|
\\ const cmd_ptr = loader({s}name) orelse return error.CommandLoadFailure;
|
||||||
\\ @field(self, field.name) = @ptrCast(field.field_type, cmd_ptr);
|
\\ @field(self.dispatch, field.name) = @ptrCast(field.field_type, cmd_ptr);
|
||||||
\\ }}
|
\\ }}
|
||||||
\\ return self;
|
\\ return self;
|
||||||
\\}}
|
\\}}
|
||||||
\\
|
\\
|
||||||
, .{params, loader_first_param}
|
, .{ params, loader_first_param });
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derefName(name: []const u8) []const u8 {
|
fn derefName(name: []const u8) []const u8 {
|
||||||
@@ -1016,7 +1110,8 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
.bitflags, // Special stuff handled in renderWrapperCall
|
.bitflags, // Special stuff handled in renderWrapperCall
|
||||||
.buffer_len,
|
.buffer_len,
|
||||||
.mut_buffer_len,
|
.mut_buffer_len,
|
||||||
.other => {
|
.other,
|
||||||
|
=> {
|
||||||
try self.writeIdentifierWithCase(.snake, param.name);
|
try self.writeIdentifierWithCase(.snake, param.name);
|
||||||
try self.writer.writeAll(": ");
|
try self.writer.writeAll(": ");
|
||||||
try self.renderTypeInfo(param.param_type);
|
try self.renderTypeInfo(param.param_type);
|
||||||
@@ -1028,8 +1123,8 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
|
|
||||||
try self.writer.writeAll(") ");
|
try self.writer.writeAll(") ");
|
||||||
|
|
||||||
if (command.return_type.* == .name and mem.eql(u8, command.return_type.name, "VkResult")) {
|
if (command.error_codes.len > 0) {
|
||||||
try self.renderErrorSet(command.error_codes);
|
try self.renderErrorSetName(name);
|
||||||
try self.writer.writeByte('!');
|
try self.writer.writeByte('!');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1043,7 +1138,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn renderWrapperCall(self: *Self, name: []const u8, command: reg.Command, returns: []const ReturnValue) !void {
|
fn renderWrapperCall(self: *Self, name: []const u8, command: reg.Command, returns: []const ReturnValue) !void {
|
||||||
try self.writer.writeAll("self.");
|
try self.writer.writeAll("self.dispatch.");
|
||||||
try self.writeIdentifier(name);
|
try self.writeIdentifier(name);
|
||||||
try self.writer.writeAll("(");
|
try self.writer.writeAll("(");
|
||||||
|
|
||||||
@@ -1064,10 +1159,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writeIdentifierWithCase(.snake, param.name);
|
try self.writeIdentifierWithCase(.snake, param.name);
|
||||||
try self.writer.writeAll(".toInt()");
|
try self.writer.writeAll(".toInt()");
|
||||||
},
|
},
|
||||||
.in_out_pointer,
|
.in_out_pointer, .buffer_len, .mut_buffer_len, .other => {
|
||||||
.buffer_len,
|
|
||||||
.mut_buffer_len,
|
|
||||||
.other => {
|
|
||||||
try self.writeIdentifierWithCase(.snake, param.name);
|
try self.writeIdentifierWithCase(.snake, param.name);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1122,6 +1214,11 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writeIdentifierFmt("{s}Result", .{trimVkNamespace(command_name)});
|
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 {
|
fn renderReturnStruct(self: *Self, command_name: []const u8, returns: []const ReturnValue) !void {
|
||||||
try self.writer.writeAll("pub const ");
|
try self.writer.writeAll("pub const ");
|
||||||
try self.renderReturnStructName(command_name);
|
try self.renderReturnStructName(command_name);
|
||||||
@@ -1131,16 +1228,13 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writer.writeAll(": ");
|
try self.writer.writeAll(": ");
|
||||||
try self.renderTypeInfo(ret.return_value_type);
|
try self.renderTypeInfo(ret.return_value_type);
|
||||||
try self.writer.writeAll(", ");
|
try self.writer.writeAll(", ");
|
||||||
|
|
||||||
}
|
}
|
||||||
try self.writer.writeAll("};\n");
|
try self.writer.writeAll("};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderWrapper(self: *Self, name: []const u8, command: reg.Command) !void {
|
fn renderWrapper(self: *Self, name: []const u8, command: reg.Command) !void {
|
||||||
const returns_vk_result = command.return_type.* == .name
|
const returns_vk_result = command.return_type.* == .name and mem.eql(u8, command.return_type.name, "VkResult");
|
||||||
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_void = command.return_type.* == .name
|
|
||||||
and mem.eql(u8, command.return_type.name, "void");
|
|
||||||
|
|
||||||
const returns = try self.extractReturns(command);
|
const returns = try self.extractReturns(command);
|
||||||
|
|
||||||
@@ -1148,6 +1242,14 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.renderReturnStruct(name, returns);
|
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);
|
try self.renderWrapperPrototype(name, command, returns);
|
||||||
|
|
||||||
if (returns.len == 1 and returns[0].origin == .inner_return_value) {
|
if (returns.len == 1 and returns[0].origin == .inner_return_value) {
|
||||||
@@ -1217,13 +1319,13 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writer.writeAll(") {\n");
|
try self.writer.writeAll(") {\n");
|
||||||
|
|
||||||
for (command.success_codes) |success| {
|
for (command.success_codes) |success| {
|
||||||
try self.writer.writeByte('.');
|
try self.writer.writeAll("Result.");
|
||||||
try self.renderEnumFieldName("VkResult", success);
|
try self.renderEnumFieldName("VkResult", success);
|
||||||
try self.writer.writeAll(" => {},");
|
try self.writer.writeAll(" => {},");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (command.error_codes) |err| {
|
for (command.error_codes) |err| {
|
||||||
try self.writer.writeByte('.');
|
try self.writer.writeAll("Result.");
|
||||||
try self.renderEnumFieldName("VkResult", err);
|
try self.renderEnumFieldName("VkResult", err);
|
||||||
try self.writer.writeAll(" => return error.");
|
try self.writer.writeAll(" => return error.");
|
||||||
try self.renderResultAsErrorName(err);
|
try self.renderResultAsErrorName(err);
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ const ArrayList = std.ArrayList;
|
|||||||
|
|
||||||
pub const Attribute = struct {
|
pub const Attribute = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
value: []const u8
|
value: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Content = union(enum) {
|
pub const Content = union(enum) {
|
||||||
CharData: []const u8,
|
CharData: []const u8,
|
||||||
Comment: []const u8,
|
Comment: []const u8,
|
||||||
Element: *Element
|
Element: *Element,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Element = struct {
|
pub const Element = struct {
|
||||||
@@ -50,7 +50,7 @@ pub const Element = struct {
|
|||||||
|
|
||||||
return switch (child.children.items[0]) {
|
return switch (child.children.items[0]) {
|
||||||
.CharData => |char_data| char_data,
|
.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 {
|
pub fn findChildrenByTag(self: *Element, tag: []const u8) FindChildrenByTagIterator {
|
||||||
return .{
|
return .{
|
||||||
.inner = self.elements(),
|
.inner = self.elements(),
|
||||||
.tag = tag
|
.tag = tag,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ pub const Element = struct {
|
|||||||
pub const XmlDecl = struct {
|
pub const XmlDecl = struct {
|
||||||
version: []const u8,
|
version: []const u8,
|
||||||
encoding: ?[]const u8,
|
encoding: ?[]const u8,
|
||||||
standalone: ?bool
|
standalone: ?bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Document = struct {
|
pub const Document = struct {
|
||||||
@@ -154,7 +154,7 @@ const ParseContext = struct {
|
|||||||
.source = source,
|
.source = source,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.line = 0,
|
.line = 0,
|
||||||
.column = 0
|
.column = 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ const ParseContext = struct {
|
|||||||
ws = true;
|
ws = true;
|
||||||
_ = self.consumeNoEof();
|
_ = self.consumeNoEof();
|
||||||
},
|
},
|
||||||
else => break
|
else => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +311,7 @@ pub const ParseError = error {
|
|||||||
InvalidStandaloneValue,
|
InvalidStandaloneValue,
|
||||||
NonMatchingClosingTag,
|
NonMatchingClosingTag,
|
||||||
InvalidDocument,
|
InvalidDocument,
|
||||||
OutOfMemory
|
OutOfMemory,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(backing_allocator: *Allocator, source: []const u8) !Document {
|
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{
|
var doc = Document{
|
||||||
.arena = ArenaAllocator.init(backing_allocator),
|
.arena = ArenaAllocator.init(backing_allocator),
|
||||||
.xml_decl = null,
|
.xml_decl = null,
|
||||||
.root = undefined
|
.root = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
errdefer doc.deinit();
|
errdefer doc.deinit();
|
||||||
@@ -376,7 +376,7 @@ fn parseNameNoDupe(ctx: *ParseContext) ![]const u8 {
|
|||||||
switch (ch) {
|
switch (ch) {
|
||||||
' ', '\t', '\n', '\r' => break,
|
' ', '\t', '\n', '\r' => break,
|
||||||
'&', '"', '\'', '<', '>', '?', '=', '/' => break,
|
'&', '"', '\'', '<', '>', '?', '=', '/' => break,
|
||||||
else => _ = ctx.consumeNoEof()
|
else => _ = ctx.consumeNoEof(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +392,7 @@ fn tryParseCharData(ctx: *ParseContext, alloc: *Allocator) !?[]const u8 {
|
|||||||
while (ctx.peek()) |ch| {
|
while (ctx.peek()) |ch| {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
'<' => break,
|
'<' => break,
|
||||||
else => _ = ctx.consumeNoEof()
|
else => _ = ctx.consumeNoEof(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,17 +605,14 @@ fn tryParseComment(ctx: *ParseContext, alloc: *Allocator) !?[]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unescapeEntity(text: []const u8) !u8 {
|
fn unescapeEntity(text: []const u8) !u8 {
|
||||||
const EntitySubstition = struct {
|
const EntitySubstition = struct { text: []const u8, replacement: u8 };
|
||||||
text: []const u8,
|
|
||||||
replacement: u8
|
|
||||||
};
|
|
||||||
|
|
||||||
const entities = [_]EntitySubstition{
|
const entities = [_]EntitySubstition{
|
||||||
.{ .text = "<", .replacement = '<' },
|
.{ .text = "<", .replacement = '<' },
|
||||||
.{ .text = ">", .replacement = '>' },
|
.{ .text = ">", .replacement = '>' },
|
||||||
.{ .text = "&", .replacement = '&' },
|
.{ .text = "&", .replacement = '&' },
|
||||||
.{ .text = "'", .replacement = '\'' },
|
.{ .text = "'", .replacement = '\'' },
|
||||||
.{.text = """, .replacement = '"'}
|
.{ .text = """, .replacement = '"' },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (entities) |entity| {
|
for (entities) |entity| {
|
||||||
|
|||||||
Reference in New Issue
Block a user