Skip to content

Commit 4f56990

Browse files
authored
Use uint64 AS descriptor heap stride (#11494)
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))
1 parent 35d5189 commit 4f56990

8 files changed

Lines changed: 149 additions & 35 deletions

docs/command-line-slangc-reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ Specify the space index for the system defined global bindless resource array.
633633

634634
**-spirv-resource-heap-stride &lt;stride&gt;**
635635

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.
637637

638638

639639
<a id="spirv-sampler-heap-stride"></a>

docs/user-guide/03-convenience-features.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -697,14 +697,16 @@ state, and combines the objects with an `OpSampledImage` instruction.
697697
By default, when using the `spvDescriptorHeapEXT` capability, Slang reinterprets the resource or sampler
698698
heap as an array of the requested resource type, whose stride is defined by the resource type and obtained
699699
from the `OpConstantSizeOfEXT` instruction. The user can override this behavior and specify a different
700-
stride with the `-spirv-resource-heap-stride` or `-spirv-sampler-heap-stride` compiler options.
700+
stride with the `-spirv-resource-heap-stride` or `-spirv-sampler-heap-stride` compiler options. For
701+
acceleration-structure entries, an explicit resource heap stride must be at least 8 bytes.
701702

702703
> **Note on `RaytracingAccelerationStructure`:** When the `spvDescriptorHeapEXT` capability is active and
703704
> a `DescriptorHandle<RaytracingAccelerationStructure>` is dereferenced, Slang loads a 64-bit device address
704705
> from the descriptor heap and converts it to an acceleration structure handle via
705-
> `OpConvertUToAccelerationStructureKHR`. This matches how GPU drivers expose acceleration structure
706-
> descriptors in the heap (as device addresses), and requires either the `SPV_KHR_ray_tracing` or
707-
> `SPV_KHR_ray_query` extension.
706+
> `OpConvertUToAccelerationStructureKHR`. The heap entry type is `uint64_t`, so the default heap stride is
707+
> based on the address width rather than the opaque acceleration structure type. This matches how GPU
708+
> drivers expose acceleration structure descriptors in the heap (as device addresses), and requires either
709+
> the `SPV_KHR_ray_tracing` or `SPV_KHR_ray_query` extension.
708710
709711
### Custom Descriptor Fetch
710712

docs/user-guide/08-compiling.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ meanings of their `CompilerOptionValue` encodings.
10891089
| 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. |
10901090
| 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. |
10911091
| 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. |
10931093
| 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`. |
10941094
| 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. |
10951095
| 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. |

source/slang/slang-diagnostics.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5397,7 +5397,7 @@ err(
53975397
span { loc = "location", message = "SubpassInput cannot be placed inside a ParameterBlock on Metal; framebuffer fetch inputs must be direct entry-point parameters." }
53985398
)
53995399

5400-
-- SPIRV (57001-57004)
5400+
-- SPIRV (57001-57005)
54015401

54025402
warning(
54035403
"spirv-opt-failed",
@@ -5427,6 +5427,12 @@ err(
54275427
span { loc = "location", message = "output SPIR-V contains no exported symbols. Please make sure to specify at least one entrypoint." }
54285428
)
54295429

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."
5434+
)
5435+
54305436
-- GLSL Compatibility (58001-58003)
54315437

54325438
err(

source/slang/slang-emit-spirv.cpp

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4960,7 +4960,10 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
49604960
{
49614961
auto loadDesc = as<IRSPIRVLoadTexelPointerFromHeap>(inst);
49624962
auto resourceType = loadDesc->getTextureType();
4963-
auto resourceArrayType = getDescriptorRuntimeArrayType(ensureInst(resourceType));
4963+
auto descriptorElementType = ensureInst(resourceType);
4964+
auto resourceArrayType = getDescriptorRuntimeArrayType(
4965+
descriptorElementType,
4966+
getDescriptorHeapArrayStride(descriptorElementType));
49644967
auto imagePtr = emitInst(
49654968
parent,
49664969
nullptr,
@@ -6965,9 +6968,29 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
69656968
}
69666969
};
69676970
Dictionary<BuiltinSpvVarKey, SpvInst*> m_builtinGlobalVars;
6971+
struct DescriptorRuntimeArrayKey
6972+
{
6973+
SpvInst* descriptorElementType = nullptr;
6974+
int arrayStride = 0;
6975+
6976+
bool operator==(const DescriptorRuntimeArrayKey& other) const
6977+
{
6978+
return descriptorElementType == other.descriptorElementType &&
6979+
arrayStride == other.arrayStride;
6980+
}
6981+
6982+
HashCode getHashCode() const
6983+
{
6984+
return combineHash(
6985+
Slang::getHashCode(descriptorElementType),
6986+
Slang::getHashCode(arrayStride));
6987+
}
6988+
};
6989+
69686990
SpvInst* m_descriptorHeapUntypedPointerType = nullptr;
69696991
Dictionary<SpvStorageClass, SpvInst*> m_descriptorHeapBufferDescriptorTypes;
6970-
Dictionary<SpvInst*, SpvInst*> m_descriptorHeapRuntimeArrayTypes;
6992+
Dictionary<DescriptorRuntimeArrayKey, SpvInst*> m_descriptorHeapRuntimeArrayTypes;
6993+
bool m_didDiagnoseAccelerationStructureDescriptorHeapStrideTooSmall = false;
69716994

69726995

69736996
bool isInstUsedInStage(IRInst* inst, Stage s)
@@ -7140,24 +7163,40 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
71407163
return type;
71417164
}
71427165

7143-
SpvInst* getDescriptorRuntimeArrayType(SpvInst* descriptorElementType)
7166+
// Selects the configured heap stride for a non-acceleration-structure descriptor element.
7167+
// Keeping this lookup at the call site makes `getDescriptorRuntimeArrayType` consume only a
7168+
// caller-chosen stride; for example, sampler heaps use `SPIRVSamplerHeapStride`, while
7169+
// texture and buffer resource heaps use `SPIRVResourceHeapStride`.
7170+
int getDescriptorHeapArrayStride(SpvInst* descriptorElementType)
71447171
{
7145-
if (auto found = m_descriptorHeapRuntimeArrayTypes.tryGetValue(descriptorElementType))
7146-
return *found;
7147-
7148-
SpvInst* stride = nullptr;
7149-
int userDefinedStride = 0;
71507172
if (descriptorElementType->opcode == SpvOpTypeSampler)
71517173
{
7152-
userDefinedStride = m_targetProgram->getOptionSet().getIntOption(
7174+
return m_targetProgram->getOptionSet().getIntOption(
71537175
CompilerOptionName::SPIRVSamplerHeapStride);
71547176
}
7155-
else
7156-
{
7157-
userDefinedStride = m_targetProgram->getOptionSet().getIntOption(
7158-
CompilerOptionName::SPIRVResourceHeapStride);
7159-
}
7160-
if (userDefinedStride == 0)
7177+
7178+
return m_targetProgram->getOptionSet().getIntOption(
7179+
CompilerOptionName::SPIRVResourceHeapStride);
7180+
}
7181+
7182+
// Builds or reuses the descriptor runtime array for a specific element type and stride.
7183+
// A zero stride emits an `ArrayStrideIdEXT` from `OpConstantSizeOfEXT` for descriptor-typed
7184+
// resources, while acceleration-structure heap entries pass the explicit `uint64` stride
7185+
// computed by `getAccelerationStructureDescriptorHeapStride`.
7186+
SpvInst* getDescriptorRuntimeArrayType(SpvInst* descriptorElementType, int arrayStride)
7187+
{
7188+
SLANG_RELEASE_ASSERT(
7189+
descriptorElementType->opcode != SpvOpTypeAccelerationStructureKHR &&
7190+
"acceleration structure descriptor heaps must use uint64 elements");
7191+
7192+
DescriptorRuntimeArrayKey key;
7193+
key.descriptorElementType = descriptorElementType;
7194+
key.arrayStride = arrayStride;
7195+
if (auto found = m_descriptorHeapRuntimeArrayTypes.tryGetValue(key))
7196+
return *found;
7197+
7198+
SpvInst* stride = nullptr;
7199+
if (arrayStride == 0)
71617200
{
71627201
IRBuilder builder(m_irModule);
71637202
builder.setInsertInto(m_irModule->getModuleInst());
@@ -7166,7 +7205,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
71667205
}
71677206

71687207
auto runtimeArrayType = emitOpTypeRuntimeArray(nullptr, descriptorElementType);
7169-
m_descriptorHeapRuntimeArrayTypes[descriptorElementType] = runtimeArrayType;
7208+
m_descriptorHeapRuntimeArrayTypes[key] = runtimeArrayType;
71707209

71717210
if (stride)
71727211
{
@@ -7182,23 +7221,62 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
71827221
getSection(SpvLogicalSectionID::Annotations),
71837222
nullptr,
71847223
runtimeArrayType,
7185-
SpvLiteralInteger::from32(userDefinedStride));
7224+
SpvLiteralInteger::from32(arrayStride));
71867225
}
71877226
return runtimeArrayType;
71887227
}
71897228

7229+
int getAccelerationStructureDescriptorHeapStride()
7230+
{
7231+
static const int kAccelerationStructureDescriptorHeapStride = 8;
7232+
7233+
auto userDefinedStride = m_targetProgram->getOptionSet().getIntOption(
7234+
CompilerOptionName::SPIRVResourceHeapStride);
7235+
if (userDefinedStride == 0)
7236+
{
7237+
userDefinedStride = kAccelerationStructureDescriptorHeapStride;
7238+
}
7239+
else if (userDefinedStride < kAccelerationStructureDescriptorHeapStride)
7240+
{
7241+
if (!m_didDiagnoseAccelerationStructureDescriptorHeapStrideTooSmall)
7242+
{
7243+
m_sink->diagnose(Diagnostics::SpirvResourceHeapStrideTooSmall{
7244+
.stride = userDefinedStride,
7245+
.minimumStride = kAccelerationStructureDescriptorHeapStride,
7246+
});
7247+
m_didDiagnoseAccelerationStructureDescriptorHeapStrideTooSmall = true;
7248+
}
7249+
userDefinedStride = kAccelerationStructureDescriptorHeapStride;
7250+
}
7251+
7252+
return userDefinedStride;
7253+
}
7254+
71907255
SpvInst* getDescriptorHeapBaseType(IRType* valueType, bool* outIsBufferResource = nullptr)
71917256
{
71927257
SpvInst* descriptorElementType = nullptr;
71937258
bool isBufferResource = false;
71947259
switch (valueType->getOp())
71957260
{
71967261
case kIROp_TextureType:
7197-
case kIROp_RaytracingAccelerationStructureType:
71987262
case kIROp_SamplerStateType:
71997263
case kIROp_SamplerComparisonStateType:
72007264
descriptorElementType = ensureInst(valueType);
72017265
break;
7266+
case kIROp_RaytracingAccelerationStructureType:
7267+
{
7268+
if (outIsBufferResource)
7269+
*outIsBufferResource = false;
7270+
7271+
IRBuilder builder(m_irModule);
7272+
builder.setInsertInto(m_irModule->getModuleInst());
7273+
7274+
// Acceleration structure heap entries are 64-bit device addresses that are
7275+
// converted to acceleration structure handles after loading.
7276+
descriptorElementType = ensureInst(builder.getUInt64Type());
7277+
auto arrayStride = getAccelerationStructureDescriptorHeapStride();
7278+
return getDescriptorRuntimeArrayType(descriptorElementType, arrayStride);
7279+
}
72027280
default:
72037281
isBufferResource = true;
72047282
descriptorElementType = ensureDescriptorHeapBufferDescriptorType(
@@ -7209,7 +7287,8 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
72097287
if (outIsBufferResource)
72107288
*outIsBufferResource = isBufferResource;
72117289

7212-
return getDescriptorRuntimeArrayType(descriptorElementType);
7290+
auto arrayStride = getDescriptorHeapArrayStride(descriptorElementType);
7291+
return getDescriptorRuntimeArrayType(descriptorElementType, arrayStride);
72137292
}
72147293

72157294
SpvInst* emitAccelerationStructureFromDescriptorHeap(

source/slang/slang-options.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,11 @@ void initCommandOptions(CommandOptions& options)
915915
"-spirv-resource-heap-stride",
916916
"-spirv-resource-heap-stride <stride>",
917917
"Specify the byte stride for the resource descriptor heap when generating SPIRV with "
918-
"spvDescriptorHeapEXT. Defaults to 0, which will use OpConstantSizeOfEXT(ResourceType)."},
918+
"spvDescriptorHeapEXT. Defaults to 0, which will use OpConstantSizeOfEXT(ResourceType); "
919+
"for RaytracingAccelerationStructure entries, the 0 default emits a literal 8-byte "
920+
"ArrayStride for the uint64 device address elements. An explicit stride value still "
921+
"overrides these defaults; for acceleration-structure entries it must be at least 8 "
922+
"bytes."},
919923
{OptionKind::SPIRVSamplerHeapStride,
920924
"-spirv-sampler-heap-stride",
921925
"-spirv-sampler-heap-stride <stride>",

tests/spirv/descriptor-heap-acceleration-structure-raygen.slang

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
// Exercises the RayTracingKHR branch of requireSPIRVAnyCapability when
33
// loading a RaytracingAccelerationStructure from a descriptor heap in a
44
// raygeneration shader (which already requires SpvCapabilityRayTracingKHR).
5-
//TEST:SIMPLE(filecheck=CHECK): -target spirv-asm -stage raygeneration -entry rayGenMain -profile sm_6_6 -capability spvDescriptorHeapEXT -spirv-resource-heap-stride 32
5+
//TEST:SIMPLE(filecheck=CHECK): -target spirv-asm -stage raygeneration -entry rayGenMain -profile sm_6_6 -capability spvDescriptorHeapEXT
6+
//TEST:SIMPLE(filecheck=OVERRIDE): -target spirv-asm -stage raygeneration -entry rayGenMain -profile sm_6_6 -capability spvDescriptorHeapEXT -spirv-resource-heap-stride 32
67

78
struct PushConstants
89
{
@@ -20,8 +21,12 @@ void rayGenMain(uniform PushConstants pushConstants)
2021
{
2122
// CHECK-DAG: %[[U64:[A-Za-z0-9_]+]] = OpTypeInt 64 0
2223
// CHECK-DAG: %[[AS_TYPE:[A-Za-z0-9_]+]] = OpTypeAccelerationStructureKHR
23-
// CHECK-DAG: %[[AS_HEAP_ARRAY:[A-Za-z0-9_]+]] = OpTypeRuntimeArray %[[AS_TYPE]]
24-
// CHECK-DAG: OpDecorate %[[AS_HEAP_ARRAY]] ArrayStride 32
24+
// CHECK-DAG: %[[AS_HEAP_ARRAY:[A-Za-z0-9_]+]] = OpTypeRuntimeArray %[[U64]]
25+
// CHECK-DAG: OpDecorate %[[AS_HEAP_ARRAY]] ArrayStride 8
26+
// OVERRIDE-DAG: %[[OVERRIDE_U64:[A-Za-z0-9_]+]] = OpTypeInt 64 0
27+
// OVERRIDE-DAG: %[[OVERRIDE_AS_TYPE:[A-Za-z0-9_]+]] = OpTypeAccelerationStructureKHR
28+
// OVERRIDE-DAG: %[[OVERRIDE_AS_HEAP_ARRAY:[A-Za-z0-9_]+]] = OpTypeRuntimeArray %[[OVERRIDE_U64]]
29+
// OVERRIDE-DAG: OpDecorate %[[OVERRIDE_AS_HEAP_ARRAY]] ArrayStride 32
2530
// CHECK-DAG: OpCapability RayTracingKHR
2631
// CHECK: OpUntypedAccessChainKHR %_ptr_UniformConstant %[[AS_HEAP_ARRAY]] %slang_resourceHeap
2732
// CHECK-NEXT: %[[AS_ADDR:[A-Za-z0-9_]+]] = OpLoad %[[U64]]

tests/spirv/descriptor-heap-acceleration-structure.slang

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
// Regression test for GitHub issue #10671.
2-
//TEST:SIMPLE(filecheck=CHECK): -target spirv-asm -stage compute -entry computeMain -profile sm_6_6 -capability spvDescriptorHeapEXT -capability spvRayQueryKHR -spirv-resource-heap-stride 32
1+
// Regression test for GitHub issues #10671 and #11231.
2+
//TEST:SIMPLE(filecheck=CHECK): -target spirv-asm -stage compute -entry computeMain -profile sm_6_6 -capability spvDescriptorHeapEXT -capability spvRayQueryKHR
3+
//TEST:SIMPLE(filecheck=OVERRIDE): -target spirv-asm -stage compute -entry computeMain -profile sm_6_6 -capability spvDescriptorHeapEXT -capability spvRayQueryKHR -spirv-resource-heap-stride 32
4+
//TEST:SIMPLE(filecheck=TOO_SMALL): -target spirv-asm -stage compute -entry computeMain -profile sm_6_6 -capability spvDescriptorHeapEXT -capability spvRayQueryKHR -spirv-resource-heap-stride 4
5+
// TOO_SMALL-NOT: ArrayStride 4
6+
// 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
8+
// TOO_SMALL-NOT: ArrayStride 4
39

410
struct PushConstants
511
{
612
DescriptorHandle<RaytracingAccelerationStructure> accelerationStructure;
13+
DescriptorHandle<RaytracingAccelerationStructure> secondaryAccelerationStructure;
714
DescriptorHandle<RWTexture2D<float4>> outputTexture;
815
}
916

@@ -39,8 +46,12 @@ void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID, uniform PushConsta
3946
{
4047
// CHECK-DAG: %[[U64:[A-Za-z0-9_]+]] = OpTypeInt 64 0
4148
// CHECK-DAG: %[[AS_TYPE:[A-Za-z0-9_]+]] = OpTypeAccelerationStructureKHR
42-
// CHECK-DAG: %[[AS_HEAP_ARRAY:[A-Za-z0-9_]+]] = OpTypeRuntimeArray %[[AS_TYPE]]
43-
// CHECK-DAG: OpDecorate %[[AS_HEAP_ARRAY]] ArrayStride 32
49+
// CHECK-DAG: %[[AS_HEAP_ARRAY:[A-Za-z0-9_]+]] = OpTypeRuntimeArray %[[U64]]
50+
// CHECK-DAG: OpDecorate %[[AS_HEAP_ARRAY]] ArrayStride 8
51+
// OVERRIDE-DAG: %[[OVERRIDE_U64:[A-Za-z0-9_]+]] = OpTypeInt 64 0
52+
// OVERRIDE-DAG: %[[OVERRIDE_AS_TYPE:[A-Za-z0-9_]+]] = OpTypeAccelerationStructureKHR
53+
// OVERRIDE-DAG: %[[OVERRIDE_AS_HEAP_ARRAY:[A-Za-z0-9_]+]] = OpTypeRuntimeArray %[[OVERRIDE_U64]]
54+
// OVERRIDE-DAG: OpDecorate %[[OVERRIDE_AS_HEAP_ARRAY]] ArrayStride 32
4455
// CHECK-DAG: OpCapability RayQueryKHR
4556
// CHECK: OpUntypedAccessChainKHR %_ptr_UniformConstant %[[AS_HEAP_ARRAY]] %slang_resourceHeap
4657
// CHECK-NEXT: %[[AS_ADDR:[A-Za-z0-9_]+]] = OpLoad %[[U64]]
@@ -53,6 +64,13 @@ void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID, uniform PushConsta
5364
float3(0.0, 0.0, 1.0),
5465
t);
5566

67+
float secondaryT = 0.0;
68+
traceRayClosestHit(
69+
RaytracingAccelerationStructure(pushConstants.secondaryAccelerationStructure),
70+
float3(0.2, 0.2, 0.0),
71+
float3(0.0, 0.0, 1.0),
72+
secondaryT);
73+
5674
RWTexture2D<float4> outputTexture = pushConstants.outputTexture;
57-
outputTexture[dispatchThreadID.xy] = t;
75+
outputTexture[dispatchThreadID.xy] = t + secondaryT;
5876
}

0 commit comments

Comments
 (0)