2026-05-02 00:03:24 +02:00
|
|
|
|
# VulkanTriangle
|
2025-06-13 23:59:36 +02:00
|
|
|
|
|
2026-05-02 00:03:24 +02:00
|
|
|
|
The minimal ray-traced example. Renders a single static triangle through
|
|
|
|
|
|
`vkCmdTraceRaysKHR`. No UI.
|
2025-06-13 23:59:36 +02:00
|
|
|
|
|
2026-05-02 00:03:24 +02:00
|
|
|
|
## What it shows
|
2025-06-13 23:59:36 +02:00
|
|
|
|
|
2026-05-02 00:03:24 +02:00
|
|
|
|
- `Device::Initialize()` + `Window` + swapchain bring-up.
|
|
|
|
|
|
- A `DescriptorHeapVulkan` sized for one image + one buffer slot, with
|
|
|
|
|
|
slot ranges allocated via the bump-allocator API
|
|
|
|
|
|
(`AllocateImageSlots`, `AllocateBufferSlots`).
|
|
|
|
|
|
- A `PipelineRTVulkan` built from raygen / miss / closesthit SPIR-V
|
|
|
|
|
|
shaders compiled at build time.
|
|
|
|
|
|
- `Mesh::Build` constructing a BLAS and `RenderingElement3D::BuildTLAS`
|
|
|
|
|
|
the per-frame TLAS.
|
|
|
|
|
|
- Direct descriptor writes via `vkWriteResourceDescriptorsEXT` for the
|
|
|
|
|
|
swapchain views and TLAS device addresses.
|
|
|
|
|
|
- `RTPass{&pipeline}` plugged into `window.passes` — the canonical
|
|
|
|
|
|
way to add ray tracing to a window in this library.
|
2025-06-13 23:59:36 +02:00
|
|
|
|
|
2026-05-02 00:03:24 +02:00
|
|
|
|
It's the smallest sensible test of the bindless `VK_EXT_descriptor_heap`
|
|
|
|
|
|
+ ray-tracing path.
|
2025-06-13 23:59:36 +02:00
|
|
|
|
|
2026-05-02 00:03:24 +02:00
|
|
|
|
## Run
|
2025-06-13 23:59:36 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-05-02 00:03:24 +02:00
|
|
|
|
cd examples/VulkanTriangle
|
|
|
|
|
|
crafter-build -r
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-03 01:59:54 +00:00
|
|
|
|
You should see a 1280×720 window with an RGB-barycentric triangle filling
|
|
|
|
|
|
roughly the centre. On the NVIDIA driver this works through an engine-side
|
|
|
|
|
|
workaround for a driver fault — see below.
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
2026-06-03 01:59:54 +00:00
|
|
|
|
## Native status — NVIDIA driver fault, worked around
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
2026-06-03 01:59:54 +00:00
|
|
|
|
On NVIDIA driver `610.43.02` (Vulkan 1.4) reading the acceleration
|
|
|
|
|
|
structure through `VK_EXT_descriptor_heap` aborts the device with
|
|
|
|
|
|
`VK_ERROR_DEVICE_LOST` on the first frame. This is a **driver-side fault**
|
|
|
|
|
|
in the brand-new descriptor-heap acceleration-structure path, not an engine
|
|
|
|
|
|
bug (full investigation in #7, summarised below).
|
2026-05-31 22:21:57 +00:00
|
|
|
|
|
2026-06-03 01:59:54 +00:00
|
|
|
|
**The engine works around it transparently** (issue #15). On the NVIDIA
|
|
|
|
|
|
proprietary driver only, `VulkanShader` rewrites the compiled SPIR-V at
|
|
|
|
|
|
module-load time so that every `OpLoad` of an `accelerationStructureEXT`
|
|
|
|
|
|
out of the heap becomes a load of the TLAS *device address* (from a
|
2026-06-03 02:28:02 +00:00
|
|
|
|
push-constant block) followed by
|
2026-06-03 01:59:54 +00:00
|
|
|
|
`OpConvertUToAccelerationStructureKHR` — which reads no descriptor and so
|
|
|
|
|
|
never touches the faulting path. `RTPass` feeds the active frame's TLAS
|
2026-06-03 02:28:02 +00:00
|
|
|
|
address in as push data. SPIR-V allows only one push-constant block per
|
|
|
|
|
|
entry point, so when a shader already declares one the TLAS address is
|
|
|
|
|
|
appended to *that* block (rather than adding a second, which would fail
|
|
|
|
|
|
validation — issue #18); shaders without a push constant get a freshly
|
|
|
|
|
|
synthesized single-member block. `raygen.glsl` and the example code are
|
|
|
|
|
|
unchanged; acceleration structures still bind into the heap normally. On
|
|
|
|
|
|
every other driver the workaround is inert. It's gated on
|
2026-06-03 01:59:54 +00:00
|
|
|
|
`Device::workaroundDescriptorHeapAS` and confined to one fenced block in
|
|
|
|
|
|
`interfaces/Crafter.Graphics-ShaderVulkan.cppm` so it can be deleted wholesale
|
|
|
|
|
|
once a fixed NVIDIA driver ships.
|
|
|
|
|
|
|
|
|
|
|
|
### The underlying fault (#7)
|
|
|
|
|
|
|
|
|
|
|
|
The fault was traced to the **acceleration-structure read through
|
|
|
|
|
|
`VK_EXT_descriptor_heap`**, *not* to the engine's RT setup:
|
2026-05-31 22:21:57 +00:00
|
|
|
|
|
|
|
|
|
|
- The BLAS/TLAS build is correct and finishes before rendering
|
|
|
|
|
|
(`Window::FinishInit` does `vkQueueWaitIdle`). The built TLAS instance
|
|
|
|
|
|
has an identity transform, `mask = 0xFF`, and the correct BLAS device
|
|
|
|
|
|
address.
|
|
|
|
|
|
- The AS descriptor is written correctly — `vkWriteResourceDescriptorsEXT`
|
|
|
|
|
|
stores the TLAS device address at the expected heap byte offset (verified
|
|
|
|
|
|
by dumping the raw heap bytes after the write).
|
|
|
|
|
|
- The Khronos validation layers (1.4.350, current) report **zero** errors
|
|
|
|
|
|
for the whole frame, including the SBT regions handed to
|
|
|
|
|
|
`vkCmdTraceRaysKHR`.
|
|
|
|
|
|
- Storage images and buffers bound through the **same** descriptor heap
|
|
|
|
|
|
work — with `traceRayEXT` removed, the raygen shader's `imageStore`
|
|
|
|
|
|
renders correctly, so the heap binding / image path is sound.
|
|
|
|
|
|
- Both the ray-tracing pipeline (`traceRayEXT`) **and** inline ray query
|
|
|
|
|
|
(`rayQueryEXT`, which uses no shader binding table) fault identically
|
|
|
|
|
|
when they read the acceleration structure from the heap. That isolates
|
|
|
|
|
|
the fault to the AS-via-heap read, not the SBT or the RT pipeline.
|
|
|
|
|
|
- The fault reproduces even with the AS descriptor written at heap byte 0
|
|
|
|
|
|
and read at shader index 0 (no descriptor offset/stride ambiguity), and
|
|
|
|
|
|
is unaffected by the `pAddressRange` size.
|
|
|
|
|
|
- `VK_EXT_descriptor_heap` is brand new; on this machine NVIDIA is the only
|
|
|
|
|
|
implementation that advertises it (llvmpipe does not), so there is no
|
|
|
|
|
|
second conformant implementation to cross-check against.
|
|
|
|
|
|
|
|
|
|
|
|
**Conclusion:** this is a driver-side fault in NVIDIA's
|
2026-06-03 01:59:54 +00:00
|
|
|
|
`VK_EXT_descriptor_heap` acceleration-structure path, not an engine bug, and
|
|
|
|
|
|
it should be reported to NVIDIA. Until a fixed driver ships, the SPIR-V
|
|
|
|
|
|
rewrite above keeps the native RT path working; once it does, remove the
|
|
|
|
|
|
workaround and the heap AS read becomes the direct path again.
|