HLSL: Partially address issue #463: accept GLSL layout(...).

This includes all "per variable" layout qualifiers, but the
key ones mattering and tested for now are:
  set=
  binding=
  constant_id=
  push_constant
This commit is contained in:
John Kessenich 2016-08-17 10:22:08 -06:00
parent 78a8b0737c
commit b9e39120b4
9 changed files with 270 additions and 55 deletions

View File

@ -0,0 +1,112 @@
hlsl.layout.frag
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:15 Function Definition: PixelShaderFunction(vf4; (global 4-component vector of float)
0:12 Function Parameters:
0:12 'input' (in 4-component vector of float)
0:? Sequence
0:13 Branch: Return with expression
0:13 add (temp 4-component vector of float)
0:13 add (temp 4-component vector of float)
0:13 'input' (in 4-component vector of float)
0:13 v1: direct index for structure (layout(column_major std430 offset=16 ) buffer 4-component vector of float)
0:13 'anon@0' (layout(set=3 binding=5 column_major std430 ) buffer block{layout(column_major std430 offset=16 ) buffer 4-component vector of float v1})
0:13 Constant:
0:13 0 (const uint)
0:13 v5: direct index for structure (layout(column_major std430 offset=0 ) buffer 4-component vector of float)
0:13 'anon@1' (layout(column_major std430 push_constant ) buffer block{layout(column_major std430 offset=0 ) buffer 4-component vector of float v5})
0:13 Constant:
0:13 0 (const uint)
0:? Linker Objects
0:? 'anon@0' (layout(set=3 binding=5 column_major std430 ) buffer block{layout(column_major std430 offset=16 ) buffer 4-component vector of float v1})
0:? 'anon@1' (layout(column_major std430 push_constant ) buffer block{layout(column_major std430 offset=0 ) buffer 4-component vector of float v5})
0:? 'specConst' (specialization-constant const int)
0:? 10 (const int)
Linked fragment stage:
Shader version: 450
gl_FragCoord origin is upper left
0:? Sequence
0:15 Function Definition: PixelShaderFunction(vf4; (global 4-component vector of float)
0:12 Function Parameters:
0:12 'input' (in 4-component vector of float)
0:? Sequence
0:13 Branch: Return with expression
0:13 add (temp 4-component vector of float)
0:13 add (temp 4-component vector of float)
0:13 'input' (in 4-component vector of float)
0:13 v1: direct index for structure (layout(column_major std430 offset=16 ) buffer 4-component vector of float)
0:13 'anon@0' (layout(set=3 binding=5 column_major std430 ) buffer block{layout(column_major std430 offset=16 ) buffer 4-component vector of float v1})
0:13 Constant:
0:13 0 (const uint)
0:13 v5: direct index for structure (layout(column_major std430 offset=0 ) buffer 4-component vector of float)
0:13 'anon@1' (layout(column_major std430 push_constant ) buffer block{layout(column_major std430 offset=0 ) buffer 4-component vector of float v5})
0:13 Constant:
0:13 0 (const uint)
0:? Linker Objects
0:? 'anon@0' (layout(set=3 binding=5 column_major std430 ) buffer block{layout(column_major std430 offset=16 ) buffer 4-component vector of float v1})
0:? 'anon@1' (layout(column_major std430 push_constant ) buffer block{layout(column_major std430 offset=0 ) buffer 4-component vector of float v5})
0:? 'specConst' (specialization-constant const int)
0:? 10 (const int)
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 33
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main"
ExecutionMode 4 OriginUpperLeft
Name 4 "main"
Name 11 "PixelShaderFunction(vf4;"
Name 10 "input"
Name 14 ""
MemberName 14 0 "v1"
Name 16 ""
Name 23 ""
MemberName 23 0 "v5"
Name 25 ""
MemberDecorate 14 0 Offset 16
Decorate 14 BufferBlock
Decorate 16 DescriptorSet 3
Decorate 16 Binding 5
MemberDecorate 23 0 Offset 0
Decorate 23 BufferBlock
Decorate 32 SpecId 17
2: TypeVoid
3: TypeFunction 2
6: TypeFloat 32
7: TypeVector 6(float) 4
8: TypePointer Function 7(fvec4)
9: TypeFunction 7(fvec4) 8(ptr)
14: TypeStruct 7(fvec4)
15: TypePointer Uniform 14(struct)
16: 15(ptr) Variable Uniform
17: TypeInt 32 1
18: 17(int) Constant 0
19: TypePointer Uniform 7(fvec4)
23: TypeStruct 7(fvec4)
24: TypePointer PushConstant 23(struct)
25: 24(ptr) Variable PushConstant
26: TypePointer PushConstant 7(fvec4)
32: 17(int) SpecConstant 10
4(main): 2 Function None 3
5: Label
FunctionEnd
11(PixelShaderFunction(vf4;): 7(fvec4) Function None 9
10(input): 8(ptr) FunctionParameter
12: Label
13: 7(fvec4) Load 10(input)
20: 19(ptr) AccessChain 16 18
21: 7(fvec4) Load 20
22: 7(fvec4) FAdd 13 21
27: 26(ptr) AccessChain 25 18
28: 7(fvec4) Load 27
29: 7(fvec4) FAdd 22 28
ReturnValue 29
FunctionEnd

14
Test/hlsl.layout.frag Normal file
View File

@ -0,0 +1,14 @@
layout(set=3,binding=5) tbuffer tbufName {
layout(offset = 16) float4 v1;
};
layout(push_constant) tbuffer tbufName2 {
float4 v5;
};
layout(constant_id=17) const int specConst = 10;
float4 PixelShaderFunction(float4 input) : COLOR0
{
return input + v1 + v5;
}

View File

@ -112,6 +112,7 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.intrinsics.negative.comp", "ComputeShaderFunction"},
{"hlsl.intrinsics.negative.frag", "PixelShaderFunction"},
{"hlsl.intrinsics.negative.vert", "VertexShaderFunction"},
{"hlsl.layout.frag", "main"},
{"hlsl.load.2dms.dx10.frag", "main"},
{"hlsl.load.array.dx10.frag", "main"},
{"hlsl.load.basic.dx10.frag", "main"},

View File

@ -426,7 +426,8 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type)
// type_qualifier
TQualifier qualifier;
qualifier.clear();
acceptQualifier(qualifier);
if (! acceptQualifier(qualifier))
return false;
TSourceLoc loc = token.loc;
// type_specifier
@ -449,7 +450,7 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type)
//
// Zero or more of these, so this can't return false.
//
void HlslGrammar::acceptQualifier(TQualifier& qualifier)
bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
{
do {
switch (peek()) {
@ -508,13 +509,66 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier)
case EHTokInOut:
qualifier.storage = EvqInOut;
break;
case EHTokLayout:
if (! acceptLayoutQualifierList(qualifier))
return false;
continue;
default:
return;
return true;
}
advanceToken();
} while (true);
}
// layout_qualifier_list
// : LEFT_PAREN layout_qualifier COMMA layout_qualifier ... RIGHT_PAREN
//
// layout_qualifier
// : identifier
// | identifier EQUAL expresion
//
// Zero or more of these, so this can't return false.
//
bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
{
if (! acceptTokenClass(EHTokLayout))
return false;
// LEFT_PAREN
if (! acceptTokenClass(EHTokLeftParen))
return false;
do {
// identifier
HlslToken idToken;
if (! acceptIdentifier(idToken))
break;
// EQUAL expression
if (acceptTokenClass(EHTokAssign)) {
TIntermTyped* expr;
if (! acceptConditionalExpression(expr)) {
expected("expression");
return false;
}
parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string, expr);
} else
parseContext.setLayoutQualifier(idToken.loc, qualifier, *idToken.string);
// COMMA
if (! acceptTokenClass(EHTokComma))
break;
} while (true);
// RIGHT_PAREN
if (! acceptTokenClass(EHTokRightParen)) {
expected(")");
return false;
}
return true;
}
// template_type
// : FLOAT
// | DOUBLE

View File

@ -67,7 +67,8 @@ namespace glslang {
bool acceptSamplerDeclarationDX9(TType&);
bool acceptSamplerState();
bool acceptFullySpecifiedType(TType&);
void acceptQualifier(TQualifier&);
bool acceptQualifier(TQualifier&);
bool acceptLayoutQualifierList(TQualifier&);
bool acceptType(TType&);
bool acceptTemplateType(TBasicType&);
bool acceptVectorTemplateType(TType&);

View File

@ -3112,51 +3112,58 @@ void HlslParseContext::specializationCheck(const TSourceLoc& loc, const TType& t
// Put the id's layout qualification into the public type, for qualifiers not having a number set.
// This is before we know any type information for error checking.
void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id)
void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TQualifier& qualifier, TString& id)
{
std::transform(id.begin(), id.end(), id.begin(), ::tolower);
if (id == TQualifier::getLayoutMatrixString(ElmColumnMajor)) {
publicType.qualifier.layoutMatrix = ElmColumnMajor;
qualifier.layoutMatrix = ElmColumnMajor;
return;
}
if (id == TQualifier::getLayoutMatrixString(ElmRowMajor)) {
publicType.qualifier.layoutMatrix = ElmRowMajor;
qualifier.layoutMatrix = ElmRowMajor;
return;
}
if (id == "push_constant") {
requireVulkan(loc, "push_constant");
publicType.qualifier.layoutPushConstant = true;
qualifier.layoutPushConstant = true;
return;
}
if (language == EShLangGeometry || language == EShLangTessEvaluation) {
if (id == TQualifier::getGeometryString(ElgTriangles)) {
publicType.shaderQualifiers.geometry = ElgTriangles;
//publicType.shaderQualifiers.geometry = ElgTriangles;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (language == EShLangGeometry) {
if (id == TQualifier::getGeometryString(ElgPoints)) {
publicType.shaderQualifiers.geometry = ElgPoints;
//publicType.shaderQualifiers.geometry = ElgPoints;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getGeometryString(ElgLineStrip)) {
publicType.shaderQualifiers.geometry = ElgLineStrip;
//publicType.shaderQualifiers.geometry = ElgLineStrip;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getGeometryString(ElgLines)) {
publicType.shaderQualifiers.geometry = ElgLines;
//publicType.shaderQualifiers.geometry = ElgLines;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getGeometryString(ElgLinesAdjacency)) {
publicType.shaderQualifiers.geometry = ElgLinesAdjacency;
//publicType.shaderQualifiers.geometry = ElgLinesAdjacency;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getGeometryString(ElgTrianglesAdjacency)) {
publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency;
//publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getGeometryString(ElgTriangleStrip)) {
publicType.shaderQualifiers.geometry = ElgTriangleStrip;
//publicType.shaderQualifiers.geometry = ElgTriangleStrip;
warn(loc, "ignored", id.c_str(), "");
return;
}
} else {
@ -3164,65 +3171,78 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
// input primitive
if (id == TQualifier::getGeometryString(ElgTriangles)) {
publicType.shaderQualifiers.geometry = ElgTriangles;
//publicType.shaderQualifiers.geometry = ElgTriangles;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getGeometryString(ElgQuads)) {
publicType.shaderQualifiers.geometry = ElgQuads;
//publicType.shaderQualifiers.geometry = ElgQuads;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getGeometryString(ElgIsolines)) {
publicType.shaderQualifiers.geometry = ElgIsolines;
//publicType.shaderQualifiers.geometry = ElgIsolines;
warn(loc, "ignored", id.c_str(), "");
return;
}
// vertex spacing
if (id == TQualifier::getVertexSpacingString(EvsEqual)) {
publicType.shaderQualifiers.spacing = EvsEqual;
//publicType.shaderQualifiers.spacing = EvsEqual;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getVertexSpacingString(EvsFractionalEven)) {
publicType.shaderQualifiers.spacing = EvsFractionalEven;
//publicType.shaderQualifiers.spacing = EvsFractionalEven;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getVertexSpacingString(EvsFractionalOdd)) {
publicType.shaderQualifiers.spacing = EvsFractionalOdd;
//publicType.shaderQualifiers.spacing = EvsFractionalOdd;
warn(loc, "ignored", id.c_str(), "");
return;
}
// triangle order
if (id == TQualifier::getVertexOrderString(EvoCw)) {
publicType.shaderQualifiers.order = EvoCw;
//publicType.shaderQualifiers.order = EvoCw;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == TQualifier::getVertexOrderString(EvoCcw)) {
publicType.shaderQualifiers.order = EvoCcw;
//publicType.shaderQualifiers.order = EvoCcw;
warn(loc, "ignored", id.c_str(), "");
return;
}
// point mode
if (id == "point_mode") {
publicType.shaderQualifiers.pointMode = true;
//publicType.shaderQualifiers.pointMode = true;
warn(loc, "ignored", id.c_str(), "");
return;
}
}
}
if (language == EShLangFragment) {
if (id == "origin_upper_left") {
publicType.shaderQualifiers.originUpperLeft = true;
//publicType.shaderQualifiers.originUpperLeft = true;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == "pixel_center_integer") {
publicType.shaderQualifiers.pixelCenterInteger = true;
//publicType.shaderQualifiers.pixelCenterInteger = true;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == "early_fragment_tests") {
publicType.shaderQualifiers.earlyFragmentTests = true;
//publicType.shaderQualifiers.earlyFragmentTests = true;
warn(loc, "ignored", id.c_str(), "");
return;
}
for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth + 1)) {
if (id == TQualifier::getLayoutDepthString(depth)) {
publicType.shaderQualifiers.layoutDepth = depth;
//publicType.shaderQualifiers.layoutDepth = depth;
warn(loc, "ignored", id.c_str(), "");
return;
}
}
@ -3232,7 +3252,8 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
if (id == TQualifier::getBlendEquationString(be)) {
requireExtensions(loc, 1, &E_GL_KHR_blend_equation_advanced, "blend equation");
intermediate.addBlendEquation(be);
publicType.shaderQualifiers.blendEquation = true;
//publicType.shaderQualifiers.blendEquation = true;
warn(loc, "ignored", id.c_str(), "");
found = true;
break;
}
@ -3247,7 +3268,7 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
// Put the id's layout qualifier value into the public type, for qualifiers having a number set.
// This is before we know any type information for error checking.
void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publicType, TString& id, const TIntermTyped* node)
void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TQualifier& qualifier, TString& id, const TIntermTyped* node)
{
const char* feature = "layout-id value";
//const char* nonLiteralFeature = "non-literal layout-id value";
@ -3262,38 +3283,38 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
std::transform(id.begin(), id.end(), id.begin(), ::tolower);
if (id == "offset") {
publicType.qualifier.layoutOffset = value;
qualifier.layoutOffset = value;
return;
} else if (id == "align") {
// "The specified alignment must be a power of 2, or a compile-time error results."
if (! IsPow2(value))
error(loc, "must be a power of 2", "align", "");
else
publicType.qualifier.layoutAlign = value;
qualifier.layoutAlign = value;
return;
} else if (id == "location") {
if ((unsigned int)value >= TQualifier::layoutLocationEnd)
error(loc, "location is too large", id.c_str(), "");
else
publicType.qualifier.layoutLocation = value;
qualifier.layoutLocation = value;
return;
} else if (id == "set") {
if ((unsigned int)value >= TQualifier::layoutSetEnd)
error(loc, "set is too large", id.c_str(), "");
else
publicType.qualifier.layoutSet = value;
qualifier.layoutSet = value;
return;
} else if (id == "binding") {
if ((unsigned int)value >= TQualifier::layoutBindingEnd)
error(loc, "binding is too large", id.c_str(), "");
else
publicType.qualifier.layoutBinding = value;
qualifier.layoutBinding = value;
return;
} else if (id == "component") {
if ((unsigned)value >= TQualifier::layoutComponentEnd)
error(loc, "component is too large", id.c_str(), "");
else
publicType.qualifier.layoutComponent = value;
qualifier.layoutComponent = value;
return;
} else if (id.compare(0, 4, "xfb_") == 0) {
// "Any shader making any static use (after preprocessing) of any of these
@ -3309,13 +3330,13 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
if (value >= (int)TQualifier::layoutXfbBufferEnd)
error(loc, "buffer is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbBufferEnd - 1);
else
publicType.qualifier.layoutXfbBuffer = value;
qualifier.layoutXfbBuffer = value;
return;
} else if (id == "xfb_offset") {
if (value >= (int)TQualifier::layoutXfbOffsetEnd)
error(loc, "offset is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbOffsetEnd - 1);
else
publicType.qualifier.layoutXfbOffset = value;
qualifier.layoutXfbOffset = value;
return;
} else if (id == "xfb_stride") {
// "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
@ -3325,7 +3346,7 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
else if (value >= (int)TQualifier::layoutXfbStrideEnd)
error(loc, "stride is too large:", id.c_str(), "internal max is %d", TQualifier::layoutXfbStrideEnd - 1);
if (value < (int)TQualifier::layoutXfbStrideEnd)
publicType.qualifier.layoutXfbStride = value;
qualifier.layoutXfbStride = value;
return;
}
}
@ -3335,7 +3356,7 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
if (value >= (int)TQualifier::layoutAttachmentEnd)
error(loc, "attachment index is too large", id.c_str(), "");
else
publicType.qualifier.layoutAttachment = value;
qualifier.layoutAttachment = value;
return;
}
if (id == "constant_id") {
@ -3343,8 +3364,8 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
if (value >= (int)TQualifier::layoutSpecConstantIdEnd) {
error(loc, "specialization-constant id is too large", id.c_str(), "");
} else {
publicType.qualifier.layoutSpecConstantId = value;
publicType.qualifier.specConstant = true;
qualifier.layoutSpecConstantId = value;
qualifier.specConstant = true;
if (! intermediate.addUsedConstantId(value))
error(loc, "specialization-constant id already used", id.c_str(), "");
}
@ -3360,7 +3381,8 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
if (value == 0)
error(loc, "must be greater than 0", "vertices", "");
else
publicType.shaderQualifiers.vertices = value;
//publicType.shaderQualifiers.vertices = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
break;
@ -3373,24 +3395,26 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
if (value == 0)
error(loc, "must be at least 1", "invocations", "");
else
publicType.shaderQualifiers.invocations = value;
//publicType.shaderQualifiers.invocations = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == "max_vertices") {
publicType.shaderQualifiers.vertices = value;
//publicType.shaderQualifiers.vertices = value;
warn(loc, "ignored", id.c_str(), "");
if (value > resources.maxGeometryOutputVertices)
error(loc, "too large, must be less than gl_MaxGeometryOutputVertices", "max_vertices", "");
return;
}
if (id == "stream") {
publicType.qualifier.layoutStream = value;
qualifier.layoutStream = value;
return;
}
break;
case EShLangFragment:
if (id == "index") {
publicType.qualifier.layoutIndex = value;
qualifier.layoutIndex = value;
return;
}
break;
@ -3398,28 +3422,34 @@ void HlslParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& pu
case EShLangCompute:
if (id.compare(0, 11, "local_size_") == 0) {
if (id == "local_size_x") {
publicType.shaderQualifiers.localSize[0] = value;
//publicType.shaderQualifiers.localSize[0] = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == "local_size_y") {
publicType.shaderQualifiers.localSize[1] = value;
//publicType.shaderQualifiers.localSize[1] = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == "local_size_z") {
publicType.shaderQualifiers.localSize[2] = value;
//publicType.shaderQualifiers.localSize[2] = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (spvVersion.spv != 0) {
if (id == "local_size_x_id") {
publicType.shaderQualifiers.localSizeSpecId[0] = value;
//publicType.shaderQualifiers.localSizeSpecId[0] = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == "local_size_y_id") {
publicType.shaderQualifiers.localSizeSpecId[1] = value;
//publicType.shaderQualifiers.localSizeSpecId[1] = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
if (id == "local_size_z_id") {
publicType.shaderQualifiers.localSizeSpecId[2] = value;
//publicType.shaderQualifiers.localSizeSpecId[2] = value;
warn(loc, "ignored", id.c_str(), "");
return;
}
}

View File

@ -128,8 +128,8 @@ public:
void paramFix(TType& type);
void specializationCheck(const TSourceLoc&, const TType&, const char* op);
void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&);
void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&, const TIntermTyped*);
void setLayoutQualifier(const TSourceLoc&, TQualifier&, TString&);
void setLayoutQualifier(const TSourceLoc&, TQualifier&, TString&, const TIntermTyped*);
void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly);
void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&);

View File

@ -117,6 +117,7 @@ void HlslScanContext::fillInKeywordMap()
(*KeywordMap)["in"] = EHTokIn;
(*KeywordMap)["out"] = EHTokOut;
(*KeywordMap)["inout"] = EHTokInOut;
(*KeywordMap)["layout"] = EHTokLayout;
(*KeywordMap)["Buffer"] = EHTokBuffer;
(*KeywordMap)["vector"] = EHTokVector;
@ -457,6 +458,7 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokIn:
case EHTokOut:
case EHTokInOut:
case EHTokLayout:
return keyword;
// template types

View File

@ -64,6 +64,7 @@ enum EHlslTokenClass {
EHTokIn,
EHTokOut,
EHTokInOut,
EHTokLayout,
// template types
EHTokBuffer,