---
id: vk
title: Vk
order: 61
---
Vulkan for Ludic. Vk.* binds Vulkan 1.0–1.4 and the extensions a modern renderer is built around — swapchain and HDR colour spaces, ray query and acceleration structures, opacity micromaps, mesh shaders, variable rate shading, memory budget, pipeline libraries, NVIDIA low latency, and portability enumeration for MoltenVK. Every command is a method named by its snake case (vkCreateInstance → Vk.create_instance, vkCmdDrawIndexedIndirectCount → Vk.cmd_draw_indexed_indirect_count), every VK_* constant is available as written, and every struct has its size and field offsets as constants: VkDeviceCreateInfo_sizeof, VkDeviceCreateInfo_queueCreateInfoCount. The binding is generated by ludic-dev vkgen from the Vulkan registry (vk.xml), and every size and offset is checked against the SDK's C headers.
A struct is plain memory filled by field name: bytes(Vk…_sizeof), Vk.zero(p, n), then Vk.put_i32 / Vk.put_i64 / Vk.put_ptr(p, offset, value), read back with Vk.get_i32 / get_i64 / get_ptr, and Vk.at(p, offset) for a nested struct or an inline array. Numbers follow the C types: a float is its IEEE bit pattern in an int, and uint64_t, VkDeviceSize and non-dispatchable handles are long. A negative long has to come from a long variable — an int literal passed straight to a long parameter is zero-extended.
The loader is opened at run time by Vk.open(), never linked: vulkan-1.dll on Windows, libvulkan.1.dylib (the LunarG loader and MoltenVK) on macOS — beside the executable, in the library paths, or under $VULKAN_SDK. It returns 0 on a machine without Vulkan, and the program carries on; Vk.has(name) says whether one command is there. Using Vk.* links the generated thunks and the loader; a program that does not is unchanged. See examples/rendering/vk_probe.ludic (what a machine's Vulkan can do) and vk_compute.ludic (a Slang compute shader, dispatched and read back).
```ludic
program Probe {
property Marker { on: int = 1 }
model Anchor { Marker }
handler Boot phase Start {
spawn Anchor {}
if Vk.open() == 0 { print("no Vulkan here"); quit() }
let app = bytes(VkApplicationInfo_sizeof)
Vk.zero(app, VkApplicationInfo_sizeof)
Vk.put_i32(app, VkApplicationInfo_sType, VK_STRUCTURE_TYPE_APPLICATION_INFO)
Vk.put_i32(app, VkApplicationInfo_apiVersion, (1 << 22) | (3 << 12))
let ci = bytes(VkInstanceCreateInfo_sizeof)
Vk.zero(ci, VkInstanceCreateInfo_sizeof)
Vk.put_i32(ci, VkInstanceCreateInfo_sType, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO)
Vk.put_ptr(ci, VkInstanceCreateInfo_pApplicationInfo, app)
let out = bytes(8)
if Vk.create_instance(ci, null, out) == VK_SUCCESS {
print("a Vulkan instance")
Vk.destroy_instance(Vk.get_ptr(out, 0), null)
}
quit()
}
}
```