diff options
| author | Yong He <yonghe@outlook.com> | 2023-10-02 03:33:58 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-02 18:33:58 +0800 |
| commit | ccf2611c024ab12dcccd978f3f501d4ee9fc52bc (patch) | |
| tree | f4df843e3b46886005d6bfbae34dc3bcc6fb8321 | |
| parent | 6138de5f084cafdc98381237c2d8bed7c8804f1c (diff) | |
Add SPIRV intrinsics for ShaderExecutionReordering and RW/Buffer. (#3252)
* Add SPIRV intrinsics for ShaderExecutionReordering.
* Add intrinsics for `Buffer` and `RWBuffer`.
* Various spirv fixes.
* Marshal bool vector type.
* Inline global constants + OpFOrdNotEqual->OpFUnordNotEqual.
* Fix.
---------
Co-authored-by: Yong He <yhe@nvidia.com>
24 files changed, 1123 insertions, 369 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 49fcbe346..5eb08e980 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -7132,35 +7132,75 @@ for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) sb << "struct "; sb << kBaseBufferAccessLevels[aa].name; sb << "Buffer {\n"; - sb << "[__readNone]\n"; - sb << "void GetDimensions(out uint dim);\n"; + char const* glslTextureSizeFunc = (access == SLANG_RESOURCE_ACCESS_READ) ? "textureSize" : "imageSize"; char const* glslLoadFuncName = (access == SLANG_RESOURCE_ACCESS_READ) ? "texelFetch" : "imageLoad"; + char const* spvLoadInstName = (access == SLANG_RESOURCE_ACCESS_READ) ? "OpImageFetch" : "OpImageRead"; +}}}} + [__readNone] + void GetDimensions(out uint dim) + { + __target_switch + { + case hlsl: __intrinsic_asm ".GetDimensions"; + case glsl: __intrinsic_asm "($1 = $(glslTextureSizeFunc)($0))"; + case spirv: + dim = spirv_asm { + OpCapability ImageQuery; + result:$$uint = OpImageQuerySize $this; + }; + } + } - sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)"; - sb << "__target_intrinsic(glsl, \"" << glslLoadFuncName << "($0, $1)$z\")\n"; - if (isReadOnly) sb << "[__readNone]\n"; - sb << "T Load(int location);\n"; + __glsl_extension(GL_EXT_samplerless_texture_functions) + $(isReadOnly?"[__readNone] ":"") + T Load(int location) + { + __target_switch + { + case hlsl: __intrinsic_asm ".Load"; + case glsl: __intrinsic_asm "$(glslLoadFuncName)($0, $1)$z"; + case spirv: return spirv_asm { + %sampled:__sampledType(T) = $(spvLoadInstName) $this $location; + __truncate $$T result __sampledType(T) %sampled; + }; + } + } - if (isReadOnly) sb << "[__readNone]\n"; - sb << "T Load(int location, out uint status);\n"; + $(isReadOnly?"[__readNone] ":"") + T Load(int location, out uint status); - sb << "__subscript(uint index) -> T {\n"; + __subscript(uint index) -> T { - if (isReadOnly) sb << "[__readNone]\n"; - sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)"; - sb << "__target_intrinsic(glsl, \"" << glslLoadFuncName << "($0, int($1))$z\") get;\n"; + $(isReadOnly?"[__readNone] ":"") + [ForceInline] + get { return Load((int)index); } +${{{{ + if (access != SLANG_RESOURCE_ACCESS_READ) { +}}}} + [nonmutating] set + { + __target_switch + { + case hlsl: __intrinsic_asm "($0)[$1] = $2"; + case glsl: __intrinsic_asm "imageStore($0, int($1), $V2)"; + case spirv: spirv_asm { + OpImageWrite $this $index $newValue; + }; + } + } - if (access != SLANG_RESOURCE_ACCESS_READ) - { - sb << "__target_intrinsic(glsl, \"imageStore($0, int($1), $V2)\") [nonmutating] set;\n"; + __intrinsic_op($(kIROp_ImageSubscript)) + ref; +${{{{ + } // access != SLANG_RESOURCE_ACCESS_READ +}}}} - sb << "__intrinsic_op(" << int(kIROp_ImageSubscript) << ") ref;\n"; } + - sb << "}\n"; - - sb << "};\n"; + }; +${{{{ } }}}} @@ -8595,6 +8635,13 @@ Ref<T> __hitObjectAttributes<T>() static T t; return t; } +[ForceInline] +Ptr<T> __allocHitObjectAttributes<T>() +{ + [__vulkanHitObjectAttributes] + static T t; + return &t; +} // Next is the custom intrinsic that will compute the hitObjectAttributes location // for GLSL-based targets. @@ -8618,7 +8665,7 @@ struct HitObject /// Executes ray traversal (including anyhit and intersection shaders) like TraceRay, but returns the /// resulting hit information as a HitObject and does not trigger closesthit or miss shaders. - __specialized_for_target(hlsl) + [ForceInline] static HitObject TraceRay<payload_t>( RaytracingAccelerationStructure AccelerationStructure, uint RayFlags, @@ -8629,60 +8676,85 @@ struct HitObject RayDesc Ray, inout payload_t Payload) { - HitObject hitObj; - __hlslTraceRay( - AccelerationStructure, - RayFlags, - InstanceInclusionMask, - RayContributionToHitGroupIndex, - MultiplierForGeometryContributionToHitGroupIndex, - MissShaderIndex, - Ray, - Payload, - hitObj); - return hitObj; - } - - [ForceInline] - __specialized_for_target(glsl) - static HitObject TraceRay<payload_t>( - RaytracingAccelerationStructure AccelerationStructure, - uint RayFlags, - uint InstanceInclusionMask, - uint RayContributionToHitGroupIndex, - uint MultiplierForGeometryContributionToHitGroupIndex, - uint MissShaderIndex, - RayDesc Ray, - inout payload_t Payload) - { - [__vulkanRayPayload] - static payload_t p; - - // Save the payload - p = Payload; - - __glslTraceRay( - __return_val, - AccelerationStructure, - RayFlags, // Assumes D3D/VK have some RayFlags values - InstanceInclusionMask, // cullMask - RayContributionToHitGroupIndex, // sbtRecordOffset - MultiplierForGeometryContributionToHitGroupIndex, // sbtRecordStride - MissShaderIndex, - Ray.Origin, - Ray.TMin, - Ray.Direction, - Ray.TMax, - __rayPayloadLocation(p)); + __target_switch + { + case hlsl: + { + HitObject hitObj; + __hlslTraceRay( + AccelerationStructure, + RayFlags, + InstanceInclusionMask, + RayContributionToHitGroupIndex, + MultiplierForGeometryContributionToHitGroupIndex, + MissShaderIndex, + Ray, + Payload, + hitObj); + return hitObj; + } + case glsl: + { + [__vulkanRayPayload] + static payload_t p; + + // Save the payload + p = Payload; + + __glslTraceRay( + __return_val, + AccelerationStructure, + RayFlags, // Assumes D3D/VK have some RayFlags values + InstanceInclusionMask, // cullMask + RayContributionToHitGroupIndex, // sbtRecordOffset + MultiplierForGeometryContributionToHitGroupIndex, // sbtRecordStride + MissShaderIndex, + Ray.Origin, + Ray.TMin, + Ray.Direction, + Ray.TMax, + __rayPayloadLocation(p)); - // Write the payload out - Payload = p; + // Write the payload out + Payload = p; + } + case spirv: + { + [__vulkanRayPayload] + static payload_t p; + + // Save the payload + p = Payload; + + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpHitObjectTraceRayNV + /**/ &__return_val + /**/ $AccelerationStructure + /**/ $RayFlags + /**/ $InstanceInclusionMask + /**/ $RayContributionToHitGroupIndex + /**/ $MultiplierForGeometryContributionToHitGroupIndex + /**/ $MissShaderIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax + /**/ &p; + }; + + // Write the payload out + Payload = p; + } + } } /// Executes motion ray traversal (including anyhit and intersection shaders) like TraceRay, but returns the /// resulting hit information as a HitObject and does not trigger closesthit or miss shaders. [ForceInline] - __specialized_for_target(glsl) static HitObject TraceMotionRay<payload_t>( RaytracingAccelerationStructure AccelerationStructure, uint RayFlags, @@ -8694,29 +8766,72 @@ struct HitObject float CurrentTime, inout payload_t Payload) { - [__vulkanRayPayload] - static payload_t p; - - // Save the payload - p = Payload; - - __glslTraceMotionRay( - __return_val, - AccelerationStructure, - RayFlags, // Assumes D3D/VK have some RayFlags values - InstanceInclusionMask, // cullMask - RayContributionToHitGroupIndex, // sbtRecordOffset - MultiplierForGeometryContributionToHitGroupIndex, // sbtRecordStride - MissShaderIndex, - Ray.Origin, - Ray.TMin, - Ray.Direction, - Ray.TMax, - CurrentTime, - __rayPayloadLocation(p)); + __target_switch + { + case hlsl: + __intrinsic_asm "TraceMotionRay"; + case glsl: + { + [__vulkanRayPayload] + static payload_t p; + + // Save the payload + p = Payload; + + __glslTraceMotionRay( + __return_val, + AccelerationStructure, + RayFlags, // Assumes D3D/VK have some RayFlags values + InstanceInclusionMask, // cullMask + RayContributionToHitGroupIndex, // sbtRecordOffset + MultiplierForGeometryContributionToHitGroupIndex, // sbtRecordStride + MissShaderIndex, + Ray.Origin, + Ray.TMin, + Ray.Direction, + Ray.TMax, + CurrentTime, + __rayPayloadLocation(p)); + + // Write the payload out + Payload = p; + } + case spirv: + { + [__vulkanRayPayload] + static payload_t p; + + // Save the payload + p = Payload; + + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpCapability RayTracingMotionBlurNV; + OpExtension "SPV_NV_ray_tracing_motion_blur"; + OpHitObjectTraceRayMotionNV + /**/ &__return_val + /**/ $AccelerationStructure + /**/ $RayFlags + /**/ $InstanceInclusionMask + /**/ $RayContributionToHitGroupIndex + /**/ $MultiplierForGeometryContributionToHitGroupIndex + /**/ $MissShaderIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax + /**/ $CurrentTime + /**/ &p; + }; + + // Write the payload out + Payload = p; + } + } - // Write the payload out - Payload = p; } /// Creates a HitObject representing a hit based on values explicitly passed as arguments, without @@ -8725,7 +8840,7 @@ struct HitObject /// TraceRay. The computed index must reference a valid hit group record in the shader table. The /// Attributes parameter must either be an attribute struct, such as /// BuiltInTriangleIntersectionAttributes, or another HitObject to copy the attributes from. - __specialized_for_target(hlsl) + [ForceInline] static HitObject MakeHit<attr_t>( RaytracingAccelerationStructure AccelerationStructure, uint InstanceIndex, @@ -8737,59 +8852,78 @@ struct HitObject RayDesc Ray, attr_t attributes) { - HitObject hitObj; - __hlslMakeHit( - AccelerationStructure, - InstanceIndex, - GeometryIndex, - PrimitiveIndex, - HitKind, - RayContributionToHitGroupIndex, - MultiplierForGeometryContributionToHitGroupIndex, - Ray, - attributes, - hitObj); - return hitObj; - } - - [ForceInline] - __specialized_for_target(glsl) - static HitObject MakeHit<attr_t>( - RaytracingAccelerationStructure AccelerationStructure, - uint InstanceIndex, - uint GeometryIndex, - uint PrimitiveIndex, - uint HitKind, - uint RayContributionToHitGroupIndex, - uint MultiplierForGeometryContributionToHitGroupIndex, - RayDesc Ray, - attr_t attributes) - { - // Save the attributes - __ref attr_t attr = __hitObjectAttributes<attr_t>(); - - attr = attributes; - - __glslMakeHit( - __return_val, - AccelerationStructure, - InstanceIndex, - PrimitiveIndex, - GeometryIndex, - HitKind, - RayContributionToHitGroupIndex, /// sbtRecordOffset? - MultiplierForGeometryContributionToHitGroupIndex, /// sbtRecordStride? - Ray.Origin, - Ray.TMin, - Ray.Direction, - Ray.TMax, - __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + __target_switch + { + case hlsl: + HitObject hitObj; + __hlslMakeHit( + AccelerationStructure, + InstanceIndex, + GeometryIndex, + PrimitiveIndex, + HitKind, + RayContributionToHitGroupIndex, + MultiplierForGeometryContributionToHitGroupIndex, + Ray, + attributes, + hitObj); + return hitObj; + case glsl: + { + // Save the attributes + __ref attr_t attr = __hitObjectAttributes<attr_t>(); + + attr = attributes; + + __glslMakeHit( + __return_val, + AccelerationStructure, + InstanceIndex, + PrimitiveIndex, + GeometryIndex, + HitKind, + RayContributionToHitGroupIndex, /// sbtRecordOffset? + MultiplierForGeometryContributionToHitGroupIndex, /// sbtRecordStride? + Ray.Origin, + Ray.TMin, + Ray.Direction, + Ray.TMax, + __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + } + case spirv: + { + // Save the attributes + Ptr<attr_t> attr = __allocHitObjectAttributes<attr_t>(); + + *attr = attributes; + + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpHitObjectRecordHitNV + /**/ &__return_val + /**/ $AccelerationStructure + /**/ $InstanceIndex + /**/ $PrimitiveIndex + /**/ $GeometryIndex + /**/ $HitKind + /**/ $RayContributionToHitGroupIndex + /**/ $MultiplierForGeometryContributionToHitGroupIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax + /**/ $attr; + }; + } + } } /// See MakeHit but handles Motion /// Currently only supported on VK [ForceInline] - __specialized_for_target(glsl) static HitObject MakeMotionHit<attr_t>( RaytracingAccelerationStructure AccelerationStructure, uint InstanceIndex, @@ -8802,26 +8936,64 @@ struct HitObject float CurrentTime, attr_t attributes) { - // Save the attributes - __ref attr_t attr = __hitObjectAttributes<attr_t>(); + __target_switch + { + case hlsl: __intrinsic_asm "MakeMotionHit"; + case glsl: + { + // Save the attributes + __ref attr_t attr = __hitObjectAttributes<attr_t>(); + + attr = attributes; + + __glslMakeMotionHit( + __return_val, + AccelerationStructure, + InstanceIndex, + PrimitiveIndex, + GeometryIndex, + HitKind, + RayContributionToHitGroupIndex, /// sbtRecordOffset? + MultiplierForGeometryContributionToHitGroupIndex, /// sbtRecordStride? + Ray.Origin, + Ray.TMin, + Ray.Direction, + Ray.TMax, + CurrentTime, + __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + } + case spirv: + { + // Save the attributes + Ptr<attr_t> attr = __allocHitObjectAttributes<attr_t>(); - attr = attributes; + *attr = attributes; - __glslMakeMotionHit( - __return_val, - AccelerationStructure, - InstanceIndex, - PrimitiveIndex, - GeometryIndex, - HitKind, - RayContributionToHitGroupIndex, /// sbtRecordOffset? - MultiplierForGeometryContributionToHitGroupIndex, /// sbtRecordStride? - Ray.Origin, - Ray.TMin, - Ray.Direction, - Ray.TMax, - CurrentTime, - __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpCapability RayTracingMotionBlurNV; + OpExtension "SPV_NV_ray_tracing_motion_blur"; + OpHitObjectRecordHitMotionNV + /**/ &__return_val + /**/ $AccelerationStructure + /**/ $InstanceIndex + /**/ $PrimitiveIndex + /**/ $GeometryIndex + /**/ $HitKind + /**/ $RayContributionToHitGroupIndex + /**/ $MultiplierForGeometryContributionToHitGroupIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax + /**/ $CurrentTime + /**/ $attr; + }; + } + } } /// Creates a HitObject representing a hit based on values explicitly passed as arguments, without @@ -8831,7 +9003,7 @@ struct HitObject /// reference a valid hit group record in the shader table. The Attributes parameter must either be an /// attribute struct, such as BuiltInTriangleIntersectionAttributes, or another HitObject to copy the /// attributes from. - __specialized_for_target(hlsl) + [ForceInline] static HitObject MakeHit<attr_t>( uint HitGroupRecordIndex, RaytracingAccelerationStructure AccelerationStructure, @@ -8842,55 +9014,72 @@ struct HitObject RayDesc Ray, attr_t attributes) { - HitObject hitObj; - __hlslMakeHitWithRecordIndex( - HitGroupRecordIndex, - AccelerationStructure, - InstanceIndex, - GeometryIndex, - PrimitiveIndex, - HitKind, - Ray, - attributes, - hitObj); - return hitObj; - } - - [ForceInline] - __specialized_for_target(glsl) - static HitObject MakeHit<attr_t>( - uint HitGroupRecordIndex, - RaytracingAccelerationStructure AccelerationStructure, - uint InstanceIndex, - uint GeometryIndex, - uint PrimitiveIndex, - uint HitKind, - RayDesc Ray, - attr_t attributes) - { - // Save the attributes - __ref attr_t attr = __hitObjectAttributes<attr_t>(); - attr = attributes; - - __glslMakeHitWithIndex( - __return_val, - AccelerationStructure, - InstanceIndex, ///? Same as instanceid ? - GeometryIndex, - PrimitiveIndex, - HitKind, /// Assuming HitKinds are compatible - HitGroupRecordIndex, /// sbtRecordIndex - Ray.Origin, - Ray.TMin, - Ray.Direction, - Ray.TMax, - __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + __target_switch + { + case hlsl: + HitObject hitObj; + __hlslMakeHitWithRecordIndex( + HitGroupRecordIndex, + AccelerationStructure, + InstanceIndex, + GeometryIndex, + PrimitiveIndex, + HitKind, + Ray, + attributes, + hitObj); + return hitObj; + case glsl: + { + // Save the attributes + __ref attr_t attr = __hitObjectAttributes<attr_t>(); + attr = attributes; + + __glslMakeHitWithIndex( + __return_val, + AccelerationStructure, + InstanceIndex, ///? Same as instanceid ? + GeometryIndex, + PrimitiveIndex, + HitKind, /// Assuming HitKinds are compatible + HitGroupRecordIndex, /// sbtRecordIndex + Ray.Origin, + Ray.TMin, + Ray.Direction, + Ray.TMax, + __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + } + case spirv: + { + // Save the attributes + Ptr<attr_t> attr = __allocHitObjectAttributes<attr_t>(); + *attr = attributes; + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpHitObjectRecordHitWithIndexNV + /**/ &__return_val + /**/ $AccelerationStructure + /**/ $InstanceIndex + /**/ $PrimitiveIndex + /**/ $GeometryIndex + /**/ $HitKind + /**/ $HitGroupRecordIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax + /**/ $attr; + }; + } + } } - /// See MakeHit but handles Motion /// Currently only supported on VK + [ForceInline] - __specialized_for_target(glsl) static HitObject MakeMotionHit<attr_t>( uint HitGroupRecordIndex, RaytracingAccelerationStructure AccelerationStructure, @@ -8902,44 +9091,91 @@ struct HitObject float CurrentTime, attr_t attributes) { - HitObject hitObj; - - // Save the attributes - __ref attr_t attr = __hitObjectAttributes<attr_t>(); - attr = attributes; - - __glslMakeMotionHitWithIndex( - __return_val, - AccelerationStructure, - InstanceIndex, ///? Same as instanceid ? - GeometryIndex, - PrimitiveIndex, - HitKind, /// Assuming HitKinds are compatible - HitGroupRecordIndex, /// sbtRecordIndex - Ray.Origin, - Ray.TMin, - Ray.Direction, - Ray.TMax, - CurrentTime, - __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + __target_switch + { + case glsl: + { + // Save the attributes + __ref attr_t attr = __hitObjectAttributes<attr_t>(); + attr = attributes; + + __glslMakeMotionHitWithIndex( + __return_val, + AccelerationStructure, + InstanceIndex, ///? Same as instanceid ? + GeometryIndex, + PrimitiveIndex, + HitKind, /// Assuming HitKinds are compatible + HitGroupRecordIndex, /// sbtRecordIndex + Ray.Origin, + Ray.TMin, + Ray.Direction, + Ray.TMax, + CurrentTime, + __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>())); + } + case spirv: + { + // Save the attributes + Ptr<attr_t> attr = __allocHitObjectAttributes<attr_t>(); + *attr = attributes; + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpCapability RayTracingMotionBlurNV; + OpExtension "SPV_NV_ray_tracing_motion_blur"; + OpHitObjectRecordHitWithIndexMotionNV + /**/ &__return_val + /**/ $AccelerationStructure + /**/ $InstanceIndex + /**/ $PrimitiveIndex + /**/ $GeometryIndex + /**/ $HitKind + /**/ $HitGroupRecordIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax + /**/ $CurrentTime + /**/ $attr; + }; + } + } } /// Creates a HitObject representing a miss based on values explicitly passed as arguments, without /// tracing a ray. The provided shader table index must reference a valid miss record in the shader /// table. [__requiresNVAPI] - __target_intrinsic(hlsl, "($2=NvMakeMiss($0,$1))") - static HitObject MakeMiss( - uint MissShaderIndex, - RayDesc Ray); - [ForceInline] - __specialized_for_target(glsl) static HitObject MakeMiss( uint MissShaderIndex, RayDesc Ray) { - __glslMakeMiss(__return_val, MissShaderIndex, Ray.Origin, Ray.TMin, Ray.Direction, Ray.TMax); + __target_switch + { + case hlsl: __intrinsic_asm "($2=NvMakeMiss($0,$1))"; + case glsl: + __glslMakeMiss(__return_val, MissShaderIndex, Ray.Origin, Ray.TMin, Ray.Direction, Ray.TMax); + case spirv: + { + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpHitObjectRecordMissNV + /**/ &__return_val + /**/ $MissShaderIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax; + }; + } + } } /// See MakeMiss but handles Motion @@ -8951,7 +9187,31 @@ struct HitObject RayDesc Ray, float CurrentTime) { - __glslMakeMotionMiss(__return_val, MissShaderIndex, Ray.Origin, Ray.TMin, Ray.Direction, Ray.TMax, CurrentTime); + __target_switch + { + case hlsl: __intrinsic_asm "($3=NvMakeMotionMiss($0,$1,$2))"; + case glsl: + __glslMakeMotionMiss(__return_val, MissShaderIndex, Ray.Origin, Ray.TMin, Ray.Direction, Ray.TMax, CurrentTime); + case spirv: + { + let origin = Ray.Origin; + let direction = Ray.Direction; + let tmin = Ray.TMin; + let tmax = Ray.TMax; + spirv_asm { + OpCapability RayTracingMotionBlurNV; + OpExtension "SPV_NV_ray_tracing_motion_blur"; + OpHitObjectRecordMissMotionNV + /**/ &__return_val + /**/ $MissShaderIndex + /**/ $origin + /**/ $tmin + /**/ $direction + /**/ $tmax + /**/ $CurrentTime; + }; + } + } } /// Creates a HitObject representing “NOP” (no operation) which is neither a hit nor a miss. Invoking a @@ -8960,138 +9220,270 @@ struct HitObject /// scenarios where future control flow for some threads is known to process neither a hit nor a /// miss. [__requiresNVAPI] - __target_intrinsic(hlsl, "($0 = NvMakeNop())") - static HitObject MakeNop(); - [ForceInline] - __specialized_for_target(glsl) static HitObject MakeNop() { - __glslMakeNop(__return_val); + __target_switch + { + case hlsl: + __intrinsic_asm "($0 = NvMakeNop())"; + case glsl: + __glslMakeNop(__return_val); + case spirv: + spirv_asm { + OpHitObjectRecordEmptyNV + /**/ &__return_val; + }; + } } /// Invokes closesthit or miss shading for the specified hit object. In case of a NOP HitObject, no /// shader is invoked. [__requiresNVAPI] - __target_intrinsic(hlsl, "NvInvokeHitObject") + [ForceInline] static void Invoke<payload_t>( RaytracingAccelerationStructure AccelerationStructure, HitObject HitOrMiss, - inout payload_t Payload); - - __specialized_for_target(glsl) - static void Invoke<payload_t>( - RaytracingAccelerationStructure AccelerationStructure, - HitObject HitOrMiss, inout payload_t Payload) { - [__vulkanRayPayload] - static payload_t p; + __target_switch + { + case hlsl: __intrinsic_asm "NvInvokeHitObject"; + case glsl: + { + [__vulkanRayPayload] + static payload_t p; - // Save the payload - p = Payload; + // Save the payload + p = Payload; - __glslInvoke(HitOrMiss, __rayPayloadLocation(p)); + __glslInvoke(HitOrMiss, __rayPayloadLocation(p)); - // Write payload result - Payload = p; + // Write payload result + Payload = p; + } + case spirv: + { + [__vulkanRayPayload] + static payload_t p; + + // Save the payload + p = Payload; + + spirv_asm { + OpHitObjectExecuteShaderNV + /**/ &HitOrMiss + /**/ &p; + }; + + // Write payload result + Payload = p; + } + } } /// Returns true if the HitObject encodes a miss, otherwise returns false. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectIsMissNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - bool IsMiss(); + bool IsMiss() + { + __target_switch + { + case hlsl: __intrinsic_asm ".IsMiss"; + case glsl: __intrinsic_asm "hitObjectIsMissNV($0)"; + case spirv: return spirv_asm { + result:$$bool = OpHitObjectIsMissNV &this; + }; + } + } /// Returns true if the HitObject encodes a hit, otherwise returns false. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectIsHitNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - bool IsHit(); + bool IsHit() + { + __target_switch + { + case hlsl: __intrinsic_asm ".IsHit"; + case glsl: __intrinsic_asm "hitObjectIsHitNV($0)"; + case spirv: return spirv_asm { + result:$$bool = OpHitObjectIsHitNV &this; + }; + } + } /// Returns true if the HitObject encodes a nop, otherwise returns false. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectIsEmptyNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - bool IsNop(); + bool IsNop() + { + __target_switch + { + case hlsl: __intrinsic_asm ".IsNop"; + case glsl: __intrinsic_asm "hitObjectIsEmptyNV($0)"; + case spirv: return spirv_asm { + result:$$bool = OpHitObjectIsEmptyNV &this; + }; + } + } /// Queries ray properties from HitObject. Valid if the hit object represents a hit or a miss. [__requiresNVAPI] + [ForceInline] __target_intrinsic(hlsl) - RayDesc GetRayDesc(); - - __specialized_for_target(glsl) RayDesc GetRayDesc() { - RayDesc ray = { __glslGetRayWorldOrigin(), __glslGetTMin(), __glslGetRayDirection(), __glslGetTMax() }; - return ray; + __target_switch + { + case hlsl: + __intrinsic_asm ".GetRayDesc"; + case glsl: + { + RayDesc ray = { __glslGetRayWorldOrigin(), __glslGetTMin(), __glslGetRayWorldDirection(), __glslGetTMax() }; + return ray; + } + case spirv: + return spirv_asm { + %origin:$$float3 = OpHitObjectGetWorldRayOriginNV &this; + %tmin:$$float = OpHitObjectGetRayTMinNV &this; + %direction:$$float3 = OpHitObjectGetWorldRayDirectionNV &this; + %tmax:$$float = OpHitObjectGetRayTMaxNV &this; + result:$$RayDesc = OpCompositeConstruct %origin %tmin %direction %tmax; + }; + } } /// Queries shader table index from HitObject. Valid if the hit object represents a hit or a miss. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectGetShaderBindingTableRecordIndexNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - uint GetShaderTableIndex(); + uint GetShaderTableIndex() + { + __target_switch + { + case hlsl: __intrinsic_asm ".GetShaderTableIndex"; + case glsl: __intrinsic_asm "hitObjectGetShaderBindingTableRecordIndexNV($0)"; + case spirv: return spirv_asm { + result:$$uint = OpHitObjectGetShaderBindingTableRecordIndexNV &this; + }; + } + } /// Returns the instance index of a hit. Valid if the hit object represents a hit. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectGetInstanceCustomIndexNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - uint GetInstanceIndex(); + uint GetInstanceIndex() + { + __target_switch + { + case hlsl: __intrinsic_asm ".GetInstanceIndex"; + case glsl: __intrinsic_asm "hitObjectGetInstanceCustomIndexNV($0)"; + case spirv: return spirv_asm { + result:$$uint = OpHitObjectGetInstanceCustomIndexNV &this; + }; + } + } /// Returns the instance ID of a hit. Valid if the hit object represents a hit. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectGetInstanceIdNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - uint GetInstanceID(); + uint GetInstanceID() + { + __target_switch + { + case hlsl: __intrinsic_asm ".GetInstanceID"; + case glsl: __intrinsic_asm "hitObjectGetInstanceIdNV($0)"; + case spirv: return spirv_asm { + result:$$uint = OpHitObjectGetInstanceIdNV &this; + }; + } + } /// Returns the geometry index of a hit. Valid if the hit object represents a hit. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectGetGeometryIndexNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - uint GetGeometryIndex(); + uint GetGeometryIndex() + { + __target_switch + { + case hlsl: __intrinsic_asm ".GetGeometryIndex"; + case glsl: __intrinsic_asm "hitObjectGetGeometryIndexNV($0)"; + case spirv: return spirv_asm { + result:$$uint = OpHitObjectGetGeometryIndexNV &this; + }; + } + } /// Returns the primitive index of a hit. Valid if the hit object represents a hit. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectGetPrimitiveIndexNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - uint GetPrimitiveIndex(); + uint GetPrimitiveIndex() + { + __target_switch + { + case hlsl: __intrinsic_asm ".GetPrimitiveIndex"; + case glsl: __intrinsic_asm "hitObjectGetPrimitiveIndexNV($0)"; + case spirv: return spirv_asm { + result:$$uint = OpHitObjectGetPrimitiveIndexNV &this; + }; + } + } /// Returns the hit kind. Valid if the hit object represents a hit. [__requiresNVAPI] - __target_intrinsic(hlsl) - __target_intrinsic(glsl, "hitObjectGetHitKindNV($0)") + [ForceInline] __glsl_extension(GL_EXT_ray_tracing) - uint GetHitKind(); - - /// Returns the attributes of a hit. Valid if the hit object represents a hit or a miss. - __specialized_for_target(hlsl) - attr_t GetAttributes<attr_t>() + uint GetHitKind() { - attr_t v; - __hlslGetAttributesFromHitObject(v); - return v; + __target_switch + { + case hlsl: __intrinsic_asm ".GetHitKind"; + case glsl: __intrinsic_asm "hitObjectGetHitKindNV($0)"; + case spirv: return spirv_asm { + result:$$uint = OpHitObjectGetHitKindNV &this; + }; + } } - __specialized_for_target(glsl) + /// Returns the attributes of a hit. Valid if the hit object represents a hit or a miss. + [ForceInline] attr_t GetAttributes<attr_t>() { - // Work out the location - int attributeLocation = __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>()); + __target_switch + { + case hlsl: + { + attr_t v; + __hlslGetAttributesFromHitObject(v); + return v; + } + case glsl: + { + // Work out the location + int attributeLocation = __hitObjectAttributesLocation(__hitObjectAttributes<attr_t>()); - // Load the attributes from the location - __glslGetAttributes(attributeLocation); + // Load the attributes from the location + __glslGetAttributes(attributeLocation); - // Return the attributes - return __hitObjectAttributes<attr_t>(); + // Return the attributes + return __hitObjectAttributes<attr_t>(); + } + case spirv: + { + Ptr<attr_t> attr = __allocHitObjectAttributes<attr_t>(); + spirv_asm { + OpHitObjectGetAttributesNV &this $attr; + }; + return *attr; + } + } } /// Loads a root constant from the local root table referenced by the hit object. Valid if the hit object /// represents a hit or a miss. RootConstantOffsetInBytes must be a multiple of 4. @@ -9187,6 +9579,10 @@ struct HitObject float3 __glslGetRayDirection(); __glsl_extension(GL_NV_shader_invocation_reorder) + __target_intrinsic(glsl, "hitObjectGetWorldRayDirectionNV($0)") + float3 __glslGetRayWorldDirection(); + + __glsl_extension(GL_NV_shader_invocation_reorder) __target_intrinsic(glsl, "hitObjectGetWorldRayOriginNV($0)") float3 __glslGetRayWorldOrigin(); @@ -9335,11 +9731,22 @@ struct HitObject /// Where possible, reordering will also attempt to retain locality in the thread’s launch indices /// (DispatchRaysIndex in DXR). [__requiresNVAPI] -__target_intrinsic(hlsl, "NvReorderThread") __glsl_extension(GL_NV_shader_invocation_reorder) __glsl_extension(GL_EXT_ray_tracing) -__target_intrinsic(glsl, "reorderThreadNV") -void ReorderThread( uint CoherenceHint, uint NumCoherenceHintBitsFromLSB ); +void ReorderThread( uint CoherenceHint, uint NumCoherenceHintBitsFromLSB ) +{ + __target_switch + { + case hlsl: __intrinsic_asm "NvReorderThread"; + case glsl: __intrinsic_asm "reorderThreadNV"; + case spirv: + spirv_asm { + OpCapability ShaderInvocationReorderNV; + OpExtension "SPV_NV_shader_invocation_reorder"; + OpReorderThreadWithHintNV $CoherenceHint $NumCoherenceHintBitsFromLSB; + }; + } +} /// Reorders threads based on a hit object, optionally extended by a coherence hint value. Coherence /// hints behave as described in the generic variant of ReorderThread. The maximum number of @@ -9357,11 +9764,20 @@ void ReorderThread( uint CoherenceHint, uint NumCoherenceHintBitsFromLSB ); /// groups, it will attempt to order threads by the value of their coherence hints. And within ranges /// of equal coherence hints, it will attempt to maximize locality in 3D space of the ray hit (if any). [__requiresNVAPI] -__target_intrinsic(hlsl, "NvReorderThread") __glsl_extension(GL_NV_shader_invocation_reorder) __glsl_extension(GL_EXT_ray_tracing) -__target_intrinsic(glsl, "reorderThreadNV") -void ReorderThread( HitObject HitOrMiss, uint CoherenceHint, uint NumCoherenceHintBitsFromLSB ); +void ReorderThread( HitObject HitOrMiss, uint CoherenceHint, uint NumCoherenceHintBitsFromLSB ) +{ + __target_switch + { + case hlsl: __intrinsic_asm "NvReorderThread"; + case glsl: __intrinsic_asm "reorderThreadNV"; + case spirv: + spirv_asm { + OpReorderThreadWithHitObjectNV &HitOrMiss $CoherenceHint $NumCoherenceHintBitsFromLSB; + }; + } +} /// Is equivalent to /// ``` @@ -9369,10 +9785,19 @@ void ReorderThread( HitObject HitOrMiss, uint CoherenceHint, uint NumCoherenceHi /// ``` /// With CoherenceHint and NumCoherenceHintBitsFromLSB as 0, meaning they are ignored. [__requiresNVAPI] -__target_intrinsic(hlsl, "NvReorderThread") __glsl_extension(GL_NV_shader_invocation_reorder) -__target_intrinsic(glsl, "reorderThreadNV") -void ReorderThread( HitObject HitOrMiss ); +void ReorderThread( HitObject HitOrMiss ) +{ + __target_switch + { + case hlsl: __intrinsic_asm "NvReorderThread"; + case glsl: __intrinsic_asm "reorderThreadNV"; + case spirv: + spirv_asm { + OpReorderThreadWithHitObjectNV &HitOrMiss; + }; + } +} /// diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index aae18d08f..c5bd3348c 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1564,6 +1564,18 @@ namespace Slang Binary = SLANG_WRITER_MODE_BINARY, }; + class TargetRequest; + + /// Are we generating code for a D3D API? + bool isD3DTarget(TargetRequest* targetReq); + + /// Are we generating code for a Khronos API (OpenGL or Vulkan)? + bool isKhronosTarget(TargetRequest* targetReq); + + /// Are we generating code for a CUDA API (CUDA / OptiX)? + bool isCUDATarget(TargetRequest* targetReq); + + /// A request to generate output in some target format. class TargetRequest : public RefObject { @@ -1601,7 +1613,7 @@ namespace Slang bool shouldEmitSPIRVDirectly() { - return targetFlags & SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY; + return isKhronosTarget(this) && ((targetFlags & SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY) != 0); } bool isWholeProgramRequest() @@ -1653,15 +1665,6 @@ namespace Slang RefPtr<HLSLToVulkanLayoutOptions> hlslToVulkanLayoutOptions; ///< Optional vulkan layout options }; - /// Are we generating code for a D3D API? - bool isD3DTarget(TargetRequest* targetReq); - - /// Are we generating code for a Khronos API (OpenGL or Vulkan)? - bool isKhronosTarget(TargetRequest* targetReq); - - /// Are we generating code for a CUDA API (CUDA / OptiX)? - bool isCUDATarget(TargetRequest* targetReq); - /// Given a target request returns which (if any) intermediate source language is required /// to produce it. /// diff --git a/source/slang/slang-emit-spirv-ops.h b/source/slang/slang-emit-spirv-ops.h index 9bd645e5d..f64fc7f9a 100644 --- a/source/slang/slang-emit-spirv-ops.h +++ b/source/slang/slang-emit-spirv-ops.h @@ -311,6 +311,13 @@ SpvInst* emitOpTypeRayQuery(IRInst* inst) ); } +SpvInst* emitOpTypeHitObject(IRInst* inst) +{ + return emitInstMemoized( + getSection(SpvLogicalSectionID::ConstantsAndTypes), inst, SpvOpTypeHitObjectNV, kResultID + ); +} + // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeArray template<typename T1, typename T2> SpvInst* emitOpTypeArray(IRInst* inst, const T1& elementType, const T2& length) diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 6bd781e62..104fab339 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1378,6 +1378,11 @@ struct SPIRVEmitContext requireSPIRVCapability(SpvCapabilityRayQueryKHR); return emitOpTypeRayQuery(inst); + case kIROp_HitObjectType: + ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_shader_invocation_reorder")); + requireSPIRVCapability(SpvCapabilityShaderInvocationReorderNV); + return emitOpTypeHitObject(inst); + case kIROp_FuncType: // > OpTypeFunction // @@ -2263,6 +2268,12 @@ struct SPIRVEmitContext case kIROp_Rsh: case kIROp_Lsh: return emitArithmetic(parent, inst); + case kIROp_GlobalValueRef: + { + auto inner = ensureInst(inst->getOperand(0)); + registerInst(inst, inner); + return inner; + } case kIROp_Return: if (as<IRReturn>(inst)->getVal()->getOp() == kIROp_VoidLit) return emitOpReturn(parent, inst); @@ -3938,14 +3949,33 @@ struct SPIRVEmitContext SLANG_ASSERT(!as<IRVectorType>(fromTypeV) == !as<IRVectorType>(toTypeV)); const auto fromType = dropVector(fromTypeV); const auto toType = dropVector(toTypeV); - SLANG_ASSERT(isIntegralType(fromType)); SLANG_ASSERT(isFloatingType(toType)); - const auto fromInfo = getIntTypeInfo(fromType); + if (isIntegralType(fromType)) + { + const auto fromInfo = getIntTypeInfo(fromType); - return fromInfo.isSigned - ? emitOpConvertSToF(parent, inst, toTypeV, inst->getOperand(0)) - : emitOpConvertUToF(parent, inst, toTypeV, inst->getOperand(0)); + return fromInfo.isSigned + ? emitOpConvertSToF(parent, inst, toTypeV, inst->getOperand(0)) + : emitOpConvertUToF(parent, inst, toTypeV, inst->getOperand(0)); + } + else if (as<IRBoolType>(fromType)) + { + IRBuilder builder(inst); + builder.setInsertBefore(inst); + auto one = builder.getFloatValue(toType, 1.0f); + auto zero = builder.getFloatValue(toType, 0.0f); + if (as<IRVectorType>(toTypeV)) + { + one = builder.emitMakeVectorFromScalar(toTypeV, one); + zero = builder.emitMakeVectorFromScalar(toTypeV, zero); + } + return emitInst(parent, inst, SpvOpSelect, inst->getFullType(), kResultID, inst->getOperand(0), one, zero); + } + else + { + SLANG_UNREACHABLE("unknown from type"); + } } SpvInst* emitFloatToIntCast(SpvInstParent* parent, IRCastFloatToInt* inst) @@ -4206,7 +4236,7 @@ struct SPIRVEmitContext opCode = isFloatingPoint ? SpvOpFOrdEqual : isBool ? SpvOpLogicalEqual : SpvOpIEqual; break; case kIROp_Neq: - opCode = isFloatingPoint ? SpvOpFOrdNotEqual + opCode = isFloatingPoint ? SpvOpFUnordNotEqual : isBool ? SpvOpLogicalNotEqual : SpvOpINotEqual; break; case kIROp_Geq: diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 0865a9170..5a8d7fe06 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -304,6 +304,8 @@ INST(GetSequentialID, GetSequentialID, 1, HOISTABLE) INST(BindGlobalGenericParam, bind_global_generic_param, 2, 0) INST(AllocObj, allocObj, 0, 0) +INST(GlobalValueRef, globalValueRef, 1, 0) + INST(MakeUInt64, makeUInt64, 2, 0) INST(MakeVector, makeVector, 0, 0) INST(MakeMatrix, makeMatrix, 0, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index e2bb53a78..9ff2df889 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -1199,6 +1199,17 @@ struct IRAlloca : IRInst IRInst* getAllocSize() { return getOperand(0); } }; +/// A non-hoistable inst used to "pin" a global value inside a function body so any insts dependent on `value` +/// can be emitted as local insts instead of global insts, as required by targets (e.g. spirv) that doesn't +/// allow the dependent computation in the global scope. +/// +struct IRGlobalValueRef : IRInst +{ + IR_LEAF_ISA(GlobalValueRef) + + IRInst* getValue() { return getOperand(0); } +}; + /// Packs a value into an `AnyValue`. /// Return type is `IRAnyValueType`. struct IRPackAnyValue : IRInst @@ -3458,6 +3469,8 @@ public: IRInst* emitAlloca(IRInst* type, IRInst* rttiObjPtr); + IRInst* emitGlobalValueRef(IRInst* globalInst); + IRInst* emitPackAnyValue(IRType* type, IRInst* value); IRInst* emitUnpackAnyValue(IRType* type, IRInst* value); diff --git a/source/slang/slang-ir-lower-buffer-element-type.cpp b/source/slang/slang-ir-lower-buffer-element-type.cpp index ffdd4584a..378201fdb 100644 --- a/source/slang/slang-ir-lower-buffer-element-type.cpp +++ b/source/slang/slang-ir-lower-buffer-element-type.cpp @@ -409,10 +409,18 @@ namespace Slang { case CodeGenTarget::SPIRV: case CodeGenTarget::SPIRVAssembly: - if (as<IRBoolType>(type)) + { + auto scalarType = type; + auto vectorType = as<IRVectorType>(scalarType); + if (vectorType) + scalarType = vectorType->getElementType(); + + if (as<IRBoolType>(scalarType)) { // Bool is an abstract type in SPIRV, so we need to lower them into an int. info.loweredType = builder.getIntType(); + if (vectorType) + info.loweredType = builder.getVectorType(info.loweredType, vectorType->getElementCount()); // Create unpack func. { builder.setInsertAfter(type); @@ -440,6 +448,7 @@ namespace Slang } return info; } + } default: break; } @@ -642,6 +651,11 @@ namespace Slang break; case kIROp_Call: { + // If a structured buffer typed value is used directly as an argument, + // we don't need to do any marshalling here. + if (as<IRHLSLStructuredBufferTypeBase>(ptrVal->getDataType())) + break; + // If we are calling a function with an l-value pointer from buffer access, // we need to materialize the object as a local variable, and pass the address // of the local variable to the function. diff --git a/source/slang/slang-ir-simplify-for-emit.cpp b/source/slang/slang-ir-simplify-for-emit.cpp index 469368ca4..7fd609011 100644 --- a/source/slang/slang-ir-simplify-for-emit.cpp +++ b/source/slang/slang-ir-simplify-for-emit.cpp @@ -137,7 +137,7 @@ struct SimplifyForEmitContext : public InstPassBase // If we reach here, it is OK to defer the load at use site. IRBuilder builder(module); builder.setInsertBefore(user); - auto newLoad = builder.emitLoad(load->getPtr()); + auto newLoad = builder.emitLoad(load->getFullType(), load->getPtr()); builder.replaceOperand(use, newLoad); } diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp index 87d00a32b..49f1b3177 100644 --- a/source/slang/slang-ir-specialize-resources.cpp +++ b/source/slang/slang-ir-specialize-resources.cpp @@ -62,19 +62,18 @@ struct ResourceParameterSpecializationCondition : FunctionCallSpecializeConditio // if( isKhronosTarget(targetRequest) ) { - return isIllegalGLSLParameterType(type); + if (targetRequest->shouldEmitSPIRVDirectly()) + return isIllegalSPIRVParameterType(type); + else + return isIllegalGLSLParameterType(type); } + // For now, we will not treat any other parameters as // needing specialization, even if they use resource // types like `Texure2D`, because these are allowed // as function parameters in both HLSL and GLSL. // - // TODO: Eventually, if we start generating SPIR-V - // directly rather than through glslang, we will need - // to specialize *all* resource-type parameters - // to follow the restrictions in the spec. - // // TODO: We may want to perform more aggressive // specialization in general, especially insofar // as it could simplify the task of supporting @@ -1237,4 +1236,15 @@ bool isIllegalGLSLParameterType(IRType* type) return false; } +bool isIllegalSPIRVParameterType(IRType* type) +{ + if (isIllegalGLSLParameterType(type)) + return true; + + // If we are emitting SPIRV direclty, we need to specialize + // all Texture types. + if (auto texType = as<IRTextureType>(type)) + return true; + return false; +} } // namespace Slang diff --git a/source/slang/slang-ir-specialize-resources.h b/source/slang/slang-ir-specialize-resources.h index ec831ac24..d5665155f 100644 --- a/source/slang/slang-ir-specialize-resources.h +++ b/source/slang/slang-ir-specialize-resources.h @@ -31,5 +31,6 @@ namespace Slang IRModule* irModule); bool isIllegalGLSLParameterType(IRType* type); + bool isIllegalSPIRVParameterType(IRType* type); } diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp index 121452533..5d4673981 100644 --- a/source/slang/slang-ir-spirv-legalize.cpp +++ b/source/slang/slang-ir-spirv-legalize.cpp @@ -694,6 +694,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase List<WriteBackPair> writeBacks; IRBuilder builder(inst); builder.setInsertBefore(inst); + auto funcType = as<IRFuncType>(funcValue->getFullType()); for (UInt i = 0; i < inst->getArgCount(); i++) { auto arg = inst->getArg(i); @@ -727,8 +728,17 @@ struct SPIRVLegalizationContext : public SourceEmitterBase switch (root->getOp()) { case kIROp_RWStructuredBufferGetElementPtr: - newArgs.add(arg); - continue; + if (funcType) + { + if (funcType->getParamCount() > i && as<IRRefType>(funcType->getParamType(i))) + { + // If we are passing an address from a structured buffer as a + // ref argument, pass the original pointer as is. + // This is to support stdlib atomic functions. + newArgs.add(arg); + continue; + } + } } } @@ -1181,31 +1191,165 @@ struct SPIRVLegalizationContext : public SourceEmitterBase void legalizeSPIRVEntryPoint(IRFunc* func, IREntryPointDecoration* entryPointDecor) { - if (entryPointDecor->getProfile().getStage() == Stage::Geometry) + auto stage = entryPointDecor->getProfile().getStage(); + switch (stage) { + case Stage::Geometry: if (!func->findDecoration<IRInstanceDecoration>()) { IRBuilder builder(func); builder.addDecoration(func, kIROp_InstanceDecoration, builder.getIntValue(builder.getUIntType(), 1)); } + break; + case Stage::Compute: + if (!func->findDecoration<IRNumThreadsDecoration>()) + { + IRBuilder builder(func); + auto one = builder.getIntValue(builder.getUIntType(), 1); + IRInst* args[3] = { one, one, one }; + builder.addDecoration(func, kIROp_NumThreadsDecoration, args, 3); + } + break; } + } - void processModule() + // Opcodes that can exist in global scope, as long as the operands are. + bool isLegalGlobalInst(IRInst* inst) { - // Process global params before anything else, so we don't generate inefficient - // array marhalling code for array-typed global params. - for (auto globalInst : m_module->getGlobalInsts()) + switch (inst->getOp()) { - if (auto globalParam = as<IRGlobalParam>(globalInst)) - { - processGlobalParam(globalParam); - } - else + case kIROp_MakeStruct: + case kIROp_MakeArray: + case kIROp_MakeArrayFromElement: + case kIROp_MakeVector: + case kIROp_MakeMatrix: + case kIROp_MakeMatrixFromScalar: + case kIROp_MakeVectorFromScalar: + return true; + default: + return false; + } + } + + // Opcodes that can be inlined into function bodies. + bool isInlinableGlobalInst(IRInst* inst) + { + switch (inst->getOp()) + { + case kIROp_Add: + case kIROp_Sub: + case kIROp_Mul: + case kIROp_FRem: + case kIROp_IRem: + case kIROp_Lsh: + case kIROp_Rsh: + case kIROp_And: + case kIROp_Or: + case kIROp_Not: + case kIROp_Neg: + case kIROp_FieldExtract: + case kIROp_FieldAddress: + case kIROp_GetElement: + case kIROp_GetElementPtr: + case kIROp_UpdateElement: + case kIROp_MakeTuple: + case kIROp_GetTupleElement: + case kIROp_MakeStruct: + case kIROp_MakeArray: + case kIROp_MakeArrayFromElement: + case kIROp_MakeVector: + case kIROp_MakeMatrix: + case kIROp_MakeMatrixFromScalar: + case kIROp_MakeVectorFromScalar: + case kIROp_swizzle: + case kIROp_swizzleSet: + case kIROp_MatrixReshape: + case kIROp_MakeString: + case kIROp_MakeResultError: + case kIROp_MakeResultValue: + case kIROp_GetResultError: + case kIROp_GetResultValue: + case kIROp_CastFloatToInt: + case kIROp_CastIntToFloat: + case kIROp_CastIntToPtr: + case kIROp_CastPtrToBool: + case kIROp_CastPtrToInt: + case kIROp_BitAnd: + case kIROp_BitNot: + case kIROp_BitOr: + case kIROp_BitXor: + case kIROp_BitCast: + case kIROp_IntCast: + case kIROp_FloatCast: + case kIROp_Greater: + case kIROp_Less: + case kIROp_Geq: + case kIROp_Leq: + case kIROp_Neq: + case kIROp_Eql: + case kIROp_Call: + return true; + default: + return false; + } + } + + bool shouldInlineInst(IRInst* inst) + { + if (!isInlinableGlobalInst(inst)) + return false; + if (isLegalGlobalInst(inst)) + { + for (UInt i = 0; i < inst->getOperandCount(); i++) + if (shouldInlineInst(inst->getOperand(i))) + return true; + return false; + } + return true; + } + + /// Inline `inst` in the local function body so they can be emitted as a local inst. + /// + IRInst* maybeInlineGlobalValue(IRBuilder& builder, IRInst* inst, IRCloneEnv& cloneEnv) + { + if (!shouldInlineInst(inst)) + { + switch (inst->getOp()) { - addToWorkList(globalInst); + case kIROp_Func: + case kIROp_Specialize: + case kIROp_Generic: + case kIROp_LookupWitness: + return inst; } + if (as<IRType>(inst)) + return inst; + + // If we encounter a global value that shouldn't be inlined, e.g. a const literal, + // we should insert a GlobalValueRef() inst to wrap around it, so all the dependent uses + // can be pinned to the function body. + auto result = builder.emitGlobalValueRef(inst); + cloneEnv.mapOldValToNew[inst] = result; + return result; + } + + // If the global value is inlinable, we make all its operands avaialble locally, and then copy it + // to the local scope. + ShortList<IRInst*> args; + for (UInt i = 0; i < inst->getOperandCount(); i++) + { + auto operand = inst->getOperand(i); + auto inlinedOperand = maybeInlineGlobalValue(builder, operand, cloneEnv); + args.add(inlinedOperand); } + auto result = cloneInst(&cloneEnv, &builder, inst); + cloneEnv.mapOldValToNew[inst] = result; + return result; + } + + void processWorkList() + { while (workList.getCount() != 0) { @@ -1284,6 +1428,39 @@ struct SPIRVLegalizationContext : public SourceEmitterBase break; } } + } + + void setInsertBeforeOutsideASM(IRBuilder& builder, IRInst* beforeInst) + { + auto parent = beforeInst->getParent(); + while (parent) + { + if (as<IRSPIRVAsm>(parent)) + { + builder.setInsertBefore(parent); + return; + } + parent = parent->getParent(); + } + builder.setInsertBefore(beforeInst); + } + + void processModule() + { + // Process global params before anything else, so we don't generate inefficient + // array marhalling code for array-typed global params. + for (auto globalInst : m_module->getGlobalInsts()) + { + if (auto globalParam = as<IRGlobalParam>(globalInst)) + { + processGlobalParam(globalParam); + } + else + { + addToWorkList(globalInst); + } + } + processWorkList(); // Translate types. List<IRHLSLStructuredBufferTypeBase*> instsToProcess; @@ -1302,6 +1479,8 @@ struct SPIRVLegalizationContext : public SourceEmitterBase t->replaceUsesWith(builder.getPtrType(kIROp_PtrType, lowered.structType, SpvStorageClassStorageBuffer)); } + List<IRUse*> globalInstUsesToInline; + for (auto globalInst : m_module->getGlobalInsts()) { if (auto func = as<IRFunc>(globalInst)) @@ -1314,8 +1493,27 @@ struct SPIRVLegalizationContext : public SourceEmitterBase // After legalizing the control flow, we need to sort our blocks to ensure this is true. sortBlocksInFunc(func); } + + if (isInlinableGlobalInst(globalInst)) + { + for (auto use = globalInst->firstUse; use; use = use->nextUse) + { + if (getParentFunc(use->getUser()) != nullptr) + globalInstUsesToInline.add(use); + } + } } + for (auto use : globalInstUsesToInline) + { + auto user = use->getUser(); + IRBuilder builder(user); + setInsertBeforeOutsideASM(builder, user); + IRCloneEnv cloneEnv; + auto val = maybeInlineGlobalValue(builder, use->get(), cloneEnv); + if (val != use->get()) + builder.replaceOperand(use, val); + } } }; diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index f8d2b3117..3b7fb9ac8 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -3448,6 +3448,18 @@ namespace Slang return inst; } + IRInst* IRBuilder::emitGlobalValueRef(IRInst* globalInst) + { + auto inst = createInst<IRGlobalValueRef>( + this, + kIROp_GlobalValueRef, + (IRType*)globalInst->getFullType(), + globalInst); + + addInst(inst); + return inst; + } + IRInst* IRBuilder::emitPackAnyValue(IRType* type, IRInst* value) { auto inst = createInst<IRPackAnyValue>( diff --git a/source/slang/slang-spirv-val.cpp b/source/slang/slang-spirv-val.cpp index b5a02f3fe..c03102d9f 100644 --- a/source/slang/slang-spirv-val.cpp +++ b/source/slang/slang-spirv-val.cpp @@ -18,20 +18,10 @@ static SlangResult disassembleSPIRV(const List<uint8_t>& spirv, String& outErr, const auto out = p->getStream(StdStreamType::Out); const auto err = p->getStream(StdStreamType::ErrorOut); - // Write the assembly - SLANG_RETURN_ON_FAIL(in->write(spirv.getBuffer(), spirv.getCount())); - in->close(); - - // Wait for it to finish List<Byte> outData; List<Byte> outErrData; - while (!out->isEnd() || !err->isEnd()) - { - if (!out->isEnd()) - StreamUtil::readAll(out, 0, outData); - if (!err->isEnd()) - StreamUtil::readAll(err, 0, outErrData); - } + SLANG_RETURN_ON_FAIL(StreamUtil::readAndWrite(in, spirv.getArrayView(), out, outData, err, outErrData)); + SLANG_RETURN_ON_FAIL(p->waitForTermination(10)); outDis = String( diff --git a/tests/cross-compile/rw-buffer.slang b/tests/cross-compile/rw-buffer.slang index f5246ed78..7cd04e93f 100644 --- a/tests/cross-compile/rw-buffer.slang +++ b/tests/cross-compile/rw-buffer.slang @@ -2,13 +2,26 @@ // Confirm that writing into a `RWBuffer` generates appropriate GLSL/SPIR-V. -//TEST:CROSS_COMPILE: -profile ps_5_0 -entry main -target spirv-assembly +//TEST:SIMPLE(filecheck=CHECK): -profile ps_5_0 -entry main -target spirv-assembly +//TEST:SIMPLE(filecheck=CHECK): -profile ps_5_0 -entry main -target spirv-assembly -emit-spirv-directly RWBuffer<float> buffer; - +Buffer<float> inBuffer; float4 main(float u : U, int idx : IDX) : SV_Target { - buffer[idx] = u; + // CHECK-DAG: OpImageQuerySize + + // CHECK-DAG: OpImageRead + + // CHECK-DAG: OpImageFetch + + // CHECK-DAG: OpImageWrite + + uint s1, s2; + buffer.GetDimensions(s1); + buffer.GetDimensions(s2); + + buffer[idx] = buffer[idx] + inBuffer[idx] + s1 + s2; return u; } diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-assign.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-assign.slang index 49fef7a4c..89b3b6b44 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-assign.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-assign.slang @@ -2,6 +2,7 @@ //TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile glsl_460+GL_EXT_ray_tracing -O0 -line-directive-mode none +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -O0 -emit-spirv-directly //DISABLE_TEST:COMPARE_COMPUTE_EX:-slang -compute -dx12 -output-using-type -profile sm_6_5 -nvapi-slot u0 //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_5 -render-feature ray-query diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-hit.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-hit.slang index 8fea9cf67..73278b6d2 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-hit.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-hit.slang @@ -1,8 +1,8 @@ // hit-object-make-hit.slang //TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 -//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none - +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none -O0 +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -emit-spirv-directly //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_5 -render-feature ray-query //DISABLE_TEST(compute):COMPARE_COMPUTE:-vk -output-using-type -render-feature ray-query @@ -22,12 +22,12 @@ struct SomeValues uint calcValue(HitObject hit) { // SPIRV-DAG: OpHitObjectIsHitNV - // SPIRV: OpHitObjectGetInstanceCustomIndexNV - // SPIRV: OpHitObjectGetInstanceIdNV - // SPIRV: OpHitObjectGetGeometryIndexNV - // SPIRV: OpHitObjectGetPrimitiveIndexNV - // SPIRV: OpHitObjectGetHitKindNV - // SPIRV: OpHitObjectIsMissNV + // SPIRV-DAG: OpHitObjectGetInstanceCustomIndexNV + // SPIRV-DAG: OpHitObjectGetInstanceIdNV + // SPIRV-DAG: OpHitObjectGetGeometryIndexNV + // SPIRV-DAG: OpHitObjectGetPrimitiveIndexNV + // SPIRV-DAG: OpHitObjectGetHitKindNV + // SPIRV-DAG: OpHitObjectIsMissNV uint r = 0; if (hit.IsHit()) diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-miss.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-miss.slang index 9aea89573..83e665069 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-miss.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-miss.slang @@ -2,6 +2,7 @@ //TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -emit-spirv-directly //DISABLE_TEST:COMPARE_COMPUTE_EX:-slang -compute -dx12 -output-using-type -profile sm_6_5 -nvapi-slot u0 //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_5 -render-feature ray-query diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-nop.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-nop.slang index e8c88e1ad..b8b91c90b 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-nop.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-make-nop.slang @@ -2,6 +2,7 @@ //TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -emit-spirv-directly //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_5 -render-feature ray-query //DISABLE_TEST(compute):COMPARE_COMPUTE:-vk -output-using-type -render-feature ray-query diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-output.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-output.slang index e06e63693..ba493ba08 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-output.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-output.slang @@ -5,6 +5,7 @@ //TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -emit-spirv-directly //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_5 -render-feature ray-query //DISABLE_TEST(compute):COMPARE_COMPUTE:-vk -output-using-type -render-feature ray-query diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-reorder-thread.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-reorder-thread.slang index 8498b9304..0d455df72 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-reorder-thread.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-reorder-thread.slang @@ -2,6 +2,7 @@ //TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -emit-spirv-directly //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_5 -render-feature ray-query //DISABLE_TEST(compute):COMPARE_COMPUTE:-vk -output-using-type -render-feature ray-query diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-motion-ray.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-motion-ray.slang index 4e8d52e10..4255a3936 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-motion-ray.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-motion-ray.slang @@ -3,6 +3,7 @@ // Motion rays not supported on HLSL impl currently //DISABLE_TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -emit-spirv-directly //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_6 -render-feature ray-query //DISABLE_TEST(compute):COMPARE_COMPUTE:-vk -output-using-type -render-feature ray-query diff --git a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-ray.slang b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-ray.slang index c1a29d647..0f60e3cf5 100644 --- a/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-ray.slang +++ b/tests/hlsl-intrinsic/shader-execution-reordering/hit-object-trace-ray.slang @@ -2,6 +2,7 @@ //TEST:SIMPLE: -target dxil -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -DNV_SHADER_EXTN_SLOT=u0 //TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -profile sm_6_5 -line-directive-mode none +//TEST:SIMPLE(filecheck=SPIRV): -target spirv -entry rayGenerationMain -stage raygeneration -emit-spirv-directly //DISABLE_TEST(compute):COMPARE_COMPUTE:-d3d12 -output-using-type -use-dxil -profile sm_6_6 -render-feature ray-query //DISABLE_TEST(compute):COMPARE_COMPUTE:-vk -output-using-type -render-feature ray-query diff --git a/tests/spirv/bool-vector.slang b/tests/spirv/bool-vector.slang new file mode 100644 index 000000000..17c58a29a --- /dev/null +++ b/tests/spirv/bool-vector.slang @@ -0,0 +1,25 @@ +// bool-vector.slang + +//TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -output-using-type + +// Test direct SPIR-V emit on arrays in uniforms. + +//TEST_INPUT:set resultBuffer = out ubuffer(data=[0 0 0 0], stride=4) +RWStructuredBuffer<uint> resultBuffer; + +struct Data +{ + bool4 bv; +}; + +//TEST_INPUT:set dataBuffer = ubuffer(data=[0 1 1 0], stride=4) +RWStructuredBuffer<Data> dataBuffer; + +[numthreads(1, 1, 1)] +void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID) +{ + // CHECK: 0 + // CHECK: 100 + resultBuffer[0] = dataBuffer[0].bv.x; + resultBuffer[1] = dataBuffer[0].bv.y ? 100 : 0; +} diff --git a/tools/gfx/d3d12/d3d12-shader-object.cpp b/tools/gfx/d3d12/d3d12-shader-object.cpp index fd92dbfa0..c5389f6ea 100644 --- a/tools/gfx/d3d12/d3d12-shader-object.cpp +++ b/tools/gfx/d3d12/d3d12-shader-object.cpp @@ -923,10 +923,14 @@ Result ShaderObjectImpl::setResource(ShaderOffset const& offset, IResourceView* if (resourceView == nullptr) { - // Create null descriptor for the binding. - auto destDescriptor = m_descriptorSet.resourceTable.getCpuHandle( - bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex); - return createNullDescriptor(d3dDevice, destDescriptor, bindingRange); + if (!bindingRange.isRootParameter) + { + // Create null descriptor for the binding. + auto destDescriptor = m_descriptorSet.resourceTable.getCpuHandle( + bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex); + return createNullDescriptor(d3dDevice, destDescriptor, bindingRange); + } + return SLANG_OK; } ResourceViewInternalImpl* internalResourceView = nullptr; |
