feat(vk): Vk.* - Vulkan 1.0-1.4 generated from the registry, loaded at run time
ludic-dev vkgen reads vk.xml into runtime/native/vk_api.ludic (constants, every struct's <Struct>_sizeof and <Struct>_<field> offsets, one extern per command) and vk_thunks.ll. Every size and offset was compiled against the SDK's C headers; `ludic-dev test` checks the tracked files against the registry wherever the Vulkan SDK is installed. vk_win.ll (vulkan-1.dll) and vk_mac.ll (libvulkan.1.dylib, MoltenVK) open the loader at run time, so a program built with Vk.* starts on a machine without Vulkan. ludicc and ludic build link both for any program that uses Vk.*. The seeds are regenerated for the new compiler. vk_probe reports what a machine's Vulkan can do; vk_compute dispatches a Slang compute shader and reads the picture back, clean under the validation layer on an RTX 3070 Ti and on an M4 Pro through MoltenVK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
043d8d81a2
commit
208cad7ca1
18 changed files with 52468 additions and 40972 deletions
36
docs/language/vk/_section.md
Normal file
36
docs/language/vk/_section.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
id: vk
|
||||
title: Vk
|
||||
order: 61
|
||||
---
|
||||
|
||||
Vulkan for Ludic. <code>Vk.*</code> binds <strong>Vulkan 1.0–1.4</strong> 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 (<code>vkCreateInstance</code> → <code>Vk.create_instance</code>, <code>vkCmdDrawIndexedIndirectCount</code> → <code>Vk.cmd_draw_indexed_indirect_count</code>), every <code>VK_*</code> constant is available as written, and every struct has its size and field offsets as constants: <code>VkDeviceCreateInfo_sizeof</code>, <code>VkDeviceCreateInfo_queueCreateInfoCount</code>. The binding is generated by <code>ludic-dev vkgen</code> from the Vulkan registry (<code>vk.xml</code>), and every size and offset is checked against the SDK's C headers.
|
||||
|
||||
A struct is plain memory filled by field name: <code>bytes(Vk…_sizeof)</code>, <code>Vk.zero(p, n)</code>, then <code>Vk.put_i32</code> / <code>Vk.put_i64</code> / <code>Vk.put_ptr(p, offset, value)</code>, read back with <code>Vk.get_i32</code> / <code>get_i64</code> / <code>get_ptr</code>, and <code>Vk.at(p, offset)</code> for a nested struct or an inline array. Numbers follow the C types: a <code>float</code> is its IEEE bit pattern in an <code>int</code>, and <code>uint64_t</code>, <code>VkDeviceSize</code> and non-dispatchable handles are <code>long</code>. A negative <code>long</code> has to come from a <code>long</code> variable — an <code>int</code> literal passed straight to a <code>long</code> parameter is zero-extended.
|
||||
|
||||
The loader is opened <strong>at run time</strong> by <code>Vk.open()</code>, never linked: <code>vulkan-1.dll</code> on Windows, <code>libvulkan.1.dylib</code> (the LunarG loader and MoltenVK) on macOS — beside the executable, in the library paths, or under <code>$VULKAN_SDK</code>. It returns 0 on a machine without Vulkan, and the program carries on; <code>Vk.has(name)</code> says whether one command is there. Using <code>Vk.*</code> links the generated thunks and the loader; a program that does not is unchanged. See <code>examples/rendering/vk_probe.ludic</code> (what a machine's Vulkan can do) and <code>vk_compute.ludic</code> (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()
|
||||
}
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue