summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2024-06-28 04:07:12 -0400
committerGitHub <noreply@github.com>2024-06-28 04:07:12 -0400
commite49419b0637a357d2e713a0435f0c5ad0c102487 (patch)
tree61f815078f7b3b6187abd28101cea76f611462a2
parentfd32b1879c8a4de7e97a99be7e0e8093ade8b340 (diff)
Implement HLSL resource bindings and default type `float4` to `SubpassInput<T>` (#4462)
* Add case to `emitVectorReshape` for `vector<>` type, `scalar` value 1. Add new case 2. Add test * fix warning * fix warning * Implement HLSL resource bindings and default type `float4` to `SubpassInput<T>` fixes: #4440 1. Removed GLSLInputAttachmentIndexLayout modifier and the somewhat 'hacky' binding model 'Input Attachment' previously relied upon. This was changed to work with the slang-type-layout rules system. This change allows Slang automatic bindings, HLSL bindings, GLSL bindings, and translation of GLSL to and from HLSL bindings to work. 2. Added default argument `float4` to SubpassInput<T>. 3. Merged glsl.meta and hlsl.meta SubpassInput logic. * fix InputAttachment attribute checks fix InputAttachment attribute checks for HLSL and GLSL syntax * remove unused var * validate attribute correctly Attributes do not have type information. We must check the type expression to validate attribute usage. * remove hacky validation type based validation before types are fully resolved is quite hacky and unstable to changes and wrapped types * fix warning * remove redundant `!= nullptr` * remove extra `!= nullptr` * fix some warnings/errors * subpass capability to limit to dxc & remove default values in some functions * revert logic to previous logic revert logic to return if we have a binding regardless of if a VarDecl is given the binding
-rw-r--r--source/slang/core.meta.slang3
-rw-r--r--source/slang/glsl.meta.slang30
-rw-r--r--source/slang/hlsl.meta.slang10
-rw-r--r--source/slang/slang-ast-modifier.h13
-rw-r--r--source/slang/slang-capabilities.capdef2
-rw-r--r--source/slang/slang-check-modifier.cpp15
-rw-r--r--source/slang/slang-check-shader.cpp2
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-emit-c-like.cpp15
-rw-r--r--source/slang/slang-emit-c-like.h12
-rw-r--r--source/slang/slang-emit-cuda.cpp4
-rw-r--r--source/slang/slang-emit-cuda.h2
-rw-r--r--source/slang/slang-emit-glsl.cpp17
-rw-r--r--source/slang/slang-emit-hlsl.cpp29
-rw-r--r--source/slang/slang-emit-hlsl.h8
-rw-r--r--source/slang/slang-emit-spirv.cpp21
-rw-r--r--source/slang/slang-ir-inst-defs.h1
-rw-r--r--source/slang/slang-ir-insts.h5
-rw-r--r--source/slang/slang-lower-to-ir.cpp10
-rw-r--r--source/slang/slang-parameter-binding.cpp138
-rw-r--r--source/slang/slang-parser.cpp16
-rw-r--r--source/slang/slang-type-layout.cpp21
-rw-r--r--tests/glsl-intrinsic/subpass-input/input-attachment-index-use-error.slang11
-rw-r--r--tests/glsl-intrinsic/subpass-input/subpass-input-hlsl.slang32
24 files changed, 243 insertions, 175 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 6b396a621..631c09d19 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -2475,6 +2475,9 @@ attribute_syntax [vk_index(index : int)] : GLSLIndexAttribute;
__attributeTarget(FuncDecl)
attribute_syntax [vk_spirv_instruction(op : int, set : String = "")] : SPIRVInstructionOpAttribute;
+__attributeTarget(VarDeclBase)
+attribute_syntax [vk_input_attachment_index(location : int)] : GLSLInputAttachmentIndexLayoutAttribute;
+
__attributeTarget(FuncDecl)
attribute_syntax [spv_target_env_1_3] : SPIRVTargetEnv13Attribute;
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang
index f18e07fbd..85d39493b 100644
--- a/source/slang/glsl.meta.slang
+++ b/source/slang/glsl.meta.slang
@@ -9556,20 +9556,7 @@ ${{{{
[require(glsl_hlsl_spirv, subpass)]
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
- };
- }
- }
+ return subpass.SubpassLoad();
}
__generic<T>
[__NoSideEffect]
@@ -9577,20 +9564,7 @@ ${{{{
[require(glsl_hlsl_spirv, subpass)]
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
- };
- }
- }
+ return subpass.SubpassLoad(sample);
}
/// Section 8.19. Shader Invocation Group Functions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 0a440f986..8509b4005 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -17304,19 +17304,20 @@ struct __SubpassImpl<T, let isMS:int>
{
}
-__generic<T, let isMS:int=0>
+__generic<T = float4, let isMS:int=0>
typealias SubpassInput = __SubpassImpl<T, isMS>;
__generic<T>
extension __SubpassImpl<T, 0>
{
[ForceInline]
- [require(hlsl_spirv, subpass)]
+ [require(glsl_hlsl_spirv, subpass)]
T SubpassLoad()
{
__target_switch
{
case hlsl: __intrinsic_asm "$0.SubpassLoad()";
+ case glsl: __intrinsic_asm "subpassLoad($0)";
case spirv:
{
let zeroVec = int2(0);
@@ -17330,19 +17331,20 @@ extension __SubpassImpl<T, 0>
}
}
-__generic<T, let isMS:int=1>
+__generic<T = float4, let isMS:int=1>
typealias SubpassInputMS = __SubpassImpl<T, isMS>;
__generic<T>
extension __SubpassImpl<T, 1>
{
[ForceInline]
- [require(hlsl_spirv, subpass)]
+ [require(glsl_hlsl_spirv, subpass)]
T SubpassLoad(int sample)
{
__target_switch
{
case hlsl: __intrinsic_asm "$0.SubpassLoad($1)";
+ case glsl: __intrinsic_asm "subpassLoad($0, $1)";
case spirv:
{
let zeroVec = int2(0);
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 39e167ab8..a4e01477c 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -242,11 +242,6 @@ class GLSLLocationLayoutModifier : public GLSLParsedLayoutModifier
SLANG_AST_CLASS(GLSLLocationLayoutModifier)
};
-class GLSLInputAttachmentIndexLayoutModifier : public GLSLParsedLayoutModifier
-{
- SLANG_AST_CLASS(GLSLInputAttachmentIndexLayoutModifier)
-};
-
class GLSLBufferDataLayoutModifier : public GLSLParsedLayoutModifier
{
SLANG_AST_CLASS(GLSLBufferDataLayoutModifier)
@@ -775,6 +770,14 @@ class GLSLSimpleIntegerLayoutAttribute : public Attribute
int32_t value = 0;
};
+/// [[vk_input_attachment_index]]
+class GLSLInputAttachmentIndexLayoutAttribute : public Attribute
+{
+ SLANG_AST_CLASS(GLSLInputAttachmentIndexLayoutAttribute)
+
+ IntegerLiteralValue location;
+};
+
// [[vk_location]]
class GLSLLocationAttribute : public GLSLSimpleIntegerLayoutAttribute
{
diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef
index b011021bc..1511c3a08 100644
--- a/source/slang/slang-capabilities.capdef
+++ b/source/slang/slang-capabilities.capdef
@@ -410,7 +410,7 @@ alias atomicfloat2 = GL_EXT_shader_atomic_float2 | _sm_6_6 + hlsl_nvapi | cpp |
alias fragmentshaderbarycentric = GL_EXT_fragment_shader_barycentric | _sm_6_1;
alias shadermemorycontrol = glsl | _spirv_1_0 | _sm_5_0;
alias shadermemorycontrol_compute = raytracingstages_compute + shadermemorycontrol;
-alias subpass = fragment + any_gfx_target;
+alias subpass = fragment + _sm_6_0 | fragment + any_gfx_target;
alias waveprefix = _sm_6_5 | _cuda_sm_7_0 | GL_KHR_shader_subgroup_arithmetic;
alias bufferreference = GL_EXT_buffer_reference;
alias bufferreference_int64 = bufferreference + GL_EXT_shader_explicit_arithmetic_types_int64;
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index aa30f66ca..7721fedbf 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -474,6 +474,17 @@ namespace Slang
}
overloadRankAttr->rank = int32_t(rank->getValue());
}
+ else if (auto inputAttachmentIndexLayoutAttribute = as<GLSLInputAttachmentIndexLayoutAttribute>(attr))
+ {
+ if (attr->args.getCount() != 1)
+ return false;
+
+ auto location = checkConstantIntVal(attr->args[0]);
+ if(!location)
+ return false;
+
+ inputAttachmentIndexLayoutAttribute->location = location->getValue();
+ }
else if (auto bindingAttr = as<GLSLBindingAttribute>(attr))
{
// This must be vk::binding or gl::binding (as specified in core.meta.slang under vk_binding/gl_binding)
@@ -1105,7 +1116,7 @@ namespace Slang
case ASTNodeType::GLSLParsedLayoutModifier:
case ASTNodeType::GLSLConstantIDLayoutModifier:
case ASTNodeType::GLSLLocationLayoutModifier:
- case ASTNodeType::GLSLInputAttachmentIndexLayoutModifier:
+ case ASTNodeType::GLSLInputAttachmentIndexLayoutAttribute:
case ASTNodeType::GLSLOffsetLayoutAttribute:
case ASTNodeType::GLSLUnparsedLayoutModifier:
case ASTNodeType::GLSLLayoutModifierGroupMarker:
@@ -1185,7 +1196,7 @@ namespace Slang
case ASTNodeType::GLSLParsedLayoutModifier:
case ASTNodeType::GLSLConstantIDLayoutModifier:
case ASTNodeType::GLSLLocationLayoutModifier:
- case ASTNodeType::GLSLInputAttachmentIndexLayoutModifier:
+ case ASTNodeType::GLSLInputAttachmentIndexLayoutAttribute:
case ASTNodeType::GLSLOffsetLayoutAttribute:
case ASTNodeType::GLSLUnparsedLayoutModifier:
case ASTNodeType::GLSLLayoutModifierGroupMarker:
diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp
index 67abb56b7..14495dd6e 100644
--- a/source/slang/slang-check-shader.cpp
+++ b/source/slang/slang-check-shader.cpp
@@ -312,6 +312,8 @@ namespace Slang
{
if (as<ResourceType>(type))
return true;
+ if (as<SubpassInputType>(type))
+ return true;
if (as<HLSLStructuredBufferTypeBase>(type))
return true;
if (as<UntypedBufferResourceType>(type))
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 5b9c3e65a..cb994b904 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -453,7 +453,6 @@ 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.")
DIAGNOSTIC(31210, Error, derivativeGroupQuadMustBeMultiple2ForXYThreads, "compute derivative group quad requires thread dispatch count of X and Y to each be at a multiple of 2")
DIAGNOSTIC(31211, Error, derivativeGroupLinearMustBeMultiple4ForTotalThreadCount, "compute derivative group linear requires total thread dispatch count to be at a multiple of 4")
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index 6062875b3..66ee12ca6 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -3160,9 +3160,14 @@ void CLikeSourceEmitter::emitSemantics(IRInst* inst, bool allowOffsetLayout)
emitSemanticsImpl(inst, allowOffsetLayout);
}
+void CLikeSourceEmitter::emitDecorationLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling)
+{
+ emitLayoutSemanticsImpl(inst, uniformSemanticSpelling, EmitLayoutSemanticOption::kPreType);
+}
+
void CLikeSourceEmitter::emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling)
{
- emitLayoutSemanticsImpl(inst, uniformSemanticSpelling);
+ emitLayoutSemanticsImpl(inst, uniformSemanticSpelling, EmitLayoutSemanticOption::kPostType);
}
void CLikeSourceEmitter::emitRegion(Region* inRegion)
@@ -3959,7 +3964,7 @@ void CLikeSourceEmitter::emitVar(IRVar* varDecl)
emitType(varType, getName(varDecl));
emitSemantics(varDecl);
- emitLayoutSemantics(varDecl);
+ emitLayoutSemantics(varDecl, "register");
emitPostDeclarationAttributesForType(varType);
// TODO: ideally this logic should scan ahead to see if it can find a `store`
@@ -4092,7 +4097,7 @@ void CLikeSourceEmitter::emitGlobalVar(IRGlobalVar* varDecl)
// global variables.
//
emitSemantics(varDecl);
- emitLayoutSemantics(varDecl);
+ emitLayoutSemantics(varDecl, "register");
if (varDecl->getFirstBlock())
{
@@ -4155,13 +4160,15 @@ void CLikeSourceEmitter::emitGlobalParam(IRGlobalParam* varDecl)
SLANG_ASSERT(layout);
emitVarModifiers(layout, varDecl, varType);
+
+ emitDecorationLayoutSemantics(varDecl, "register");
emitRateQualifiersAndAddressSpace(varDecl);
emitType(varType, getName(varDecl));
emitSemantics(varDecl);
- emitLayoutSemantics(varDecl);
+ emitLayoutSemantics(varDecl, "register");
// A shader parameter cannot have an initializer,
// so we do need to consider emitting one here.
diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h
index ecff57296..07cb4a0bc 100644
--- a/source/slang/slang-emit-c-like.h
+++ b/source/slang/slang-emit-c-like.h
@@ -20,6 +20,13 @@ namespace Slang
class CLikeSourceEmitter: public SourceEmitterBase
{
public:
+
+ enum class EmitLayoutSemanticOption
+ {
+ kPreType,
+ kPostType
+ };
+
struct Desc
{
CodeGenContext* codeGenContext = nullptr;
@@ -344,7 +351,8 @@ public:
void emitSemantics(IRInst* inst, bool allowOffsets = false);
void emitSemanticsUsingVarLayout(IRVarLayout* varLayout);
- void emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling = "register");
+ void emitDecorationLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling);
+ void emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling);
/// Emit high-level language statements from a structured region.
void emitRegion(Region* inRegion);
@@ -463,7 +471,7 @@ public:
virtual void emitPostDeclarationAttributesForType(IRInst* type) { SLANG_UNUSED(type); }
virtual bool doesTargetSupportPtrTypes() { return false; }
- virtual void emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling = "register") { SLANG_UNUSED(inst); SLANG_UNUSED(uniformSemanticSpelling); }
+ virtual void emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption) { SLANG_UNUSED(inst); SLANG_UNUSED(uniformSemanticSpelling); SLANG_UNUSED(layoutSemanticOption); }
virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type) = 0;
virtual void emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPointDecoration* entryPointDecor) = 0;
diff --git a/source/slang/slang-emit-cuda.cpp b/source/slang/slang-emit-cuda.cpp
index 2417a64ec..f4b45b7aa 100644
--- a/source/slang/slang-emit-cuda.cpp
+++ b/source/slang/slang-emit-cuda.cpp
@@ -212,9 +212,9 @@ SlangResult CUDASourceEmitter::calcTypeName(IRType* type, CodeGenTarget target,
return Super::calcTypeName(type, target, out);
}
-void CUDASourceEmitter::emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling)
+void CUDASourceEmitter::emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption)
{
- Super::emitLayoutSemanticsImpl(inst, uniformSemanticSpelling);
+ Super::emitLayoutSemanticsImpl(inst, uniformSemanticSpelling, layoutSemanticOption);
}
void CUDASourceEmitter::emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type)
diff --git a/source/slang/slang-emit-cuda.h b/source/slang/slang-emit-cuda.h
index 13a497343..5d76c4ef3 100644
--- a/source/slang/slang-emit-cuda.h
+++ b/source/slang/slang-emit-cuda.h
@@ -63,7 +63,7 @@ public:
protected:
- virtual void emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling) SLANG_OVERRIDE;
+ virtual void emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption) SLANG_OVERRIDE;
virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type) SLANG_OVERRIDE;
virtual void emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPointDecoration* entryPointDecor) SLANG_OVERRIDE;
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index b6c3c0d67..7cf478c36 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -751,6 +751,11 @@ bool GLSLSourceEmitter::_emitGLSLLayoutQualifierWithBindingKinds(LayoutResourceK
m_writer->emit("layout(shaderRecordEXT)\n");
break;
+ case LayoutResourceKind::InputAttachmentIndex:
+ m_writer->emit("layout(input_attachment_index = ");
+ m_writer->emit(index);
+ m_writer->emit(")\n");
+ break;
}
return true;
}
@@ -1338,7 +1343,7 @@ void GLSLSourceEmitter::_emitGLSLPerVertexVaryingFragmentInput(IRGlobalParam* pa
emitSemantics(param, false);
- emitLayoutSemantics(param);
+ emitLayoutSemantics(param, "register");
m_writer->emit(";\n\n");
}
@@ -2825,16 +2830,6 @@ 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"));
- }
- }
}
void GLSLSourceEmitter::emitMatrixLayoutModifiersImpl(IRVarLayout* layout)
diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp
index 04f5bd643..4d3830969 100644
--- a/source/slang/slang-emit-hlsl.cpp
+++ b/source/slang/slang-emit-hlsl.cpp
@@ -93,6 +93,13 @@ void HLSLSourceEmitter::_emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitV
break;
case LayoutResourceKind::InputAttachmentIndex:
+ {
+ m_writer->emit("[[vk::input_attachment_index(");
+ m_writer->emit(index);
+ m_writer->emit(")]]");
+ }
+ break;
+
case LayoutResourceKind::RegisterSpace:
case LayoutResourceKind::GenericResource:
case LayoutResourceKind::ExistentialTypeParam:
@@ -141,7 +148,7 @@ void HLSLSourceEmitter::_emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitV
}
}
-void HLSLSourceEmitter::_emitHLSLRegisterSemantics(EmitVarChain* chain, IRInst* inst, char const* uniformSemanticSpelling)
+void HLSLSourceEmitter::_emitHLSLRegisterSemantics(EmitVarChain* chain, IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption)
{
if (!chain) return;
@@ -158,17 +165,20 @@ void HLSLSourceEmitter::_emitHLSLRegisterSemantics(EmitVarChain* chain, IRInst*
for (auto rr : layout->getOffsetAttrs())
{
+ if (layoutSemanticOption == EmitLayoutSemanticOption::kPreType
+ && rr->getResourceKind() != LayoutResourceKind::InputAttachmentIndex)
+ continue;
_emitHLSLRegisterSemantic(rr->getResourceKind(), chain, inst, uniformSemanticSpelling);
}
}
-void HLSLSourceEmitter::_emitHLSLRegisterSemantics(IRVarLayout* varLayout, IRInst* inst, char const* uniformSemanticSpelling)
+void HLSLSourceEmitter::_emitHLSLRegisterSemantics(IRVarLayout* varLayout, IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption)
{
if (!varLayout)
return;
EmitVarChain chain(varLayout);
- _emitHLSLRegisterSemantics(&chain, inst, uniformSemanticSpelling);
+ _emitHLSLRegisterSemantics(&chain, inst, uniformSemanticSpelling, layoutSemanticOption);
}
void HLSLSourceEmitter::_emitHLSLParameterGroupFieldLayoutSemantics(EmitVarChain* chain)
@@ -220,7 +230,7 @@ void HLSLSourceEmitter::_emitHLSLParameterGroup(IRGlobalParam* varDecl, IRUnifor
typeLayout = parameterGroupTypeLayout->getElementVarLayout()->getTypeLayout();
}
- _emitHLSLRegisterSemantic(layoutResourceKind, &containerChain, varDecl);
+ _emitHLSLRegisterSemantic(layoutResourceKind, &containerChain, varDecl, "register");
auto elementType = type->getElementType();
if (shouldForceUnpackConstantBufferElements(type) || hasExplicitConstantBufferOffset(type))
@@ -320,12 +330,12 @@ void HLSLSourceEmitter::_emitHLSLSubpassInputType(IRSubpassInputType* subpassTyp
m_writer->emit(">");
}
-void HLSLSourceEmitter::emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling)
+void HLSLSourceEmitter::emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption)
{
auto layout = getVarLayout(inst);
if (layout)
{
- _emitHLSLRegisterSemantics(layout, inst, uniformSemanticSpelling);
+ _emitHLSLRegisterSemantics(layout, inst, uniformSemanticSpelling, layoutSemanticOption);
}
}
@@ -1281,13 +1291,6 @@ void HLSLSourceEmitter::emitVarDecorationsImpl(IRInst* varDecl)
{
for(auto decoration : varDecl->getDecorations())
{
- if(auto glslInputAttachmentIndex = as<IRGLSLInputAttachmentIndexDecoration>(decoration))
- {
- m_writer->emit("[[vk::input_attachment_index(");
- m_writer->emit(glslInputAttachmentIndex->getIndex()->getValue());
- m_writer->emit(")]]\n");
- continue;
- }
if (auto collection = as<IRMemoryQualifierSetDecoration>(decoration))
{
auto flags = collection->getMemoryQualifierBit();
diff --git a/source/slang/slang-emit-hlsl.h b/source/slang/slang-emit-hlsl.h
index 30f38b415..abc673a3d 100644
--- a/source/slang/slang-emit-hlsl.h
+++ b/source/slang/slang-emit-hlsl.h
@@ -29,7 +29,7 @@ public:
protected:
RefPtr<HLSLExtensionTracker> m_extensionTracker;
- virtual void emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling) SLANG_OVERRIDE;
+ virtual void emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption) SLANG_OVERRIDE;
virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type) SLANG_OVERRIDE;
virtual void emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPointDecoration* entryPointDecor) SLANG_OVERRIDE;
@@ -66,11 +66,11 @@ protected:
// Emit a single `register` semantic, as appropriate for a given resource-type-specific layout info
// Keyword to use in the uniform case (`register` for globals, `packoffset` inside a `cbuffer`)
- void _emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitVarChain* chain, IRInst* inst, char const* uniformSemanticSpelling = "register");
+ void _emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitVarChain* chain, IRInst* inst, char const* uniformSemanticSpelling);
// Emit all the `register` semantics that are appropriate for a particular variable layout
- void _emitHLSLRegisterSemantics(EmitVarChain* chain, IRInst* inst, char const* uniformSemanticSpelling = "register");
- void _emitHLSLRegisterSemantics(IRVarLayout* varLayout, IRInst* inst, char const* uniformSemanticSpelling = "register");
+ void _emitHLSLRegisterSemantics(EmitVarChain* chain, IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption);
+ void _emitHLSLRegisterSemantics(IRVarLayout* varLayout, IRInst* inst, char const* uniformSemanticSpelling, EmitLayoutSemanticOption layoutSemanticOption);
void _emitHLSLParameterGroupFieldLayoutSemantics(EmitVarChain* chain);
void _emitHLSLParameterGroupFieldLayoutSemantics(IRVarLayout* fieldLayout, EmitVarChain* inChain);
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 51a71d65c..1a4d80ae1 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -2230,6 +2230,16 @@ struct SPIRVEmitContext
isDescirptorSetDecorated = true;
}
break;
+ case LayoutResourceKind::InputAttachmentIndex:
+ {
+ emitOpDecorateInputAttachmentIndex(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ varInst,
+ SpvLiteralInteger::from32((int32_t)index)
+ );
+ }
+ break;
default:
break;
}
@@ -3576,17 +3586,6 @@ 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-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 19117c00e..3132536e3 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -893,7 +893,6 @@ INST_RANGE(BindingQuery, GetRegisterIndex, GetRegisterSpace)
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(PayloadDecoration, payload, 0, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index a63cc5c22..fb9a9613a 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -437,11 +437,6 @@ 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
{
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index cc4704fe9..c946072f9 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -2212,16 +2212,6 @@ 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,
diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp
index d76dda4e1..6a1080b0e 100644
--- a/source/slang/slang-parameter-binding.cpp
+++ b/source/slang/slang-parameter-binding.cpp
@@ -996,6 +996,16 @@ static void addExplicitParameterBindings_HLSL(
// If the declaration has explicit binding modifiers, then
// here is where we want to extract and apply them...
+ if (auto inputAttachmentIndexLayoutAttribute = varDecl.getDecl()->findModifier<GLSLInputAttachmentIndexLayoutAttribute>())
+ {
+ LayoutSemanticInfo semanticInfo;
+ semanticInfo.index = (UInt)inputAttachmentIndexLayoutAttribute->location;
+ semanticInfo.space = 0;
+ semanticInfo.kind = LayoutResourceKind::InputAttachmentIndex;
+
+ if (auto varDeclBase = varDecl.as<VarDeclBase>())
+ addExplicitParameterBinding(context, parameterInfo, varDeclBase.getDecl(), semanticInfo, 1);
+ }
// Look for HLSL `register` or `packoffset` semantics.
for (auto semantic : varDecl.getDecl()->getModifiersOfType<HLSLLayoutSemantic>())
@@ -1065,82 +1075,96 @@ static void addExplicitParameterBindings_GLSL(
// the index/offset/etc.
//
- TypeLayout::ResourceInfo* resInfo = nullptr;
- TypeLayout::ResourceInfo* foundResInfo = nullptr;
-
- LayoutSemanticInfo semanticInfo;
- semanticInfo.index = 0;
- semanticInfo.space = 0;
+ enum
+ {
+ kResInfo = 0,
+ kSubpassResInfo,
+ kMaxResCount,
+ };
- LayoutSemanticInfo subpassSemanticInfo;
- bool foundBinding = false;
- bool foundSubpass = false;
+ TypeLayout::ResourceInfo* foundResInfo = nullptr;
+ struct ResAndSemanticInfo
+ {
+ TypeLayout::ResourceInfo* resInfo = nullptr;
+ LayoutSemanticInfo semanticInfo;
+ ResAndSemanticInfo()
+ {
+ semanticInfo.index = 0;
+ semanticInfo.space = 0;
+ }
+ };
+ ResAndSemanticInfo info[kMaxResCount] = {};
+
+ if (auto foundInputAttachmentIndex = typeLayout->FindResourceInfo(LayoutResourceKind::InputAttachmentIndex))
+ {
+ foundResInfo = foundInputAttachmentIndex;
+ // Try to find `input_attachment_index`
+ if (auto glslAttachmentIndexAttr = varDecl.getDecl()->findModifier<GLSLInputAttachmentIndexLayoutAttribute>())
+ {
+ info[kSubpassResInfo].resInfo = foundResInfo;
+ // Subpass fills semantic info of a descriptor and subpass
+ info[kSubpassResInfo].semanticInfo.index = (UInt)glslAttachmentIndexAttr->location;
+ info[kSubpassResInfo].semanticInfo.space = 0;
+ }
+ }
- if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot)) != nullptr )
+ if(auto foundDescriptorTableSlot = typeLayout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot))
{
- for (auto dec : varDecl.getDecl()->modifiers)
+ foundResInfo = foundDescriptorTableSlot;
+ // Try to find `binding` and `set`
+ if (auto glslBindingAttr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>())
{
- // 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;
- }
+ info[kResInfo].resInfo = foundResInfo;
+ info[kResInfo].semanticInfo.index = glslBindingAttr->binding;
+ info[kResInfo].semanticInfo.space = glslBindingAttr->set;
}
}
- else if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::SubElementRegisterSpace)) != nullptr )
+ else if(auto foundSubElementRegisterSpace = typeLayout->FindResourceInfo(LayoutResourceKind::SubElementRegisterSpace))
{
+ foundResInfo = foundSubElementRegisterSpace;
// Try to find `set`
if (auto attr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>())
{
- resInfo = foundResInfo;
+ info[kResInfo].resInfo = foundResInfo;
if (attr->binding != 0)
{
getSink(context)->diagnose(attr, Diagnostics::wholeSpaceParameterRequiresZeroBinding, varDecl.getName(), attr->binding);
}
- semanticInfo.index = attr->set;
- semanticInfo.space = 0;
+ info[kResInfo].semanticInfo.index = attr->set;
+ info[kResInfo].semanticInfo.space = 0;
}
}
- else if( (resInfo = typeLayout->FindResourceInfo(LayoutResourceKind::SpecializationConstant)) != nullptr )
+ else if(auto foundSpecializationConstant = typeLayout->FindResourceInfo(LayoutResourceKind::SpecializationConstant))
{
+ info[kResInfo].resInfo = foundSpecializationConstant;
DeclRef<Decl> varDecl2(varDecl);
// Try to find `constant_id` binding
- if(!findLayoutArg<GLSLConstantIDLayoutModifier>(varDecl2, &semanticInfo.index))
+ if(!findLayoutArg<GLSLConstantIDLayoutModifier>(varDecl2, &info[kResInfo].semanticInfo.index))
return;
}
- // if we found resInfo, we add the explicit binding
- if (resInfo)
+
+ auto varDeclBase = as<VarDeclBase>(varDecl);
+ bool hasABinding = false;
+ for (int i = 0; i < kMaxResCount; i++)
{
- auto kind = resInfo->kind;
- auto count = resInfo->count;
+ auto* resInfoItem = info[i].resInfo;
+ auto& semanticInfo = info[i].semanticInfo;
+ if (!resInfoItem)
+ continue;
+
+ auto kind = resInfoItem->kind;
+ auto count = resInfoItem->count;
semanticInfo.kind = kind;
+ hasABinding = true;
+ if(!varDeclBase)
+ break;
- if (auto varDeclBase = varDecl.as<VarDeclBase>())
- {
- addExplicitParameterBinding(context, parameterInfo, varDeclBase.getDecl(), semanticInfo, count);
- if (foundSubpass)
- addExplicitParameterBinding(context, parameterInfo, varDeclBase.getDecl(), subpassSemanticInfo, count);
- }
- return;
+ addExplicitParameterBinding(context, parameterInfo, varDeclBase.getDecl(), semanticInfo, count);
}
+ if(hasABinding)
+ return;
auto hlslToVulkanLayoutOptions = context->getTargetProgram()->getHLSLToVulkanLayoutOptions();
bool warnedMissingVulkanLayoutModifier = false;
@@ -1196,7 +1220,7 @@ static void addExplicitParameterBindings_GLSL(
// We use the HLSL binding directly (even though this notionally for GLSL/Vulkan)
// We'll do the shifting at later later point in _maybeApplyHLSLToVulkanShifts
- resInfo = typeLayout->findOrAddResourceInfo(hlslInfo.kind);
+ info[kResInfo].resInfo = typeLayout->findOrAddResourceInfo(hlslInfo.kind);
if (warnedMissingVulkanLayoutModifier)
{
@@ -1205,8 +1229,8 @@ static void addExplicitParameterBindings_GLSL(
if(!hlslToVulkanLayoutOptions
|| hlslToVulkanLayoutOptions->getKindShiftEnabledFlags() == HLSLToVulkanLayoutOptions::KindFlag::None)
{
- resInfo->kind = LayoutResourceKind::DescriptorTableSlot;
- resInfo->count = 1;
+ info[kResInfo].resInfo->kind = LayoutResourceKind::DescriptorTableSlot;
+ info[kResInfo].resInfo->count = 1;
}
else
{
@@ -1214,12 +1238,12 @@ static void addExplicitParameterBindings_GLSL(
}
}
- semanticInfo.kind = resInfo->kind;
- semanticInfo.index = UInt(hlslInfo.index);
- semanticInfo.space = UInt(hlslInfo.space);
- const LayoutSize count = resInfo->count;
+ info[kResInfo].semanticInfo.kind = info[kResInfo].resInfo->kind;
+ info[kResInfo].semanticInfo.index = UInt(hlslInfo.index);
+ info[kResInfo].semanticInfo.space = UInt(hlslInfo.space);
+ const LayoutSize count = info[kResInfo].resInfo->count;
- addExplicitParameterBinding(context, parameterInfo, as<VarDeclBase>(varDecl.getDecl()), semanticInfo, count);
+ addExplicitParameterBinding(context, parameterInfo, as<VarDeclBase>(varDecl.getDecl()), info[kResInfo].semanticInfo, count);
}
// Given a single parameter, collect whatever information we have on
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 3d9f1c199..e6913c6c0 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -8061,7 +8061,7 @@ namespace Slang
GLSLLayoutLocalSizeAttribute* numThreadsAttrib = nullptr;
GLSLLayoutDerivativeGroupQuadAttribute* derivativeGroupQuadAttrib = nullptr;
GLSLLayoutDerivativeGroupLinearAttribute* derivativeGroupLinearAttrib = nullptr;
-
+ GLSLInputAttachmentIndexLayoutAttribute* inputAttachmentIndexLayoutAttribute = nullptr;
ImageFormat format;
listBuilder.add(parser->astBuilder->create<GLSLLayoutModifierGroupBegin>());
@@ -8115,6 +8115,17 @@ namespace Slang
{
derivativeGroupLinearAttrib = parser->astBuilder->create<GLSLLayoutDerivativeGroupLinearAttribute>();
}
+ else if (nameText == "input_attachment_index")
+ {
+ inputAttachmentIndexLayoutAttribute = parser->astBuilder->create<GLSLInputAttachmentIndexLayoutAttribute>();
+ if (AdvanceIf(parser, TokenType::OpAssign))
+ {
+ auto token = parser->ReadToken(TokenType::IntegerLiteral);
+ auto intVal = getIntegerLiteralValue(token);
+ inputAttachmentIndexLayoutAttribute->location = intVal;
+ }
+
+ }
else if (nameText == "binding" ||
nameText == "set")
{
@@ -8165,7 +8176,6 @@ namespace Slang
CASE(scalar, GLSLScalarModifier)
CASE(offset, GLSLOffsetLayoutAttribute)
CASE(location, GLSLLocationLayoutModifier)
- CASE(input_attachment_index, GLSLInputAttachmentIndexLayoutModifier)
{
modifier = parser->astBuilder->create<GLSLUnparsedLayoutModifier>();
}
@@ -8227,6 +8237,8 @@ namespace Slang
listBuilder.add(derivativeGroupQuadAttrib);
if(derivativeGroupLinearAttrib)
listBuilder.add(derivativeGroupLinearAttrib);
+ if(inputAttachmentIndexLayoutAttribute)
+ listBuilder.add(inputAttachmentIndexLayoutAttribute);
listBuilder.add(parser->astBuilder->create<GLSLLayoutModifierGroupEnd>());
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index 22aa3f304..293dce7c6 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -722,6 +722,9 @@ static LayoutResourceKind _getHLSLLayoutResourceKind(ShaderParameterKind kind)
{
switch (kind)
{
+ case ShaderParameterKind::SubpassInput:
+ return LayoutResourceKind::InputAttachmentIndex;
+
case ShaderParameterKind::ConstantBuffer:
return LayoutResourceKind::ConstantBuffer;
@@ -778,6 +781,13 @@ struct GLSLObjectLayoutRulesImpl : ObjectLayoutRulesImpl
}
}
+ switch (kind)
+ {
+ case ShaderParameterKind::SubpassInput:
+ return SimpleLayoutInfo(LayoutResourceKind::InputAttachmentIndex, slotCount);
+ default:
+ break;
+ }
return SimpleLayoutInfo(LayoutResourceKind::DescriptorTableSlot, slotCount);
}
};
@@ -4089,6 +4099,17 @@ static TypeLayoutResult _createTypeLayout(
type,
rules);
}
+ else if (as<SubpassInputType>(type))
+ {
+ // SubpassInputType fills 2 slots, 'shader resource' and 'input_attachment_index'
+ auto objLayout1 = rules->GetObjectLayout(ShaderParameterKind::Texture, context.objectLayoutOptions);
+ auto objLayout2 = rules->GetObjectLayout(ShaderParameterKind::SubpassInput, context.objectLayoutOptions);
+ objLayout1.layoutInfos.add(objLayout2.layoutInfos.getFirst());
+ return createSimpleTypeLayout(
+ objLayout1,
+ type,
+ rules);
+ }
else if (auto textureType = as<TextureType>(type))
{
// TODO: the logic here should really be defined by the rules,
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
deleted file mode 100644
index 889a4e205..000000000
--- a/tests/glsl-intrinsic/subpass-input/input-attachment-index-use-error.slang
+++ /dev/null
@@ -1,11 +0,0 @@
-//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-hlsl.slang b/tests/glsl-intrinsic/subpass-input/subpass-input-hlsl.slang
new file mode 100644
index 000000000..0b8e4896f
--- /dev/null
+++ b/tests/glsl-intrinsic/subpass-input/subpass-input-hlsl.slang
@@ -0,0 +1,32 @@
+//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
+
+// CHECK_SPV-DAG: OpEntryPoint
+// CHECK_SPV-DAG: InputAttachmentIndex 3
+// CHECK_SPV-DAG: InputAttachmentIndex
+
+// CHECK_GLSL-DAG: void main()
+// CHECK_GLSL-DAG: input_attachment_index = 3
+// CHECK_GLSL-DAG: input_attachment_index
+
+// CHECK_HLSL-DAG: main()
+// CHECK_HLSL-DAG: [vk::input_attachment_index(3)]
+// CHECK_HLSL-DAG: vk::input_attachment_index
+[[vk::input_attachment_index(3)]] SubpassInput subpassHLSL1;
+SubpassInput subpassHLSL2;
+
+RWTexture2D<float4> t;
+
+layout (location = 0) out vec4 outColor;
+
+void main() {
+// CHECK_SPV-COUNT-2: OpImageRead
+// CHECK_GLSL-COUNT-2: subpassLoad
+// CHECK_HLSL-COUNT-2: SubpassLoad
+ outColor = vec4(true
+ && subpassHLSL1.SubpassLoad() == vec4(1)
+ && subpassHLSL2.SubpassLoad() == vec4(1)
+ && t.Load(int2(0,0)) != float4(0,0,0,0)
+ );
+} \ No newline at end of file