Commit 7f93d56e by LoopDawg

HLSL: add subpass input types and methods

Add support for Subpass Input proposal of issue #1069. Subpass input types are given as: layout(input_attachment_index = 1) SubpassInput<float4> subpass_f; layout(input_attachment_index = 2) SubpassInput<int4> subpass_i; layout(input_attachment_index = 3) SubpassInput<uint4> subpass_u; layout(input_attachment_index = 1) SubpassInputMS<float4> subpass_ms_f; layout(input_attachment_index = 2) SubpassInputMS<int4> subpass_ms_i; layout(input_attachment_index = 3) SubpassInputMS<uint4> subpass_ms_u; The input attachment may also be specified using attribute syntax: [[vk::input_attachment_index(7)]] SubpassInput subpass_2; The template type may be a shorter-than-vec4 vector, but currently user structs are not supported. (An unimplemented error will be issued). The load operations are methods on objects of the above type: float4 result = subpass_f.SubpassLoad(); int4 result = subpass_i.SubpassLoad(); uint4 result = subpass_u.SubpassLoad(); float4 result = subpass_ms_f.SubpassLoad(samp); int4 result = subpass_ms_i.SubpassLoad(samp); uint4 result = subpass_ms_u.SubpassLoad(samp); Additionally, the AST printer could not print EOpSubpass* nodes. Now it can. Fixes #1069
parent 092b7d2e
spv.register.subpass.frag
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 40
Capability Shader
Capability StorageImageMultisample
Capability InputAttachment
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 38
ExecutionMode 4 OriginUpperLeft
Source HLSL 500
Name 4 "main"
Name 9 "@main("
Name 12 "result00"
Name 15 "subpass_f4"
Name 22 "result10"
Name 25 "subpass_ms_f4"
Name 29 "result73"
Name 30 "subpass_2"
Name 38 "@entryPointOutput"
Decorate 15(subpass_f4) DescriptorSet 0
Decorate 15(subpass_f4) Binding 21
Decorate 15(subpass_f4) InputAttachmentIndex 1
Decorate 25(subpass_ms_f4) DescriptorSet 0
Decorate 25(subpass_ms_f4) Binding 20
Decorate 25(subpass_ms_f4) InputAttachmentIndex 4
Decorate 30(subpass_2) DescriptorSet 0
Decorate 30(subpass_2) Binding 22
Decorate 30(subpass_2) InputAttachmentIndex 7
Decorate 38(@entryPointOutput) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 4
8: TypeFunction 7(fvec4)
11: TypePointer Function 7(fvec4)
13: TypeImage 6(float) SubpassData nonsampled format:Unknown
14: TypePointer UniformConstant 13
15(subpass_f4): 14(ptr) Variable UniformConstant
17: TypeInt 32 1
18: 17(int) Constant 0
19: TypeVector 17(int) 2
20: 19(ivec2) ConstantComposite 18 18
23: TypeImage 6(float) SubpassData multi-sampled nonsampled format:Unknown
24: TypePointer UniformConstant 23
25(subpass_ms_f4): 24(ptr) Variable UniformConstant
27: 17(int) Constant 3
30(subpass_2): 14(ptr) Variable UniformConstant
33: 6(float) Constant 0
34: 7(fvec4) ConstantComposite 33 33 33 33
37: TypePointer Output 7(fvec4)
38(@entryPointOutput): 37(ptr) Variable Output
4(main): 2 Function None 3
5: Label
39: 7(fvec4) FunctionCall 9(@main()
Store 38(@entryPointOutput) 39
Return
FunctionEnd
9(@main(): 7(fvec4) Function None 8
10: Label
12(result00): 11(ptr) Variable Function
22(result10): 11(ptr) Variable Function
29(result73): 11(ptr) Variable Function
16: 13 Load 15(subpass_f4)
21: 7(fvec4) ImageRead 16 20
Store 12(result00) 21
26: 23 Load 25(subpass_ms_f4)
28: 7(fvec4) ImageRead 26 20 Sample 27
Store 22(result10) 28
31: 13 Load 30(subpass_2)
32: 7(fvec4) ImageRead 31 20
Store 29(result73) 32
ReturnValue 34
FunctionEnd
layout(input_attachment_index = 1) SubpassInput<float4> subpass_f4 : register(t1);
layout(input_attachment_index = 2) SubpassInput<int4> subpass_i4;
layout(input_attachment_index = 3) SubpassInput<uint4> subpass_u4;
layout(input_attachment_index = 4) SubpassInputMS<float4> subpass_ms_f4;
layout(input_attachment_index = 5) SubpassInputMS<int4> subpass_ms_i4;
layout(input_attachment_index = 6) SubpassInputMS<uint4> subpass_ms_u4;
layout(input_attachment_index = 1) SubpassInput<float3> subpass_f3;
layout(input_attachment_index = 2) SubpassInput<int3> subpass_i3;
layout(input_attachment_index = 3) SubpassInput<uint3> subpass_u3;
layout(input_attachment_index = 4) SubpassInputMS<float3> subpass_ms_f3;
layout(input_attachment_index = 5) SubpassInputMS<int3> subpass_ms_i3;
layout(input_attachment_index = 6) SubpassInputMS<uint3> subpass_ms_u3;
layout(input_attachment_index = 1) SubpassInput<float2> subpass_f2;
layout(input_attachment_index = 2) SubpassInput<int2> subpass_i2;
layout(input_attachment_index = 3) SubpassInput<uint2> subpass_u2;
layout(input_attachment_index = 4) SubpassInputMS<float2> subpass_ms_f2;
layout(input_attachment_index = 5) SubpassInputMS<int2> subpass_ms_i2;
layout(input_attachment_index = 6) SubpassInputMS<uint2> subpass_ms_u2;
layout(input_attachment_index = 1) SubpassInput<float> subpass_f;
layout(input_attachment_index = 2) SubpassInput<int> subpass_i;
layout(input_attachment_index = 3) SubpassInput<uint> subpass_u;
layout(input_attachment_index = 4) SubpassInputMS<float> subpass_ms_f;
layout(input_attachment_index = 5) SubpassInputMS<int> subpass_ms_i;
layout(input_attachment_index = 6) SubpassInputMS<uint> subpass_ms_u;
[[vk::input_attachment_index(7)]] SubpassInput subpass_2;
struct mystruct_f_t
{
float c0;
float2 c1;
float c2;
};
struct mystruct_i_t
{
int c0;
int2 c1;
int c2;
};
struct mystruct_u_t
{
uint c0;
uint2 c1;
uint c2;
};
// TODO: ...
// layout(input_attachment_index = 7) SubpassInput<mystruct_f_t> subpass_fs;
// layout(input_attachment_index = 8) SubpassInputMS<mystruct_f_t> subpass_ms_fs;
// layout(input_attachment_index = 7) SubpassInput<mystruct_i_t> subpass_is;
// layout(input_attachment_index = 8) SubpassInputMS<mystruct_i_t> subpass_ms_is;
// layout(input_attachment_index = 7) SubpassInput<mystruct_u_t> subpass_us;
// layout(input_attachment_index = 8) SubpassInputMS<mystruct_u_t> subpass_ms_us;
float4 main() : SV_Target0
{
float4 result00 = subpass_f4.SubpassLoad();
int4 result01 = subpass_i4.SubpassLoad();
uint4 result02 = subpass_u4.SubpassLoad();
float4 result10 = subpass_ms_f4.SubpassLoad(3);
int4 result11 = subpass_ms_i4.SubpassLoad(3);
uint4 result12 = subpass_ms_u4.SubpassLoad(3);
float3 result20 = subpass_f3.SubpassLoad();
int3 result21 = subpass_i3.SubpassLoad();
uint3 result22 = subpass_u3.SubpassLoad();
float3 result30 = subpass_ms_f3.SubpassLoad(3);
int3 result31 = subpass_ms_i3.SubpassLoad(3);
uint3 result32 = subpass_ms_u3.SubpassLoad(3);
float2 result40 = subpass_f2.SubpassLoad();
int2 result41 = subpass_i2.SubpassLoad();
uint2 result42 = subpass_u2.SubpassLoad();
float2 result50 = subpass_ms_f2.SubpassLoad(2);
int2 result51 = subpass_ms_i2.SubpassLoad(2);
uint2 result52 = subpass_ms_u2.SubpassLoad(2);
float result60 = subpass_f.SubpassLoad();
int result61 = subpass_i.SubpassLoad();
uint result62 = subpass_u.SubpassLoad();
float result70 = subpass_ms_f.SubpassLoad(2);
int result71 = subpass_ms_i.SubpassLoad(2);
uint result72 = subpass_ms_u.SubpassLoad(2);
float4 result73 = subpass_2.SubpassLoad();
// TODO:
// mystruct_f_t result80 = subpass_fs.SubpassLoad();
// mystruct_i_t result81 = subpass_is.SubpassLoad();
// mystruct_u_t result82 = subpass_us.SubpassLoad();
// mystruct_f_t result90 = subpass_ms_sf.SubpassLoad(2);
// mystruct_i_t result91 = subpass_ms_if.SubpassLoad(2);
// mystruct_u_t result92 = subpass_ms_uf.SubpassLoad(2);
return 0;
}
// Test binding autoassignment and offset for SubpassInput objects
layout(input_attachment_index = 1) SubpassInput<float4> subpass_f4 : register(t1);
layout(input_attachment_index = 4) SubpassInputMS<float4> subpass_ms_f4;
[[vk::input_attachment_index(7)]] SubpassInput subpass_2;
float4 main() : SV_Target0
{
float4 result00 = subpass_f4.SubpassLoad();
float4 result10 = subpass_ms_f4.SubpassLoad(3);
float4 result73 = subpass_2.SubpassLoad();
return 0;
}
......@@ -196,6 +196,7 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
case EOpLogicalOr: out.debug << "logical-or"; break;
case EOpLogicalXor: out.debug << "logical-xor"; break;
case EOpLogicalAnd: out.debug << "logical-and"; break;
default: out.debug << "<unknown op>";
}
......@@ -491,6 +492,9 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpConvUint16ToUint64: out.debug << "Convert uint16 to uint64"; break;
#endif
case EOpSubpassLoad: out.debug << "subpassLoad"; break;
case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
default: out.debug.message(EPrefixError, "Bad unary op");
}
......@@ -791,6 +795,9 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpWorkgroupMemoryBarrier: out.debug << "WorkgroupMemoryBarrier"; break;
case EOpWorkgroupMemoryBarrierWithGroupSync: out.debug << "WorkgroupMemoryBarrierWithGroupSync"; break;
case EOpSubpassLoad: out.debug << "subpassLoad"; break;
case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
default: out.debug.message(EPrefixError, "Bad aggregation op");
}
......
......@@ -497,7 +497,8 @@ protected:
}
static bool isTextureType(const glslang::TType& type) {
return type.getBasicType() == glslang::EbtSampler && type.getSampler().isTexture();
return (type.getBasicType() == glslang::EbtSampler &&
(type.getSampler().isTexture() || type.getSampler().isSubpass()));
}
static bool isUboType(const glslang::TType& type) {
......
......@@ -318,6 +318,7 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.structin.vert", "main"},
{"hlsl.structIoFourWay.frag", "main"},
{"hlsl.structStructName.frag", "main"},
{"hlsl.subpass.frag", "main"},
{"hlsl.synthesizeInput.frag", "main"},
{"hlsl.texture.struct.frag", "main"},
{"hlsl.texture.subvec4.frag", "main"},
......
......@@ -334,6 +334,7 @@ INSTANTIATE_TEST_CASE_P(
{ "spv.register.autoassign.frag", "main_ep", 5, 10, 0, 20, 30, true, false },
{ "spv.register.noautoassign.frag", "main_ep", 5, 10, 0, 15, 30, false, false },
{ "spv.register.autoassign-2.frag", "main", 5, 10, 0, 15, 30, true, true },
{ "spv.register.subpass.frag", "main", 0, 20, 0, 0, 0, true, true },
{ "spv.buffer.autoassign.frag", "main", 5, 10, 0, 15, 30, true, true },
{ "spv.ssbo.autoassign.frag", "main", 5, 10, 0, 15, 30, true, true },
{ "spv.ssboAlias.frag", "main", 0, 0, 0, 0, 83, true, false },
......
......@@ -1088,6 +1088,69 @@ bool HlslGrammar::acceptAnnotations(TQualifier&)
return true;
}
// subpass input type
// : SUBPASSINPUT
// | SUBPASSINPUT VECTOR LEFT_ANGLE template_type RIGHT_ANGLE
// | SUBPASSINPUTMS
// | SUBPASSINPUTMS VECTOR LEFT_ANGLE template_type RIGHT_ANGLE
bool HlslGrammar::acceptSubpassInputType(TType& type)
{
// read subpass type
const EHlslTokenClass subpassInputType = peek();
bool multisample;
switch (subpassInputType) {
case EHTokSubpassInput: multisample = false; break;
case EHTokSubpassInputMS: multisample = true; break;
default:
return false; // not a subpass input declaration
}
advanceToken(); // consume the sampler type keyword
TType subpassType(EbtFloat, EvqUniform, 4); // default type is float4
if (acceptTokenClass(EHTokLeftAngle)) {
if (! acceptType(subpassType)) {
expected("scalar or vector type");
return false;
}
const TBasicType basicRetType = subpassType.getBasicType() ;
switch (basicRetType) {
case EbtFloat:
case EbtUint:
case EbtInt:
case EbtStruct:
break;
default:
unimplemented("basic type in subpass input");
return false;
}
if (! acceptTokenClass(EHTokRightAngle)) {
expected("right angle bracket");
return false;
}
}
const TBasicType subpassBasicType = subpassType.isStruct() ? (*subpassType.getStruct())[0].type->getBasicType()
: subpassType.getBasicType();
TSampler sampler;
sampler.setSubpass(subpassBasicType, multisample);
// Remember the declared return type. Function returns false on error.
if (!parseContext.setTextureReturnType(sampler, subpassType, token.loc))
return false;
type.shallowCopy(TType(sampler, EvqUniform));
return true;
}
// sampler_type
// : SAMPLER
// | SAMPLER1D
......@@ -1357,6 +1420,11 @@ bool HlslGrammar::acceptType(TType& type, TIntermNode*& nodeList)
return acceptSamplerType(type);
break;
case EHTokSubpassInput: // fall through
case EHTokSubpassInputMS: // ...
return acceptSubpassInputType(type);
break;
case EHTokBuffer: // fall through
case EHTokTexture1d: // ...
case EHTokTexture1darray: // ...
......
......@@ -87,6 +87,7 @@ namespace glslang {
bool acceptAnnotations(TQualifier&);
bool acceptSamplerType(TType&);
bool acceptTextureType(TType&);
bool acceptSubpassInputType(TType&);
bool acceptStructBufferType(TType&);
bool acceptConstantBufferType(TType&);
bool acceptStruct(TType&, TIntermNode*& nodeList);
......
......@@ -4215,6 +4215,25 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
break;
}
case EOpSubpassLoad:
{
const TIntermTyped* argSubpass =
argAggregate ? argAggregate->getSequence()[0]->getAsTyped() :
arguments->getAsTyped();
const TSampler& sampler = argSubpass->getType().getSampler();
// subpass load: the multisample form is overloaded. Here, we convert that to
// the EOpSubpassLoadMS opcode.
if (argAggregate != nullptr && argAggregate->getSequence().size() > 1)
node->getAsOperator()->setOp(EOpSubpassLoadMS);
node = convertReturn(node, sampler);
break;
}
default:
break; // most pass through unchanged
}
......@@ -8952,6 +8971,12 @@ bool HlslParseContext::setTextureReturnType(TSampler& sampler, const TType& retT
return false;
}
// TODO: Subpass doesn't handle struct returns, due to some oddities with fn overloading.
if (sampler.isSubpass()) {
error(loc, "Unimplemented: structure template type in subpass input", "", "");
return false;
}
TTypeList* members = retType.getWritableStruct();
// Check for too many or not enough structure members.
......
......@@ -68,14 +68,21 @@ const char* BaseTypeName(const char argOrder, const char* scalarName, const char
}
}
bool IsSamplerType(const char argType) { return argType == 'S' || argType == 's'; }
bool IsArrayed(const char argOrder) { return argOrder == '@' || argOrder == '&' || argOrder == '#'; }
bool IsTextureMS(const char argOrder) { return argOrder == '$' || argOrder == '&'; }
bool IsBuffer(const char argOrder) { return argOrder == '*' || argOrder == '~'; }
bool IsImage(const char argOrder) { return argOrder == '!' || argOrder == '#' || argOrder == '~'; }
// arg order queries
bool IsSamplerType(const char argType) { return argType == 'S' || argType == 's'; }
bool IsArrayed(const char argOrder) { return argOrder == '@' || argOrder == '&' || argOrder == '#'; }
bool IsTextureNonMS(const char argOrder) { return argOrder == '%'; }
bool IsSubpassInput(const char argOrder) { return argOrder == '[' || argOrder == ']'; }
bool IsArrayedTexture(const char argOrder) { return argOrder == '@'; }
bool IsTextureMS(const char argOrder) { return argOrder == '$' || argOrder == '&'; }
bool IsMS(const char argOrder) { return IsTextureMS(argOrder) || argOrder == ']'; }
bool IsBuffer(const char argOrder) { return argOrder == '*' || argOrder == '~'; }
bool IsImage(const char argOrder) { return argOrder == '!' || argOrder == '#' || argOrder == '~'; }
bool IsTextureType(const char argOrder)
{
return argOrder == '%' || argOrder == '@' || IsTextureMS(argOrder) || IsBuffer(argOrder) | IsImage(argOrder);
return IsTextureNonMS(argOrder) || IsArrayedTexture(argOrder) ||
IsTextureMS(argOrder) || IsBuffer(argOrder) || IsImage(argOrder);
}
// Reject certain combinations that are illegal sample methods. For example,
......@@ -222,15 +229,16 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
const bool isTexture = IsTextureType(argOrder[0]);
const bool isArrayed = IsArrayed(argOrder[0]);
const bool isSampler = IsSamplerType(argType[0]);
const bool isMS = IsTextureMS(argOrder[0]);
const bool isMS = IsMS(argOrder[0]);
const bool isBuffer = IsBuffer(argOrder[0]);
const bool isImage = IsImage(argOrder[0]);
const bool isSubpass = IsSubpassInput(argOrder[0]);
char type = *argType;
if (isTranspose) { // Take transpose of matrix dimensions
std::swap(dim0, dim1);
} else if (isTexture) {
} else if (isTexture || isSubpass) {
if (type == 'F') // map base type to texture of that type.
type = 'T'; // e.g, int -> itexture, uint -> utexture, etc.
else if (type == 'I')
......@@ -255,16 +263,23 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
case 'S': s += "sampler"; break;
case 's': s += "SamplerComparisonState"; break;
case 'T': s += ((isBuffer && isImage) ? "RWBuffer" :
isSubpass ? "SubpassInput" :
isBuffer ? "Buffer" :
isImage ? "RWTexture" : "Texture"); break;
case 'i': s += ((isBuffer && isImage) ? "RWBuffer" :
isSubpass ? "SubpassInput" :
isBuffer ? "Buffer" :
isImage ? "RWTexture" : "Texture"); break;
case 'u': s += ((isBuffer && isImage) ? "RWBuffer" :
isSubpass ? "SubpassInput" :
isBuffer ? "Buffer" :
isImage ? "RWTexture" : "Texture"); break;
default: s += "UNKNOWN_TYPE"; break;
}
if (isSubpass && isMS)
s += "MS";
} else {
switch (type) {
case '-': s += "void"; break;
......@@ -282,6 +297,7 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
s += type;
s += ((isImage && isBuffer) ? "imageBuffer" :
isSubpass ? "subpassInput" :
isImage ? "image" :
isBuffer ? "samplerBuffer" :
"texture");
......@@ -296,6 +312,9 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
if (fixedVecSize != 0)
dim0 = dim1 = fixedVecSize;
const char dim0Char = ('0' + char(dim0));
const char dim1Char = ('0' + char(dim1));
// Add sampler dimensions
if (isSampler || isTexture) {
if ((order == 'V' || isTexture) && !isBuffer) {
......@@ -320,12 +339,12 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
case '-': break; // no dimensions for voids
case 'S': break; // no dimensions on scalars
case 'V':
s += ('0' + char(dim0));
s += dim0Char;
break;
case 'M':
s += ('0' + char(dim0));
s += dim0Char;
s += 'x';
s += ('0' + char(dim1));
s += dim1Char;
break;
default:
break;
......@@ -339,9 +358,9 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
// For HLSL, append return type for texture types
if (UseHlslTypes) {
switch (type) {
case 'i': s += "<int4>"; break;
case 'u': s += "<uint4>"; break;
case 'T': s += "<float4>"; break;
case 'i': s += "<int"; s += dim0Char; s += ">"; break;
case 'u': s += "<uint"; s += dim0Char; s += ">"; break;
case 'T': s += "<float"; s += dim0Char; s += ">"; break;
default: break;
}
}
......@@ -414,7 +433,7 @@ inline void FindVectorMatrixBounds(const char* argOrder, int fixedVecSize, int&
const char* nthArgOrder(NthArg(argOrder, arg));
if (nthArgOrder == nullptr)
break;
else if (*nthArgOrder == 'V')
else if (*nthArgOrder == 'V' || IsSubpassInput(*nthArgOrder))
dim0Max = 4;
else if (*nthArgOrder == 'M')
dim0Max = dim1Max = 4;
......@@ -537,6 +556,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
// '!' as first letter of order creates image object
// '#' as first letter of order creates arrayed image object
// '~' as first letter of order creates an image buffer object
// '[' / ']' as first letter of order creates a SubpassInput/SubpassInputMS object
static const struct {
const char* name; // intrinsic name
......@@ -882,6 +902,10 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
{ "DecrementCounter", nullptr, nullptr, "-", "-", EShLangAll, true },
{ "Consume", nullptr, nullptr, "-", "-", EShLangAll, true },
// Methods for subpass input objects
{ "SubpassLoad", "V4", nullptr, "[", "FIU", EShLangPS, true },
{ "SubpassLoad", "V4", nullptr, "],S", "FIU,I", EShLangPS, true },
// Mark end of list, since we want to avoid a range-based for, as some compilers don't handle it yet.
{ nullptr, nullptr, nullptr, nullptr, nullptr, 0, false },
};
......@@ -1219,6 +1243,10 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
// GS methods
symbolTable.relateToOperator(BUILTIN_PREFIX "Append", EOpMethodAppend);
symbolTable.relateToOperator(BUILTIN_PREFIX "RestartStrip", EOpMethodRestartStrip);
// Subpass input methods
symbolTable.relateToOperator(BUILTIN_PREFIX "SubpassLoad", EOpSubpassLoad);
symbolTable.relateToOperator(BUILTIN_PREFIX "SubpassLoadMS", EOpSubpassLoadMS);
}
//
......
......@@ -336,6 +336,8 @@ void HlslScanContext::fillInKeywordMap()
(*KeywordMap)["RWTexture2DArray"] = EHTokRWTexture2darray;
(*KeywordMap)["RWTexture3D"] = EHTokRWTexture3d;
(*KeywordMap)["RWBuffer"] = EHTokRWBuffer;
(*KeywordMap)["SubpassInput"] = EHTokSubpassInput;
(*KeywordMap)["SubpassInputMS"] = EHTokSubpassInputMS;
(*KeywordMap)["AppendStructuredBuffer"] = EHTokAppendStructuredBuffer;
(*KeywordMap)["ByteAddressBuffer"] = EHTokByteAddressBuffer;
......@@ -827,6 +829,8 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokRWByteAddressBuffer:
case EHTokRWStructuredBuffer:
case EHTokStructuredBuffer:
case EHTokSubpassInput:
case EHTokSubpassInputMS:
return keyword;
// variable, user type, ...
......
......@@ -273,6 +273,8 @@ enum EHlslTokenClass {
EHTokRWTexture2darray,
EHTokRWTexture3d,
EHTokRWBuffer,
EHTokSubpassInput,
EHTokSubpassInputMS,
// Structure buffer variants
EHTokAppendStructuredBuffer,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment