test(rt): pick hit-shader descriptors from the heap by a runtime index

On NVIDIA 610.43.02, selecting a descriptor-heap descriptor with a
runtime index in a hit shader lost the device, for storage buffers and
sampled images alike, which is why the examples use spec constants
there. HeapDynamicIndexHit renders two instances whose closest-hit picks
a buffer and a texture by a runtime index: one instance uses the same
set across every wave, the other a different set in every other pixel
column, so neighbouring lanes select different descriptors. It passes
on 615.78.08 and on llvmpipe.

On NVIDIA drivers older than 615.78.08 it skips rather than abort the
suite. With validation on it also renders in a child process with
validation off, since GPU-assisted validation hides the fault.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-10-19 03:03:16 +02:00
commit 37fe0dc49f
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
5 changed files with 523 additions and 0 deletions

View file

@ -471,6 +471,37 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
heapAsImpls.emplace_back("tests/HeapASRead/main");
ha.GetInterfacesAndImplementations(ifaces, heapAsImpls);
cfg.tests.push_back(std::move(heapAsTest));
// Dynamic descriptor-heap indexing in a hit shader: a closest-hit
// picks a storage buffer and a sampled image by a runtime index
// (the same across a wave on one instance, different between
// neighbouring lanes on the other), which lost the device on
// NVIDIA 610.43.02; skips on NVIDIA drivers older than 615.78.08.
// Same requirements as HeapASRead.
Test dynIndexTest;
Configuration& di = dynIndexTest.config;
di.path = cfg.path;
di.name = "HeapDynamicIndexHit";
di.outputName = "HeapDynamicIndexHit";
di.type = ConfigurationType::Executable;
di.target = cfg.target;
di.march = cfg.march;
di.mtune = cfg.mtune;
di.debug = cfg.debug;
di.sysroot = cfg.sysroot;
di.dependencies = cfg.dependencies;
di.externalDependencies = cfg.externalDependencies;
di.compileFlags = cfg.compileFlags;
di.linkFlags = cfg.linkFlags;
di.defines = cfg.defines;
di.cFiles = cfg.cFiles;
di.shaders.emplace_back(fs::path("tests/HeapDynamicIndexHit/dynidx-raygen.glsl"), std::string("main"), ShaderType::RayGen);
di.shaders.emplace_back(fs::path("tests/HeapDynamicIndexHit/dynidx-closesthit.glsl"), std::string("main"), ShaderType::ClosestHit);
di.shaders.emplace_back(fs::path("tests/HeapDynamicIndexHit/dynidx-miss.glsl"), std::string("main"), ShaderType::Miss);
std::vector<fs::path> dynIndexImpls(impls.begin(), impls.end());
dynIndexImpls.emplace_back("tests/HeapDynamicIndexHit/main");
di.GetInterfacesAndImplementations(ifaces, dynIndexImpls);
cfg.tests.push_back(std::move(dynIndexTest));
}
// Issue #36: BLAS build options. Drives the real hardware AS-build