diff options
| author | ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> | 2024-04-03 09:30:46 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-03 09:30:46 -0400 |
| commit | a697b2c6707ee699cb734a03fa529dd214ac66cc (patch) | |
| tree | 1b68f4267159828092b512361faff4729510ea39 | |
| parent | c0482ec12d683e53aca56543b620a4ec02082e29 (diff) | |
Implement 8.14-8.19 of OpenGL-GLSL specification
The following PR implements 8.14-8.19 of the [OpenGL-GLSL specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf).
Fully implements all functions and built-in type's, resolves https://github.com/shader-slang/slang/issues/3692 for GLSL & SPRI-V targets.
_Notes:_
Testing Tools:
* Fragment shaders cannot test computational results. Only OpCodes are checked for proper emitting.
Implementation Notes:
* SubpassInput requires an unknown image format.
* SubpassInput is disjoint from TextureType: __SubpassImpl (.slang) & SubpassInputType (Compiler) to reduce code generation required.
* SubpassInput required an additional input layout modifier, input_attachment_index, this was added as a new parameter binding attribute. Since the following qualifiers can overlap with different resources (`layout(input_attachment_index = 0, binding = 0, set = 0)`) input_attachment_index is checked for overlapping resource bindings separately from other qualifiers with `LayoutResourceKind::InputAttachmentIndex`.
* `GLSLInputAttachmentIndexLayoutModifier` was added to enforce function parameters only accepting `in` decorated variables.
* `in` decorated variables needed to have emitting modified to allow directly emitting the variable into function calls if used as a parameter, normally Slang has a "global variable" shadow as a "global parameter" through a copy. This does not work and is solved using `GlobalVariableShadowingGlobalParameterDecoration` to build a relationship of "global variable" to "global parameter", we then resolve this relationship and replace "global variable" uses later in compile.
* `AtomicCounterMemory` memory-constraint requires `OpCapability AtomicStorage`, `AtomicStorage` is invalid for Vulkan targets. glslang outputs for `barrier`, `memoryBarrier`, and `groupMemoryBarrier` `AtomicCounterMemory` as a memory constraint. This compiles as valid SPIR-V for Vulkan since `OpCapability AtomicStorage` is not declared. This behavior of glslang is undefined as per [3.31.Capability of the SPIR-V specification](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_capability). We will omit `AtomicCounterMemory` from our barrier calls.
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 @@ -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 |
