Commit e670fc72 by Jamie Madill Committed by Commit Bot

Implement shader compiler changes for Tessellation.

Numerous rule changes to support validating Tessellation Control and Evaluation shaders. New per-patch inputs and output variable support. Includes a new traverser step that validates barrier function calls. Functionality changes upcoming in http://crrev.com/c/2568234 Bug: angleproject:3572 Change-Id: If8da1c21d30efa12c60ed0d6c3f8cf0b27e4c86f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2633936 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarMohan Maiya <m.maiya@samsung.com>
parent 20f8828c
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 250 #define ANGLE_SH_VERSION 251
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -789,11 +789,20 @@ const std::set<std::string> *GetUsedImage2DFunctionNames(const ShHandle handle); ...@@ -789,11 +789,20 @@ const std::set<std::string> *GetUsedImage2DFunctionNames(const ShHandle handle);
bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle); bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle);
bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle); bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle);
bool HasValidGeometryShaderMaxVertices(const ShHandle handle); bool HasValidGeometryShaderMaxVertices(const ShHandle handle);
bool HasValidTessGenMode(const ShHandle handle);
bool HasValidTessGenSpacing(const ShHandle handle);
bool HasValidTessGenVertexOrder(const ShHandle handle);
bool HasValidTessGenPointMode(const ShHandle handle);
GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle); GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle);
GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle); GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle);
int GetGeometryShaderInvocations(const ShHandle handle); int GetGeometryShaderInvocations(const ShHandle handle);
int GetGeometryShaderMaxVertices(const ShHandle handle); int GetGeometryShaderMaxVertices(const ShHandle handle);
unsigned int GetShaderSharedMemorySize(const ShHandle handle); unsigned int GetShaderSharedMemorySize(const ShHandle handle);
int GetTessControlShaderVertices(const ShHandle handle);
GLenum GetTessGenMode(const ShHandle handle);
GLenum GetTessGenSpacing(const ShHandle handle);
GLenum GetTessGenVertexOrder(const ShHandle handle);
GLenum GetTessGenPointMode(const ShHandle handle);
// //
// Helper function to identify specs that are based on the WebGL spec. // Helper function to identify specs that are based on the WebGL spec.
......
...@@ -201,6 +201,8 @@ struct ShaderVariable ...@@ -201,6 +201,8 @@ struct ShaderVariable
InterpolationType interpolation; InterpolationType interpolation;
bool isInvariant; bool isInvariant;
bool isShaderIOBlock; bool isShaderIOBlock;
bool isPatch;
// Decide whether two varyings are the same at shader link time, // Decide whether two varyings are the same at shader link time,
// assuming they are from consecutive shader stages. // assuming they are from consecutive shader stages.
// Invariance needs to match only in ESSL1. Relevant spec sections: // Invariance needs to match only in ESSL1. Relevant spec sections:
......
...@@ -6,11 +6,11 @@ ...@@ -6,11 +6,11 @@
"src/compiler/translator/glslang.l": "src/compiler/translator/glslang.l":
"a04170178bdc8511bff69ec4ff144576", "a04170178bdc8511bff69ec4ff144576",
"src/compiler/translator/glslang.y": "src/compiler/translator/glslang.y":
"1c7a2f4fa0f62ebc42f855bb8a8deeaf", "d5e97733e569b408728a1645b6763890",
"src/compiler/translator/glslang_lex_autogen.cpp": "src/compiler/translator/glslang_lex_autogen.cpp":
"5d6469e58f9855f93987b5ddbd663920", "5d6469e58f9855f93987b5ddbd663920",
"src/compiler/translator/glslang_tab_autogen.cpp": "src/compiler/translator/glslang_tab_autogen.cpp":
"821a6cccd98a7d89666bfb3fabee3585", "f4d714cad4bd92c4b9ecfebc81349dc7",
"src/compiler/translator/glslang_tab_autogen.h": "src/compiler/translator/glslang_tab_autogen.h":
"840c12db9f7824afd05b5306c8816d95", "840c12db9f7824afd05b5306c8816d95",
"tools/flex-bison/linux/bison.sha1": "tools/flex-bison/linux/bison.sha1":
......
...@@ -92,6 +92,8 @@ angle_translator_sources = [ ...@@ -92,6 +92,8 @@ angle_translator_sources = [
"src/compiler/translator/Types.h", "src/compiler/translator/Types.h",
"src/compiler/translator/ValidateAST.cpp", "src/compiler/translator/ValidateAST.cpp",
"src/compiler/translator/ValidateAST.h", "src/compiler/translator/ValidateAST.h",
"src/compiler/translator/ValidateBarrierFunctionCall.cpp",
"src/compiler/translator/ValidateBarrierFunctionCall.h",
"src/compiler/translator/ValidateClipCullDistance.cpp", "src/compiler/translator/ValidateClipCullDistance.cpp",
"src/compiler/translator/ValidateClipCullDistance.h", "src/compiler/translator/ValidateClipCullDistance.h",
"src/compiler/translator/ValidateGlobalInitializer.cpp", "src/compiler/translator/ValidateGlobalInitializer.cpp",
......
...@@ -1060,6 +1060,8 @@ inline bool IsShaderIn(TQualifier qualifier) ...@@ -1060,6 +1060,8 @@ inline bool IsShaderIn(TQualifier qualifier)
switch (qualifier) switch (qualifier)
{ {
case EvqVertexIn: case EvqVertexIn:
case EvqTessControlIn:
case EvqTessEvaluationIn:
case EvqGeometryIn: case EvqGeometryIn:
case EvqFragmentIn: case EvqFragmentIn:
case EvqAttribute: case EvqAttribute:
...@@ -1069,6 +1071,7 @@ inline bool IsShaderIn(TQualifier qualifier) ...@@ -1069,6 +1071,7 @@ inline bool IsShaderIn(TQualifier qualifier)
case EvqNoPerspectiveIn: case EvqNoPerspectiveIn:
case EvqCentroidIn: case EvqCentroidIn:
case EvqSampleIn: case EvqSampleIn:
case EvqPatchIn:
return true; return true;
default: default:
return false; return false;
...@@ -1080,6 +1083,8 @@ inline bool IsShaderOut(TQualifier qualifier) ...@@ -1080,6 +1083,8 @@ inline bool IsShaderOut(TQualifier qualifier)
switch (qualifier) switch (qualifier)
{ {
case EvqVertexOut: case EvqVertexOut:
case EvqTessControlOut:
case EvqTessEvaluationOut:
case EvqGeometryOut: case EvqGeometryOut:
case EvqFragmentOut: case EvqFragmentOut:
case EvqVaryingOut: case EvqVaryingOut:
...@@ -1088,6 +1093,7 @@ inline bool IsShaderOut(TQualifier qualifier) ...@@ -1088,6 +1093,7 @@ inline bool IsShaderOut(TQualifier qualifier)
case EvqNoPerspectiveOut: case EvqNoPerspectiveOut:
case EvqCentroidOut: case EvqCentroidOut:
case EvqSampleOut: case EvqSampleOut:
case EvqPatchOut:
return true; return true;
default: default:
return false; return false;
...@@ -1168,6 +1174,20 @@ enum TLayoutPrimitiveType ...@@ -1168,6 +1174,20 @@ enum TLayoutPrimitiveType
EptTriangleStrip EptTriangleStrip
}; };
enum TLayoutTessEvaluationType
{
EtetUndefined,
EtetTriangles,
EtetQuads,
EtetIsolines,
EtetEqualSpacing,
EtetFractionalEvenSpacing,
EtetFractionalOddSpacing,
EtetCw,
EtetCcw,
EtetPointMode
};
struct TLayoutQualifier struct TLayoutQualifier
{ {
// Must have a trivial default constructor since it is used in YYSTYPE. // Must have a trivial default constructor since it is used in YYSTYPE.
...@@ -1181,7 +1201,9 @@ struct TLayoutQualifier ...@@ -1181,7 +1201,9 @@ struct TLayoutQualifier
earlyFragmentTests == false && matrixPacking == EmpUnspecified && earlyFragmentTests == false && matrixPacking == EmpUnspecified &&
blockStorage == EbsUnspecified && !localSize.isAnyValueSet() && blockStorage == EbsUnspecified && !localSize.isAnyValueSet() &&
imageInternalFormat == EiifUnspecified && primitiveType == EptUndefined && imageInternalFormat == EiifUnspecified && primitiveType == EptUndefined &&
invocations == 0 && maxVertices == -1 && index == -1; invocations == 0 && maxVertices == -1 && vertices == 0 &&
tesPrimitiveType == EtetUndefined && tesVertexSpacingType == EtetUndefined &&
tesOrderingType == EtetUndefined && tesPointType == EtetUndefined && index == -1;
} }
bool isCombinationValid() const bool isCombinationValid() const
...@@ -1236,6 +1258,13 @@ struct TLayoutQualifier ...@@ -1236,6 +1258,13 @@ struct TLayoutQualifier
int invocations; int invocations;
int maxVertices; int maxVertices;
// EXT_tessellation_control shader layout qualifiers
int vertices;
TLayoutTessEvaluationType tesPrimitiveType;
TLayoutTessEvaluationType tesVertexSpacingType;
TLayoutTessEvaluationType tesOrderingType;
TLayoutTessEvaluationType tesPointType;
// EXT_blend_func_extended fragment output layout qualifier // EXT_blend_func_extended fragment output layout qualifier
int index; int index;
...@@ -1255,6 +1284,11 @@ struct TLayoutQualifier ...@@ -1255,6 +1284,11 @@ struct TLayoutQualifier
primitiveType(EptUndefined), primitiveType(EptUndefined),
invocations(0), invocations(0),
maxVertices(-1), maxVertices(-1),
vertices(0),
tesPrimitiveType(EtetUndefined),
tesVertexSpacingType(EtetUndefined),
tesOrderingType(EtetUndefined),
tesPointType(EtetUndefined),
index(-1) index(-1)
{} {}
}; };
...@@ -1324,6 +1358,7 @@ inline const char *getQualifierString(TQualifier q) ...@@ -1324,6 +1358,7 @@ inline const char *getQualifierString(TQualifier q)
case EvqVaryingOut: return "varying"; case EvqVaryingOut: return "varying";
case EvqUniform: return "uniform"; case EvqUniform: return "uniform";
case EvqBuffer: return "buffer"; case EvqBuffer: return "buffer";
case EvqPatch: return "patch";
case EvqVertexIn: return "in"; case EvqVertexIn: return "in";
case EvqFragmentOut: return "out"; case EvqFragmentOut: return "out";
case EvqVertexOut: return "out"; case EvqVertexOut: return "out";
...@@ -1389,6 +1424,17 @@ inline const char *getQualifierString(TQualifier q) ...@@ -1389,6 +1424,17 @@ inline const char *getQualifierString(TQualifier q)
case EvqSampleMaskIn: return "SampleMaskIn"; case EvqSampleMaskIn: return "SampleMaskIn";
case EvqSampleMask: return "SampleMask"; case EvqSampleMask: return "SampleMask";
case EvqNumSamples: return "NumSamples"; case EvqNumSamples: return "NumSamples";
case EvqPatchIn: return "patch in";
case EvqPatchOut: return "patch out";
case EvqTessControlIn: return "in";
case EvqTessControlOut: return "out";
case EvqPerVertexOut: return "gl_out";
case EvqPatchVerticesIn: return "PatchVerticesIn";
case EvqTessLevelOuter: return "TessLevelOuter";
case EvqTessLevelInner: return "TessLevelInner";
case EvqTessEvaluationIn: return "in";
case EvqTessEvaluationOut: return "out";
case EvqTessCoord: return "TessCoord";
default: UNREACHABLE(); return "unknown qualifier"; default: UNREACHABLE(); return "unknown qualifier";
} }
// clang-format on // clang-format on
...@@ -1517,6 +1563,34 @@ inline const char *getGeometryShaderPrimitiveTypeString(TLayoutPrimitiveType pri ...@@ -1517,6 +1563,34 @@ inline const char *getGeometryShaderPrimitiveTypeString(TLayoutPrimitiveType pri
} }
} }
inline const char *getTessEvaluationShaderTypeString(TLayoutTessEvaluationType type)
{
switch (type)
{
case EtetTriangles:
return "triangles";
case EtetQuads:
return "quads";
case EtetIsolines:
return "isolines";
case EtetEqualSpacing:
return "equal_spacing";
case EtetFractionalEvenSpacing:
return "fractional_even_spacing";
case EtetFractionalOddSpacing:
return "fractional_odd_spacing";
case EtetCw:
return "cw";
case EtetCcw:
return "ccw";
case EtetPointMode:
return "point_mode";
default:
UNREACHABLE();
return "unknown tessellation evaluation shader variable type";
}
}
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_BASETYPES_H_ #endif // COMPILER_TRANSLATOR_BASETYPES_H_
...@@ -124,7 +124,9 @@ class CollectVariablesTraverser : public TIntermTraverser ...@@ -124,7 +124,9 @@ class CollectVariablesTraverser : public TIntermTraverser
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
GLenum shaderType, GLenum shaderType,
const TExtensionBehavior &extensionBehavior); const TExtensionBehavior &extensionBehavior,
const ShBuiltInResources &resources,
int tessControlShaderOutputVertices);
bool visitGlobalQualifierDeclaration(Visit visit, bool visitGlobalQualifierDeclaration(Visit visit,
TIntermGlobalQualifierDeclaration *node) override; TIntermGlobalQualifierDeclaration *node) override;
...@@ -138,11 +140,13 @@ class CollectVariablesTraverser : public TIntermTraverser ...@@ -138,11 +140,13 @@ class CollectVariablesTraverser : public TIntermTraverser
void setFieldOrVariableProperties(const TType &type, void setFieldOrVariableProperties(const TType &type,
bool staticUse, bool staticUse,
bool isShaderIOBlock, bool isShaderIOBlock,
bool isPatch,
ShaderVariable *variableOut) const; ShaderVariable *variableOut) const;
void setFieldProperties(const TType &type, void setFieldProperties(const TType &type,
const ImmutableString &name, const ImmutableString &name,
bool staticUse, bool staticUse,
bool isShaderIOBlock, bool isShaderIOBlock,
bool isPatch,
ShaderVariable *variableOut) const; ShaderVariable *variableOut) const;
void setCommonVariableProperties(const TType &type, void setCommonVariableProperties(const TType &type,
const TVariable &variable, const TVariable &variable,
...@@ -217,8 +221,11 @@ class CollectVariablesTraverser : public TIntermTraverser ...@@ -217,8 +221,11 @@ class CollectVariablesTraverser : public TIntermTraverser
bool mSampleMaskAdded; bool mSampleMaskAdded;
bool mSampleMaskInAdded; bool mSampleMaskInAdded;
// Geometry Shader builtins // Geometry and Tessellation Shader builtins
bool mPerVertexInAdded; bool mPerVertexInAdded;
bool mPerVertexOutAdded;
// Geometry Shader builtins
bool mPrimitiveIDInAdded; bool mPrimitiveIDInAdded;
bool mInvocationIDAdded; bool mInvocationIDAdded;
...@@ -229,10 +236,18 @@ class CollectVariablesTraverser : public TIntermTraverser ...@@ -229,10 +236,18 @@ class CollectVariablesTraverser : public TIntermTraverser
// Shared memory variables // Shared memory variables
bool mSharedVariableAdded; bool mSharedVariableAdded;
// Tessellation Shader builtins
bool mPatchVerticesInAdded;
bool mTessLevelOuterAdded;
bool mTessLevelInnerAdded;
bool mTessCoordAdded;
const int mTessControlShaderOutputVertices;
ShHashFunction64 mHashFunction; ShHashFunction64 mHashFunction;
GLenum mShaderType; GLenum mShaderType;
const TExtensionBehavior &mExtensionBehavior; const TExtensionBehavior &mExtensionBehavior;
const ShBuiltInResources &mResources;
}; };
CollectVariablesTraverser::CollectVariablesTraverser( CollectVariablesTraverser::CollectVariablesTraverser(
...@@ -247,7 +262,9 @@ CollectVariablesTraverser::CollectVariablesTraverser( ...@@ -247,7 +262,9 @@ CollectVariablesTraverser::CollectVariablesTraverser(
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
GLenum shaderType, GLenum shaderType,
const TExtensionBehavior &extensionBehavior) const TExtensionBehavior &extensionBehavior,
const ShBuiltInResources &resources,
int tessControlShaderOutputVertices)
: TIntermTraverser(true, false, false, symbolTable), : TIntermTraverser(true, false, false, symbolTable),
mAttribs(attribs), mAttribs(attribs),
mOutputVariables(outputVariables), mOutputVariables(outputVariables),
...@@ -289,14 +306,21 @@ CollectVariablesTraverser::CollectVariablesTraverser( ...@@ -289,14 +306,21 @@ CollectVariablesTraverser::CollectVariablesTraverser(
mSampleMaskAdded(false), mSampleMaskAdded(false),
mSampleMaskInAdded(false), mSampleMaskInAdded(false),
mPerVertexInAdded(false), mPerVertexInAdded(false),
mPerVertexOutAdded(false),
mPrimitiveIDInAdded(false), mPrimitiveIDInAdded(false),
mInvocationIDAdded(false), mInvocationIDAdded(false),
mPrimitiveIDAdded(false), mPrimitiveIDAdded(false),
mLayerAdded(false), mLayerAdded(false),
mSharedVariableAdded(false), mSharedVariableAdded(false),
mPatchVerticesInAdded(false),
mTessLevelOuterAdded(false),
mTessLevelInnerAdded(false),
mTessCoordAdded(false),
mTessControlShaderOutputVertices(tessControlShaderOutputVertices),
mHashFunction(hashFunction), mHashFunction(hashFunction),
mShaderType(shaderType), mShaderType(shaderType),
mExtensionBehavior(extensionBehavior) mExtensionBehavior(extensionBehavior),
mResources(resources)
{} {}
std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const
...@@ -314,8 +338,10 @@ void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variab ...@@ -314,8 +338,10 @@ void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variab
bool isShaderIOBlock = bool isShaderIOBlock =
IsShaderIoBlock(type.getQualifier()) && type.getInterfaceBlock() != nullptr; IsShaderIoBlock(type.getQualifier()) && type.getInterfaceBlock() != nullptr;
bool isPatch =
type.getQualifier() == EvqTessLevelInner || type.getQualifier() == EvqTessLevelOuter;
setFieldOrVariableProperties(type, true, isShaderIOBlock, info); setFieldOrVariableProperties(type, true, isShaderIOBlock, isPatch, info);
} }
void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable, void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,
...@@ -618,7 +644,9 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) ...@@ -618,7 +644,9 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
} }
else else
{ {
ASSERT(mShaderType == GL_FRAGMENT_SHADER); ASSERT(mShaderType == GL_FRAGMENT_SHADER ||
mShaderType == GL_TESS_CONTROL_SHADER ||
mShaderType == GL_TESS_EVALUATION_SHADER);
recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded, recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
mInputVaryings); mInputVaryings);
} }
...@@ -664,6 +692,39 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) ...@@ -664,6 +692,39 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
case EvqCullDistance: case EvqCullDistance:
recordBuiltInVaryingUsed(symbol->variable(), &mCullDistanceAdded, mOutputVaryings); recordBuiltInVaryingUsed(symbol->variable(), &mCullDistanceAdded, mOutputVaryings);
return; return;
case EvqPatchVerticesIn:
recordBuiltInVaryingUsed(symbol->variable(), &mPatchVerticesInAdded,
mInputVaryings);
break;
case EvqTessCoord:
recordBuiltInVaryingUsed(symbol->variable(), &mTessCoordAdded, mInputVaryings);
break;
case EvqTessLevelOuter:
if (mShaderType == GL_TESS_CONTROL_SHADER)
{
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,
mOutputVaryings);
}
else
{
ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,
mInputVaryings);
}
break;
case EvqTessLevelInner:
if (mShaderType == GL_TESS_CONTROL_SHADER)
{
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,
mOutputVaryings);
}
else
{
ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,
mInputVaryings);
}
break;
default: default:
break; break;
} }
...@@ -677,12 +738,14 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) ...@@ -677,12 +738,14 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type, void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
bool staticUse, bool staticUse,
bool isShaderIOBlock, bool isShaderIOBlock,
bool isPatch,
ShaderVariable *variableOut) const ShaderVariable *variableOut) const
{ {
ASSERT(variableOut); ASSERT(variableOut);
variableOut->staticUse = staticUse; variableOut->staticUse = staticUse;
variableOut->isShaderIOBlock = isShaderIOBlock; variableOut->isShaderIOBlock = isShaderIOBlock;
variableOut->isPatch = isPatch;
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
...@@ -702,7 +765,7 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type, ...@@ -702,7 +765,7 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
// Regardless of the variable type (uniform, in/out etc.) its fields are always plain // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
// ShaderVariable objects. // ShaderVariable objects.
ShaderVariable fieldVariable; ShaderVariable fieldVariable;
setFieldProperties(*field->type(), field->name(), staticUse, isShaderIOBlock, setFieldProperties(*field->type(), field->name(), staticUse, isShaderIOBlock, isPatch,
&fieldVariable); &fieldVariable);
variableOut->fields.push_back(fieldVariable); variableOut->fields.push_back(fieldVariable);
} }
...@@ -720,7 +783,8 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type, ...@@ -720,7 +783,8 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
for (const TField *field : fields) for (const TField *field : fields)
{ {
ShaderVariable fieldVariable; ShaderVariable fieldVariable;
setFieldProperties(*field->type(), field->name(), staticUse, true, &fieldVariable); setFieldProperties(*field->type(), field->name(), staticUse, true, isPatch,
&fieldVariable);
fieldVariable.isShaderIOBlock = true; fieldVariable.isShaderIOBlock = true;
variableOut->fields.push_back(fieldVariable); variableOut->fields.push_back(fieldVariable);
} }
...@@ -735,6 +799,27 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type, ...@@ -735,6 +799,27 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
if (!arraySizes.empty()) if (!arraySizes.empty())
{ {
variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end()); variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());
if (arraySizes[0] == 0)
{
// Tessellation Control & Evaluation shader inputs:
// Declaring an array size is optional. If no size is specified, it will be taken from
// the implementation-dependent maximum patch size (gl_MaxPatchVertices).
if (type.getQualifier() == EvqTessControlIn ||
type.getQualifier() == EvqTessEvaluationIn)
{
variableOut->arraySizes[0] = mResources.MaxPatchVertices;
}
// Tessellation Control shader outputs:
// Declaring an array size is optional. If no size is specified, it will be taken from
// output patch size declared in the shader.
if (type.getQualifier() == EvqTessControlOut)
{
ASSERT(mTessControlShaderOutputVertices > 0);
variableOut->arraySizes[0] = mTessControlShaderOutputVertices;
}
}
} }
} }
...@@ -742,10 +827,11 @@ void CollectVariablesTraverser::setFieldProperties(const TType &type, ...@@ -742,10 +827,11 @@ void CollectVariablesTraverser::setFieldProperties(const TType &type,
const ImmutableString &name, const ImmutableString &name,
bool staticUse, bool staticUse,
bool isShaderIOBlock, bool isShaderIOBlock,
bool isPatch,
ShaderVariable *variableOut) const ShaderVariable *variableOut) const
{ {
ASSERT(variableOut); ASSERT(variableOut);
setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, variableOut); setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
variableOut->name.assign(name.data(), name.length()); variableOut->name.assign(name.data(), name.length());
variableOut->mappedName = HashName(name, mHashFunction, nullptr).data(); variableOut->mappedName = HashName(name, mHashFunction, nullptr).data();
} }
...@@ -755,12 +841,14 @@ void CollectVariablesTraverser::setCommonVariableProperties(const TType &type, ...@@ -755,12 +841,14 @@ void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
ShaderVariable *variableOut) const ShaderVariable *variableOut) const
{ {
ASSERT(variableOut); ASSERT(variableOut);
ASSERT(type.getInterfaceBlock() == nullptr || IsShaderIoBlock(type.getQualifier()) ||
type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut);
const bool staticUse = mSymbolTable->isStaticallyUsed(variable); const bool staticUse = mSymbolTable->isStaticallyUsed(variable);
const bool isShaderIOBlock = const bool isShaderIOBlock = type.getInterfaceBlock() != nullptr;
IsShaderIoBlock(type.getQualifier()) && type.getInterfaceBlock() != nullptr; const bool isPatch = type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut;
setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, variableOut); setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
const bool isNamed = variable.symbolType() != SymbolType::Empty; const bool isNamed = variable.symbolType() != SymbolType::Empty;
...@@ -836,6 +924,10 @@ ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &var ...@@ -836,6 +924,10 @@ ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &var
varying.isInvariant = true; varying.isInvariant = true;
} }
break; break;
case EvqPatchIn:
case EvqPatchOut:
varying.isPatch = true;
break;
default: default:
break; break;
} }
...@@ -865,6 +957,7 @@ ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &var ...@@ -865,6 +957,7 @@ ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &var
const TType &fieldType = *blockField->type(); const TType &fieldType = *blockField->type();
fieldVariable.hasImplicitLocation = isBlockImplicitLocation; fieldVariable.hasImplicitLocation = isBlockImplicitLocation;
fieldVariable.isPatch = varying.isPatch;
int fieldLocation = fieldType.getLayoutQualifier().location; int fieldLocation = fieldType.getLayoutQualifier().location;
if (fieldLocation >= 0) if (fieldLocation >= 0)
...@@ -957,7 +1050,7 @@ void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName, ...@@ -957,7 +1050,7 @@ void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,
} }
ShaderVariable fieldVariable; ShaderVariable fieldVariable;
setFieldProperties(fieldType, field->name(), staticUse, false, &fieldVariable); setFieldProperties(fieldType, field->name(), staticUse, false, false, &fieldVariable);
fieldVariable.isRowMajorLayout = fieldVariable.isRowMajorLayout =
(fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
interfaceBlock->fields.push_back(fieldVariable); interfaceBlock->fields.push_back(fieldVariable);
...@@ -1016,7 +1109,8 @@ bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node ...@@ -1016,7 +1109,8 @@ bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node
// (named or unnamed) structure as ShaderVariable. at link between two shaders, validation // (named or unnamed) structure as ShaderVariable. at link between two shaders, validation
// between of named and unnamed, needs the same structure, its members, and members order // between of named and unnamed, needs the same structure, its members, and members order
// except instance name. // except instance name.
if (typedNode.getBasicType() == EbtInterfaceBlock && !IsShaderIoBlock(qualifier)) if (typedNode.getBasicType() == EbtInterfaceBlock && !IsShaderIoBlock(qualifier) &&
qualifier != EvqPatchIn && qualifier != EvqPatchOut)
{ {
InterfaceBlock interfaceBlock; InterfaceBlock interfaceBlock;
bool isUnnamed = variable.variable().symbolType() == SymbolType::Empty; bool isUnnamed = variable.variable().symbolType() == SymbolType::Empty;
...@@ -1041,7 +1135,8 @@ bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node ...@@ -1041,7 +1135,8 @@ bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node
else else
{ {
ASSERT(variable.variable().symbolType() != SymbolType::Empty || ASSERT(variable.variable().symbolType() != SymbolType::Empty ||
IsShaderIoBlock(qualifier)); IsShaderIoBlock(qualifier) || qualifier == EvqPatchIn ||
qualifier == EvqPatchOut);
switch (qualifier) switch (qualifier)
{ {
case EvqAttribute: case EvqAttribute:
...@@ -1125,6 +1220,13 @@ bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode) ...@@ -1125,6 +1220,13 @@ bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
{ {
ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings); ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
} }
else if (qualifier == EvqPerVertexOut)
{
TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();
ASSERT(symbolNode);
recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexOutAdded, mOutputVaryings);
ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
}
else if (IsVaryingOut(qualifier)) else if (IsVaryingOut(qualifier))
{ {
ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings); ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
...@@ -1177,12 +1279,14 @@ void CollectVariables(TIntermBlock *root, ...@@ -1177,12 +1279,14 @@ void CollectVariables(TIntermBlock *root,
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
GLenum shaderType, GLenum shaderType,
const TExtensionBehavior &extensionBehavior) const TExtensionBehavior &extensionBehavior,
const ShBuiltInResources &resources,
int tessControlShaderOutputVertices)
{ {
CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings, CollectVariablesTraverser collect(
outputVaryings, sharedVariables, uniformBlocks, attributes, outputVariables, uniforms, inputVaryings, outputVaryings, sharedVariables,
shaderStorageBlocks, hashFunction, symbolTable, shaderType, uniformBlocks, shaderStorageBlocks, hashFunction, symbolTable, shaderType,
extensionBehavior); extensionBehavior, resources, tessControlShaderOutputVertices);
root->traverse(&collect); root->traverse(&collect);
} }
......
...@@ -30,7 +30,9 @@ void CollectVariables(TIntermBlock *root, ...@@ -30,7 +30,9 @@ void CollectVariables(TIntermBlock *root,
ShHashFunction64 hashFunction, ShHashFunction64 hashFunction,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
GLenum shaderType, GLenum shaderType,
const TExtensionBehavior &extensionBehavior); const TExtensionBehavior &extensionBehavior,
const ShBuiltInResources &resources,
int tessControlShaderOutputVertices);
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_COLLECTVARIABLES_H_ #endif // COMPILER_TRANSLATOR_COLLECTVARIABLES_H_
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "compiler/translator/IsASTDepthBelowLimit.h" #include "compiler/translator/IsASTDepthBelowLimit.h"
#include "compiler/translator/OutputTree.h" #include "compiler/translator/OutputTree.h"
#include "compiler/translator/ParseContext.h" #include "compiler/translator/ParseContext.h"
#include "compiler/translator/ValidateBarrierFunctionCall.h"
#include "compiler/translator/ValidateClipCullDistance.h" #include "compiler/translator/ValidateClipCullDistance.h"
#include "compiler/translator/ValidateLimitations.h" #include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/ValidateMaxParameters.h" #include "compiler/translator/ValidateMaxParameters.h"
...@@ -305,6 +306,11 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) ...@@ -305,6 +306,11 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
mGeometryShaderInvocations(0), mGeometryShaderInvocations(0),
mGeometryShaderInputPrimitiveType(EptUndefined), mGeometryShaderInputPrimitiveType(EptUndefined),
mGeometryShaderOutputPrimitiveType(EptUndefined), mGeometryShaderOutputPrimitiveType(EptUndefined),
mTessControlShaderOutputVertices(0),
mTessEvaluationShaderInputPrimitiveType(EtetUndefined),
mTessEvaluationShaderInputVertexSpacingType(EtetUndefined),
mTessEvaluationShaderInputOrderingType(EtetUndefined),
mTessEvaluationShaderInputPointType(EtetUndefined),
mCompileOptions(0) mCompileOptions(0)
{} {}
...@@ -492,6 +498,20 @@ void TCompiler::setASTMetadata(const TParseContext &parseContext) ...@@ -492,6 +498,20 @@ void TCompiler::setASTMetadata(const TParseContext &parseContext)
mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices(); mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices();
mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations(); mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations();
} }
if (mShaderType == GL_TESS_CONTROL_SHADER_EXT)
{
mTessControlShaderOutputVertices = parseContext.getTessControlShaderOutputVertices();
}
if (mShaderType == GL_TESS_EVALUATION_SHADER_EXT)
{
mTessEvaluationShaderInputPrimitiveType =
parseContext.getTessEvaluationShaderInputPrimitiveType();
mTessEvaluationShaderInputVertexSpacingType =
parseContext.getTessEvaluationShaderInputVertexSpacingType();
mTessEvaluationShaderInputOrderingType =
parseContext.getTessEvaluationShaderInputOrderingType();
mTessEvaluationShaderInputPointType = parseContext.getTessEvaluationShaderInputPointType();
}
} }
unsigned int TCompiler::getSharedMemorySize() const unsigned int TCompiler::getSharedMemorySize() const
...@@ -620,6 +640,11 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, ...@@ -620,6 +640,11 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
return false; return false;
} }
if (mShaderType == GL_TESS_CONTROL_SHADER && !ValidateBarrierFunctionCall(root, &mDiagnostics))
{
return false;
}
// Fail compilation if precision emulation not supported. // Fail compilation if precision emulation not supported.
if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision && if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision &&
!EmulatePrecision::SupportedInLanguage(mOutputType)) !EmulatePrecision::SupportedInLanguage(mOutputType))
...@@ -816,7 +841,7 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, ...@@ -816,7 +841,7 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
CollectVariables(root, &mAttributes, &mOutputVariables, &mUniforms, &mInputVaryings, CollectVariables(root, &mAttributes, &mOutputVariables, &mUniforms, &mInputVaryings,
&mOutputVaryings, &mSharedVariables, &mUniformBlocks, &mOutputVaryings, &mSharedVariables, &mUniformBlocks,
&mShaderStorageBlocks, mResources.HashFunction, &mSymbolTable, mShaderType, &mShaderStorageBlocks, mResources.HashFunction, &mSymbolTable, mShaderType,
mExtensionBehavior); mExtensionBehavior, mResources, mTessControlShaderOutputVertices);
collectInterfaceBlocks(); collectInterfaceBlocks();
mVariablesCollected = true; mVariablesCollected = true;
if ((compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS) != 0) if ((compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS) != 0)
...@@ -1115,6 +1140,7 @@ void TCompiler::setResourceString() ...@@ -1115,6 +1140,7 @@ void TCompiler::setResourceString()
<< ":EXT_shadow_samplers:" << mResources.EXT_shadow_samplers << ":EXT_shadow_samplers:" << mResources.EXT_shadow_samplers
<< ":OES_shader_multisample_interpolation:" << mResources.OES_shader_multisample_interpolation << ":OES_shader_multisample_interpolation:" << mResources.OES_shader_multisample_interpolation
<< ":OES_shader_image_atomic:" << mResources.OES_shader_image_atomic << ":OES_shader_image_atomic:" << mResources.OES_shader_image_atomic
<< ":EXT_tessellation_shader:" << mResources.EXT_tessellation_shader
<< ":OES_texture_buffer:" << mResources.OES_texture_buffer << ":OES_texture_buffer:" << mResources.OES_texture_buffer
<< ":EXT_texture_buffer:" << mResources.EXT_texture_buffer << ":EXT_texture_buffer:" << mResources.EXT_texture_buffer
<< ":OES_sample_variables:" << mResources.OES_sample_variables << ":OES_sample_variables:" << mResources.OES_sample_variables
...@@ -1160,7 +1186,25 @@ void TCompiler::setResourceString() ...@@ -1160,7 +1186,25 @@ void TCompiler::setResourceString()
<< ":MaxGeometryImageUniforms:" << mResources.MaxGeometryImageUniforms << ":MaxGeometryImageUniforms:" << mResources.MaxGeometryImageUniforms
<< ":MaxClipDistances" << mResources.MaxClipDistances << ":MaxClipDistances" << mResources.MaxClipDistances
<< ":MaxCullDistances" << mResources.MaxCullDistances << ":MaxCullDistances" << mResources.MaxCullDistances
<< ":MaxCombinedClipAndCullDistances" << mResources.MaxCombinedClipAndCullDistances; << ":MaxCombinedClipAndCullDistances" << mResources.MaxCombinedClipAndCullDistances
<< ":MaxTessControlInputComponents:" << mResources.MaxTessControlInputComponents
<< ":MaxTessControlOutputComponents:" << mResources.MaxTessControlOutputComponents
<< ":MaxTessControlTextureImageUnits:" << mResources.MaxTessControlTextureImageUnits
<< ":MaxTessControlUniformComponents:" << mResources.MaxTessControlUniformComponents
<< ":MaxTessControlTotalOutputComponents:" << mResources.MaxTessControlTotalOutputComponents
<< ":MaxTessControlImageUniforms:" << mResources.MaxTessControlImageUniforms
<< ":MaxTessControlAtomicCounters:" << mResources.MaxTessControlAtomicCounters
<< ":MaxTessControlAtomicCounterBuffers:" << mResources.MaxTessControlAtomicCounterBuffers
<< ":MaxTessPatchComponents:" << mResources.MaxTessPatchComponents
<< ":MaxPatchVertices:" << mResources.MaxPatchVertices
<< ":MaxTessGenLevel:" << mResources.MaxTessGenLevel
<< ":MaxTessEvaluationInputComponents:" << mResources.MaxTessEvaluationInputComponents
<< ":MaxTessEvaluationOutputComponents:" << mResources.MaxTessEvaluationOutputComponents
<< ":MaxTessEvaluationTextureImageUnits:" << mResources.MaxTessEvaluationTextureImageUnits
<< ":MaxTessEvaluationUniformComponents:" << mResources.MaxTessEvaluationUniformComponents
<< ":MaxTessEvaluationImageUniforms:" << mResources.MaxTessEvaluationImageUniforms
<< ":MaxTessEvaluationAtomicCounters:" << mResources.MaxTessEvaluationAtomicCounters
<< ":MaxTessEvaluationAtomicCounterBuffers:" << mResources.MaxTessEvaluationAtomicCounterBuffers;
// clang-format on // clang-format on
mBuiltInResourcesString = strstream.str(); mBuiltInResourcesString = strstream.str();
...@@ -1222,6 +1266,12 @@ void TCompiler::clearResults() ...@@ -1222,6 +1266,12 @@ void TCompiler::clearResults()
mGeometryShaderInvocations = 0; mGeometryShaderInvocations = 0;
mGeometryShaderMaxVertices = -1; mGeometryShaderMaxVertices = -1;
mTessControlShaderOutputVertices = 0;
mTessEvaluationShaderInputPrimitiveType = EtetUndefined;
mTessEvaluationShaderInputVertexSpacingType = EtetUndefined;
mTessEvaluationShaderInputOrderingType = EtetUndefined;
mTessEvaluationShaderInputPointType = EtetUndefined;
mBuiltInFunctionEmulator.cleanup(); mBuiltInFunctionEmulator.cleanup();
mNameMap.clear(); mNameMap.clear();
......
...@@ -148,6 +148,25 @@ class TCompiler : public TShHandleBase ...@@ -148,6 +148,25 @@ class TCompiler : public TShHandleBase
} }
unsigned int getStructSize(const ShaderVariable &var) const; unsigned int getStructSize(const ShaderVariable &var) const;
int getTessControlShaderOutputVertices() const { return mTessControlShaderOutputVertices; }
TLayoutTessEvaluationType getTessEvaluationShaderInputPrimitiveType() const
{
return mTessEvaluationShaderInputPrimitiveType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputVertexSpacingType() const
{
return mTessEvaluationShaderInputVertexSpacingType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputOrderingType() const
{
return mTessEvaluationShaderInputOrderingType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputPointType() const
{
return mTessEvaluationShaderInputPointType;
}
unsigned int getSharedMemorySize() const; unsigned int getSharedMemorySize() const;
sh::GLenum getShaderType() const { return mShaderType; } sh::GLenum getShaderType() const { return mShaderType; }
...@@ -299,6 +318,13 @@ class TCompiler : public TShHandleBase ...@@ -299,6 +318,13 @@ class TCompiler : public TShHandleBase
TLayoutPrimitiveType mGeometryShaderInputPrimitiveType; TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType; TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
// tesssellation shader parameters
int mTessControlShaderOutputVertices;
TLayoutTessEvaluationType mTessEvaluationShaderInputPrimitiveType;
TLayoutTessEvaluationType mTessEvaluationShaderInputVertexSpacingType;
TLayoutTessEvaluationType mTessEvaluationShaderInputOrderingType;
TLayoutTessEvaluationType mTessEvaluationShaderInputPointType;
// name hashing. // name hashing.
NameMap mNameMap; NameMap mNameMap;
......
...@@ -1404,7 +1404,8 @@ void TOutputGLSLBase::declareInterfaceBlock(const TType &type) ...@@ -1404,7 +1404,8 @@ void TOutputGLSLBase::declareInterfaceBlock(const TType &type)
const TFieldList &fields = interfaceBlock->fields(); const TFieldList &fields = interfaceBlock->fields();
for (const TField *field : fields) for (const TField *field : fields)
{ {
if (!IsShaderIoBlock(type.getQualifier())) if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn &&
type.getQualifier() != EvqPatchOut)
{ {
writeFieldLayoutQualifier(field); writeFieldLayoutQualifier(field);
} }
...@@ -1473,6 +1474,40 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, ...@@ -1473,6 +1474,40 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
} }
} }
void WriteTessControlShaderLayoutQualifiers(TInfoSinkBase &out, int inputVertices)
{
if (inputVertices != 0)
{
out << "layout (vertices = " << inputVertices << ") out;\n";
}
}
void WriteTessEvaluationShaderLayoutQualifiers(TInfoSinkBase &out,
sh::TLayoutTessEvaluationType inputPrimitive,
sh::TLayoutTessEvaluationType inputVertexSpacing,
sh::TLayoutTessEvaluationType inputOrdering,
sh::TLayoutTessEvaluationType inputPoint)
{
if (inputPrimitive != EtetUndefined)
{
out << "layout (";
out << getTessEvaluationShaderTypeString(inputPrimitive);
if (inputVertexSpacing != EtetUndefined)
{
out << ", " << getTessEvaluationShaderTypeString(inputVertexSpacing);
}
if (inputOrdering != EtetUndefined)
{
out << ", " << getTessEvaluationShaderTypeString(inputOrdering);
}
if (inputPoint != EtetUndefined)
{
out << ", " << getTessEvaluationShaderTypeString(inputPoint);
}
out << ") in;\n";
}
}
// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever // If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
// variables with specified layout qualifiers are copied. Additional checks are needed against the // variables with specified layout qualifiers are copied. Additional checks are needed against the
// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted. // type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
......
...@@ -129,6 +129,14 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, ...@@ -129,6 +129,14 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
sh::TLayoutPrimitiveType outputPrimitive, sh::TLayoutPrimitiveType outputPrimitive,
int maxVertices); int maxVertices);
void WriteTessControlShaderLayoutQualifiers(TInfoSinkBase &out, int inputVertices);
void WriteTessEvaluationShaderLayoutQualifiers(TInfoSinkBase &out,
sh::TLayoutTessEvaluationType inputPrimitive,
sh::TLayoutTessEvaluationType inputVertexSpacing,
sh::TLayoutTessEvaluationType inputOrdering,
sh::TLayoutTessEvaluationType inputPoint);
bool NeedsToWriteLayoutQualifier(const TType &type); bool NeedsToWriteLayoutQualifier(const TType &type);
} // namespace sh } // namespace sh
......
...@@ -241,6 +241,12 @@ TParseContext::TParseContext(TSymbolTable &symt, ...@@ -241,6 +241,12 @@ TParseContext::TParseContext(TSymbolTable &symt,
mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations), mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations),
mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices), mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices),
mGeometryInputArraySize(0), mGeometryInputArraySize(0),
mMaxPatchVertices(resources.MaxPatchVertices),
mTessControlShaderOutputVertices(0),
mTessEvaluationShaderInputPrimitiveType(EtetUndefined),
mTessEvaluationShaderInputVertexSpacingType(EtetUndefined),
mTessEvaluationShaderInputOrderingType(EtetUndefined),
mTessEvaluationShaderInputPointType(EtetUndefined),
mFunctionBodyNewScope(false), mFunctionBodyNewScope(false),
mOutputType(outputType) mOutputType(outputType)
{} {}
...@@ -551,6 +557,8 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn ...@@ -551,6 +557,8 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
case EvqFragmentIn: case EvqFragmentIn:
case EvqVertexIn: case EvqVertexIn:
case EvqGeometryIn: case EvqGeometryIn:
case EvqTessControlIn:
case EvqTessEvaluationIn:
case EvqFlatIn: case EvqFlatIn:
case EvqNoPerspectiveIn: case EvqNoPerspectiveIn:
case EvqSmoothIn: case EvqSmoothIn:
...@@ -1163,7 +1171,10 @@ bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &index ...@@ -1163,7 +1171,10 @@ bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &index
// as arrays (GL_EXT_geometry_shader section 7.4.1). // as arrays (GL_EXT_geometry_shader section 7.4.1).
if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct && if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct &&
sh::IsVarying(elementType.qualifier) && sh::IsVarying(elementType.qualifier) &&
!IsGeometryShaderInput(mShaderType, elementType.qualifier)) !IsGeometryShaderInput(mShaderType, elementType.qualifier) &&
!IsTessellationControlShaderInput(mShaderType, elementType.qualifier) &&
!IsTessellationEvaluationShaderInput(mShaderType, elementType.qualifier) &&
!IsTessellationControlShaderOutput(mShaderType, elementType.qualifier))
{ {
TInfoSinkBase typeString; TInfoSinkBase typeString;
typeString << TType(elementType); typeString << TType(elementType);
...@@ -1199,7 +1210,6 @@ void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, ...@@ -1199,7 +1210,6 @@ void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
error(line, "variables with qualifier 'const' must be initialized", identifier); error(line, "variables with qualifier 'const' must be initialized", identifier);
} }
} }
// This will make the type sized if it isn't sized yet.
checkIsNotUnsizedArray(line, "implicitly sized arrays need to be initialized", identifier, checkIsNotUnsizedArray(line, "implicitly sized arrays need to be initialized", identifier,
type); type);
} }
...@@ -1744,7 +1754,7 @@ void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, co ...@@ -1744,7 +1754,7 @@ void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, co
} }
} }
void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location, bool TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location,
const ImmutableString &layoutQualifierName, const ImmutableString &layoutQualifierName,
int versionRequired) int versionRequired)
{ {
...@@ -1752,7 +1762,9 @@ void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location, ...@@ -1752,7 +1762,9 @@ void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location,
if (mShaderVersion < versionRequired) if (mShaderVersion < versionRequired)
{ {
error(location, "invalid layout qualifier: not supported", layoutQualifierName); error(location, "invalid layout qualifier: not supported", layoutQualifierName);
return false;
} }
return true;
} }
bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
...@@ -2487,8 +2499,9 @@ void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier, ...@@ -2487,8 +2499,9 @@ void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
bool typeContainsIntegers = bool typeContainsIntegers =
(type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt || (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt ||
type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt)); type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt));
bool extendedShaderTypes = bool extendedShaderTypes = mShaderVersion == 320 ||
mShaderVersion == 320 || isExtensionEnabled(TExtension::EXT_geometry_shader); isExtensionEnabled(TExtension::EXT_geometry_shader) ||
isExtensionEnabled(TExtension::EXT_tessellation_shader);
if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut && if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut &&
(!extendedShaderTypes || mShaderType == GL_FRAGMENT_SHADER)) (!extendedShaderTypes || mShaderType == GL_FRAGMENT_SHADER))
{ {
...@@ -2645,6 +2658,85 @@ void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &lo ...@@ -2645,6 +2658,85 @@ void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &lo
} }
} }
void TParseContext::checkTessellationShaderUnsizedArraysAndSetSize(const TSourceLoc &location,
const ImmutableString &token,
TType *type)
{
TQualifier qualifier = type->getQualifier();
if (!IsTessellationControlShaderOutput(mShaderType, qualifier) &&
!IsTessellationControlShaderInput(mShaderType, qualifier) &&
!IsTessellationEvaluationShaderInput(mShaderType, qualifier))
{
return;
}
// Such variables must be declared as arrays or inside output blocks declared as arrays.
if (!type->isArray())
{
error(location, "Tessellation interface variables must be declared as an array", token);
return;
}
// If a size is specified, it must match the maximum patch size.
unsigned int outermostSize = type->getOutermostArraySize();
if (outermostSize == 0u)
{
switch (qualifier)
{
case EvqTessControlIn:
case EvqTessEvaluationIn:
case EvqFlatIn:
case EvqCentroidIn:
case EvqSmoothIn:
// Declaring an array size is optional. If no size is specified, it will be taken
// from the implementation-dependent maximum patch size (gl_MaxPatchVertices).
ASSERT(mMaxPatchVertices > 0);
type->sizeOutermostUnsizedArray(mMaxPatchVertices);
break;
case EvqTessControlOut:
case EvqFlatOut:
case EvqCentroidOut:
case EvqSmoothOut:
// Declaring an array size is optional. If no size is specified, it will be taken
// from output patch size declared in the shader.
type->sizeOutermostUnsizedArray(mTessControlShaderOutputVertices);
break;
default:
UNREACHABLE();
break;
}
}
else
{
if (IsTessellationControlShaderInput(mShaderType, qualifier) ||
IsTessellationEvaluationShaderInput(mShaderType, qualifier))
{
if (outermostSize != static_cast<unsigned int>(mMaxPatchVertices))
{
error(
location,
"If a size is specified for a tessellation control or evaluation user-defined "
"input variable, it must match the maximum patch size (gl_MaxPatchVertices).",
token);
}
}
else if (IsTessellationControlShaderOutput(mShaderType, qualifier))
{
if (outermostSize != static_cast<unsigned int>(mTessControlShaderOutputVertices) &&
mTessControlShaderOutputVertices != 0)
{
error(location,
"If a size is specified for a tessellation control user-defined per-vertex "
"output variable, it must match the the number of vertices in the output "
"patch.",
token);
}
}
return;
}
}
TIntermDeclaration *TParseContext::parseSingleDeclaration( TIntermDeclaration *TParseContext::parseSingleDeclaration(
TPublicType &publicType, TPublicType &publicType,
const TSourceLoc &identifierOrTypeLocation, const TSourceLoc &identifierOrTypeLocation,
...@@ -2675,6 +2767,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration( ...@@ -2675,6 +2767,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
} }
checkGeometryShaderInputAndSetArraySize(identifierOrTypeLocation, identifier, type); checkGeometryShaderInputAndSetArraySize(identifierOrTypeLocation, identifier, type);
checkTessellationShaderUnsizedArraysAndSetSize(identifierOrTypeLocation, identifier, type);
declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier,
identifierOrTypeLocation); identifierOrTypeLocation);
...@@ -2751,6 +2844,7 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration( ...@@ -2751,6 +2844,7 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(
checkArrayOfArraysInOut(indexLocation, elementType, *arrayType); checkArrayOfArraysInOut(indexLocation, elementType, *arrayType);
checkGeometryShaderInputAndSetArraySize(indexLocation, identifier, arrayType); checkGeometryShaderInputAndSetArraySize(indexLocation, identifier, arrayType);
checkTessellationShaderUnsizedArraysAndSetSize(indexLocation, identifier, arrayType);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType);
...@@ -2915,6 +3009,7 @@ void TParseContext::parseDeclarator(TPublicType &publicType, ...@@ -2915,6 +3009,7 @@ void TParseContext::parseDeclarator(TPublicType &publicType,
TType *type = new TType(publicType); TType *type = new TType(publicType);
checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, type); checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, type);
checkTessellationShaderUnsizedArraysAndSetSize(identifierLocation, identifier, type);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, type); checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, type);
...@@ -2957,6 +3052,7 @@ void TParseContext::parseArrayDeclarator(TPublicType &elementType, ...@@ -2957,6 +3052,7 @@ void TParseContext::parseArrayDeclarator(TPublicType &elementType,
arrayType->makeArrays(arraySizes); arrayType->makeArrays(arraySizes);
checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, arrayType); checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, arrayType);
checkTessellationShaderUnsizedArraysAndSetSize(identifierLocation, identifier, arrayType);
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType);
...@@ -3227,6 +3323,89 @@ bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifie ...@@ -3227,6 +3323,89 @@ bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifie
return true; return true;
} }
bool TParseContext::parseTessControlShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier)
{
ASSERT(typeQualifier.qualifier == EvqTessControlOut);
const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier;
if (layoutQualifier.vertices == 0)
{
error(typeQualifier.line, "No vertices specified", "layout");
return false;
}
// Set mTessControlShaderOutputVertices if exists
if (mTessControlShaderOutputVertices == 0)
{
mTessControlShaderOutputVertices = layoutQualifier.vertices;
}
else
{
error(typeQualifier.line, "Duplicated vertices specified", "layout");
}
return true;
}
bool TParseContext::parseTessEvaluationShaderInputLayoutQualifier(
const TTypeQualifier &typeQualifier)
{
ASSERT(typeQualifier.qualifier == EvqTessEvaluationIn);
const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier;
// Set mTessEvaluationShaderInputPrimitiveType if exists
if (layoutQualifier.tesPrimitiveType != EtetUndefined)
{
if (mTessEvaluationShaderInputPrimitiveType == EtetUndefined)
{
mTessEvaluationShaderInputPrimitiveType = layoutQualifier.tesPrimitiveType;
}
else
{
error(typeQualifier.line, "Duplicated primitive type declaration", "layout");
}
}
// Set mTessEvaluationShaderVertexSpacingType if exists
if (layoutQualifier.tesVertexSpacingType != EtetUndefined)
{
if (mTessEvaluationShaderInputVertexSpacingType == EtetUndefined)
{
mTessEvaluationShaderInputVertexSpacingType = layoutQualifier.tesVertexSpacingType;
}
else
{
error(typeQualifier.line, "Duplicated vertex spacing declaration", "layout");
}
}
// Set mTessEvaluationShaderInputOrderingType if exists
if (layoutQualifier.tesOrderingType != EtetUndefined)
{
if (mTessEvaluationShaderInputOrderingType == EtetUndefined)
{
mTessEvaluationShaderInputOrderingType = layoutQualifier.tesOrderingType;
}
else
{
error(typeQualifier.line, "Duplicated ordering declaration", "layout");
}
}
// Set mTessEvaluationShaderInputPointType if exists
if (layoutQualifier.tesPointType != EtetUndefined)
{
if (mTessEvaluationShaderInputPointType == EtetUndefined)
{
mTessEvaluationShaderInputPointType = layoutQualifier.tesPointType;
}
else
{
error(typeQualifier.line, "Duplicated point type declaration", "layout");
}
}
return true;
}
void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder) void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
{ {
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
...@@ -3377,7 +3556,8 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type ...@@ -3377,7 +3556,8 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
if (mShaderVersion < 310) if (mShaderVersion < 310)
{ {
error(typeQualifier.line, error(typeQualifier.line,
"in type qualifier without variable declaration supported in GLSL ES 3.10 only", "in type qualifier without variable declaration supported in GLSL ES 3.10 and "
"after",
"layout"); "layout");
return; return;
} }
...@@ -3393,6 +3573,34 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type ...@@ -3393,6 +3573,34 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
mEarlyFragmentTestsSpecified = true; mEarlyFragmentTestsSpecified = true;
} }
else if (typeQualifier.qualifier == EvqTessControlOut)
{
if (mShaderVersion < 310)
{
error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 and after",
"layout");
return;
}
if (!parseTessControlShaderOutputLayoutQualifier(typeQualifier))
{
return;
}
}
else if (typeQualifier.qualifier == EvqTessEvaluationIn)
{
if (mShaderVersion < 310)
{
error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 and after",
"layout");
return;
}
if (!parseTessEvaluationShaderInputLayoutQualifier(typeQualifier))
{
return;
}
}
else else
{ {
if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier)) if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier))
...@@ -3409,7 +3617,7 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type ...@@ -3409,7 +3617,7 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
if (mShaderVersion < 300) if (mShaderVersion < 300)
{ {
error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above", error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and after",
"layout"); "layout");
return; return;
} }
...@@ -3902,6 +4110,26 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -3902,6 +4110,26 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
"3.10", "3.10",
getQualifierString(typeQualifier.qualifier)); getQualifierString(typeQualifier.qualifier));
} }
else if (typeQualifier.qualifier == EvqPatchOut)
{
if ((!isExtensionEnabled(TExtension::EXT_tessellation_shader) && mShaderVersion < 320) ||
mShaderType != GL_TESS_CONTROL_SHADER)
{
error(typeQualifier.line,
"invalid qualifier: 'patch out' requires a tessellation control shader",
getQualifierString(typeQualifier.qualifier));
}
}
else if (typeQualifier.qualifier == EvqPatchIn)
{
if ((!isExtensionEnabled(TExtension::EXT_tessellation_shader) && mShaderVersion < 320) ||
mShaderType != GL_TESS_EVALUATION_SHADER)
{
error(typeQualifier.line,
"invalid qualifier: 'patch in' requires a tessellation evaluation shader",
getQualifierString(typeQualifier.qualifier));
}
}
else if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) else if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer)
{ {
if (isShaderIoBlock) if (isShaderIoBlock)
...@@ -3910,9 +4138,14 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -3910,9 +4138,14 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
!isExtensionEnabled(TExtension::EXT_shader_io_blocks)) !isExtensionEnabled(TExtension::EXT_shader_io_blocks))
{ {
error(typeQualifier.line, error(typeQualifier.line,
"invalid qualifier: interface blocks need shader io block extension", "invalid qualifier: shader IO blocks need shader io block extension",
getQualifierString(typeQualifier.qualifier)); getQualifierString(typeQualifier.qualifier));
} }
if (mShaderType == GL_TESS_CONTROL_SHADER && arraySizes == nullptr)
{
error(typeQualifier.line, "type must be an array", blockName);
}
} }
else else
{ {
...@@ -3999,7 +4232,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -3999,7 +4232,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
typeQualifier.layoutQualifier.earlyFragmentTests); typeQualifier.layoutQualifier.earlyFragmentTests);
TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
if (!IsShaderIoBlock(typeQualifier.qualifier)) if (!IsShaderIoBlock(typeQualifier.qualifier) && typeQualifier.qualifier != EvqPatchIn &&
typeQualifier.qualifier != EvqPatchOut)
{ {
checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier); checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier);
} }
...@@ -4082,7 +4316,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -4082,7 +4316,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
case EvqFlat: case EvqFlat:
case EvqNoPerspective: case EvqNoPerspective:
case EvqCentroid: case EvqCentroid:
if (!IsShaderIoBlock(typeQualifier.qualifier)) if (!IsShaderIoBlock(typeQualifier.qualifier) &&
typeQualifier.qualifier != EvqPatchIn && typeQualifier.qualifier != EvqPatchOut)
{ {
error(field->line(), "invalid qualifier on interface block member", error(field->line(), "invalid qualifier on interface block member",
getQualifierString(qualifier)); getQualifierString(qualifier));
...@@ -4291,14 +4526,28 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, ...@@ -4291,14 +4526,28 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
if (baseExpression->getQualifier() == EvqPerVertexIn) if (baseExpression->getQualifier() == EvqPerVertexIn)
{ {
ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT); if (mGeometryShaderInputPrimitiveType == EptUndefined &&
if (mGeometryShaderInputPrimitiveType == EptUndefined) mShaderType == GL_GEOMETRY_SHADER_EXT)
{ {
error(location, "missing input primitive declaration before indexing gl_in.", "["); error(location, "missing input primitive declaration before indexing gl_in.", "[");
return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
} }
} }
if (mShaderType == GL_TESS_CONTROL_SHADER &&
IsTessellationControlShaderOutput(mShaderType, baseExpression->getQualifier()))
{
const TIntermSymbol *intermSymbol = indexExpression->getAsSymbolNode();
if (!intermSymbol || intermSymbol->getName() != "gl_InvocationID")
{
error(location,
"tessellation-control per-vertex output l-value must be indexed with "
"gl_InvocationID",
"[");
return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
}
}
TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
// ES3.2 or ES3.1's EXT_gpu_shader5 allow dynamically uniform expressions to be used as indices // ES3.2 or ES3.1's EXT_gpu_shader5 allow dynamically uniform expressions to be used as indices
...@@ -4335,7 +4584,9 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, ...@@ -4335,7 +4584,9 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
break; break;
default: default:
// It's ok for shader I/O blocks to be dynamically indexed // It's ok for shader I/O blocks to be dynamically indexed
if (!IsShaderIoBlock(baseExpression->getQualifier())) if (!IsShaderIoBlock(baseExpression->getQualifier()) &&
baseExpression->getQualifier() != EvqPatchIn &&
baseExpression->getQualifier() != EvqPatchOut)
{ {
// We can reach here only in error cases. // We can reach here only in error cases.
ASSERT(mDiagnostics->numErrors() > 0); ASSERT(mDiagnostics->numErrors() > 0);
...@@ -4729,49 +4980,88 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qual ...@@ -4729,49 +4980,88 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qual
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.imageInternalFormat = EiifR32UI; qualifier.imageInternalFormat = EiifR32UI;
} }
else if (qualifierType == "points" && mShaderType == GL_GEOMETRY_SHADER_EXT && else if (mShaderType == GL_GEOMETRY_SHADER_EXT &&
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader) &&
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310))
{
if (qualifierType == "points")
{ {
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptPoints; qualifier.primitiveType = EptPoints;
} }
else if (qualifierType == "lines" && mShaderType == GL_GEOMETRY_SHADER_EXT && else if (qualifierType == "lines")
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
{ {
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptLines; qualifier.primitiveType = EptLines;
} }
else if (qualifierType == "lines_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT && else if (qualifierType == "lines_adjacency")
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
{ {
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptLinesAdjacency; qualifier.primitiveType = EptLinesAdjacency;
} }
else if (qualifierType == "triangles" && mShaderType == GL_GEOMETRY_SHADER_EXT && else if (qualifierType == "triangles")
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
{ {
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptTriangles; qualifier.primitiveType = EptTriangles;
} }
else if (qualifierType == "triangles_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT && else if (qualifierType == "triangles_adjacency")
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
{ {
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptTrianglesAdjacency; qualifier.primitiveType = EptTrianglesAdjacency;
} }
else if (qualifierType == "line_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT && else if (qualifierType == "line_strip")
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
{ {
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptLineStrip; qualifier.primitiveType = EptLineStrip;
} }
else if (qualifierType == "triangle_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT && else if (qualifierType == "triangle_strip")
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader))
{ {
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptTriangleStrip; qualifier.primitiveType = EptTriangleStrip;
} }
else
{
error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
}
}
else if (mShaderType == GL_TESS_EVALUATION_SHADER_EXT &&
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_tessellation_shader) &&
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310))
{
if (qualifierType == "triangles")
{
qualifier.tesPrimitiveType = EtetTriangles;
}
else if (qualifierType == "quads")
{
qualifier.tesPrimitiveType = EtetQuads;
}
else if (qualifierType == "isolines")
{
qualifier.tesPrimitiveType = EtetIsolines;
}
else if (qualifierType == "equal_spacing")
{
qualifier.tesVertexSpacingType = EtetEqualSpacing;
}
else if (qualifierType == "fractional_even_spacing")
{
qualifier.tesVertexSpacingType = EtetFractionalEvenSpacing;
}
else if (qualifierType == "fractional_odd_spacing")
{
qualifier.tesVertexSpacingType = EtetFractionalOddSpacing;
}
else if (qualifierType == "cw")
{
qualifier.tesOrderingType = EtetCw;
}
else if (qualifierType == "ccw")
{
qualifier.tesOrderingType = EtetCcw;
}
else if (qualifierType == "point_mode")
{
qualifier.tesPointType = EtetPointMode;
}
else
{
error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
}
}
else else
{ {
error(qualifierTypeLine, "invalid layout qualifier", qualifierType); error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
...@@ -4853,6 +5143,23 @@ void TParseContext::parseMaxVertices(int intValue, ...@@ -4853,6 +5143,23 @@ void TParseContext::parseMaxVertices(int intValue,
} }
} }
void TParseContext::parseVertices(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *vertices)
{
if (intValue < 1 || intValue > mMaxPatchVertices)
{
error(intValueLine,
"out of range : vertices must be in the range of [1, gl_MaxPatchVertices]",
intValueString.c_str());
}
else
{
*vertices = intValue;
}
}
void TParseContext::parseIndexLayoutQualifier(int intValue, void TParseContext::parseIndexLayoutQualifier(int intValue,
const TSourceLoc &intValueLine, const TSourceLoc &intValueLine,
const std::string &intValueString, const std::string &intValueString,
...@@ -4961,6 +5268,11 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qual ...@@ -4961,6 +5268,11 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qual
{ {
parseIndexLayoutQualifier(intValue, intValueLine, intValueString, &qualifier.index); parseIndexLayoutQualifier(intValue, intValueLine, intValueString, &qualifier.index);
} }
else if (qualifierType == "vertices" && mShaderType == GL_TESS_CONTROL_SHADER_EXT &&
checkCanUseExtension(qualifierTypeLine, TExtension::EXT_tessellation_shader))
{
parseVertices(intValue, intValueLine, intValueString, &qualifier.vertices);
}
else else
{ {
error(qualifierTypeLine, "invalid layout qualifier", qualifierType); error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
...@@ -5022,10 +5334,18 @@ TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc) ...@@ -5022,10 +5334,18 @@ TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc)
{ {
return new TStorageQualifierWrapper(EvqComputeIn, loc); return new TStorageQualifierWrapper(EvqComputeIn, loc);
} }
case GL_GEOMETRY_SHADER_EXT: case GL_GEOMETRY_SHADER:
{ {
return new TStorageQualifierWrapper(EvqGeometryIn, loc); return new TStorageQualifierWrapper(EvqGeometryIn, loc);
} }
case GL_TESS_CONTROL_SHADER:
{
return new TStorageQualifierWrapper(EvqTessControlIn, loc);
}
case GL_TESS_EVALUATION_SHADER:
{
return new TStorageQualifierWrapper(EvqTessEvaluationIn, loc);
}
default: default:
{ {
UNREACHABLE(); UNREACHABLE();
...@@ -5067,6 +5387,14 @@ TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc ...@@ -5067,6 +5387,14 @@ TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc
{ {
return new TStorageQualifierWrapper(EvqGeometryOut, loc); return new TStorageQualifierWrapper(EvqGeometryOut, loc);
} }
case GL_TESS_CONTROL_SHADER_EXT:
{
return new TStorageQualifierWrapper(EvqTessControlOut, loc);
}
case GL_TESS_EVALUATION_SHADER_EXT:
{
return new TStorageQualifierWrapper(EvqTessEvaluationOut, loc);
}
default: default:
{ {
UNREACHABLE(); UNREACHABLE();
......
...@@ -177,7 +177,7 @@ class TParseContext : angle::NonCopyable ...@@ -177,7 +177,7 @@ class TParseContext : angle::NonCopyable
// Done only for empty declarations. // Done only for empty declarations.
void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location); void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location);
void checkLayoutQualifierSupported(const TSourceLoc &location, bool checkLayoutQualifierSupported(const TSourceLoc &location,
const ImmutableString &layoutQualifierName, const ImmutableString &layoutQualifierName,
int versionRequired); int versionRequired);
bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
...@@ -380,6 +380,10 @@ class TParseContext : angle::NonCopyable ...@@ -380,6 +380,10 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &intValueLine, const TSourceLoc &intValueLine,
const std::string &intValueString, const std::string &intValueString,
int *numMaxVertices); int *numMaxVertices);
void parseVertices(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numVertices);
void parseIndexLayoutQualifier(int intValue, void parseIndexLayoutQualifier(int intValue,
const TSourceLoc &intValueLine, const TSourceLoc &intValueLine,
const std::string &intValueString, const std::string &intValueString,
...@@ -465,6 +469,23 @@ class TParseContext : angle::NonCopyable ...@@ -465,6 +469,23 @@ class TParseContext : angle::NonCopyable
{ {
return mGeometryShaderOutputPrimitiveType; return mGeometryShaderOutputPrimitiveType;
} }
int getTessControlShaderOutputVertices() const { return mTessControlShaderOutputVertices; }
TLayoutTessEvaluationType getTessEvaluationShaderInputPrimitiveType() const
{
return mTessEvaluationShaderInputPrimitiveType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputVertexSpacingType() const
{
return mTessEvaluationShaderInputVertexSpacingType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputOrderingType() const
{
return mTessEvaluationShaderInputOrderingType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputPointType() const
{
return mTessEvaluationShaderInputPointType;
}
ShShaderOutput getOutputType() const { return mOutputType; } ShShaderOutput getOutputType() const { return mOutputType; }
...@@ -574,6 +595,11 @@ class TParseContext : angle::NonCopyable ...@@ -574,6 +595,11 @@ class TParseContext : angle::NonCopyable
const ImmutableString &token, const ImmutableString &token,
TType *type); TType *type);
// Similar, for tessellation shaders.
void checkTessellationShaderUnsizedArraysAndSetSize(const TSourceLoc &location,
const ImmutableString &token,
TType *type);
// Will size any unsized array type so unsized arrays won't need to be taken into account // Will size any unsized array type so unsized arrays won't need to be taken into account
// further along the line in parsing. // further along the line in parsing.
void checkIsNotUnsizedArray(const TSourceLoc &line, void checkIsNotUnsizedArray(const TSourceLoc &line,
...@@ -616,6 +642,9 @@ class TParseContext : angle::NonCopyable ...@@ -616,6 +642,9 @@ class TParseContext : angle::NonCopyable
bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier); bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
void setGeometryShaderInputArraySize(unsigned int inputArraySize, const TSourceLoc &line); void setGeometryShaderInputArraySize(unsigned int inputArraySize, const TSourceLoc &line);
bool parseTessControlShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
bool parseTessEvaluationShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier);
// Set to true when the last/current declarator list was started with an empty declaration. The // Set to true when the last/current declarator list was started with an empty declaration. The
// non-empty declaration error check will need to be performed if the empty declaration is // non-empty declaration error check will need to be performed if the empty declaration is
// followed by a declarator. // followed by a declarator.
...@@ -681,6 +710,13 @@ class TParseContext : angle::NonCopyable ...@@ -681,6 +710,13 @@ class TParseContext : angle::NonCopyable
int mMaxGeometryShaderMaxVertices; int mMaxGeometryShaderMaxVertices;
unsigned int mGeometryInputArraySize; unsigned int mGeometryInputArraySize;
int mMaxPatchVertices;
int mTessControlShaderOutputVertices;
TLayoutTessEvaluationType mTessEvaluationShaderInputPrimitiveType;
TLayoutTessEvaluationType mTessEvaluationShaderInputVertexSpacingType;
TLayoutTessEvaluationType mTessEvaluationShaderInputOrderingType;
TLayoutTessEvaluationType mTessEvaluationShaderInputPointType;
// Track when we add new scope for func body in ESSL 1.00 spec // Track when we add new scope for func body in ESSL 1.00 spec
bool mFunctionBodyNewScope; bool mFunctionBodyNewScope;
......
...@@ -372,10 +372,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag ...@@ -372,10 +372,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag
break; break;
case EvqVertexOut: case EvqVertexOut:
case EvqGeometryOut: case EvqGeometryOut:
case EvqTessControlOut:
case EvqTessEvaluationOut:
*joinedQualifier = EvqSmoothOut; *joinedQualifier = EvqSmoothOut;
break; break;
case EvqFragmentIn: case EvqFragmentIn:
case EvqGeometryIn: case EvqGeometryIn:
case EvqTessControlIn:
case EvqTessEvaluationIn:
*joinedQualifier = EvqSmoothIn; *joinedQualifier = EvqSmoothIn;
break; break;
default: default:
...@@ -392,10 +396,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag ...@@ -392,10 +396,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag
break; break;
case EvqVertexOut: case EvqVertexOut:
case EvqGeometryOut: case EvqGeometryOut:
case EvqTessControlOut:
case EvqTessEvaluationOut:
*joinedQualifier = EvqFlatOut; *joinedQualifier = EvqFlatOut;
break; break;
case EvqFragmentIn: case EvqFragmentIn:
case EvqGeometryIn: case EvqGeometryIn:
case EvqTessControlIn:
case EvqTessEvaluationIn:
*joinedQualifier = EvqFlatIn; *joinedQualifier = EvqFlatIn;
break; break;
default: default:
...@@ -412,10 +420,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag ...@@ -412,10 +420,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag
break; break;
case EvqVertexOut: case EvqVertexOut:
case EvqGeometryOut: case EvqGeometryOut:
case EvqTessControlOut:
case EvqTessEvaluationOut:
*joinedQualifier = EvqNoPerspectiveOut; *joinedQualifier = EvqNoPerspectiveOut;
break; break;
case EvqFragmentIn: case EvqFragmentIn:
case EvqGeometryIn: case EvqGeometryIn:
case EvqTessControlIn:
case EvqTessEvaluationIn:
*joinedQualifier = EvqNoPerspectiveIn; *joinedQualifier = EvqNoPerspectiveIn;
break; break;
default: default:
...@@ -429,10 +441,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag ...@@ -429,10 +441,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag
{ {
case EvqVertexOut: case EvqVertexOut:
case EvqGeometryOut: case EvqGeometryOut:
case EvqTessControlOut:
case EvqTessEvaluationOut:
*joinedQualifier = EvqCentroidOut; *joinedQualifier = EvqCentroidOut;
break; break;
case EvqFragmentIn: case EvqFragmentIn:
case EvqGeometryIn: case EvqGeometryIn:
case EvqTessControlIn:
case EvqTessEvaluationIn:
*joinedQualifier = EvqCentroidIn; *joinedQualifier = EvqCentroidIn;
break; break;
default: default:
...@@ -446,10 +462,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag ...@@ -446,10 +462,14 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag
{ {
case EvqVertexOut: case EvqVertexOut:
case EvqGeometryOut: case EvqGeometryOut:
case EvqTessControlOut:
case EvqTessEvaluationOut:
*joinedQualifier = EvqSampleOut; *joinedQualifier = EvqSampleOut;
break; break;
case EvqFragmentIn: case EvqFragmentIn:
case EvqGeometryIn: case EvqGeometryIn:
case EvqTessControlIn:
case EvqTessEvaluationIn:
*joinedQualifier = EvqSampleIn; *joinedQualifier = EvqSampleIn;
break; break;
default: default:
...@@ -457,6 +477,21 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag ...@@ -457,6 +477,21 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag
} }
break; break;
} }
case EvqPatch:
{
switch (storageQualifier)
{
case EvqTessControlOut:
*joinedQualifier = EvqPatchOut;
break;
case EvqTessEvaluationIn:
*joinedQualifier = EvqPatchIn;
break;
default:
return false;
}
break;
}
default: default:
return false; return false;
} }
...@@ -757,6 +792,48 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, ...@@ -757,6 +792,48 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
joinedQualifier.maxVertices = rightQualifier.maxVertices; joinedQualifier.maxVertices = rightQualifier.maxVertices;
} }
if (rightQualifier.tesPrimitiveType != EtetUndefined)
{
if (joinedQualifier.tesPrimitiveType == EtetUndefined)
{
joinedQualifier.tesPrimitiveType = rightQualifier.tesPrimitiveType;
}
}
if (rightQualifier.tesVertexSpacingType != EtetUndefined)
{
if (joinedQualifier.tesVertexSpacingType == EtetUndefined)
{
joinedQualifier.tesVertexSpacingType = rightQualifier.tesVertexSpacingType;
}
}
if (rightQualifier.tesOrderingType != EtetUndefined)
{
if (joinedQualifier.tesOrderingType == EtetUndefined)
{
joinedQualifier.tesOrderingType = rightQualifier.tesOrderingType;
}
}
if (rightQualifier.tesPointType != EtetUndefined)
{
if (joinedQualifier.tesPointType == EtetUndefined)
{
joinedQualifier.tesPointType = rightQualifier.tesPointType;
}
}
if (rightQualifier.vertices != 0)
{
if (joinedQualifier.vertices != 0 && joinedQualifier.vertices != rightQualifier.vertices)
{
diagnostics->error(rightQualifierLocation,
"Cannot have multiple different vertices specifiers", "vertices");
}
joinedQualifier.vertices = rightQualifier.vertices;
}
if (rightQualifier.index != -1) if (rightQualifier.index != -1)
{ {
if (joinedQualifier.index != -1) if (joinedQualifier.index != -1)
......
...@@ -102,6 +102,36 @@ GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType ...@@ -102,6 +102,36 @@ GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType
} }
} }
GLenum GetTessellationShaderTypeEnum(sh::TLayoutTessEvaluationType type)
{
switch (type)
{
case EtetTriangles:
return GL_TRIANGLES;
case EtetQuads:
return GL_QUADS;
case EtetIsolines:
return GL_ISOLINES;
case EtetEqualSpacing:
return GL_EQUAL;
case EtetFractionalEvenSpacing:
return GL_FRACTIONAL_EVEN;
case EtetFractionalOddSpacing:
return GL_FRACTIONAL_ODD;
case EtetCw:
return GL_CW;
case EtetCcw:
return GL_CCW;
case EtetPointMode:
return GL_TESS_GEN_POINT_MODE;
case EtetUndefined:
default:
UNREACHABLE();
return GL_INVALID_VALUE;
}
}
} // anonymous namespace } // anonymous namespace
// //
...@@ -713,6 +743,50 @@ bool HasValidGeometryShaderMaxVertices(const ShHandle handle) ...@@ -713,6 +743,50 @@ bool HasValidGeometryShaderMaxVertices(const ShHandle handle)
return compiler->getGeometryShaderMaxVertices() >= 0; return compiler->getGeometryShaderMaxVertices() >= 0;
} }
bool HasValidTessGenMode(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getTessEvaluationShaderInputPrimitiveType() != EtetUndefined;
}
bool HasValidTessGenSpacing(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getTessEvaluationShaderInputVertexSpacingType() != EtetUndefined;
}
bool HasValidTessGenVertexOrder(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getTessEvaluationShaderInputOrderingType() != EtetUndefined;
}
bool HasValidTessGenPointMode(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getTessEvaluationShaderInputPointType() != EtetUndefined;
}
GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle) GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle)
{ {
ASSERT(handle); ASSERT(handle);
...@@ -759,6 +833,62 @@ int GetGeometryShaderMaxVertices(const ShHandle handle) ...@@ -759,6 +833,62 @@ int GetGeometryShaderMaxVertices(const ShHandle handle)
return maxVertices; return maxVertices;
} }
int GetTessControlShaderVertices(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
int vertices = compiler->getTessControlShaderOutputVertices();
return vertices;
}
GLenum GetTessGenMode(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return GetTessellationShaderTypeEnum(compiler->getTessEvaluationShaderInputPrimitiveType());
}
GLenum GetTessGenSpacing(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return GetTessellationShaderTypeEnum(compiler->getTessEvaluationShaderInputVertexSpacingType());
}
GLenum GetTessGenVertexOrder(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return GetTessellationShaderTypeEnum(compiler->getTessEvaluationShaderInputOrderingType());
}
GLenum GetTessGenPointMode(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return GetTessellationShaderTypeEnum(compiler->getTessEvaluationShaderInputPointType());
}
unsigned int GetShaderSharedMemorySize(const ShHandle handle) unsigned int GetShaderSharedMemorySize(const ShHandle handle)
{ {
ASSERT(handle); ASSERT(handle);
......
...@@ -51,6 +51,7 @@ ShaderVariable::ShaderVariable(GLenum typeIn) ...@@ -51,6 +51,7 @@ ShaderVariable::ShaderVariable(GLenum typeIn)
interpolation(INTERPOLATION_SMOOTH), interpolation(INTERPOLATION_SMOOTH),
isInvariant(false), isInvariant(false),
isShaderIOBlock(false), isShaderIOBlock(false),
isPatch(false),
texelFetchStaticUse(false), texelFetchStaticUse(false),
flattenedOffsetInParentArrays(-1) flattenedOffsetInParentArrays(-1)
{} {}
...@@ -87,6 +88,7 @@ ShaderVariable::ShaderVariable(const ShaderVariable &other) ...@@ -87,6 +88,7 @@ ShaderVariable::ShaderVariable(const ShaderVariable &other)
interpolation(other.interpolation), interpolation(other.interpolation),
isInvariant(other.isInvariant), isInvariant(other.isInvariant),
isShaderIOBlock(other.isShaderIOBlock), isShaderIOBlock(other.isShaderIOBlock),
isPatch(other.isPatch),
texelFetchStaticUse(other.texelFetchStaticUse), texelFetchStaticUse(other.texelFetchStaticUse),
flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays) flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
{} {}
...@@ -117,6 +119,7 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other) ...@@ -117,6 +119,7 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
interpolation = other.interpolation; interpolation = other.interpolation;
isInvariant = other.isInvariant; isInvariant = other.isInvariant;
isShaderIOBlock = other.isShaderIOBlock; isShaderIOBlock = other.isShaderIOBlock;
isPatch = other.isPatch;
texelFetchStaticUse = other.texelFetchStaticUse; texelFetchStaticUse = other.texelFetchStaticUse;
return *this; return *this;
} }
...@@ -133,7 +136,7 @@ bool ShaderVariable::operator==(const ShaderVariable &other) const ...@@ -133,7 +136,7 @@ bool ShaderVariable::operator==(const ShaderVariable &other) const
offset != other.offset || readonly != other.readonly || writeonly != other.writeonly || offset != other.offset || readonly != other.readonly || writeonly != other.writeonly ||
index != other.index || yuv != other.yuv || interpolation != other.interpolation || index != other.index || yuv != other.yuv || interpolation != other.interpolation ||
isInvariant != other.isInvariant || isShaderIOBlock != other.isShaderIOBlock || isInvariant != other.isInvariant || isShaderIOBlock != other.isShaderIOBlock ||
texelFetchStaticUse != other.texelFetchStaticUse) isPatch != other.isPatch || texelFetchStaticUse != other.texelFetchStaticUse)
{ {
return false; return false;
} }
...@@ -444,7 +447,7 @@ bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other, int sh ...@@ -444,7 +447,7 @@ bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other, int sh
return ShaderVariable::isSameVariableAtLinkTime(other, false, false) && return ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
InterpolationTypesMatch(interpolation, other.interpolation) && InterpolationTypesMatch(interpolation, other.interpolation) &&
(shaderVersion >= 300 || isInvariant == other.isInvariant) && (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
location == other.location && (isPatch == other.isPatch) && location == other.location &&
(isSameNameAtLinkTime(other) || (shaderVersion >= 310 && location >= 0)); (isSameNameAtLinkTime(other) || (shaderVersion >= 310 && location >= 0));
} }
......
...@@ -39,6 +39,10 @@ bool CheckShaderType(Shader expected, GLenum actual) ...@@ -39,6 +39,10 @@ bool CheckShaderType(Shader expected, GLenum actual)
return actual == GL_GEOMETRY_SHADER; return actual == GL_GEOMETRY_SHADER;
case Shader::GEOMETRY_EXT: case Shader::GEOMETRY_EXT:
return actual == GL_GEOMETRY_SHADER_EXT; return actual == GL_GEOMETRY_SHADER_EXT;
case Shader::TESS_CONTROL_EXT:
return actual == GL_TESS_CONTROL_SHADER_EXT;
case Shader::TESS_EVALUATION_EXT:
return actual == GL_TESS_EVALUATION_SHADER_EXT;
case Shader::NOT_COMPUTE: case Shader::NOT_COMPUTE:
return actual != GL_COMPUTE_SHADER; return actual != GL_COMPUTE_SHADER;
default: default:
...@@ -411,6 +415,8 @@ void TSymbolTable::initializeBuiltIns(sh::GLenum type, ...@@ -411,6 +415,8 @@ void TSymbolTable::initializeBuiltIns(sh::GLenum type,
case GL_VERTEX_SHADER: case GL_VERTEX_SHADER:
case GL_COMPUTE_SHADER: case GL_COMPUTE_SHADER:
case GL_GEOMETRY_SHADER_EXT: case GL_GEOMETRY_SHADER_EXT:
case GL_TESS_CONTROL_SHADER_EXT:
case GL_TESS_EVALUATION_SHADER_EXT:
setDefaultPrecision(EbtInt, EbpHigh); setDefaultPrecision(EbtInt, EbpHigh);
setDefaultPrecision(EbtFloat, EbpHigh); setDefaultPrecision(EbtFloat, EbpHigh);
break; break;
......
...@@ -171,6 +171,8 @@ constexpr ImmutableString kFlippedFragCoordName = ImmutableString("flippedFragC ...@@ -171,6 +171,8 @@ constexpr ImmutableString kFlippedFragCoordName = ImmutableString("flippedFragC
constexpr gl::ShaderMap<const char *> kDefaultUniformNames = { constexpr gl::ShaderMap<const char *> kDefaultUniformNames = {
{gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS}, {gl::ShaderType::Vertex, vk::kDefaultUniformsNameVS},
{gl::ShaderType::TessControl, vk::kDefaultUniformsNameTCS},
{gl::ShaderType::TessEvaluation, vk::kDefaultUniformsNameTES},
{gl::ShaderType::Geometry, vk::kDefaultUniformsNameGS}, {gl::ShaderType::Geometry, vk::kDefaultUniformsNameGS},
{gl::ShaderType::Fragment, vk::kDefaultUniformsNameFS}, {gl::ShaderType::Fragment, vk::kDefaultUniformsNameFS},
{gl::ShaderType::Compute, vk::kDefaultUniformsNameCS}, {gl::ShaderType::Compute, vk::kDefaultUniformsNameCS},
...@@ -1156,6 +1158,22 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -1156,6 +1158,22 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
break; break;
} }
case gl::ShaderType::TessControl:
{
WriteTessControlShaderLayoutQualifiers(sink, getTessControlShaderOutputVertices());
break;
}
case gl::ShaderType::TessEvaluation:
{
WriteTessEvaluationShaderLayoutQualifiers(
sink, getTessEvaluationShaderInputPrimitiveType(),
getTessEvaluationShaderInputVertexSpacingType(),
getTessEvaluationShaderInputOrderingType(),
getTessEvaluationShaderInputPointType());
break;
}
case gl::ShaderType::Compute: case gl::ShaderType::Compute:
{ {
EmitWorkGroupSizeGLSL(*this, sink); EmitWorkGroupSizeGLSL(*this, sink);
......
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ValidateBarrierFunctionCalls:
// Runs compilation checks related to the "barrier built-in function.
#include "compiler/translator/ValidateBarrierFunctionCall.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
class Traverser : public TIntermTraverser
{
public:
Traverser(TDiagnostics *diagnostics)
: TIntermTraverser(true, false, true), mDiagnostics(diagnostics)
{}
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
{
if (!node->getFunction()->isMain())
{
return false;
}
mInMain = visit == PreVisit;
return true;
}
bool visitBranch(Visit visit, TIntermBranch *branch) override
{
if (branch->getFlowOp() == EOpReturn)
{
mSeenReturn = true;
}
return true;
}
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
if (node->getOp() != EOpBarrier)
{
return true;
}
if (mSeenReturn)
{
mDiagnostics->error(node->getLine(),
"barrier() may not be called at any point after a return statement "
"in the function main().",
"barrier");
mValid = false;
return false;
}
// TODO(anglebug.com/5557): Determine if we should check loops as well.
if (mBranchCount > 0)
{
mDiagnostics->error(
node->getLine(),
"barrier() may not be called in potentially divergent flow control.", "barrier");
mValid = false;
return false;
}
return true;
}
bool visitIfElse(Visit visit, TIntermIfElse *node) override
{
mBranchCount += ((visit == PreVisit) ? 1 : -1);
return true;
}
bool valid() const { return mValid; }
private:
TDiagnostics *mDiagnostics = nullptr;
bool mInMain = false;
bool mSeenReturn = false;
bool mValid = true;
uint32_t mBranchCount = 0;
};
} // anonymous namespace
bool ValidateBarrierFunctionCall(TIntermBlock *root, TDiagnostics *diagnostics)
{
Traverser traverser(diagnostics);
root->traverse(&traverser);
return traverser.valid();
}
} // namespace sh
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ValidateBarrierFunctionCalls:
// Runs compilation checks related to the "barrier built-in function.
#ifndef COMPILER_TRANSLATOR_VALIDATEBARRIERFUNCTIONCALL_H_
#define COMPILER_TRANSLATOR_VALIDATEBARRIERFUNCTIONCALL_H_
#include "common/angleutils.h"
namespace sh
{
class TDiagnostics;
class TIntermBlock;
ANGLE_NO_DISCARD bool ValidateBarrierFunctionCall(TIntermBlock *root, TDiagnostics *diagnostics);
} // namespace sh
#endif // COMPILER_TRANSLATOR_VALIDATEBARRIERFUNCTIONCALL_H_
...@@ -116,6 +116,22 @@ int GetLocationCount(const TIntermSymbol *varying, bool ignoreVaryingArraySize) ...@@ -116,6 +116,22 @@ int GetLocationCount(const TIntermSymbol *varying, bool ignoreVaryingArraySize)
return elementLocationCount * varyingType.getArraySizeProduct(); return elementLocationCount * varyingType.getArraySizeProduct();
} }
bool ShouldIgnoreVaryingArraySize(TQualifier qualifier, GLenum shaderType)
{
bool isVaryingIn = IsShaderIn(qualifier) && qualifier != EvqPatchIn;
switch (shaderType)
{
case GL_GEOMETRY_SHADER:
case GL_TESS_EVALUATION_SHADER:
return isVaryingIn;
case GL_TESS_CONTROL_SHADER:
return (IsShaderOut(qualifier) && qualifier != EvqPatchOut) || isVaryingIn;
default:
return false;
}
}
struct SymbolAndField struct SymbolAndField
{ {
const TIntermSymbol *symbol; const TIntermSymbol *symbol;
...@@ -159,9 +175,9 @@ void MarkVaryingLocations(TDiagnostics *diagnostics, ...@@ -159,9 +175,9 @@ void MarkVaryingLocations(TDiagnostics *diagnostics,
using VaryingVector = std::vector<const TIntermSymbol *>; using VaryingVector = std::vector<const TIntermSymbol *>;
void ValidateShaderInterface(TDiagnostics *diagnostics, void ValidateShaderInterfaceAndAssignLocations(TDiagnostics *diagnostics,
VaryingVector &varyingVector, const VaryingVector &varyingVector,
bool ignoreVaryingArraySize) GLenum shaderType)
{ {
// Location conflicts can only happen when there are two or more varyings in varyingVector. // Location conflicts can only happen when there are two or more varyings in varyingVector.
if (varyingVector.size() <= 1) if (varyingVector.size() <= 1)
...@@ -176,6 +192,9 @@ void ValidateShaderInterface(TDiagnostics *diagnostics, ...@@ -176,6 +192,9 @@ void ValidateShaderInterface(TDiagnostics *diagnostics,
const int location = varyingType.getLayoutQualifier().location; const int location = varyingType.getLayoutQualifier().location;
ASSERT(location >= 0); ASSERT(location >= 0);
bool ignoreVaryingArraySize =
ShouldIgnoreVaryingArraySize(varying->getQualifier(), shaderType);
// A varying is either: // A varying is either:
// //
// - A vector or matrix, which can take a number of contiguous locations // - A vector or matrix, which can take a number of contiguous locations
...@@ -318,9 +337,9 @@ void ValidateVaryingLocationsTraverser::validate(TDiagnostics *diagnostics) ...@@ -318,9 +337,9 @@ void ValidateVaryingLocationsTraverser::validate(TDiagnostics *diagnostics)
{ {
ASSERT(diagnostics); ASSERT(diagnostics);
ValidateShaderInterface(diagnostics, mInputVaryingsWithLocation, ValidateShaderInterfaceAndAssignLocations(diagnostics, mInputVaryingsWithLocation, mShaderType);
mShaderType == GL_GEOMETRY_SHADER_EXT); ValidateShaderInterfaceAndAssignLocations(diagnostics, mOutputVaryingsWithLocation,
ValidateShaderInterface(diagnostics, mOutputVaryingsWithLocation, false); mShaderType);
} }
} // anonymous namespace } // anonymous namespace
...@@ -329,8 +348,7 @@ unsigned int CalculateVaryingLocationCount(TIntermSymbol *varying, GLenum shader ...@@ -329,8 +348,7 @@ unsigned int CalculateVaryingLocationCount(TIntermSymbol *varying, GLenum shader
{ {
const TType &varyingType = varying->getType(); const TType &varyingType = varying->getType();
const TQualifier qualifier = varyingType.getQualifier(); const TQualifier qualifier = varyingType.getQualifier();
const bool isShaderIn = IsShaderIn(qualifier); const bool ignoreVaryingArraySize = ShouldIgnoreVaryingArraySize(qualifier, shaderType);
const bool ignoreVaryingArraySize = isShaderIn && shaderType == GL_GEOMETRY_SHADER_EXT;
if (varyingType.isInterfaceBlock()) if (varyingType.isInterfaceBlock())
{ {
......
...@@ -868,7 +868,11 @@ storage_qualifier ...@@ -868,7 +868,11 @@ storage_qualifier
$$ = new TStorageQualifierWrapper(EvqCentroid, @1); $$ = new TStorageQualifierWrapper(EvqCentroid, @1);
} }
| PATCH { | PATCH {
ES3_1_OR_NEWER("patch", @1, "storage qualifier"); if (context->getShaderVersion() < 320 &&
!context->checkCanUseExtension(@1, TExtension::EXT_tessellation_shader))
{
context->error(@1, "unsupported storage qualifier", "patch");
}
$$ = new TStorageQualifierWrapper(EvqPatch, @1); $$ = new TStorageQualifierWrapper(EvqPatch, @1);
} }
| UNIFORM { | UNIFORM {
......
...@@ -752,19 +752,19 @@ static const yytype_uint16 yyrline[] = { ...@@ -752,19 +752,19 @@ static const yytype_uint16 yyrline[] = {
557, 561, 565, 569, 573, 580, 583, 589, 596, 603, 606, 609, 613, 617, 621, 625, 557, 561, 565, 569, 573, 580, 583, 589, 596, 603, 606, 609, 613, 617, 621, 625,
629, 636, 643, 646, 653, 661, 678, 688, 691, 697, 701, 705, 709, 716, 723, 726, 629, 636, 643, 646, 653, 661, 678, 688, 691, 697, 701, 705, 709, 716, 723, 726,
730, 734, 739, 746, 750, 754, 758, 763, 770, 774, 780, 783, 786, 796, 800, 807, 730, 734, 739, 746, 750, 754, 758, 763, 770, 774, 780, 783, 786, 796, 800, 807,
813, 819, 823, 827, 830, 833, 837, 845, 850, 854, 857, 860, 863, 866, 870, 874, 813, 819, 823, 827, 830, 833, 837, 845, 850, 854, 857, 860, 863, 866, 870, 878,
877, 881, 884, 887, 890, 893, 896, 900, 907, 914, 917, 920, 926, 933, 936, 942, 881, 885, 888, 891, 894, 897, 900, 904, 911, 918, 921, 924, 930, 937, 940, 946,
945, 948, 951, 957, 960, 967, 972, 979, 984, 995, 998, 1001, 1004, 1007, 1010, 1014, 949, 952, 955, 961, 964, 971, 976, 983, 988, 999, 1002, 1005, 1008, 1011, 1014, 1018,
1018, 1022, 1026, 1030, 1034, 1038, 1042, 1046, 1050, 1054, 1058, 1062, 1066, 1070, 1074, 1078, 1022, 1026, 1030, 1034, 1038, 1042, 1046, 1050, 1054, 1058, 1062, 1066, 1070, 1074, 1078, 1082,
1082, 1086, 1090, 1094, 1101, 1104, 1107, 1110, 1113, 1116, 1119, 1127, 1135, 1145, 1148, 1151, 1086, 1090, 1094, 1098, 1105, 1108, 1111, 1114, 1117, 1120, 1123, 1131, 1139, 1149, 1152, 1155,
1154, 1157, 1160, 1163, 1171, 1179, 1189, 1192, 1195, 1198, 1201, 1204, 1207, 1215, 1223, 1233, 1158, 1161, 1164, 1167, 1175, 1183, 1193, 1196, 1199, 1202, 1205, 1208, 1211, 1219, 1227, 1237,
1236, 1239, 1242, 1250, 1258, 1265, 1275, 1282, 1289, 1292, 1295, 1298, 1301, 1304, 1307, 1310, 1240, 1243, 1246, 1254, 1262, 1269, 1279, 1286, 1293, 1296, 1299, 1302, 1305, 1308, 1311, 1314,
1313, 1316, 1319, 1322, 1325, 1333, 1341, 1349, 1357, 1365, 1373, 1383, 1393, 1403, 1406, 1409, 1317, 1320, 1323, 1326, 1329, 1337, 1345, 1353, 1361, 1369, 1377, 1387, 1397, 1407, 1410, 1413,
1417, 1417, 1420, 1420, 1426, 1429, 1435, 1438, 1445, 1449, 1455, 1458, 1464, 1468, 1472, 1473, 1421, 1421, 1424, 1424, 1430, 1433, 1439, 1442, 1449, 1453, 1459, 1462, 1468, 1472, 1476, 1477,
1479, 1480, 1481, 1482, 1483, 1484, 1485, 1489, 1493, 1493, 1493, 1500, 1501, 1505, 1505, 1506, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1493, 1497, 1497, 1497, 1504, 1505, 1509, 1509, 1510,
1506, 1511, 1515, 1522, 1526, 1533, 1534, 1538, 1544, 1548, 1557, 1557, 1564, 1567, 1573, 1577, 1510, 1515, 1519, 1526, 1530, 1537, 1538, 1542, 1548, 1552, 1561, 1561, 1568, 1571, 1577, 1581,
1583, 1583, 1588, 1588, 1592, 1592, 1600, 1603, 1609, 1612, 1618, 1622, 1629, 1632, 1635, 1638, 1587, 1587, 1592, 1592, 1596, 1596, 1604, 1607, 1613, 1616, 1622, 1626, 1633, 1636, 1639, 1642,
1641, 1649, 1655, 1661, 1664, 1670, 1670}; 1645, 1653, 1659, 1665, 1668, 1674, 1674};
#endif #endif
#if YYDEBUG || YYERROR_VERBOSE || 0 #if YYDEBUG || YYERROR_VERBOSE || 0
...@@ -3670,7 +3670,11 @@ yyreduce: ...@@ -3670,7 +3670,11 @@ yyreduce:
case 142: case 142:
{ {
ES3_1_OR_NEWER("patch", (yylsp[0]), "storage qualifier"); if (context->getShaderVersion() < 320 &&
!context->checkCanUseExtension((yylsp[0]), TExtension::EXT_tessellation_shader))
{
context->error((yylsp[0]), "unsupported storage qualifier", "patch");
}
(yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper(EvqPatch, (yylsp[0])); (yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper(EvqPatch, (yylsp[0]));
} }
......
...@@ -102,7 +102,8 @@ bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit, ...@@ -102,7 +102,8 @@ bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit,
// When a member has an explicit location, interface block should not be removed. // When a member has an explicit location, interface block should not be removed.
// If the member or interface would be removed, GetProgramResource could not return the // If the member or interface would be removed, GetProgramResource could not return the
// location. // location.
if (!IsShaderIoBlock(type.getQualifier())) if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn &&
type.getQualifier() != EvqPatchOut)
{ {
removeDeclaration = removeDeclaration =
!IsVariableActive(mInterfaceBlocks, type.getInterfaceBlock()->name()); !IsVariableActive(mInterfaceBlocks, type.getInterfaceBlock()->name());
......
...@@ -26,7 +26,6 @@ namespace sh ...@@ -26,7 +26,6 @@ namespace sh
namespace namespace
{ {
bool IsInterpolationIn(TQualifier qualifier) bool IsInterpolationIn(TQualifier qualifier)
{ {
switch (qualifier) switch (qualifier)
...@@ -42,6 +41,20 @@ bool IsInterpolationIn(TQualifier qualifier) ...@@ -42,6 +41,20 @@ bool IsInterpolationIn(TQualifier qualifier)
} }
} }
bool IsInterpolationOut(TQualifier qualifier)
{
switch (qualifier)
{
case EvqSmoothOut:
case EvqFlatOut:
case EvqNoPerspectiveOut:
case EvqCentroidOut:
case EvqSampleOut:
return true;
default:
return false;
}
}
} // anonymous namespace } // anonymous namespace
float NumericLexFloat32OutOfRangeToInfinity(const std::string &str) float NumericLexFloat32OutOfRangeToInfinity(const std::string &str)
...@@ -554,6 +567,7 @@ bool IsVaryingOut(TQualifier qualifier) ...@@ -554,6 +567,7 @@ bool IsVaryingOut(TQualifier qualifier)
case EvqTessControlOut: case EvqTessControlOut:
case EvqTessEvaluationOut: case EvqTessEvaluationOut:
case EvqSampleOut: case EvqSampleOut:
case EvqPatchOut:
return true; return true;
default: default:
...@@ -577,6 +591,7 @@ bool IsVaryingIn(TQualifier qualifier) ...@@ -577,6 +591,7 @@ bool IsVaryingIn(TQualifier qualifier)
case EvqTessControlIn: case EvqTessControlIn:
case EvqTessEvaluationIn: case EvqTessEvaluationIn:
case EvqSampleIn: case EvqSampleIn:
case EvqPatchIn:
return true; return true;
default: default:
...@@ -597,12 +612,34 @@ bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier) ...@@ -597,12 +612,34 @@ bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier)
((shaderType == GL_GEOMETRY_SHADER_EXT) && IsInterpolationIn(qualifier)); ((shaderType == GL_GEOMETRY_SHADER_EXT) && IsInterpolationIn(qualifier));
} }
bool IsTessellationControlShaderInput(GLenum shaderType, TQualifier qualifier)
{
return qualifier == EvqTessControlIn ||
((shaderType == GL_TESS_CONTROL_SHADER) && IsInterpolationIn(qualifier));
}
bool IsTessellationControlShaderOutput(GLenum shaderType, TQualifier qualifier)
{
return qualifier == EvqTessControlOut ||
((shaderType == GL_TESS_CONTROL_SHADER) && IsInterpolationOut(qualifier));
}
bool IsTessellationEvaluationShaderInput(GLenum shaderType, TQualifier qualifier)
{
return qualifier == EvqTessEvaluationIn ||
((shaderType == GL_TESS_EVALUATION_SHADER) && IsInterpolationIn(qualifier));
}
InterpolationType GetInterpolationType(TQualifier qualifier) InterpolationType GetInterpolationType(TQualifier qualifier)
{ {
switch (qualifier) switch (qualifier)
{ {
case EvqFlatIn: case EvqFlatIn:
case EvqFlatOut: case EvqFlatOut:
// The auxiliary storage qualifier patch is not used for interpolation
// it is a compile-time error to use interpolation qualifiers with patch
case EvqPatchIn:
case EvqPatchOut:
return INTERPOLATION_FLAT; return INTERPOLATION_FLAT;
case EvqNoPerspectiveIn: case EvqNoPerspectiveIn:
...@@ -617,6 +654,10 @@ InterpolationType GetInterpolationType(TQualifier qualifier) ...@@ -617,6 +654,10 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
case EvqVaryingOut: case EvqVaryingOut:
case EvqGeometryIn: case EvqGeometryIn:
case EvqGeometryOut: case EvqGeometryOut:
case EvqTessControlIn:
case EvqTessControlOut:
case EvqTessEvaluationIn:
case EvqTessEvaluationOut:
return INTERPOLATION_SMOOTH; return INTERPOLATION_SMOOTH;
case EvqCentroidIn: case EvqCentroidIn:
......
...@@ -55,6 +55,9 @@ bool IsVaryingIn(TQualifier qualifier); ...@@ -55,6 +55,9 @@ bool IsVaryingIn(TQualifier qualifier);
bool IsVaryingOut(TQualifier qualifier); bool IsVaryingOut(TQualifier qualifier);
bool IsVarying(TQualifier qualifier); bool IsVarying(TQualifier qualifier);
bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier); bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier);
bool IsTessellationControlShaderInput(GLenum shaderType, TQualifier qualifier);
bool IsTessellationControlShaderOutput(GLenum shaderType, TQualifier qualifier);
bool IsTessellationEvaluationShaderInput(GLenum shaderType, TQualifier qualifier);
InterpolationType GetInterpolationType(TQualifier qualifier); InterpolationType GetInterpolationType(TQualifier qualifier);
InterpolationType GetFieldInterpolationType(TQualifier qualifier); InterpolationType GetFieldInterpolationType(TQualifier qualifier);
......
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