fix(rt): split Sponza's combined image sampler into a heap texture and sampler

examples/Sponza no longer built natively (#164). Its closest-hit declared a
descriptor_heap sampler2D, which glslang has rejected since c8253623
("Reject descriptor_heap combined image samplers"), and main.cpp wrote it
through VkResourceDescriptorDataEXT::pCombinedImageSampler, which that union
no longer has: the descriptor heap has no combined image samplers. Both went
unnoticed because nothing builds the examples.

Sponza
- closesthit.glsl declares texture2D and sampler heap arrays and joins them
  where it samples, as ui-shared.glsl and HeapDynamicIndexHit do. The
  sampler slot is a second spec constant beside the image slot, so the
  shader assumes nothing about where the host put it, and a constant index
  keeps the example running on NVIDIA 610.43.02 (see its README). The
  comment no longer says the image slot is offset by bufferStartElement;
  only buffer slots are.
- main.cpp gives the heap a sampler slot, writes the albedo as a
  SAMPLED_IMAGE from a view create-info, and writes the sampler into the
  sampler heap from a VkSamplerCreateInfo with vkWriteSamplerDescriptorsEXT,
  as UIRenderer::RegisterSampler does. SamplerVulkan's VkSampler had no use
  left. The sampler keeps its linear filtering and repeat addressing and
  drops anisotropy, which a hit shader cannot use: it samples at LOD 0,
  without derivatives.

Docs
- README.md and examples/Sponza/README.md quote the new declarations, and
  the Sponza README says why the texture and the sampler are two
  descriptors. Its texture2DArray materials pattern declared a
  descriptor_heap sampler2DArray, which glslang rejects as well; it now
  joins a texture2DArray and a sampler.
- examples/SponzaBench/README.md drops its caveat that Sponza does not
  compile.

Tests
- ExampleShaders compiles every GLSL shader under examples/ with glslang as
  crafter-build does for the example (Vulkan rules, SPIR-V 1.4, shaders/ on
  the include path, and the descriptor-set build where the example
  registers one), so a glslang that starts rejecting one fails a test
  rather than an example build nobody runs. It fails on Sponza's old
  closest-hit and needs glslang only.

Closes #164.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-10-31 08:25:52 +01:00
commit 6e94cc6209
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
7 changed files with 230 additions and 40 deletions

View file

@ -549,6 +549,15 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
fusedTest.requires_ = { "tool:glslang", "tool:spirv-val" };
cfg.tests.push_back(std::move(fusedTest));
// Issue #164: every GLSL shader under examples/ compiles. Nothing here
// builds the examples, so when glslang began rejecting Sponza's
// descriptor_heap sampler2D nothing noticed. Compiles each one as
// crafter-build would for its example, the descriptor-set build too
// where it has one. No GPU; glslang is a required tool.
Test exampleShadersTest = LibraryTest("ExampleShaders");
exampleShadersTest.requires_ = { "tool:glslang" };
cfg.tests.push_back(std::move(exampleShadersTest));
// Issue #60: VulkanBuffer::FlushDevice / FlushHost now record the chosen
// memory type's propertyFlags at Create time and skip the
// flush/invalidate when the memory is HOST_COHERENT. The gate is pure