# VulkanTriangle The minimal ray-traced example. Renders a single static triangle through `vkCmdTraceRaysKHR`. No UI. ## What it shows - `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. It's the smallest sensible test of the bindless `VK_EXT_descriptor_heap` + ray-tracing path. ## Run ```bash cd examples/VulkanTriangle crafter-build -r ``` 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. ## Native status — NVIDIA driver fault, worked around 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). **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 push-constant block) followed by `OpConvertUToAccelerationStructureKHR` — which reads no descriptor and so never touches the faulting path. `RTPass` feeds the active frame's TLAS 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 `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: - 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 `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.