summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/hlsl.meta.slang1035
-rwxr-xr-xsource/slang/slang-compiler.h23
-rw-r--r--source/slang/slang-emit-spirv-ops.h7
-rw-r--r--source/slang/slang-emit-spirv.cpp42
-rw-r--r--source/slang/slang-ir-inst-defs.h2
-rw-r--r--source/slang/slang-ir-insts.h13
-rw-r--r--source/slang/slang-ir-lower-buffer-element-type.cpp16
-rw-r--r--source/slang/slang-ir-simplify-for-emit.cpp2
-rw-r--r--source/slang/slang-ir-specialize-resources.cpp22
-rw-r--r--source/slang/slang-ir-specialize-resources.h1
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp224
-rw-r--r--source/slang/slang-ir.cpp12
-rw-r--r--source/slang/slang-spirv-val.cpp14
13 files changed, 1059 insertions, 354 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(