You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes#11231
## Motivation
`DescriptorHandle<RaytracingAccelerationStructure>` descriptor-heap
loads are materialized as 64-bit device-address loads followed by
`OpConvertUToAccelerationStructureKHR`. The AS-specific load path is
selected before the ordinary descriptor heap load at
`source/slang/slang-emit-spirv.cpp:4920`, and
`emitAccelerationStructureFromDescriptorHeap` emits the access chain,
`uint64` load, and conversion at
`source/slang/slang-emit-spirv.cpp:7206`,
`source/slang/slang-emit-spirv.cpp:7215`, and
`source/slang/slang-emit-spirv.cpp:7219`.
Before this PR, the descriptor heap base type for acceleration
structures could still be an `OpTypeAccelerationStructureKHR` runtime
array. That made the access-chain stride describe the opaque
acceleration-structure type while the actual heap load consumed an
8-byte device address. Nonzero heap indices could therefore address the
wrong heap entry unless users pinned `-spirv-resource-heap-stride`.
A minimal motivating shader is:
```slang
DescriptorHandle<RaytracingAccelerationStructure> accelerationStructure;
RaytracingAccelerationStructure scene =
RaytracingAccelerationStructure(accelerationStructure);
```
## Proposed solution
Route `kIROp_RaytracingAccelerationStructureType` through the shared
descriptor runtime-array helper with a caller-computed AS stride.
`getDescriptorHeapBaseType` now materializes AS heap entries as `uint64`
elements at `source/slang/slang-emit-spirv.cpp:7175`, computes the AS
stride with `getAccelerationStructureDescriptorHeapStride`, and calls
`getDescriptorRuntimeArrayType` with that explicit stride.
The shared helper builds an `OpTypeRuntimeArray` whose element type is
`uint64` for AS heap entries, matching the device address that is
actually loaded. A zero `SPIRVResourceHeapStride` becomes a
caller-supplied literal 8-byte `ArrayStride` for AS heap entries; a
nonzero stride is still honored when it is at least 8 bytes. Undersized
explicit AS strides are diagnosed once per emit context and clamped
internally so Slang does not emit invalid SPIR-V.
This is a SPIR-V emission fix rather than a front-end or IR producer fix
because the AS descriptor-handle input shape is valid: descriptor-heap
AS entries are represented as device addresses and converted after
loading. The incorrect layer was the SPIR-V heap array type used for the
access chain.
## Change summary
- `source/slang/slang-emit-spirv.cpp:7077`: adds
`getDescriptorHeapArrayStride`, so non-AS descriptor heap call sites
calculate the resource/sampler stride before calling the runtime-array
helper.
- `source/slang/slang-emit-spirv.cpp:7089`: makes
`getDescriptorRuntimeArrayType` take an explicit stride and cache
runtime arrays by both descriptor element type and stride, while
preserving the existing `OpConstantSizeOfEXT(ResourceType)` path when
the caller passes zero.
- `source/slang/slang-emit-spirv.cpp:7141`: adds
`getAccelerationStructureDescriptorHeapStride`, which applies the 8-byte
AS default stride and validates explicit AS strides without repeating
the diagnostic for every AS heap load.
- `source/slang/slang-emit-spirv.cpp:7175`: routes
`kIROp_RaytracingAccelerationStructureType` to a `uint64` heap element
type and the shared descriptor-array path with the AS stride override.
- `source/slang/slang-diagnostics.lua:5258`: adds diagnostic `E57005`
for explicit AS resource heap strides smaller than the fixed 8-byte
entry width.
- `source/slang/slang-options.cpp:882`,
`docs/command-line-slangc-reference.md:611`,
`docs/user-guide/03-convenience-features.md:697`, and
`docs/user-guide/08-compiling.md:1092`: document the AS-specific
zero-stride behavior, the explicit override behavior, and the 8-byte
minimum.
- `tests/spirv/descriptor-heap-acceleration-structure.slang:2`: covers
the RayQueryKHR compute path for the default 8-byte stride, an explicit
32-byte override, rejection of a 4-byte stride, single-diagnostic
behavior with multiple AS heap loads, and verifies the rejected stride
is not emitted as `ArrayStride 4`.
- `tests/spirv/descriptor-heap-acceleration-structure-raygen.slang:5`:
covers the RayTracingKHR raygeneration path for the default 8-byte
stride and explicit 32-byte override.
## Concepts and vocabulary
- Descriptor heap: the `spvDescriptorHeapEXT` global resource or sampler
heap that `DescriptorHandle<T>` indexes with `OpUntypedAccessChainKHR`.
- AS heap entry: a `RaytracingAccelerationStructure` descriptor heap
entry represented as a 64-bit device address, then converted to the
opaque acceleration-structure handle with
`OpConvertUToAccelerationStructureKHR`.
- `ArrayStrideIdEXT`: the descriptor-heap stride decoration path that
uses `OpConstantSizeOfEXT(ResourceType)` for descriptor-typed runtime
arrays.
- Literal `ArrayStride`: the fixed numeric stride decoration used for
the AS `uint64` runtime array because its element type is a plain
integer device address, not a descriptor type.
## Process report
The code trace starts at `kIROp_SPIRVLoadDescriptorFromHeap`: AS loads
are detected at `source/slang/slang-emit-spirv.cpp:4920` and dispatched
to `emitAccelerationStructureFromDescriptorHeap`. That function
constructs an access chain from `getDescriptorHeapBaseType`, then
performs `OpLoad %uint64` and `OpConvertUToAccelerationStructureKHR` at
`source/slang/slang-emit-spirv.cpp:7212`,
`source/slang/slang-emit-spirv.cpp:7215`, and
`source/slang/slang-emit-spirv.cpp:7219`. The access-chain base type
therefore must have the same element width as the value being loaded. A
runtime array of opaque AS handles is the wrong representation for this
heap path; a runtime array of `uint64` device addresses is the
representation that matches the later load and conversion.
The AS special case is represented as a caller-computed literal stride
passed to `getDescriptorRuntimeArrayType`: descriptor-typed resources
still use `OpConstantSizeOfEXT(ResourceType)` through `ArrayStrideIdEXT`
when their call site passes zero, while AS heap entries pass an explicit
stride because their heap element is a `uint64` device address rather
than the opaque AS descriptor type. The explicit `SLANG_RELEASE_ASSERT`
at `source/slang/slang-emit-spirv.cpp:7091` documents that boundary and
makes a future accidental AS fallthrough fail close to the cause.
The input-shape check is intentional:
`DescriptorHandle<RaytracingAccelerationStructure>` under
`spvDescriptorHeapEXT` is a valid input shape, and the producer should
continue to express an acceleration-structure value at the source level.
The layer that knows the SPIR-V heap entry is a device address is the
SPIR-V emitter, specifically
`emitAccelerationStructureFromDescriptorHeap`; that is why the fix
belongs in the descriptor heap base-type selection and not in the
front-end type producer.
Explicit stride validation is added because the AS heap entry width is
statically known to be 8 bytes. A nonzero stride below 8 cannot safely
index a `uint64` runtime array, so
`getAccelerationStructureDescriptorHeapStride` diagnoses it at
`source/slang/slang-emit-spirv.cpp:7155` using `E57005` from
`source/slang/slang-diagnostics.lua:5258`, then clamps the internal
emission value to 8 to avoid producing invalid SPIR-V after reporting
the error. The diagnostic is gated by
`m_didDiagnoseAccelerationStructureDescriptorHeapStrideTooSmall`, so
shaders with multiple AS heap loads report the option error once while
still clamping every load path. The compute and raygen regression tests
pin the default and override shapes, and the compute test also pins the
undersized-stride diagnostic, verifies `ArrayStride 4` is not emitted,
and verifies the diagnostic is not repeated for the second AS heap load.
## Reviewer Directives (maintained by agent)
- [human @jkwak-work] Keep `arrayStride` calculation at descriptor-heap
call sites; `getDescriptorRuntimeArrayType` should accept a
caller-provided stride rather than reading compiler options or using
special-case defaults internally.
(#11494 (comment))
Copy file name to clipboardExpand all lines: docs/command-line-slangc-reference.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -633,7 +633,7 @@ Specify the space index for the system defined global bindless resource array.
633
633
634
634
**-spirv-resource-heap-stride <stride>**
635
635
636
-
Specify the byte stride for the resource descriptor heap when generating SPIRV with spvDescriptorHeapEXT. Defaults to 0, which will use OpConstantSizeOfEXT(ResourceType).
636
+
Specify the byte stride for the resource descriptor heap when generating SPIRV with spvDescriptorHeapEXT. Defaults to 0, which will use OpConstantSizeOfEXT(ResourceType); for RaytracingAccelerationStructure entries, the 0 default emits a literal 8-byte ArrayStride for the uint64 device address elements. An explicit stride value still overrides these defaults; for acceleration-structure entries it must be at least 8 bytes.
Copy file name to clipboardExpand all lines: docs/user-guide/08-compiling.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1089,7 +1089,7 @@ meanings of their `CompilerOptionValue` encodings.
1089
1089
| GenerateWholeProgram | When set will emit target code for the entire program instead of for a specific entry point. `intValue0` specifies a bool value for the setting. |
1090
1090
| UseUpToDateBinaryModule | When set will only load precompiled modules if it is up-to-date with its source. `intValue0` specifies a bool value for the setting. |
1091
1091
| ValidateUniformity | When set will perform [uniformity analysis](a1-05-uniformity.md).|
1092
-
| SPIRVResourceHeapStride | Specifies the byte stride for the resource descriptor heap when generating SPIR-V with `spvDescriptorHeapEXT`. `intValue0` encodes the stride in bytes; use 0 to let the driver compute the stride via `OpConstantSizeOfEXT`. |
1092
+
| SPIRVResourceHeapStride | Specifies the byte stride for the resource descriptor heap when generating SPIR-V with `spvDescriptorHeapEXT`. `intValue0` encodes the stride in bytes; use 0 to emit `OpConstantSizeOfEXT(ResourceType)` as the default stride. For `RaytracingAccelerationStructure` entries, the 0 default emits a literal 8-byte `ArrayStride` for the `uint64` device address elements; explicit stride values still override these defaults, but must be at least 8 bytes for acceleration-structure entries. |
1093
1093
| SPIRVSamplerHeapStride | Specifies the byte stride for the sampler descriptor heap when generating SPIR-V with `spvDescriptorHeapEXT`. `intValue0` encodes the stride in bytes; use 0 to let the driver compute the stride via `OpConstantSizeOfEXT`. |
1094
1094
| ForceDXLayout | When set forces the compiler to use DirectX-compatible (HLSL register packing) rules when laying out buffer struct fields during code generation. `intValue0` specifies a bool value for the setting. |
1095
1095
| ForceCLayout | When set forces the compiler to use C struct layout rules (natural alignment, no HLSL/GLSL padding) when laying out buffer struct fields during code generation. `intValue0` specifies a bool value for the setting. |
Copy file name to clipboardExpand all lines: source/slang/slang-diagnostics.lua
+7-1Lines changed: 7 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -5397,7 +5397,7 @@ err(
5397
5397
span { loc="location", message="SubpassInput cannot be placed inside a ParameterBlock on Metal; framebuffer fetch inputs must be direct entry-point parameters." }
5398
5398
)
5399
5399
5400
-
-- SPIRV (57001-57004)
5400
+
-- SPIRV (57001-57005)
5401
5401
5402
5402
warning(
5403
5403
"spirv-opt-failed",
@@ -5427,6 +5427,12 @@ err(
5427
5427
span { loc="location", message="output SPIR-V contains no exported symbols. Please make sure to specify at least one entrypoint." }
5428
5428
)
5429
5429
5430
+
err(
5431
+
"spirv-resource-heap-stride-too-small",
5432
+
57005,
5433
+
"SPIR-V resource heap stride '~stride:Int' is too small for RaytracingAccelerationStructure descriptor heap entries; expected at least '~minimumStride:Int' bytes."
// TOO_SMALL: error[E57005]: SPIR-V resource heap stride '4' is too small for RaytracingAccelerationStructure descriptor heap entries; expected at least '8' bytes.
7
+
// TOO_SMALL-NOT: SPIR-V resource heap stride '4' is too small
0 commit comments