Commit graph Crafter.Graphics/examples/Sponza
Author SHA1 Message Date
6e94cc6209
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>
2026-10-31 08:25:52 +01:00
bcdc885de8
feat(device): applications ask for the device features their shaders use
Device
- Device::Initialize(required, optional) takes DeviceFeatures, the five
  core feature structs vulkan10 to vulkan14. The library enables only what
  its own shaders and code use. Device::enabledFeatures says what was
  enabled, supportedFeatures what the GPU has, apiVersion the version in
  use.
- shaderInt16, shaderFloat16, storageBuffer16BitAccess, scalarBlockLayout
  and the uniform-buffer, storage-buffer and storage-image non-uniform
  indexing bits are no longer enabled for everyone. An application whose
  shaders take uint16_t spec constants passes
  {.vulkan10 = {.shaderInt16 = VK_TRUE}}. scalarBlockLayout stays on with
  the NVIDIA workaround, whose TLAS address may sit in a struct's tail
  padding.
- Every GPU is weighed before one is chosen: Vulkan 1.3, the swapchain and,
  below 1.4, maintenance5 extensions, the library's needs, the required
  features. One that can't run the application is skipped, saying why when
  it ranks higher. A CPU device runs it only when nothing else is listed,
  and CRAFTER_GRAPHICS_DEVICE never falls back. A GPU two drivers both list
  is tried through each.
- When no GPU qualifies, Initialize throws naming each GPU's gaps. It
  destroys the instance it made, before any Wayland connection, so it can
  be called again asking for less.
- maintenance5 is vulkan14's on a 1.4 GPU and VK_KHR_maintenance5's below.
  CRAFTER_GRAPHICS_NO_VULKAN_1_4 runs as a 1.3 application, to exercise
  that path on a 1.4 GPU.
- VK_KHR_spirv_1_4 and VK_KHR_shader_float_controls, core since 1.2, are no
  longer enabled, nor VK_EXT_shader_atomic_float, which was enabled without
  its feature struct. memoryDecompression's feature bit is queried before
  it is enabled.

Shaders
- VulkanShader checks a module's capabilities, declared directly or
  implicitly, against the enabled core features, the GPU's subgroup
  operations and the optional groups, and throws naming the field to pass,
  or saying the GPU lacks it. The tables are generated from vk.xml and
  SPIR-V's grammar.
- WorkaroundNvidiaAS::Patch sized a row-major matrix push member by its
  columns, so the TLAS address could land inside it.

Window
- The swapchain format is one whose own feature flags allow storage reads
  and writes without a format, which since Vulkan 1.3 each format says for
  itself; shaderStorageImageRead/WriteWithoutFormat are no longer required.

Tests
- DeviceFeatures: ResolveFeatures, ChooseDevice and CheckShaderCapabilities,
  without a GPU.
- FeatureRequests: required and optional features end to end, the 1.3
  path, and a retry after a refusal.
- PushConstantRewrite: a row-major mat3x4 push member.
- HeapASRead, HeapDynamicIndexHit, RTPassPushData and the ray-tracing
  examples ask for the features their shaders use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:40:02 +01:00
449d5da553
docs: where the NVIDIA descriptor-heap faults stand on 615.78.08
The heap acceleration-structure read still needs the rewrite on
615.78.08; the READMEs say so and point at HeapASRead --no-workaround
for checking a newer driver. Dynamic descriptor indexing in hit shaders
is fixed there, which the README and the Sponza and SponzaBench notes
now say, and the VulkanTriangle investigation no longer contradicts
itself about llvmpipe, which advertises VK_EXT_descriptor_heap now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 03:03:17 +02:00
42a479572d SPDX license update 2026-07-22 18:09:06 +02:00
catbot
097cc37347 feat(webgpu): HDR post-process primitives — float textures, storage-texture bindings, RESOLVE→HDR target (#27)
Adds the minimal WebGPU-backend surface an HDR bloom/post chain needs:

1. wgpuCreateStorageImage2D + StorageImage2D<>: runtime rgba16float (or
   other format) textures with STORAGE_BINDING|TEXTURE_BINDING usage, no
   CompressedTextureAsset upload — GPU-produced HDR targets.
2. UICustomBindingKind::StorageTexture (kind 5): write-only storage-texture
   binding carrying a texel format (the freed UICustomBinding::format byte),
   wired through all three binding paths (UI custom / RT / plain compute).
   Float textures already sample via SampledTexture (sampleType float).
3. PipelineRTWebGPU::Init(..., hdrOutputFormat): RESOLVE writes the linear
   accumulator into a user rgba16float texture (RTPass::outTexHandle)
   instead of the rgba8unorm canvas, leaving the composite→swapchain pass to
   the app. Default RGBA8Unorm keeps the canvas path byte-identical.

Existing RT examples updated for the _pad→format field rename; the default
paths are unchanged (verified RTStress builds + renders).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 12:55:14 +00:00
catbot
d08c7cea11 docs(vulkan-rt): document dynamic descriptor_heap-index hit-shader fault (#23)
Indexing a `layout(descriptor_heap)` array with a runtime (non-constant)
index inside a ray-tracing hit shader device-losts on NVIDIA 610.43.02,
for both SSBO and sampled-image descriptors. A constant/spec-constant
index is fine, and the same dynamic pattern works in fragment shaders, so
it's an RT-stage-specific driver fault — the same family as #7/#15
(descriptor-heap AS reads) and #21/#22 (RT recursion + compute TLAS push).

Unlike the AS-read fault, this cannot be worked around transparently: a
sampled image has no device-address escape hatch the way an acceleration
structure does (OpConvertUToAccelerationStructureKHR), and a buffer-only
buffer_reference rewrite would need a whole address-table architecture
while still leaving the texture half broken. So the resolution is the
documented-limitation path (the precedent set by #7).

Records the fault and its isolation in README's Native RT status and in
the Sponza example README (the textured-closest-hit example, which already
reads its albedo through a spec-constant slot for exactly this reason).
Documents the recommended consumer pattern: bind one resource and index
*within* it dynamically (single geometry SSBO / buffer_reference at a
spec-constant slot; one texture2DArray indexed by layer) rather than
selecting a descriptor dynamically — what the WebGPU path already does.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:05:12 +00:00
catbot
376e66aeed WebGPU RT: port Sponza to wavefront (shadow ray in SHADE)
Restructure Sponza for the wavefront model: raygen emits the primary ray;
closesthit (in SHADE) gathers albedo/normal, accumulates ambient, and
emits a shadow ray carrying the pending direct term; miss adds the sky
(primary) or the direct term (shadow miss). resolve.wgsl applies the same
Reinhard+gamma the megakernel raygen did inline. User bindings moved to
group 3 (groups 0..2 reserved). RTPass maxDepth=2.

Renders the atrium correctly through the wavefront pipeline (textures,
two-sided shading, sun+ambient, shadows, tonemap).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 20:16:04 +00:00
b5d0f52da0 webgpu sponza 2026-05-19 00:27:09 +02:00