summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--prelude/slang-cpp-types.h2
-rw-r--r--slang.h8
-rw-r--r--source/slang/core.meta.slang3
-rw-r--r--source/slang/glsl.meta.slang640
-rw-r--r--source/slang/hlsl.meta.slang55
-rw-r--r--source/slang/slang-ast-modifier.h14
-rw-r--r--source/slang/slang-ast-type.cpp13
-rw-r--r--source/slang/slang-ast-type.h8
-rw-r--r--source/slang/slang-capabilities.capdef23
-rw-r--r--source/slang/slang-check-modifier.cpp19
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-emit-c-like.h5
-rw-r--r--source/slang/slang-emit-glsl.cpp26
-rw-r--r--source/slang/slang-emit-glsl.h2
-rw-r--r--source/slang/slang-emit-hlsl.cpp33
-rw-r--r--source/slang/slang-emit-hlsl.h2
-rw-r--r--source/slang/slang-emit-spirv-ops.h13
-rw-r--r--source/slang/slang-emit-spirv.cpp127
-rw-r--r--source/slang/slang-ir-any-value-marshalling.cpp5
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp38
-rw-r--r--source/slang/slang-ir-inst-defs.h5
-rw-r--r--source/slang/slang-ir-insts.h12
-rw-r--r--source/slang/slang-ir-specialize-resources.cpp2
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp15
-rw-r--r--source/slang/slang-ir-translate-glsl-global-var.cpp3
-rw-r--r--source/slang/slang-ir-util.cpp8
-rw-r--r--source/slang/slang-ir.h9
-rw-r--r--source/slang/slang-legalize-types.cpp4
-rw-r--r--source/slang/slang-lower-to-ir.cpp27
-rw-r--r--source/slang/slang-parameter-binding.cpp35
-rw-r--r--source/slang/slang-parser.cpp1
-rw-r--r--source/slang/slang-type-layout.cpp11
-rw-r--r--source/slang/slang-type-layout.h5
-rw-r--r--tests/glsl-intrinsic/fragment-processing/fragment-processing-interpolate-simple.slang28
-rw-r--r--tests/glsl-intrinsic/fragment-processing/fragment-processing-non-input-param-error.slang20
-rw-r--r--tests/glsl-intrinsic/fragment-processing/fragment-processing.slang137
-rw-r--r--tests/glsl-intrinsic/noise-functions/noise-functions.slang50
-rw-r--r--tests/glsl-intrinsic/shader-invocation-control/shader-invocation-control.slang40
-rw-r--r--tests/glsl-intrinsic/shader-invocation-group/shader-invocation-group.slang47
-rw-r--r--tests/glsl-intrinsic/shader-memory-control/shader-memory-control.slang137
-rw-r--r--tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error1.slang23
-rw-r--r--tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error2.slang20
-rw-r--r--tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error3.slang20
-rw-r--r--tests/glsl-intrinsic/subpass-input/input-attachment-index-use-error.slang11
-rw-r--r--tests/glsl-intrinsic/subpass-input/subpass-input-as-parameter.slang35
-rw-r--r--tests/glsl-intrinsic/subpass-input/subpass-input.slang88
46 files changed, 1760 insertions, 71 deletions
diff --git a/prelude/slang-cpp-types.h b/prelude/slang-cpp-types.h
index 74a750b63..3f805a8b7 100644
--- a/prelude/slang-cpp-types.h
+++ b/prelude/slang-cpp-types.h
@@ -224,6 +224,7 @@ enum
SLANG_BYTE_ADDRESS_BUFFER = 0x07,
SLANG_RESOURCE_UNKNOWN = 0x08,
SLANG_ACCELERATION_STRUCTURE = 0x09,
+ SLANG_TEXTURE_SUBPASS = 0x0A,
SLANG_RESOURCE_EXT_SHAPE_MASK = 0xF0,
@@ -238,6 +239,7 @@ enum
SLANG_TEXTURE_2D_MULTISAMPLE = SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG,
SLANG_TEXTURE_2D_MULTISAMPLE_ARRAY =
SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG | SLANG_TEXTURE_ARRAY_FLAG,
+ SLANG_TEXTURE_SUBPASS_MULTISAMPLE = SLANG_TEXTURE_SUBPASS | SLANG_TEXTURE_MULTISAMPLE_FLAG,
};
#endif
diff --git a/slang.h b/slang.h
index 0c3c41fe0..4014be401 100644
--- a/slang.h
+++ b/slang.h
@@ -2149,6 +2149,7 @@ extern "C"
SLANG_BYTE_ADDRESS_BUFFER = 0x07,
SLANG_RESOURCE_UNKNOWN = 0x08,
SLANG_ACCELERATION_STRUCTURE = 0x09,
+ SLANG_TEXTURE_SUBPASS = 0x0A,
SLANG_RESOURCE_EXT_SHAPE_MASK = 0xF0,
@@ -2163,6 +2164,7 @@ extern "C"
SLANG_TEXTURE_2D_MULTISAMPLE = SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG,
SLANG_TEXTURE_2D_MULTISAMPLE_ARRAY = SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG | SLANG_TEXTURE_ARRAY_FLAG,
+ SLANG_TEXTURE_SUBPASS_MULTISAMPLE = SLANG_TEXTURE_SUBPASS | SLANG_TEXTURE_MULTISAMPLE_FLAG,
};
#endif
typedef unsigned int SlangResourceAccessIntegral;
@@ -2251,6 +2253,9 @@ extern "C"
// The register space offset for the sub-elements that occupies register spaces.
SLANG_PARAMETER_CATEGORY_SUB_ELEMENT_REGISTER_SPACE,
+ // The input_attachment_index subpass occupancy tracker
+ SLANG_PARAMETER_CATEGORY_SUBPASS,
+
//
SLANG_PARAMETER_CATEGORY_COUNT,
@@ -2258,6 +2263,7 @@ extern "C"
// DEPRECATED:
SLANG_PARAMETER_CATEGORY_VERTEX_INPUT = SLANG_PARAMETER_CATEGORY_VARYING_INPUT,
SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT = SLANG_PARAMETER_CATEGORY_VARYING_OUTPUT,
+ SLANG_PARAMETER_CATEGORY_COUNT_V1 = SLANG_PARAMETER_CATEGORY_SUBPASS,
};
/** Types of API-managed bindings that a parameter might use.
@@ -2813,6 +2819,8 @@ namespace slang
SubElementRegisterSpace = SLANG_PARAMETER_CATEGORY_SUB_ELEMENT_REGISTER_SPACE,
+ InputAttachmentIndex = SLANG_PARAMETER_CATEGORY_SUBPASS,
+
// DEPRECATED:
VertexInput = SLANG_PARAMETER_CATEGORY_VERTEX_INPUT,
FragmentOutput = SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT,
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index ef3614e2e..2e878b065 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -2625,3 +2625,6 @@ attribute_syntax [KnownBuiltin(name : String)] : KnownBuiltinAttribute;
__attributeTarget(FunctionDeclBase)
attribute_syntax [NonUniformReturn] : NonDynamicUniformAttribute;
+
+__attributeTarget(FunctionDeclBase)
+attribute_syntax [__GLSLRequireShaderInputParameter(parameterNumber:int)] : GLSLRequireShaderInputParameterAttribute; \ No newline at end of file
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang
index d7b646810..e915442c7 100644
--- a/source/slang/glsl.meta.slang
+++ b/source/slang/glsl.meta.slang
@@ -7263,3 +7263,643 @@ __glsl_version(430) [require(glsl)]
}
}
}
+
+/// Section 8.14. Fragment Processing Functions
+
+[require(any_gfx_target, fragmentprocessing)]
+[__NoSideEffect]
+[ForceInline]
+public float dFdx(float p)
+{
+ return ddx(p);
+}
+[require(any_gfx_target, fragmentprocessing)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> dFdx(vector<float, N> p)
+{
+ return ddx(p);
+}
+
+[require(any_gfx_target, fragmentprocessing)]
+[__NoSideEffect]
+[ForceInline]
+public float dFdy(float p)
+{
+ return ddy(p);
+}
+[require(any_gfx_target, fragmentprocessing)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> dFdy(vector<float, N> p)
+{
+ return ddy(p);
+}
+
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+[__NoSideEffect]
+[ForceInline]
+public float dFdxFine(float p)
+{
+ return ddx_fine(p);
+}
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> dFdxFine(vector<float, N> p)
+{
+ return ddx_fine(p);
+}
+
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+[__NoSideEffect]
+[ForceInline]
+public float dFdyFine(float p)
+{
+ return ddy_fine(p);
+}
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> dFdyFine(vector<float, N> p)
+{
+ return ddy_fine(p);
+}
+
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+[__NoSideEffect]
+[ForceInline]
+public float dFdxCoarse(float p)
+{
+ return ddx_coarse(p);
+}
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> dFdxCoarse(vector<float, N> p)
+{
+ return ddx_coarse(p);
+}
+
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+[__NoSideEffect]
+[ForceInline]
+public float dFdyCoarse(float p)
+{
+ return ddy_coarse(p);
+}
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> dFdyCoarse(vector<float, N> p)
+{
+ return ddy_coarse(p);
+}
+
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+[__NoSideEffect]
+[ForceInline]
+public float fwidthFine(float p)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return abs(ddx_fine(p)) + abs(ddy_fine(p));
+ }
+ case glsl: __intrinsic_asm "fwidthFine($0)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthFine $$float result $p;
+ };
+ }
+ }
+}
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> fwidthFine(vector<float, N> p)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return abs(ddx_fine(p)) + abs(ddy_fine(p));
+ }
+ case glsl: __intrinsic_asm "fwidthFine($0)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthFine $$vector<float, N> result $p;
+ };
+ }
+ }
+}
+
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+[__NoSideEffect]
+[ForceInline]
+public float fwidthCoarse(float p)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return abs(ddx_coarse(p)) + abs(ddy_coarse(p));
+ }
+ case glsl: __intrinsic_asm "fwidthCoarse($0)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthCoarse $$float result $p;
+ };
+ }
+ }
+}
+[require(any_gfx_target, fragmentprocessing_derivativecontrol)]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vector<float, N> fwidthCoarse(vector<float, N> p)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return abs(ddx_coarse(p)) + abs(ddy_coarse(p));
+ }
+ case glsl: __intrinsic_asm "fwidthCoarse($0)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthCoarse $$vector<float, N> result $p;
+ };
+ }
+ }
+}
+
+[require(any_gfx_target, fragmentprocessing)]
+[__NoSideEffect]
+[__GLSLRequireShaderInputParameter(0)]
+public float interpolateAtCentroid(__ref float interpolant)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return EvaluateAttributeAtCentroid(interpolant);
+ }
+ case glsl: __intrinsic_asm "interpolateAtCentroid($0)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability InterpolationFunction;
+ OpExtInst $$float result glsl450 InterpolateAtCentroid &interpolant
+ };
+ }
+ }
+}
+[require(any_gfx_target, fragmentprocessing)]
+__generic<let N : int>
+[__NoSideEffect]
+[__GLSLRequireShaderInputParameter(0)]
+public vector<float, N> interpolateAtCentroid(__ref vector<float, N> interpolant)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return EvaluateAttributeAtCentroid(interpolant);
+ }
+ case glsl: __intrinsic_asm "interpolateAtCentroid($0)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability InterpolationFunction;
+ OpExtInst $$vector<float, N> result glsl450 InterpolateAtCentroid &interpolant
+ };
+ }
+ }
+}
+
+[require(any_gfx_target, fragmentprocessing)]
+[__NoSideEffect]
+[__GLSLRequireShaderInputParameter(0)]
+public float interpolateAtSample(__ref float interpolant, int sample)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return EvaluateAttributeAtSample(interpolant, sample);
+ }
+ case glsl: __intrinsic_asm "interpolateAtSample($0,$1)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability InterpolationFunction;
+ OpExtInst $$float result glsl450 InterpolateAtSample &interpolant $sample
+ };
+ }
+ }
+}
+[require(any_gfx_target, fragmentprocessing)]
+__generic<let N : int>
+[__NoSideEffect]
+[__GLSLRequireShaderInputParameter(0)]
+public vector<float, N> interpolateAtSample(__ref vector<float, N> interpolant, int sample)
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ return EvaluateAttributeAtSample(interpolant, sample);
+ }
+ case glsl: __intrinsic_asm "interpolateAtSample($0,$1)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability InterpolationFunction;
+ OpExtInst $$vector<float, N> result glsl450 InterpolateAtSample &interpolant $sample
+ };
+ }
+ }
+}
+
+[require(glsl_spirv, fragmentprocessing)]
+[__NoSideEffect]
+[__GLSLRequireShaderInputParameter(0)]
+public float interpolateAtOffset(__ref float interpolant, vec2 offset)
+{
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "interpolateAtOffset($0,$1)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability InterpolationFunction;
+ OpExtInst $$float result glsl450 InterpolateAtOffset &interpolant $offset
+ };
+ }
+ }
+}
+[require(glsl_spirv, fragmentprocessing)]
+__generic<let N : int>
+[__NoSideEffect]
+[__GLSLRequireShaderInputParameter(0)]
+public vector<float, N> interpolateAtOffset(__ref vector<float, N> interpolant, vec2 offset)
+{
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "interpolateAtOffset($0,$1)";
+ case spirv:
+ {
+ return spirv_asm
+ {
+ OpCapability InterpolationFunction;
+ OpExtInst $$vector<float, N> result glsl450 InterpolateAtOffset &interpolant $offset
+ };
+ }
+ }
+}
+
+/// Section 8.15. Noise Functions (deprecated)
+
+[deprecated("Always returns 0")]
+[__NoSideEffect]
+[ForceInline]
+public float noise1(float x)
+{
+ return 0.0f;
+}
+[deprecated("Always returns 0")]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public float noise1(vector<float, N> x)
+{
+ return 0.0f;
+}
+
+[deprecated("Always returns 0")]
+[__NoSideEffect]
+[ForceInline]
+public vec2 noise2(float x)
+{
+ return vec2(0.0f);
+}
+[deprecated("Always returns 0")]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vec2 noise2(vector<float, N> x)
+{
+ return vec2(0.0f);
+}
+
+[deprecated("Always returns 0")]
+[__NoSideEffect]
+[ForceInline]
+public vec3 noise3(float x)
+{
+ return vec3(0.0f);
+}
+[deprecated("Always returns 0")]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vec3 noise3(vector<float, N> x)
+{
+ return vec3(0.0f);
+}
+
+[deprecated("Always returns 0")]
+[__NoSideEffect]
+[ForceInline]
+public vec4 noise4(float x)
+{
+ return vec4(0.0f);
+}
+[deprecated("Always returns 0")]
+__generic<let N : int>
+[__NoSideEffect]
+[ForceInline]
+public vec4 noise4(vector<float, N> x)
+{
+ return vec4(0.0f);
+}
+
+/// Section 8.16. Shader Invocation Control Functions
+
+// TODO: for tessellation control shader: barrier() function may only
+// be placed inside the main() of the shader and may not be called within
+// control flow.
+// TODO: if called after a return, error.
+
+[require(any_gfx_target, compute_tess_gfx)]
+[ForceInline]
+public void barrier()
+{
+ __target_switch
+ {
+ case hlsl:
+ {
+ GroupMemoryBarrier();
+ }
+ case glsl: __intrinsic_asm "barrier()";
+ case spirv:
+ {
+ spirv_asm
+ {
+ OpControlBarrier Workgroup Workgroup AcquireRelease|WorkgroupMemory
+ };
+ }
+ }
+}
+
+/// Section 8.17. Shader Memory Control Functions
+
+[require(shadermemorycontrol)]
+[ForceInline]
+public void memoryBarrier()
+{
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "AllMemoryBarrier()";
+ case glsl: __intrinsic_asm "memoryBarrier()";
+ case spirv:
+ {
+ spirv_asm
+ {
+ OpCapability Shader;
+ OpMemoryBarrier Device AcquireRelease|WorkgroupMemory|ImageMemory|UniformMemory
+ };
+ }
+ }
+}
+
+// Does not exist in vulkan. The equivlent is now `memoryBarrierBuffer`
+// for vulkan since GL_EXT_vulkan_glsl_relaxed states that a atomic_counter
+// is a storage buffer object in implementation.
+
+// glslang will compile with `AtomicCounterMemory` since it does not use
+// the `AtomicStorage` OpCapability which is required for `AtomicCounterMemory`.
+// this is invalid/undefined spir-v for vulkan targets and should not be followed
+[require(any_gfx_target, shadermemorycontrol_compute)]
+[ForceInline]
+public void memoryBarrierAtomicCounter()
+{
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "AllMemoryBarrier()";
+ case glsl: __intrinsic_asm "memoryBarrierBuffer()";
+ case spirv:
+ {
+ spirv_asm
+ {
+ OpCapability Shader;
+ OpMemoryBarrier Device AcquireRelease|UniformMemory
+ };
+ }
+ }
+}
+[require(shadermemorycontrol)]
+[ForceInline]
+public void memoryBarrierBuffer()
+{
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "DeviceMemoryBarrier()";
+ case glsl: __intrinsic_asm "memoryBarrierBuffer()";
+ case spirv:
+ {
+ spirv_asm
+ {
+ OpCapability Shader;
+ OpMemoryBarrier Device AcquireRelease|UniformMemory
+ };
+ }
+ }
+}
+
+[require(any_gfx_target, shadermemorycontrol_compute)]
+[ForceInline]
+public void memoryBarrierShared()
+{
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "GroupMemoryBarrier()";
+ case glsl: __intrinsic_asm "memoryBarrierShared()";
+ case spirv:
+ {
+ spirv_asm
+ {
+ OpCapability Shader;
+ OpMemoryBarrier Device AcquireRelease|WorkgroupMemory
+ };
+ }
+ }
+}
+[require(shadermemorycontrol)]
+[ForceInline]
+public void memoryBarrierImage()
+{
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "DeviceMemoryBarrier()";
+ case glsl: __intrinsic_asm "memoryBarrierImage()";
+ case spirv:
+ {
+ spirv_asm
+ {
+ OpMemoryBarrier Device AcquireRelease|ImageMemory
+ };
+ }
+ }
+}
+[require(any_gfx_target, shadermemorycontrol_compute)]
+[ForceInline]
+public void groupMemoryBarrier()
+{
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "GroupMemoryBarrier()";
+ case glsl: __intrinsic_asm "groupMemoryBarrier()";
+ case spirv:
+ {
+ spirv_asm
+ {
+ OpMemoryBarrier Workgroup AcquireRelease|WorkgroupMemory|ImageMemory|UniformMemory
+ };
+ }
+ }
+}
+
+/// Section 8.18. Subpass-Input Functions
+
+${{{{
+struct SubpassLoadEntriesType
+{
+ const char* typeName;
+ const char* prefix;
+};
+static const SubpassLoadEntriesType kSubpassLoadEntries[] =
+ {
+ { "vec4", "" },
+ { "uvec4", "u" },
+ { "ivec4", "i" },
+ };
+for (const auto& subpassLoadEntry : kSubpassLoadEntries)
+{
+}}}}
+ [require(glsl_spirv, subpass)]
+ public typealias $(subpassLoadEntry.prefix)subpassInput = __SubpassImpl<
+ $(subpassLoadEntry.typeName),
+ 0 // isMS
+ >;
+
+ [require(glsl_spirv, subpass)]
+ public typealias $(subpassLoadEntry.prefix)subpassInputMS = __SubpassImpl<
+ $(subpassLoadEntry.typeName),
+ 1 // isMS
+ >;
+${{{{
+}
+}}}}
+
+ __generic<T>
+ [require(glsl_spirv, subpass)]
+ [__NoSideEffect]
+ [ForceInline]
+ public T subpassLoad(__SubpassImpl<T,0> subpass)
+ {
+ __target_switch
+ {
+ case hlsl: return subpass.SubpassLoad();
+ case glsl: __intrinsic_asm "subpassLoad($0)";
+ case spirv:
+ {
+ let zeroVec = ivec2(0);
+ return spirv_asm
+ {
+ OpCapability StorageImageReadWithoutFormat;
+ result:$$T = OpImageRead $subpass $zeroVec
+ };
+ }
+ }
+ }
+ __generic<T>
+ [require(glsl_spirv, subpass)]
+ [__NoSideEffect]
+ [ForceInline]
+ public T subpassLoad(__SubpassImpl<T,1> subpass, int sample)
+ {
+ __target_switch
+ {
+ case hlsl: return subpass.SubpassLoad(sample);
+ case glsl: __intrinsic_asm "subpassLoad($0, $1)";
+ case spirv:
+ {
+ let zeroVec = ivec2(0);
+ return spirv_asm
+ {
+ OpCapability StorageImageReadWithoutFormat;
+ result:$$T = OpImageRead $subpass $zeroVec Sample $sample
+ };
+ }
+ }
+ }
+
+/// Section 8.19. Shader Invocation Group Functions
+
+// Invocation functions compiles into SubgroupVoteKHR operations.
+// Instead of using these, we directly emit the non deprecated
+// alternatives
+__glsl_version(460)
+__spirv_version(1.3)
+[require(shaderinvocationgroup)]
+[NonUniformReturn]
+[ForceInline]
+public bool anyInvocation(bool value)
+{
+ return WaveActiveAnyTrue(value);
+}
+__glsl_version(460)
+__spirv_version(1.3)
+[require(shaderinvocationgroup)]
+[NonUniformReturn]
+[ForceInline]
+public bool allInvocations(bool value)
+{
+ return WaveActiveAllTrue(value);
+}
+__glsl_version(460)
+__spirv_version(1.3)
+[require(shaderinvocationgroup)]
+[NonUniformReturn]
+[ForceInline]
+public bool allInvocationsEqual(bool value)
+{
+ return WaveActiveAllEqual(value);
+} \ No newline at end of file
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 27ac6c415..972702170 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -11404,19 +11404,64 @@ ${{{{
}
//
-// Vulkan/SPIR-V specific features
+// SubpassInput
//
-struct VkSubpassInput<T>
+__magic_type(SubpassInputType)
+__intrinsic_type($(kIROp_SubpassInputType))
+struct __SubpassImpl<T, let isMS:int>
{
- T SubpassLoad();
}
-struct VkSubpassInputMS<T>
+__generic<T, let isMS:int=0>
+typealias SubpassInput = __SubpassImpl<T, isMS>;
+
+__generic<T>
+extension __SubpassImpl<T, 0>
{
- T SubpassLoad(int sampleIndex);
+ [ForceInline]
+ T SubpassLoad()
+ {
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "$0.SubpassLoad()";
+ case spirv:
+ {
+ let zeroVec = int2(0);
+ return spirv_asm
+ {
+ OpCapability StorageImageReadWithoutFormat;
+ result:$$T = OpImageRead $this $zeroVec
+ };
+ }
+ }
+ }
}
+__generic<T, let isMS:int=1>
+typealias SubpassInputMS = __SubpassImpl<T, isMS>;
+
+__generic<T>
+extension __SubpassImpl<T, 1>
+{
+ [ForceInline]
+ T SubpassLoad(int sample)
+ {
+ __target_switch
+ {
+ case hlsl: __intrinsic_asm "$0.SubpassLoad($1)";
+ case spirv:
+ {
+ let zeroVec = int2(0);
+ return spirv_asm
+ {
+ OpCapability StorageImageReadWithoutFormat;
+ result:$$T = OpImageRead $this $zeroVec Sample $sample
+ };
+ }
+ }
+ }
+}
///
/// Shader Execution Reordering (SER)
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 31cac6dda..c9b6c6376 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -242,6 +242,11 @@ class GLSLLocationLayoutModifier : public GLSLParsedLayoutModifier
SLANG_AST_CLASS(GLSLLocationLayoutModifier)
};
+class GLSLInputAttachmentIndexLayoutModifier : public GLSLParsedLayoutModifier
+{
+ SLANG_AST_CLASS(GLSLInputAttachmentIndexLayoutModifier)
+};
+
class GLSLBufferDataLayoutModifier : public GLSLParsedLayoutModifier
{
SLANG_AST_CLASS(GLSLBufferDataLayoutModifier)
@@ -1008,6 +1013,15 @@ class ReadNoneAttribute : public Attribute
};
+// A `[__GLSLRequireShaderInputParameter]` attribute to annotate
+// functions that require a shader input as parameter
+//
+class GLSLRequireShaderInputParameterAttribute : public Attribute
+{
+ SLANG_AST_CLASS(GLSLRequireShaderInputParameterAttribute)
+
+ uint32_t parameterNumber;
+};
// HLSL modifiers for geometry shader input topology
class HLSLGeometryShaderInputPrimitiveTypeModifier : public Modifier
diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp
index a398e2690..2dc746e09 100644
--- a/source/slang/slang-ast-type.cpp
+++ b/source/slang/slang-ast-type.cpp
@@ -841,6 +841,19 @@ bool ResourceType::isCombined()
return false;
}
+Type* SubpassInputType::getElementType()
+{
+ return as<Type>(_getGenericTypeArg(this, 0));
+}
+
+bool SubpassInputType::isMultisample()
+{
+ auto isMS = _getGenericTypeArg(this, 1);
+ if (auto constIntVal = as<ConstantIntVal>(isMS))
+ return constIntVal->getValue() != 0;
+ return false;
+}
+
SlangResourceAccess ResourceType::getAccess()
{
auto access = _getGenericTypeArg(this, kStdlibTextureAccessParameterIndex);
diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h
index 1e066fb2a..74fae139c 100644
--- a/source/slang/slang-ast-type.h
+++ b/source/slang/slang-ast-type.h
@@ -179,6 +179,14 @@ class GLSLImageType : public TextureTypeBase
SLANG_AST_CLASS(GLSLImageType)
};
+class SubpassInputType : public BuiltinType
+{
+ SLANG_AST_CLASS(SubpassInputType)
+
+ bool isMultisample();
+ Type* getElementType();
+};
+
class SamplerStateType : public BuiltinType
{
SLANG_AST_CLASS(SamplerStateType)
diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef
index b8d97d021..b83585c5c 100644
--- a/source/slang/slang-capabilities.capdef
+++ b/source/slang/slang-capabilities.capdef
@@ -65,7 +65,7 @@ alias any_target = hlsl | glsl | c | cpp | cuda | spirv;
alias any_textual_target = hlsl | glsl | c | cpp | cuda;
alias any_gfx_target = hlsl | glsl | spirv;
alias any_cpp_target = cpp | cuda;
-
+alias glsl_spirv = glsl | spirv;
// Capabilities that stand for target spirv version for GLSL backend.
// These are not compilation targets.
def glsl_spirv_1_0 : glsl;
@@ -109,6 +109,10 @@ def _sm_6_7 : _sm_6_6;
def hlsl_nvapi : hlsl;
+// stage alias
+alias tess_control = hull;
+alias tess_eval = domain;
+
// SPIRV extensions.
def SPV_EXT_fragment_shader_interlock : spirv_1_0;
@@ -249,6 +253,12 @@ alias GL_NV_ray_tracing = GL_EXT_ray_tracing;
// Define feature names
+alias tess_control_gfx = tess_control + any_gfx_target;
+alias tess_eval_gfx = tess_control + any_gfx_target;
+alias fragment_gfx = fragment + any_gfx_target;
+alias compute_gfx = compute + any_gfx_target;
+alias compute_tess_gfx = compute_gfx + tess_control_gfx + tess_eval_gfx;
+
alias nvapi = hlsl_nvapi;
alias raytracing = GL_EXT_ray_tracing | _sm_6_5 | cuda;
alias raytracing_pos = GL_EXT_ray_tracing + GL_EXT_ray_tracing_position_fetch | _sm_6_5 | cuda;
@@ -269,8 +279,12 @@ alias groupnonuniform = GL_KHR_shader_subgroup_ballot + GL_KHR_shader_subgroup_s
+ GL_KHR_shader_subgroup_arithmetic + GL_KHR_shader_subgroup_quad + GL_KHR_shader_subgroup_vote
| _sm_6_0 | cuda;
alias fragmentshaderbarycentric = GL_EXT_fragment_shader_barycentric | _sm_6_1;
-
-
+alias fragmentprocessing = fragment_gfx + glsl_spirv | fragment + _sm_5_0;
+alias fragmentprocessing_derivativecontrol = fragmentprocessing + GL_ARB_derivative_control;
+alias shadermemorycontrol = glsl | spirv_1_0 | _sm_5_0;
+alias shadermemorycontrol_compute = compute_gfx + shadermemorycontrol;
+alias subpass = fragment_gfx;
+alias shaderinvocationgroup = GL_KHR_shader_subgroup_vote + glsl | spirv_1_3 | _sm_6_0;
// Define what each HLSL shader model means on different targets.
@@ -371,9 +385,6 @@ alias GLSL_440 = glsl + sm_6_0 | spirv_1_5 + sm_6_0;
alias GLSL_450 = glsl + sm_6_3 | spirv_1_5 + sm_6_3;
alias GLSL_460 = glsl_spirv_1_5 + all | spirv_1_5 + all;
-alias tess_control = hull;
-alias tess_eval = domain;
-
alias DX_4_0 = sm_4_0;
alias DX_4_1 = sm_4_1;
alias DX_5_0 = sm_5_0;
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index a387e458c..718de86cc 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -428,6 +428,23 @@ namespace Slang
anyValueSizeAttr->size = int32_t(value->getValue());
}
+ else if (auto glslRequireShaderInputParameter = as<GLSLRequireShaderInputParameterAttribute>(attr))
+ {
+ if (attr->args.getCount() != 1)
+ {
+ return false;
+ }
+ auto value = checkConstantIntVal(attr->args[0]);
+ if (value == nullptr)
+ {
+ return false;
+ }
+ if (value->getValue() < 0)
+ {
+ return false;
+ }
+ glslRequireShaderInputParameter->parameterNumber = int32_t(value->getValue());
+ }
else if (auto overloadRankAttr = as<OverloadRankAttribute>(attr))
{
if (attr->args.getCount() != 1)
@@ -1072,6 +1089,7 @@ namespace Slang
case ASTNodeType::GLSLParsedLayoutModifier:
case ASTNodeType::GLSLConstantIDLayoutModifier:
case ASTNodeType::GLSLLocationLayoutModifier:
+ case ASTNodeType::GLSLInputAttachmentIndexLayoutModifier:
case ASTNodeType::GLSLOffsetLayoutAttribute:
case ASTNodeType::GLSLUnparsedLayoutModifier:
case ASTNodeType::GLSLLayoutModifierGroupMarker:
@@ -1150,6 +1168,7 @@ namespace Slang
case ASTNodeType::GLSLParsedLayoutModifier:
case ASTNodeType::GLSLConstantIDLayoutModifier:
case ASTNodeType::GLSLLocationLayoutModifier:
+ case ASTNodeType::GLSLInputAttachmentIndexLayoutModifier:
case ASTNodeType::GLSLOffsetLayoutAttribute:
case ASTNodeType::GLSLUnparsedLayoutModifier:
case ASTNodeType::GLSLLayoutModifierGroupMarker:
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 16e494d4a..752bcf03b 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -449,6 +449,8 @@ DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete t
DIAGNOSTIC(31204, Error, incompleteTypeCannotBeUsedInBuffer, "incomplete type '$0' cannot be used in a buffer")
DIAGNOSTIC(31205, Error, incompleteTypeCannotBeUsedInUniformParameter, "incomplete type '$0' cannot be used in a uniform parameter")
DIAGNOSTIC(31206, Error, memoryQualifierNotAllowedOnANonImageTypeParameter, "modifier $0 is not allowed on a non image type parameter.")
+DIAGNOSTIC(31207, Error, InputAttachmentIndexOnlyAllowedOnSubpass, "input_attachment_index is only allowed on subpass images.")
+DIAGNOSTIC(31208, Error, requireInputDecoratedVarForParameter, "$0 expects for argument $1 a type which is a shader input (`in`) variable.")
// Enums
diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h
index 7778c78f6..ee7ce413a 100644
--- a/source/slang/slang-emit-c-like.h
+++ b/source/slang/slang-emit-c-like.h
@@ -439,6 +439,8 @@ public:
void emitTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName) { emitTextureOrTextureSamplerTypeImpl(type, baseName); }
+ void emitSubpassInputType(IRSubpassInputType* type) { emitSubpassInputTypeImpl(type); }
+
virtual RefObject* getExtensionTracker() { return nullptr; }
/// Gets a source language for a target for a target. Returns Unknown if not a known target
@@ -503,6 +505,9 @@ public:
// Only needed for glsl output with $ prefix intrinsics - so perhaps removable in the future
virtual void emitTextureOrTextureSamplerTypeImpl(IRTextureTypeBase* type, char const* baseName) { SLANG_UNUSED(type); SLANG_UNUSED(baseName); }
+
+ virtual void emitSubpassInputTypeImpl(IRSubpassInputType* type) { SLANG_UNUSED(type); }
+
// Again necessary for & prefix intrinsics. May be removable in the future
virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) = 0;
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index bbd869eda..2347d086b 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -769,6 +769,16 @@ void GLSLSourceEmitter::_emitGLSLLayoutQualifiers(IRVarLayout* layout, EmitVarCh
}
}
+void GLSLSourceEmitter::_emitGLSLSubpassInputType(IRSubpassInputType* type)
+{
+ _emitGLSLTypePrefix(type->getElementType(), true);
+ m_writer->emit("subpassInput");
+ if (type->isMultisample())
+ {
+ m_writer->emit("MS");
+ }
+}
+
void GLSLSourceEmitter::_emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName)
{
if (type->getElementType()->getOp() == kIROp_HalfType)
@@ -2487,6 +2497,11 @@ void GLSLSourceEmitter::emitSimpleTypeImpl(IRType* type)
_emitGLSLTextureOrTextureSamplerType(imageType, "image");
return;
}
+ else if (auto subpassType = as<IRSubpassInputType>(type))
+ {
+ _emitGLSLSubpassInputType(subpassType);
+ return;
+ }
else if (const auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(type))
{
// TODO: We desugar global variables with structured-buffer type into GLSL
@@ -2724,6 +2739,17 @@ void GLSLSourceEmitter::emitVarDecorationsImpl(IRInst* varDecl)
break;
}
+ // non raytracing decorations
+ for (auto decoration : varDecl->getDecorations())
+ {
+ if (auto glslInputAttachment = as<IRGLSLInputAttachmentIndexDecoration>(decoration))
+ {
+ m_writer->emit(toSlice("layout(input_attachment_index = "));
+ m_writer->emit(glslInputAttachment->getIndex()->getValue());
+ m_writer->emit(toSlice(")\n"));
+ }
+ }
+
if (varDecl->findDecoration<IRGloballyCoherentDecoration>())
{
m_writer->emit("coherent\n");
diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h
index 610a961d2..d8a3e4e81 100644
--- a/source/slang/slang-emit-glsl.h
+++ b/source/slang/slang-emit-glsl.h
@@ -27,6 +27,7 @@ protected:
virtual void emitImageFormatModifierImpl(IRInst* varDecl, IRType* varType) SLANG_OVERRIDE;
virtual void emitLayoutQualifiersImpl(IRVarLayout* layout) SLANG_OVERRIDE;
+ virtual void emitSubpassInputTypeImpl(IRSubpassInputType* type) SLANG_OVERRIDE { _emitGLSLSubpassInputType(type); }
virtual void emitTextureOrTextureSamplerTypeImpl(IRTextureTypeBase* type, char const* baseName) SLANG_OVERRIDE { _emitGLSLTextureOrTextureSamplerType(type, baseName); }
virtual void emitFrontMatterImpl(TargetRequest* targetReq) SLANG_OVERRIDE;
@@ -58,6 +59,7 @@ protected:
virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE;
void _emitMemoryQualifierDecorations(IRInst* varDecl);
+ void _emitGLSLSubpassInputType(IRSubpassInputType* type);
void _emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName);
void _emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType);
diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp
index 37411c93e..120e37f09 100644
--- a/source/slang/slang-emit-hlsl.cpp
+++ b/source/slang/slang-emit-hlsl.cpp
@@ -92,6 +92,7 @@ void HLSLSourceEmitter::_emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitV
}
break;
+ case LayoutResourceKind::InputAttachmentIndex:
case LayoutResourceKind::RegisterSpace:
case LayoutResourceKind::GenericResource:
case LayoutResourceKind::ExistentialTypeParam:
@@ -304,6 +305,18 @@ void HLSLSourceEmitter::_emitHLSLTextureType(IRTextureTypeBase* texType)
m_writer->emit(" >");
}
+void HLSLSourceEmitter::_emitHLSLSubpassInputType(IRSubpassInputType* subpassType)
+{
+ m_writer->emit("SubpassInput");
+ if (subpassType->isMultisample())
+ {
+ m_writer->emit("MS");
+ }
+ m_writer->emit("<");
+ emitType(subpassType->getElementType());
+ m_writer->emit(">");
+}
+
void HLSLSourceEmitter::emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling)
{
auto layout = getVarLayout(inst);
@@ -981,6 +994,11 @@ void HLSLSourceEmitter::emitSimpleTypeImpl(IRType* type)
_emitHLSLTextureType(imageType);
return;
}
+ else if (auto subpassType = as<IRSubpassInputType>(type))
+ {
+ _emitHLSLSubpassInputType(subpassType);
+ return;
+ }
else if (auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(type))
{
switch (structuredBufferType->getOp())
@@ -1246,9 +1264,20 @@ void HLSLSourceEmitter::emitMeshShaderModifiersImpl(IRInst* varInst)
void HLSLSourceEmitter::emitVarDecorationsImpl(IRInst* varDecl)
{
- if (varDecl->findDecoration<IRGloballyCoherentDecoration>())
+ for(auto decoration : varDecl->getDecorations())
{
- m_writer->emit("globallycoherent\n");
+ if (as<IRGloballyCoherentDecoration>(decoration))
+ {
+ m_writer->emit("globallycoherent\n");
+ continue;
+ }
+ else if(auto glslInputAttachmentIndex = as<IRGLSLInputAttachmentIndexDecoration>(decoration))
+ {
+ m_writer->emit("[[vk::input_attachment_index(");
+ m_writer->emit(glslInputAttachmentIndex->getIndex()->getValue());
+ m_writer->emit(")]]\n");
+ continue;
+ }
}
}
diff --git a/source/slang/slang-emit-hlsl.h b/source/slang/slang-emit-hlsl.h
index 049d8af65..30f38b415 100644
--- a/source/slang/slang-emit-hlsl.h
+++ b/source/slang/slang-emit-hlsl.h
@@ -79,6 +79,8 @@ protected:
void _emitHLSLTextureType(IRTextureTypeBase* texType);
+ void _emitHLSLSubpassInputType(IRSubpassInputType* subpassType);
+
void _emitHLSLDecorationSingleString(const char* name, IRFunc* entryPoint, IRStringLit* val);
void _emitHLSLDecorationSingleInt(const char* name, IRFunc* entryPoint, IRIntLit* val);
diff --git a/source/slang/slang-emit-spirv-ops.h b/source/slang/slang-emit-spirv-ops.h
index 42aeb8316..8f75796a1 100644
--- a/source/slang/slang-emit-spirv-ops.h
+++ b/source/slang/slang-emit-spirv-ops.h
@@ -818,6 +818,19 @@ SpvInst* emitOpDecorateBinding(
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpDecorate
template<typename T>
+SpvInst* emitOpDecorateInputAttachmentIndex(
+ SpvInstParent* parent,
+ IRInst* inst,
+ const T& target,
+ const SpvLiteralInteger& bindingPoint
+)
+{
+ static_assert(isSingular<T>);
+ return emitInst(parent, inst, SpvOpDecorate, target, SpvDecorationInputAttachmentIndex, bindingPoint);
+}
+
+// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpDecorate
+template<typename T>
SpvInst* emitOpDecorateDescriptorSet(
SpvInstParent* parent,
IRInst* inst,
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index d32530b90..91078e1fa 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1514,6 +1514,8 @@ struct SPIRVEmitContext
SpvLiteralInteger::from32(stride));
return arrayType;
}
+ case kIROp_SubpassInputType:
+ return ensureSubpassInputType(inst, cast<IRSubpassInputType>(inst));
case kIROp_TextureType:
return ensureTextureType(inst, cast<IRTextureType>(inst));
case kIROp_SamplerStateType:
@@ -1824,39 +1826,62 @@ struct SPIRVEmitContext
}
}
- SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst)
+ struct ImageOpConstants
{
- // Some untyped constants from OpTypeImage
- // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage
-
- // indicates not a depth image
- [[maybe_unused]]
- const SpvWord notDepthImage = 0;
- // indicates a depth image
- [[maybe_unused]]
- const SpvWord isDepthImage = 1;
- // means no indication as to whether this is a depth or non-depth image
- const SpvWord unknownDepthImage = 2;
-
- // indicates non-arrayed content
- const SpvWord notArrayed = 0;
- // indicates arrayed content
- const SpvWord isArrayed = 1;
-
- // indicates single-sampled content
- const SpvWord notMultisampled = 0;
- // indicates multisampled content
- const SpvWord isMultisampled = 1;
-
- // indicates this is only known at run time, not at compile time
- const SpvWord sampledUnknown = 0;
- // indicates an image compatible with sampling operations
- const SpvWord sampledImage = 1;
- // indicates an image compatible with read/write operations (a storage or subpass data image).
- const SpvWord readWriteImage = 2;
+ enum : SpvWord
+ {
+ // Some untyped constants from OpTypeImage
+ // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage
- //
+ // indicates not a depth image
+ notDepthImage = 0,
+ // indicates a depth image
+ isDepthImage = 1,
+ // means no indication as to whether this is a depth or non-depth image
+ unknownDepthImage = 2,
+
+ // indicates non-arrayed content
+ notArrayed = 0,
+ // indicates arrayed content
+ isArrayed = 1,
+
+ // indicates this is only known at run time, not at compile time
+ sampledUnknown = 0,
+ // indicates an image compatible with sampling operations
+ sampledImage = 1,
+ // indicates an image compatible with read/write operations (a storage or subpass data image).
+ readWriteImage = 2,
+
+ // indicates single-sampled content
+ notMultisampled = 0,
+ // indicates multisampled content
+ isMultisampled = 1,
+ };
+ };
+
+ SpvInst* ensureSubpassInputType(IRInst* assignee, IRSubpassInputType* inst)
+ {
+ IRInst* sampledType = inst->getElementType();
+ SpvDim dim = SpvDimSubpassData;
+ SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled : ImageOpConstants::notMultisampled;
+ SpvWord sampled = 2;
+ requireSPIRVCapability(SpvCapabilityInputAttachment);
+ requireSPIRVCapability(SpvCapabilityStorageImageReadWithoutFormat);
+ setImageFormatCapabilityAndExtension(SpvImageFormatUnknown, SpvCapabilityShader);
+ return emitOpTypeImage(
+ assignee,
+ dropVector((IRType*)sampledType),
+ dim,
+ SpvLiteralInteger::from32(ImageOpConstants::unknownDepthImage),
+ SpvLiteralInteger::from32(0),
+ SpvLiteralInteger::from32(ms),
+ SpvLiteralInteger::from32(sampled),
+ SpvImageFormatUnknown
+ );
+ }
+ SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst)
+ {
IRInst* sampledType = inst->getElementType();
SpvDim dim = SpvDim1D; // Silence uninitialized warnings from msvc...
switch(inst->GetBaseShape())
@@ -1877,22 +1902,22 @@ struct SPIRVEmitContext
dim = SpvDimBuffer;
break;
}
- SpvWord arrayed = inst->isArray() ? isArrayed : notArrayed;
+ SpvWord arrayed = inst->isArray() ? ImageOpConstants::isArrayed : ImageOpConstants::notArrayed;
// Vulkan spec 16.1: "The “Depth” operand of OpTypeImage is ignored."
- SpvWord depth = unknownDepthImage; // No knowledge of if this is a depth image
- SpvWord ms = inst->isMultisample() ? isMultisampled : notMultisampled;
+ SpvWord depth = ImageOpConstants::unknownDepthImage; // No knowledge of if this is a depth image
+ SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled : ImageOpConstants::notMultisampled;
- SpvWord sampled = sampledUnknown;
+ SpvWord sampled = ImageOpConstants::sampledUnknown;
switch(inst->getAccess())
{
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ_WRITE:
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_RASTER_ORDERED:
- sampled = readWriteImage;
+ sampled = ImageOpConstants::readWriteImage;
break;
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_NONE:
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ:
- sampled = sampledImage;
+ sampled = ImageOpConstants::sampledImage;
break;
}
@@ -1953,40 +1978,37 @@ struct SPIRVEmitContext
// Capabilities, according to section 3.8
//
// SPIR-V requires that the sampled/rw info on the image isn't unknown
- SLANG_ASSERT(sampled == sampledImage || sampled == readWriteImage);
- if(isMultisampled)
+ SLANG_ASSERT(sampled == ImageOpConstants::sampledImage || sampled == ImageOpConstants::readWriteImage);
+ if(ms == ImageOpConstants::isMultisampled)
requireSPIRVCapability(SpvCapabilityStorageImageMultisample);
switch(dim)
{
case SpvDim1D:
- requireSPIRVCapability(sampled == sampledImage ? SpvCapabilitySampled1D : SpvCapabilityImage1D);
+ requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampled1D : SpvCapabilityImage1D);
break;
case SpvDim2D:
// Also requires Shader or Kernel, but these are a given (?)
- if(sampled == readWriteImage && ms == isMultisampled && arrayed == isArrayed)
+ if(sampled == ImageOpConstants::readWriteImage && ms == ImageOpConstants::isMultisampled && arrayed == ImageOpConstants::isArrayed)
requireSPIRVCapability(SpvCapabilityImageMSArray);
break;
case SpvDim3D:
break;
case SpvDimCube:
// Requires shader also
- if(sampled == readWriteImage && arrayed == isArrayed)
+ if(sampled == ImageOpConstants::readWriteImage && arrayed == ImageOpConstants::isArrayed)
requireSPIRVCapability(SpvCapabilityImageCubeArray);
break;
case SpvDimRect:
- requireSPIRVCapability(sampled == sampledImage ? SpvCapabilitySampledRect : SpvCapabilityImageRect);
+ requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledRect : SpvCapabilityImageRect);
break;
case SpvDimBuffer:
- requireSPIRVCapability(sampled == sampledImage ? SpvCapabilitySampledBuffer : SpvCapabilityImageBuffer);
- break;
- case SpvDimSubpassData:
- requireSPIRVCapability(SpvCapabilityInputAttachment);
+ requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledBuffer : SpvCapabilityImageBuffer);
break;
case SpvDimTileImageDataEXT:
SLANG_UNIMPLEMENTED_X("OpTypeImage Capabilities for SpvDimTileImageDataEXT");
break;
}
- if(format == SpvImageFormatUnknown && sampled == readWriteImage)
+ if(format == SpvImageFormatUnknown && sampled == ImageOpConstants::readWriteImage)
{
// TODO: It may not be necessary to have both of these
// depending on if we read or write
@@ -3290,6 +3312,17 @@ struct SPIRVEmitContext
);
}
break;
+ case kIROp_GLSLInputAttachmentIndexDecoration:
+ {
+ const auto c = cast<IRGLSLInputAttachmentIndexDecoration>(decoration);
+ emitOpDecorateInputAttachmentIndex(
+ getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvLiteralInteger::from32(int32_t(c->getIndex()->getValue()))
+ );
+ }
+ break;
case kIROp_VulkanHitAttributesDecoration:
case kIROp_VulkanCallablePayloadDecoration:
diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp
index 200f8bc55..13059a84a 100644
--- a/source/slang/slang-ir-any-value-marshalling.cpp
+++ b/source/slang/slang-ir-any-value-marshalling.cpp
@@ -4,6 +4,7 @@
#include "slang-ir-generics-lowering-context.h"
#include "slang-ir.h"
#include "slang-ir-insts.h"
+#include "slang-legalize-types.h"
namespace Slang
{
@@ -223,7 +224,7 @@ namespace Slang
break;
}
default:
- if (as<IRTextureTypeBase>(dataType) || as<IRSamplerStateTypeBase>(dataType))
+ if (isResourceType(dataType))
{
context->marshalResourceHandle(builder, dataType, concreteTypedVar);
return;
@@ -855,7 +856,7 @@ namespace Slang
return alignUp(offset, 4) + alignUp((SlangInt)anyValueSize, 4);
}
default:
- if (as<IRTextureTypeBase>(type) || as<IRSamplerStateTypeBase>(type))
+ if (isResourceType(type))
{
return alignUp(offset, 4) + 8;
}
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index c4a8fff5d..b741e7ffa 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -2732,6 +2732,44 @@ void legalizeEntryPointParameterForGLSL(
IRInst* materialized = materializeValue(builder, globalValue);
pp->replaceUsesWith(materialized);
+
+ // We finally need to replace all global variable references of a global
+ // parameter with the actual global parameter for all function calls.
+ // Global parameters are used with a OpStore to copy its data into a global
+ // variable intermediary. We will follow the uses of a global parameter until
+ // we find this OpStore, then we will replace uses of the intermediary object.
+ IRBuilder replaceBuilder(materialized);
+ for (auto dec : pp->getDecorations())
+ {
+ if (dec->getOp() != kIROp_GlobalVariableShadowingGlobalParameterDecoration)
+ continue;
+ auto globalVar = dec->getOperand(0);
+ auto globalVarType = cast<IRPtrTypeBase>(globalVar->getDataType())->getValueType();
+ auto key = dec->getOperand(1);
+
+ // we will be replacing uses of `globalVarToReplace`, we need globalVarToReplaceNextUse
+ // to catch the next use before it is removed from the list of uses
+ IRUse* globalVarToReplaceNextUse;
+ for (auto globalVarUse = globalVar->firstUse; globalVarUse; globalVarUse = globalVarToReplaceNextUse)
+ {
+ globalVarToReplaceNextUse = globalVarUse->nextUse;
+ auto user = globalVarUse->getUser();
+ if (user->getOp() != kIROp_Call)
+ continue;
+ for (Slang::UInt operandIndex = 0; operandIndex < user->getOperandCount();
+ operandIndex++)
+ {
+ auto operand = user->getOperand(operandIndex);
+ auto operandUse = user->getOperands() + operandIndex;
+ if (operand != globalVar)
+ continue;
+ replaceBuilder.setInsertBefore(user);
+ auto field = replaceBuilder.emitFieldExtract(globalVarType, materialized, key);
+ replaceBuilder.replaceOperand(operandUse, field);
+ break;
+ }
+ }
+ }
}
}
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index b717e50b3..62283a7d6 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -140,6 +140,8 @@ INST(Nop, nop, 0, 0)
INST(Std430BufferLayoutType, Std430Layout, 0, HOISTABLE)
INST(ScalarBufferLayoutType, ScalarLayout, 0, HOISTABLE)
+ INST(SubpassInputType, SubpassInputType, 2, HOISTABLE)
+
INST(TextureFootprintType, TextureFootprintType, 1, HOISTABLE)
INST(TextureShape1DType, TextureShape1DType, 0, HOISTABLE)
@@ -713,6 +715,8 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
INST(VulkanHitAttributesDecoration, vulkanHitAttributes, 0, 0)
INST(VulkanHitObjectAttributesDecoration, vulkanHitObjectAttributes, 0, 0)
+ INST(GlobalVariableShadowingGlobalParameterDecoration, GlobalVariableShadowingGlobalParameterDecoration, 2, 0)
+
INST(RequireSPIRVVersionDecoration, requireSPIRVVersion, 1, 0)
INST(RequireGLSLVersionDecoration, requireGLSLVersion, 1, 0)
INST(RequireGLSLExtensionDecoration, requireGLSLExtension, 1, 0)
@@ -860,6 +864,7 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
INST(GlobalOutputDecoration, output, 0, 0)
INST(GlobalInputDecoration, output, 0, 0)
INST(GLSLLocationDecoration, glslLocation, 1, 0)
+ INST(GLSLInputAttachmentIndexDecoration, glslInputAttachmentIndex, 1, 0)
INST(GLSLOffsetDecoration, glslOffset, 1, 0)
INST(GLSLVolatileDecoration, glslVolatile, 1, 0)
INST(GLSLRestrictDecoration, glslRestrict, 1, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 547b034a7..8151622ae 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -392,6 +392,12 @@ struct IRGLSLLocationDecoration : IRDecoration
IRIntLit* getLocation() { return cast<IRIntLit>(getOperand(0)); }
};
+struct IRGLSLInputAttachmentIndexDecoration : IRDecoration
+{
+ IR_LEAF_ISA(GLSLInputAttachmentIndexDecoration)
+ IRIntLit* getIndex() { return cast<IRIntLit>(getOperand(0)); }
+};
+
struct IRGLSLOffsetDecoration : IRDecoration
{
IR_LEAF_ISA(GLSLOffsetDecoration)
@@ -3407,6 +3413,7 @@ public:
IRInst* isShadow,
IRInst* isCombined,
IRInst* format);
+
IRComPtrType* getComPtrType(IRType* valueType);
/// Get a 'SPIRV literal'
@@ -4807,6 +4814,11 @@ public:
addDecoration(inst, kIROp_VulkanHitObjectAttributesDecoration, getIntValue(getIntType(), location));
}
+ void addGlobalVariableShadowingGlobalParameterDecoration(IRInst* inst, IRInst* globalVar, IRInst* key)
+ {
+ addDecoration(inst, kIROp_GlobalVariableShadowingGlobalParameterDecoration, globalVar, key);
+ }
+
void addMeshOutputDecoration(IROp d, IRInst* value, IRInst* maxCount)
{
SLANG_ASSERT(IRMeshOutputDecoration::isaImpl(d));
diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp
index a2bf14f4d..93a964d95 100644
--- a/source/slang/slang-ir-specialize-resources.cpp
+++ b/source/slang/slang-ir-specialize-resources.cpp
@@ -1234,6 +1234,8 @@ bool isIllegalGLSLParameterType(IRType* type)
break;
}
}
+ if(as<IRSubpassInputType>(type))
+ return true;
if (as<IRMeshOutputType>(type))
return true;
if (as<IRHLSLStreamOutputType>(type))
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index 68f1e02a2..f6370ca37 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -203,7 +203,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
return structType;
}
- static void insertLoadAtLatestLocation(IRInst* addrInst, IRUse* inUse)
+ static void insertLoadAtLatestLocation(IRInst* addrInst, IRUse* inUse, SpvStorageClass storageClass)
{
struct WorkItem { IRInst* addr; IRUse* use; };
List<WorkItem> workList;
@@ -247,6 +247,12 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
}
else if(const auto spirvAsmOperand = as<IRSPIRVAsmOperandInst>(user))
{
+ // Skip load's for referenced `Input` variables since a ref implies
+ // passing as is, which needs to be a pointer (pass as is).
+ if (user->getDataType()
+ && user->getDataType()->getOp() == kIROp_RefType
+ && storageClass == SpvStorageClassInput)
+ continue;
// If this is being used in an asm block, insert the load to
// just prior to the block.
const auto asmBlock = spirvAsmOperand->getAsmBlock();
@@ -277,6 +283,8 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
{
if (as<IRTextureTypeBase>(type))
return true;
+ if (as<IRSubpassInputType>(type))
+ return true;
if (as<IRSamplerStateTypeBase>(type))
return true;
if (const auto arr = as<IRArrayTypeBase>(type))
@@ -363,9 +371,10 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
{
format = decor->getFormat();
}
+
+ // If the texture has no format decoration, try to infer it from the type.
if (format == ImageFormat::unknown)
{
- // If the texture has no format decoration, try to infer it from the type.
auto elementType = textureType->getElementType();
Int vectorWidth = 1;
if (auto elementVecType = as<IRVectorType>(elementType))
@@ -642,7 +651,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
// Insert an explicit load at each use site.
traverseUses(inst, [&](IRUse* use)
{
- insertLoadAtLatestLocation(inst, use);
+ insertLoadAtLatestLocation(inst, use, storageClass);
});
}
else if (arrayType)
diff --git a/source/slang/slang-ir-translate-glsl-global-var.cpp b/source/slang/slang-ir-translate-glsl-global-var.cpp
index 90bc49b32..57bd71418 100644
--- a/source/slang/slang-ir-translate-glsl-global-var.cpp
+++ b/source/slang/slang-ir-translate-glsl-global-var.cpp
@@ -125,6 +125,9 @@ namespace Slang
auto inputType = cast<IRPtrTypeBase>(input->getDataType())->getValueType();
builder.emitStore(input,
builder.emitFieldExtract(inputType, inputParam, inputKeys[i]));
+ // Relate "global variable" to a "global parameter" for use later in compilation
+ // to resolve a "global variable" shadowing a "global parameter" relationship.
+ builder.addGlobalVariableShadowingGlobalParameterDecoration(inputParam, input, inputKeys[i]);
}
// For each entry point, introduce a new parameter to represent each input parameter,
diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp
index e1eb86508..380d1141e 100644
--- a/source/slang/slang-ir-util.cpp
+++ b/source/slang/slang-ir-util.cpp
@@ -411,6 +411,14 @@ void getTypeNameHint(StringBuilder& sb, IRInst* type)
getTypeNameHint(sb, type->getOperand(0));
sb << ">";
break;
+ case kIROp_SubpassInputType:
+ {
+ auto textureType = as<IRSubpassInputType>(type);
+ sb <<"SubpassInput";
+ if(textureType->isMultisample())
+ sb << "MS";
+ break;
+ }
case kIROp_TextureType:
case kIROp_GLSLImageType:
{
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 36e145c01..fb4ce117e 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -1459,6 +1459,15 @@ struct IRGLSLImageType : IRTextureTypeBase
IR_LEAF_ISA(GLSLImageType)
};
+struct IRSubpassInputType : IRType
+{
+ IRType* getElementType() { return (IRType*)getOperand(0); }
+ IRInst* getIsMultisampleInst() { return getOperand(1); }
+ bool isMultisample() { return getIntVal(getIsMultisampleInst()) == 1; }
+
+ IR_LEAF_ISA(SubpassInputType)
+};
+
struct IRSamplerStateTypeBase : IRType
{
IR_PARENT_ISA(SamplerStateTypeBase)
diff --git a/source/slang/slang-legalize-types.cpp b/source/slang/slang-legalize-types.cpp
index c8a840ce9..792429a01 100644
--- a/source/slang/slang-legalize-types.cpp
+++ b/source/slang/slang-legalize-types.cpp
@@ -189,6 +189,10 @@ bool isResourceType(IRType* type)
{
return true;
}
+ else if (const auto subpassInputType = as<IRSubpassInputType>(type))
+ {
+ return true;
+ }
else if(const auto untypedBufferType = as<IRUntypedBufferResourceType>(type))
{
return true;
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 1e324b4a4..2d9ecf574 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -2204,6 +2204,16 @@ void addVarDecorations(
builder->addDecoration(inst, kIROp_GLSLLocationDecoration,
builder->getIntValue(builder->getIntType(), stringToInt(glslLocationMod->valToken.getContent())));
}
+ else if (auto glslInputAttachmentMod = as<GLSLInputAttachmentIndexLayoutModifier>(mod))
+ {
+ auto subpassType = as<IRSubpassInputType>(inst->getDataType());
+
+ if (!subpassType)
+ context->getSink()->diagnose(inst, Diagnostics::InputAttachmentIndexOnlyAllowedOnSubpass);
+
+ builder->addDecoration(inst, kIROp_GLSLInputAttachmentIndexDecoration,
+ builder->getIntValue(builder->getIntType(), stringToInt(glslInputAttachmentMod->valToken.getContent())));
+ }
else if (auto glslOffsetMod = as<GLSLOffsetLayoutAttribute>(mod))
{
builder->addDecoration(inst, kIROp_GLSLOffsetDecoration,
@@ -3546,6 +3556,21 @@ struct ExprLoweringContext
// TODO: also need to handle this-type substitution here?
}
+ void validateInvokeExprArgsWithFunctionModifiers(
+ InvokeExpr* expr,
+ FunctionDeclBase* decl,
+ List<IRInst*>& irArgs)
+ {
+ if (auto glslRequireShaderInputParameter = decl->findModifier<GLSLRequireShaderInputParameterAttribute>())
+ {
+ if (!irArgs[glslRequireShaderInputParameter->parameterNumber]->findDecoration<IRGlobalInputDecoration>())
+ {
+ this->context->getSink()->diagnose(expr, Diagnostics::requireInputDecoratedVarForParameter, decl, glslRequireShaderInputParameter->parameterNumber);
+ }
+ return;
+ }
+ }
+
/// Lower an invoke expr, and attempt to fuse a store of the expr's result into destination.
/// If the store is fused, returns LoweredValInfo::None. Otherwise, returns the IR val representing the RValue.
LoweredValInfo visitInvokeExprImpl(InvokeExpr* expr, LoweredValInfo destination, const TryClauseEnvironment& tryEnv)
@@ -3663,6 +3688,8 @@ struct ExprLoweringContext
auto funcType = funcTypeInfo.type;
addDirectCallArgs(expr, funcDeclRef, &irArgs, &argFixups);
+ validateInvokeExprArgsWithFunctionModifiers(expr, as<FunctionDeclBase>(funcDeclRef.getDecl()), irArgs);
+
LoweredValInfo result;
if (funcTypeInfo.returnViaLastRefParam)
{
diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp
index 01b7f6724..6725380f2 100644
--- a/source/slang/slang-parameter-binding.cpp
+++ b/source/slang/slang-parameter-binding.cpp
@@ -1072,14 +1072,35 @@ static void addExplicitParameterBindings_GLSL(
semanticInfo.index = 0;
semanticInfo.space = 0;
+ LayoutSemanticInfo subpassSemanticInfo;
+ bool foundBinding = false;
+ bool foundSubpass = false;
+
if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot)) != nullptr )
{
- // Try to find `binding` and `set`
- if (auto attr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>())
+ for (auto dec : varDecl.getDecl()->modifiers)
{
- resInfo = foundResInfo;
- semanticInfo.index = attr->binding;
- semanticInfo.space = attr->set;
+ // Try to find `binding` and `set`
+ if (auto glslBindingAttr = as<GLSLBindingAttribute>(dec))
+ {
+ resInfo = foundResInfo;
+ semanticInfo.index = glslBindingAttr->binding;
+ semanticInfo.space = glslBindingAttr->set;
+ foundBinding = true;
+ if (foundSubpass)
+ break;
+ }
+ // Try to find `input_attachment_index`
+ else if (auto glslAttachmentIndexAttr = as<GLSLInputAttachmentIndexLayoutModifier>(dec))
+ {
+ // Subpass fills semantic info of a descriptor & subpass
+ subpassSemanticInfo.index = stringToInt(glslAttachmentIndexAttr->valToken.getContent());
+ subpassSemanticInfo.space = 0;
+ subpassSemanticInfo.kind = LayoutResourceKind::InputAttachmentIndex;
+ foundSubpass = true;
+ if (foundBinding)
+ break;
+ }
}
}
else if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::SubElementRegisterSpace)) != nullptr )
@@ -1113,6 +1134,9 @@ static void addExplicitParameterBindings_GLSL(
semanticInfo.kind = kind;
addExplicitParameterBinding(context, parameterInfo, varDecl.getDecl(), semanticInfo, count);
+ if (foundSubpass)
+ addExplicitParameterBinding(context, parameterInfo, varDecl.getDecl(), subpassSemanticInfo, count);
+
return;
}
@@ -2066,6 +2090,7 @@ static RefPtr<TypeLayout> processEntryPointVaryingParameter(
return arrayTypeLayout;
}
// Ignore a bunch of types that don't make sense here...
+ else if (const auto subpassType = as<SubpassInputType>(type)) { return nullptr; }
else if (const auto textureType = as<TextureType>(type)) { return nullptr; }
else if(const auto samplerStateType = as<SamplerStateType>(type)) { return nullptr; }
else if(const auto constantBufferType = as<ConstantBufferType>(type)) { return nullptr; }
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index cc3a661f3..e564b4956 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -8018,6 +8018,7 @@ namespace Slang
CASE(scalar, GLSLScalarModifier)
CASE(offset, GLSLOffsetLayoutAttribute)
CASE(location, GLSLLocationLayoutModifier)
+ CASE(input_attachment_index, GLSLInputAttachmentIndexLayoutModifier)
{
modifier = parser->astBuilder->create<GLSLUnparsedLayoutModifier>();
}
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index f7efd4ee4..195e14d79 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -823,6 +823,9 @@ struct HLSLObjectLayoutRulesImpl : ObjectLayoutRulesImpl
case ShaderParameterKind::SamplerState:
return SimpleLayoutInfo(LayoutResourceKind::SamplerState, 1);
+ case ShaderParameterKind::SubpassInput:
+ return SimpleLayoutInfo(LayoutResourceKind::InputAttachmentIndex, 1);
+
case ShaderParameterKind::TextureSampler:
case ShaderParameterKind::MutableTextureSampler:
case ShaderParameterKind::InputRenderTarget:
@@ -3858,6 +3861,14 @@ static TypeLayoutResult _createTypeLayout(
type,
rules);
}
+ else if (auto subpassType = as<SubpassInputType>(type))
+ {
+ ShaderParameterKind kind = ShaderParameterKind::SubpassInput;
+ return createSimpleTypeLayout(
+ rules->GetObjectLayout(kind, context.objectLayoutOptions),
+ type,
+ rules);
+ }
else if (auto atomicType = as<GLSLAtomicUintType>(type))
{
ShaderParameterKind kind = ShaderParameterKind::AtomicUint;
diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h
index a12c310b9..eb0884287 100644
--- a/source/slang/slang-type-layout.h
+++ b/source/slang/slang-type-layout.h
@@ -271,7 +271,8 @@ typedef slang::ParameterCategory LayoutResourceKind;
\
x(SubElementRegisterSpace) \
x(VertexInput) \
- x(FragmentOutput)
+ x(FragmentOutput) \
+ x(InputAttachmentIndex)
#define SLANG_PARAMETER_CATEGORY_FLAG(x) x = ParameterCategoryFlags(1) << int(slang::x),
@@ -946,6 +947,8 @@ enum class ShaderParameterKind
AppendConsumeStructuredBuffer,
AtomicUint,
+
+ SubpassInput,
};
struct SimpleLayoutRulesImpl
diff --git a/tests/glsl-intrinsic/fragment-processing/fragment-processing-interpolate-simple.slang b/tests/glsl-intrinsic/fragment-processing/fragment-processing-interpolate-simple.slang
new file mode 100644
index 000000000..fb1c72ed7
--- /dev/null
+++ b/tests/glsl-intrinsic/fragment-processing/fragment-processing-interpolate-simple.slang
@@ -0,0 +1,28 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+#version 450
+// CHECK_SPV-DAG: OpEntryPoint
+// CHECK_GLSL-DAG: void main(
+
+layout(location = 0) out ivec4 outColorActual;
+
+layout (location = 0) in float inDataV1;
+
+bool isOk(float a, float b) { return (a == b); }
+
+bool testFragmentProcessingInterpolateFunctions()
+{
+ float tmpStore = inDataV1;
+ return true
+ && interpolateAtCentroid(inDataV1) != -1.0f
+ && (tmpStore + inDataV1) != -0.1f
+ && isOk(inDataV1, tmpStore)
+ && inDataV1 != -1.0f
+ ;
+}
+
+void main() {
+ outColorActual = ivec4(true
+ && testFragmentProcessingInterpolateFunctions()
+ );
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/fragment-processing/fragment-processing-non-input-param-error.slang b/tests/glsl-intrinsic/fragment-processing/fragment-processing-non-input-param-error.slang
new file mode 100644
index 000000000..638dd0ea7
--- /dev/null
+++ b/tests/glsl-intrinsic/fragment-processing/fragment-processing-non-input-param-error.slang
@@ -0,0 +1,20 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+#version 450
+// CHECK_SPV-DAG: error 31208
+// CHECK_GLSL-DAG: error 31208
+
+layout(location = 0) out ivec4 outColorActual;
+
+layout (location = 0) in float inDataV1;
+bool testFragmentProcessingInterpolateFunctions()
+{
+ float v = 1.0f;
+ return interpolateAtCentroid(v) != -1.0f;
+}
+
+void main() {
+ outColorActual = ivec4(true
+ && testFragmentProcessingInterpolateFunctions()
+ );
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/fragment-processing/fragment-processing.slang b/tests/glsl-intrinsic/fragment-processing/fragment-processing.slang
new file mode 100644
index 000000000..909679bbe
--- /dev/null
+++ b/tests/glsl-intrinsic/fragment-processing/fragment-processing.slang
@@ -0,0 +1,137 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+#version 450
+
+layout(location = 0) out ivec4 outColorActual;
+
+layout (location = 0) in float inDataV1;
+layout (location = 1) in vec2 inDataV2;
+layout (location = 2) in vec3 inDataV3;
+layout (location = 3) in vec4 inDataV4;
+
+bool testFragmentProcessingDerivativeFunctionsScalar()
+{
+// CHECK_SPV: OpDPdx
+// CHECK_GLSL: dFdx
+// CHECK_SPV: OpDPdy
+// CHECK_GLSL: dFdy
+// CHECK_SPV: OpDPdxFine
+// CHECK_GLSL: dFdxFine
+// CHECK_SPV: OpDPdyFine
+// CHECK_GLSL: dFdyFine
+// CHECK_SPV: OpDPdxCoarse
+// CHECK_GLSL: dFdxCoarse
+// CHECK_SPV: OpDPdyCoarse
+// CHECK_GLSL: dFdyCoarse
+// CHECK_SPV: OpFwidth
+// CHECK_GLSL: fwidth
+// CHECK_SPV: OpFwidthFine
+// CHECK_GLSL: fwidthFine
+// CHECK_SPV: OpFwidthCoarse
+// CHECK_GLSL: fwidthCoarse
+ return true
+ && dFdx(1.0f) != -1.0f
+ && dFdy(1.0f) != -1.0f
+ && dFdxFine(1.0f) != -1.0f
+ && dFdyFine(1.0f) != -1.0f
+ && dFdxCoarse(1.0f) != -1.0f
+ && dFdyCoarse(1.0f) != -1.0f
+ && fwidth(1.0f) != -1.0f
+ && fwidthFine(1.0f) != -1.0f
+ && fwidthCoarse(1.0f) != -1.0f
+ ;
+}
+__generic<let N:int>
+bool testFragmentProcessingDerivativeFunctionsVector()
+{
+// CHECK_SPV: OpDPdx
+// CHECK_GLSL: dFdx
+// CHECK_SPV: OpDPdy
+// CHECK_GLSL: dFdy
+// CHECK_SPV: OpDPdxFine
+// CHECK_GLSL: dFdxFine
+// CHECK_SPV: OpDPdyFine
+// CHECK_GLSL: dFdyFine
+// CHECK_SPV: OpDPdxCoarse
+// CHECK_GLSL: dFdxCoarse
+// CHECK_SPV: OpDPdyCoarse
+// CHECK_GLSL: dFdyCoarse
+// CHECK_SPV: OpFwidth
+// CHECK_GLSL: fwidth
+// CHECK_SPV: OpFwidthFine
+// CHECK_GLSL: fwidthFine
+// CHECK_SPV: OpFwidthCoarse
+// CHECK_GLSL: fwidthCoarse
+ return true
+ && dFdx(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && dFdy(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && dFdxFine(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && dFdyFine(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && dFdxCoarse(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && dFdyCoarse(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && fwidth(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && fwidthFine(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ && fwidthCoarse(vector<float,N>(1.0f)) != vector<float,N>(-1.0f)
+ ;
+}
+bool testFragmentProcessingInterpolateFunctions()
+{
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtCentroid %inDataV1
+// CHECK_GLSL: interpolateAtCentroid{{.*}}inDataV1
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtSample %inDataV1 {{.*}}
+// CHECK_GLSL: interpolateAtSample{{.*}}inDataV1
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtOffset %inDataV1 {{.*}}
+// CHECK_GLSL: interpolateAtOffset{{.*}}inDataV1
+
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtCentroid %inDataV2
+// CHECK_GLSL: interpolateAtCentroid{{.*}}inDataV2
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtSample %inDataV2 {{.*}}
+// CHECK_GLSL: interpolateAtSample{{.*}}inDataV2
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtOffset %inDataV2 {{.*}}
+// CHECK_GLSL: interpolateAtOffset{{.*}}inDataV2
+
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtCentroid %inDataV3
+// CHECK_GLSL: interpolateAtCentroid{{.*}}inDataV3
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtSample %inDataV3 {{.*}}
+// CHECK_GLSL: interpolateAtSample{{.*}}inDataV3
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtOffset %inDataV3 {{.*}}
+// CHECK_GLSL: interpolateAtOffset{{.*}}inDataV3
+
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtCentroid %inDataV4
+// CHECK_GLSL: interpolateAtCentroid{{.*}}inDataV4
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtSample %inDataV4 {{.*}}
+// CHECK_GLSL: interpolateAtSample{{.*}}inDataV4
+// CHECK_SPV: {{.*}} = OpExtInst {{.*}} {{.*}} InterpolateAtOffset %inDataV4 {{.*}}
+// CHECK_GLSL: interpolateAtOffset{{.*}}inDataV4
+ return true
+ && interpolateAtCentroid(inDataV1) != -1.0f
+ && interpolateAtSample(inDataV1, 0) != -1.0f
+ && interpolateAtOffset(inDataV1, vec2(0.0f)) != -1.0f
+ && interpolateAtCentroid(inDataV2) != vector<float,2>(-1.0f)
+ && interpolateAtSample(inDataV2, 0) != vector<float,2>(-1.0f)
+ && interpolateAtOffset(inDataV2, vec2(0.0f)) != vector<float,2>(-1.0f)
+ && interpolateAtCentroid(inDataV3) != vector<float,3>(-1.0f)
+ && interpolateAtSample(inDataV3, 0) != vector<float,3>(-1.0f)
+ && interpolateAtOffset(inDataV3, vec2(0.0f)) != vector<float,3>(-1.0f)
+ && interpolateAtCentroid(inDataV4) != vector<float,4>(-1.0f)
+ && interpolateAtSample(inDataV4, 0) != vector<float,4>(-1.0f)
+ && interpolateAtOffset(inDataV4, vec2(0.0f)) != vector<float,4>(-1.0f)
+ ;
+}
+bool testFragmentProcessingFunctions()
+{
+ return true
+ && testFragmentProcessingDerivativeFunctionsScalar()
+ && testFragmentProcessingDerivativeFunctionsVector<2>()
+ && testFragmentProcessingDerivativeFunctionsVector<3>()
+ && testFragmentProcessingDerivativeFunctionsVector<4>()
+ && testFragmentProcessingInterpolateFunctions()
+ ;
+ ;
+}
+
+void main() {
+ outColorActual = ivec4(true
+ && testFragmentProcessingFunctions()
+ );
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/noise-functions/noise-functions.slang b/tests/glsl-intrinsic/noise-functions/noise-functions.slang
new file mode 100644
index 000000000..f7d04b987
--- /dev/null
+++ b/tests/glsl-intrinsic/noise-functions/noise-functions.slang
@@ -0,0 +1,50 @@
+//TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target glsl
+//TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly
+#version 460
+// CHECK: warning 31200
+
+buffer MyBlockName2
+{
+ uint data[];
+} outputBuffer;
+
+layout(local_size_x = 4) in;
+
+bool testNoiseScalar()
+{
+ return true
+ && noise1(1.0f) == 0.0f
+ && noise2(1.0f) == vec2(0.0f)
+ && noise3(1.0f) == vec3(0.0f)
+ && noise4(1.0f) == vec4(0.0f)
+ ;
+}
+
+__generic<let N:int>
+bool testNoiseVector()
+{
+ return true
+ && noise1(vector<float, N>(1.0f)) == 0.0f
+ && noise2(vector<float, N>(1.0f)) == vec2(0.0f)
+ && noise3(vector<float, N>(1.0f)) == vec3(0.0f)
+ && noise4(vector<float, N>(1.0f)) == vec4(0.0f)
+ ;
+}
+
+bool testNoiseFunctions()
+{
+ return true
+ && testNoiseScalar()
+ && testNoiseVector<2>()
+ && testNoiseVector<3>()
+ && testNoiseVector<4>()
+ ;
+}
+
+void computeMain()
+{
+ outputBuffer.data[0] = true
+ && testNoiseFunctions()
+ ;
+ // BUF: 1
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/shader-invocation-control/shader-invocation-control.slang b/tests/glsl-intrinsic/shader-invocation-control/shader-invocation-control.slang
new file mode 100644
index 000000000..4edb249f8
--- /dev/null
+++ b/tests/glsl-intrinsic/shader-invocation-control/shader-invocation-control.slang
@@ -0,0 +1,40 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly
+
+#version 460
+
+groupshared uint raceConditionShared;
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
+buffer MyBlockName2
+{
+ uint data[];
+} outputBuffer;
+
+layout(local_size_x = 4) in;
+bool testBarrier()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ raceConditionShared = 3;
+ barrier();
+ raceConditionShared = 1;
+ if (raceConditionShared != 1)
+ return false;
+ }
+ return true
+ && raceConditionShared == 1
+ ;
+}
+
+void computeMain()
+{
+ outputBuffer.data[0] = true
+ && testBarrier()
+ ;
+ // CHECK_GLSL: void main(
+ // CHECK_SPV: OpEntryPoint
+ // BUF: 1
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/shader-invocation-group/shader-invocation-group.slang b/tests/glsl-intrinsic/shader-invocation-group/shader-invocation-group.slang
new file mode 100644
index 000000000..201f33ea2
--- /dev/null
+++ b/tests/glsl-intrinsic/shader-invocation-group/shader-invocation-group.slang
@@ -0,0 +1,47 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly
+
+#version 460
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
+buffer MyBlockName2
+{
+ uint data[];
+} outputBuffer;
+
+layout(local_size_x = 4) in;
+
+bool testAnyInvocation()
+{
+ return true
+ && anyInvocation(gl_GlobalInvocationID.x == 0)
+ && anyInvocation(gl_GlobalInvocationID.x == 8) == false
+ ;
+}
+bool testAllInvocations()
+{
+ return true
+ && allInvocations(true)
+ && allInvocations(gl_GlobalInvocationID.x == 0) == false
+ ;
+}
+bool testAllInvocationsEqual()
+{
+ return true
+ && allInvocationsEqual(false)
+ && allInvocationsEqual(gl_GlobalInvocationID.x == 0) == false
+ ;
+}
+void computeMain()
+{
+ outputBuffer.data[0] = true
+ && testAnyInvocation()
+ && testAllInvocations()
+ && testAllInvocationsEqual()
+ ;
+ // CHECK_GLSL: void main(
+ // CHECK_SPV: OpEntryPoint
+ // BUF: 1
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/shader-memory-control/shader-memory-control.slang b/tests/glsl-intrinsic/shader-memory-control/shader-memory-control.slang
new file mode 100644
index 000000000..e6d9b7984
--- /dev/null
+++ b/tests/glsl-intrinsic/shader-memory-control/shader-memory-control.slang
@@ -0,0 +1,137 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly
+#version 460
+
+// CHECK_GLSL: void main(
+// CHECK_SPV: OpEntryPoint
+
+//TEST_INPUT:ubuffer(data=[2 2 2 2], stride=4):out,name=raceCondition
+buffer MyBlockName1
+{
+ uint data[];
+} raceCondition;
+
+groupshared uint raceConditionShared;
+
+//TEST_INPUT: set raceConditionImage = RWTexture1D(format=R32_SINT, size=4, content=one, mipMaps = 1)
+uniform layout(binding=0,r32i) iimage1D raceConditionImage;
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
+buffer MyBlockName2
+{
+ uint data[];
+} outputBuffer;
+
+layout(local_size_x = 32) in;
+
+bool testMemoryBarrier()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ raceCondition.data[0] = gl_GlobalInvocationID.x;
+ memoryBarrier();
+ raceCondition.data[0] = 1;
+ memoryBarrier();
+ if (raceCondition.data[0] != 1)
+ return false;
+ }
+ return true
+ && raceCondition.data[0] == 1
+ ;
+}
+bool testMemoryBarrierAtomicCounter()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ atomicExchange(raceCondition.data[1], 2);
+ memoryBarrierAtomicCounter();
+ atomicExchange(raceCondition.data[1], 1);
+ memoryBarrierAtomicCounter();
+ if (raceCondition.data[1] != 1)
+ return false;
+ }
+ return true
+ && raceCondition.data[1] == 1
+ ;
+}
+bool testMemoryBarrierBuffer()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ raceCondition.data[2] = gl_GlobalInvocationID.x;
+ memoryBarrierBuffer();
+ raceCondition.data[2] = 1;
+ memoryBarrierBuffer();
+ if (raceCondition.data[2] != 1)
+ return false;
+ }
+ return true
+ && raceCondition.data[2] == 1
+ ;
+}
+bool testMemoryBarrierShared()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ raceConditionShared = 2;
+ memoryBarrierShared();
+ raceConditionShared = 1;
+ memoryBarrierShared();
+ if (raceConditionShared != 1)
+ return false;
+ }
+ return true
+ && raceConditionShared == 1
+ ;
+}
+bool testMemoryBarrierImage()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ imageStore(raceConditionImage, 0, 2);
+ memoryBarrierShared();
+ imageStore(raceConditionImage, 0, 1);
+ memoryBarrierShared();
+ if (imageLoad(raceConditionImage, 0).x != 1)
+ return false;
+ }
+ return true
+ && imageLoad(raceConditionImage, 0).x == 1
+ ;
+}
+bool testGroupMemoryBarrier()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ raceCondition.data[3] = gl_GlobalInvocationID.x;
+ groupMemoryBarrier();
+ raceCondition.data[3] = 1;
+ groupMemoryBarrier();
+ if (raceCondition.data[3] != 1)
+ return false;
+ }
+ return true
+ && raceCondition.data[3] == 1
+ ;
+}
+bool testMemoryBarriers()
+{
+ return true
+ && testMemoryBarrier()
+ && testMemoryBarrierAtomicCounter()
+ && testMemoryBarrierBuffer()
+ && testMemoryBarrierShared()
+ && testMemoryBarrierImage()
+ && testGroupMemoryBarrier()
+ ;
+}
+
+void computeMain()
+{
+ outputBuffer.data[0] = true
+ && testMemoryBarriers()
+ ;
+ // BUF: 1
+}
diff --git a/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error1.slang b/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error1.slang
new file mode 100644
index 000000000..82b56f872
--- /dev/null
+++ b/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error1.slang
@@ -0,0 +1,23 @@
+//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+#version 450
+// CHECK: warning 39001
+buffer MyBlockName
+{
+ uvec4 idata[2];
+} keepAliveBuffer;
+
+layout(location = 0) in highp vec4 a_position;
+layout(location = 0) in highp vec4 b_position;
+
+layout (input_attachment_index = 2, set = 0, binding = 0) uniform isubpassInput isubpass;
+layout (input_attachment_index = 2, set = 0, binding = 1) uniform isubpassInputMS isubpassMS;
+
+layout (location = 0) out vec4 outColor;
+
+void main() {
+ keepAliveBuffer.idata[0] = subpassLoad(isubpass);
+ keepAliveBuffer.idata[1] = subpassLoad(isubpassMS, 0);
+
+ outColor = vec4(0);
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error2.slang b/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error2.slang
new file mode 100644
index 000000000..d70377660
--- /dev/null
+++ b/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error2.slang
@@ -0,0 +1,20 @@
+//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+#version 450
+// CHECK: warning 39001
+buffer MyBlockName
+{
+ uvec4 idata[2];
+} keepAliveBuffer;
+
+layout (input_attachment_index = 0, set = 0, binding = 1) uniform isubpassInput isubpass;
+layout (input_attachment_index = 1, set = 0, binding = 1) uniform isubpassInputMS isubpassMS;
+
+layout (location = 0) out vec4 outColor;
+
+void main() {
+ keepAliveBuffer.idata[0] = subpassLoad(isubpass);
+ keepAliveBuffer.idata[1] = subpassLoad(isubpassMS, 0);
+
+ outColor = vec4(0);
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error3.slang b/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error3.slang
new file mode 100644
index 000000000..c2396dbfe
--- /dev/null
+++ b/tests/glsl-intrinsic/subpass-input/input-attachment-index-overlapping-error3.slang
@@ -0,0 +1,20 @@
+//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+#version 450
+// CHECK: warning 39001
+buffer MyBlockName
+{
+ uvec4 idata[2];
+} keepAliveBuffer;
+
+layout (input_attachment_index = 0, binding = 1) uniform isubpassInput isubpass;
+layout (input_attachment_index = 1, binding = 1) uniform isubpassInputMS isubpassMS;
+
+layout (location = 0) out vec4 outColor;
+
+void main() {
+ keepAliveBuffer.idata[0] = subpassLoad(isubpass);
+ keepAliveBuffer.idata[1] = subpassLoad(isubpassMS, 0);
+
+ outColor = vec4(0);
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/subpass-input/input-attachment-index-use-error.slang b/tests/glsl-intrinsic/subpass-input/input-attachment-index-use-error.slang
new file mode 100644
index 000000000..889a4e205
--- /dev/null
+++ b/tests/glsl-intrinsic/subpass-input/input-attachment-index-use-error.slang
@@ -0,0 +1,11 @@
+//TEST:SIMPLE(filecheck=CHECK): -target glsl -stage fragment -entry main -allow-glsl
+#version 450
+
+// CHECK: error 31207
+layout (input_attachment_index = 1, set = 0, binding = 1) uniform vec3 image;
+
+layout (location = 0) out vec4 outColor;
+
+void main() {
+ outColor = vec4(0);
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/subpass-input/subpass-input-as-parameter.slang b/tests/glsl-intrinsic/subpass-input/subpass-input-as-parameter.slang
new file mode 100644
index 000000000..a415fcf81
--- /dev/null
+++ b/tests/glsl-intrinsic/subpass-input/subpass-input-as-parameter.slang
@@ -0,0 +1,35 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+
+#version 450
+
+// CHECK_SPV-DAG: InputAttachmentIndex 0
+// CHECK_SPV-DAG: OpTypeImage %float SubpassData 2 0 0 2 Unknown
+// CHECK_GLSL: subpassInput
+
+layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput subpass;
+
+// CHECK_SPV-DAG: InputAttachmentIndex 1
+// CHECK_SPV-DAG: OpTypeImage %float SubpassData 2 0 1 2 Unknown
+// CHECK_GLSL: subpassInputMS
+layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInputMS subpassMS;
+
+layout (location = 0) out vec4 outColor;
+
+void someSideEffect(subpassInput subpassTmp)
+{
+ outColor.xy = subpassLoad(subpassTmp).xy;
+}
+
+void someSideEffectMS(subpassInputMS subpassTmp)
+{
+ outColor.zw = subpassLoad(subpassTmp, 0).zw;
+}
+
+// CHECK_GLSL-DAG: void main(
+// CHECK_SPV-DAG: OpEntryPoint
+
+void main() {
+ someSideEffect(subpass);
+ someSideEffectMS(subpassMS);
+} \ No newline at end of file
diff --git a/tests/glsl-intrinsic/subpass-input/subpass-input.slang b/tests/glsl-intrinsic/subpass-input/subpass-input.slang
new file mode 100644
index 000000000..0597cc06c
--- /dev/null
+++ b/tests/glsl-intrinsic/subpass-input/subpass-input.slang
@@ -0,0 +1,88 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -target glsl -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK_SPV): -target spirv -emit-spirv-directly -stage fragment -entry main -allow-glsl
+//TEST:SIMPLE(filecheck=CHECK_HLSL): -target hlsl -stage fragment -entry main -allow-glsl
+
+#version 450
+// CHECK_SPV-DAG: OpEntryPoint
+
+// CHECK_SPV-DAG: InputAttachmentIndex 0
+// CHECK_SPV-DAG: InputAttachmentIndex 1
+// CHECK_SPV-DAG: InputAttachmentIndex 2
+// CHECK_SPV-DAG: InputAttachmentIndex 3
+// CHECK_SPV-DAG: InputAttachmentIndex 4
+// CHECK_SPV-DAG: InputAttachmentIndex 5
+
+// CHECK_SPV-DAG: OpTypeImage %float SubpassData 2 0 0 2 Unknown
+// CHECK_GLSL-DAG: input_attachment_index = 0
+// CHECK_GLSL-DAG: subpassInput
+// CHECK_HLSL-DAG: vk::input_attachment_index(0)
+// CHECK_HLSL-DAG: SubpassInput<float4>
+layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput subpass;
+
+// CHECK_SPV-DAG: OpTypeImage %float SubpassData 2 0 1 2 Unknown
+// CHECK_GLSL-DAG: input_attachment_index = 1
+// CHECK_GLSL-DAG: subpassInputMS
+// CHECK_HLSL-DAG: vk::input_attachment_index(1)
+// CHECK_HLSL-DAG: SubpassInputMS<float4>
+layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInputMS subpassMS;
+
+// CHECK_SPV-DAG: OpTypeImage %uint SubpassData 2 0 0 2 Unknown
+// CHECK_GLSL-DAG: input_attachment_index = 2
+// CHECK_GLSL-DAG: usubpassInput
+// CHECK_HLSL-DAG: vk::input_attachment_index(2)
+// CHECK_HLSL-DAG: SubpassInput<uint4>
+layout (input_attachment_index = 2, set = 0, binding = 2) uniform usubpassInput usubpass;
+
+// CHECK_SPV-DAG: OpTypeImage %uint SubpassData 2 0 1 2 Unknown
+// CHECK_GLSL-DAG: input_attachment_index = 3
+// CHECK_GLSL-DAG: usubpassInputMS
+// CHECK_HLSL-DAG: vk::input_attachment_index(3)
+// CHECK_HLSL-DAG: SubpassInputMS<uint4>
+layout (input_attachment_index = 3, set = 0, binding = 3) uniform usubpassInputMS usubpassMS;
+
+// CHECK_SPV-DAG: OpTypeImage %int SubpassData 2 0 0 2 Unknown
+// CHECK_GLSL-DAG: input_attachment_index = 4
+// CHECK_GLSL-DAG: isubpassInput
+// CHECK_HLSL-DAG: vk::input_attachment_index(4)
+// CHECK_HLSL-DAG: SubpassInput<int4>
+layout (input_attachment_index = 4, set = 0, binding = 4) uniform isubpassInput isubpass;
+
+// CHECK_SPV-DAG: OpTypeImage %int SubpassData 2 0 1 2 Unknown
+// CHECK_GLSL-DAG: input_attachment_index = 5
+// CHECK_GLSL-DAG: isubpassInputMS
+// CHECK_HLSL-DAG: vk::input_attachment_index(5)
+// CHECK_HLSL-DAG: SubpassInputMS<int4>
+layout (input_attachment_index = 5, set = 0, binding = 5) uniform isubpassInputMS isubpassMS;
+
+layout (location = 0) out vec4 outColor;
+
+// CHECK_GLSL-DAG: void main()
+// CHECK_HLSL-DAG: main()
+void main() {
+// CHECK_SPV: OpImageRead
+// CHECK_GLSL: subpassLoad
+// CHECK_HLSL: SubpassLoad
+// CHECK_SPV: OpImageRead
+// CHECK_GLSL: subpassLoad
+// CHECK_HLSL: SubpassLoad
+// CHECK_SPV: OpImageRead
+// CHECK_GLSL: subpassLoad
+// CHECK_HLSL: SubpassLoad
+// CHECK_SPV: OpImageRead
+// CHECK_GLSL: subpassLoad
+// CHECK_HLSL: SubpassLoad
+// CHECK_SPV: OpImageRead
+// CHECK_GLSL: subpassLoad
+// CHECK_HLSL: SubpassLoad
+// CHECK_SPV: OpImageRead
+// CHECK_GLSL: subpassLoad
+// CHECK_HLSL: SubpassLoad
+ outColor = vec4(true
+ && subpassLoad(subpass) == vec4(1)
+ && subpassLoad(subpassMS, 0) == vec4(1)
+ && subpassLoad(isubpass) == ivec4(1)
+ && subpassLoad(isubpassMS, 0) == ivec4(1)
+ && subpassLoad(usubpass) == uvec4(1)
+ && subpassLoad(usubpassMS, 0) == uvec4(1)
+ );
+} \ No newline at end of file