Vulkan bindings for C3, auto-generated from the official Vulkan XML specification. Covers Vulkan 1.0 through 1.4 with all platform-compatible extensions included.
- Idiomatic C3 error handling — Vulkan error codes map to C3 faults
- Builder pattern — auto-generated
.set*()and.build()methods for Vulkan structs - Cross-platform — Windows, Linux (X11/Wayland), and macOS
- No link-time Vulkan dependency — the loader is opened at runtime (volk-style), so the Vulkan SDK is optional on every platform, at build time and at run time
- Ships its own loader and driver on macOS (arm64), so a Mac needs nothing installed to run
vk/ # Generated + hand-written bindings (this is the library)
vk.c3 # Types, enums, structs, unions
commands.c3 # Command pointers, staged loading, and wrappers
builders_core.c3 # Auto-generated builder/setter methods (core Vulkan structs)
builders_ext.c3 # Auto-generated builder/setter methods (extension structs)
loader.c3 # Runtime loader bootstrap (vk::init)
driver.c3 # VK_LUNARG_direct_driver_loading support
extra.c3 # Hand-written type aliases (platform types, function pointers)
helpers.c3 # Convenience wrappers (swapchain, device queries, etc.)
buffer.c3 # Memory allocator and buffer helpers
parser/ # Bindings generator (reads vk.xml, writes vk/*.c3)
build.c3 # Main generator logic
types.c3 # XML parsing types
diag.c3 # Generator diagnostics (skipped/dropped report)
macos-aarch64/ # Bundled loader + driver dylibs for macOS (see below)
libs/ # Example dependencies, as git submodules
window.c3l/ # https://github.com/tonis2/Window.c3
image.c3l/ # https://github.com/tonis2/image.c3
examples/
cube/ # 3D rotating cube with camera controls
textured_cube/ # The same cube, with a texture and descriptor sets
Nothing links against Vulkan. Every command is a function pointer, resolved in three stages (the same model as volk):
vk::init()opens the loader shared library (vulkan-1.dll,libvulkan.so.1,libvulkan.1.dylib), pullsvkGetInstanceProcAddrout of it, and binds the global-level commands — enough to query extensions and layers and to callvkCreateInstance. Pass your own candidate paths toinitto override the search:vk::init({ "/path/to/libvulkan.so" })!.- Creating an instance binds every remaining command, core and extension alike,
through
vkGetInstanceProcAddr. vk::loadDeviceCommands(device)is optional: it rebinds device-level commands throughvkGetDeviceProcAddr, so calls dispatch straight into the driver instead of through the loader trampoline.
init must run before anything else in the library — a command called before it
is a crash, not a link error.
- C3 compiler (latest version)
- Nothing else. The Vulkan SDK is optional on every platform — it is never needed to build, and at run time the loader either ships with the GPU driver (Linux, Windows) or with this library (macOS).
The examples build against the window and image libraries in libs/, which are
git submodules — clone with them, or pull them in afterwards:
git clone --recurse-submodules https://github.com/tonis2/Vulkan.c3.git
# already cloned?
git submodule update --initNothing in vk/ depends on them; they are only needed to build the examples.
Linux:
c3c run cubeWindows:
c3c run cube-winmacOS:
c3c run cubeThe Vulkan SDK is optional everywhere. Install it only when you want validation
layers and tooling (vulkaninfo, glslc, RenderDoc integration) — never to
build or run.
Linux — the loader and driver ship with the GPU stack, so nothing is needed. For validation layers and tooling:
# Ubuntu/Debian
sudo apt install libvulkan1 vulkan-tools vulkan-validationlayers spirv-tools
# Fedora
sudo dnf install vulkan-loader vulkan-tools vulkan-validation-layers spirv-tools
# Arch
sudo pacman -S vulkan-icd-loader vulkan-tools vulkan-validation-layers spirv-toolsWindows — the loader (vulkan-1.dll) ships with the GPU driver, so nothing is needed. The Vulkan SDK is only for validation layers and tooling.
macOS (arm64) — nothing is needed either. macOS has no system Vulkan, so the library carries its own in macos-aarch64/ and both are bundled into vulkan.c3l:
libvulkan.1.dylib— the Khronos loader, opened byvk::init()libvulkan_kosmickrisp.dylib— KosmicKrisp, the Mesa Vulkan-on-Metal driver, handed to the loader throughVK_LUNARG_direct_driver_loading.
Installing the .c3l gets you both. A git checkout gets only the loader —
the driver is 15 MB and is rebuilt on every Mesa bump, so it is a release asset
rather than a tracked file, and a checkout fetches it once:
./fetch-driver.shbuild.sh calls it for you. driver.sha256 is what makes it reproducible: the
tag is rolling, the hash is in git, and a mismatch fails by name. Skipping it
does not break the build — nothing links against the driver — it fails later and
silently, because vk::findBundledDriver treats "no bundled driver" as a
normal outcome and falls back to the loader's own ICD discovery. The symptom is
no devices, or the wrong ICD, never a missing file.
It used to live on a driver orphan branch. That kept it out of a checkout but
not out of the object database — git clone fetches every branch, and there is
no way to opt one out — so every clone paid for it regardless. See
fetch-driver.sh for the longer version.
vk::createDefaultInstance() wires the bundled driver up on its own. If you would
rather use an installed driver (a system MoltenVK from the LunarG SDK, say), set
skip_bundled_driver and the loader does its normal ICD discovery:
vk::Instance instance = vk::createDefaultInstance({
.app_name = "My App",
.extensions = { ...vk::DEFAULT_EXTENSIONS, "VK_KHR_surface" },
.skip_bundled_driver = true,
})!;Building the instance by hand instead? vk::findBundledDriver() returns the
shipped driver's entry point, and vk::supportsDirectDriverLoading() reports
whether the loader on the machine understands the extension — see vk/driver.c3.
Intel Macs are not covered by the bundled pair; there vk::init falls back to a
loader installed by the Vulkan SDK, or
to paths you pass it yourself.
Download vulkan.c3l from releases, place it in your project (e.g. ./libs/), and add it to your project.json:
{
"dependency-search-paths": ["./libs"],
"dependencies": ["vulkan"]
}No linked-libraries entry on any target — the loader is opened at runtime by
vk::init(). On macOS the .c3l also carries the loader and driver themselves,
so unzipping it is the whole install.
c3c build zip --trust=fullThis creates vulkan.c3l in the project root (bindings plus the macOS
loader/driver pair).
vk::createDefaultInstance handles the whole bootstrap — init, the platform
surface extension, and the bundled macOS driver:
import vk;
fn void? main() {
vk::Instance instance = vk::createDefaultInstance({
.app_name = "My App",
.extensions = { ...vk::DEFAULT_EXTENSIONS, "VK_KHR_surface" },
})!;
}Or drive it yourself, calling vk::init() first:
import vk;
fn void? main() {
vk::init()!;
ApplicationInfo info = {
.pApplicationName = "My App",
.pEngineName = "My Engine",
.applicationVersion = vk::@makeApiVersion(0, 1, 0, 0),
.engineVersion = vk::@makeApiVersion(0, 1, 0, 0),
.apiVersion = vk::@makeApiVersion(0, 1, 3, 0)
};
InstanceCreateInfo instanceInfo = vk::instanceCreateInfo()
.setApplicationInfo(&info)
.setEnabledExtensionNames(extensions.array_view());
vk::Instance instance;
vk::createInstance(&instanceInfo, null, &instance)!;
}The builder pattern lets you chain .set*() calls, then call .build() on create-info structs:
vk::Pipeline pipeline = vk::graphicsPipelineCreateInfo()
.setStages(shader_stages)
.setLayout(pipeline_layout)
.setRenderPass(render_pass)
.build(device)!;To regenerate the bindings from the latest Vulkan XML specification:
sh build.shThis downloads vk.xml from the Khronos repository, runs the parser, fetches the
macOS driver if it is not already there, and zips vulkan.c3l. All extensions compatible with supported platforms (Win32, X11, XCB, Wayland, macOS/Metal, iOS) are included. Extensions referencing undefined types are automatically skipped.
The generator prints a summary of everything it skipped or dropped (and why) to stderr. Run it with c3c run build -- --strict to make any warning fail the run.
- Window library (c3w) — windowing dependency used by the examples
- Example game — a larger project using these bindings
- C3 documentation
- Vulkan Tutorial
- Vulkan Specification
See LICENSE.