Commit 802abe01 by Martin Radev Committed by Commit Bot

Add compute shader compilation support in the glsl compiler

Support is added for compute shader compilation. There is a small extension to the parser so that 'local_size_x = ', 'local_size_y = ' and 'local_size_z = ' are supported as layout qualifiers. A few shader compilation tests are added and one which checks the AST whether the layout qualifiers are properly parsed. BUG=angleproject:1442 TEST=angle_unittests TEST=angle_end2end_tests Change-Id: I67283797d1cf13fa4ac47faa2a6e66d93a2db867 Reviewed-on: https://chromium-review.googlesource.com/362300Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 17b10a9a
......@@ -49,7 +49,7 @@ typedef unsigned int GLenum;
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 152
#define ANGLE_SH_VERSION 153
typedef enum {
SH_GLES2_SPEC,
......@@ -496,6 +496,7 @@ COMPILER_EXPORT const std::vector<sh::Varying> *ShGetVaryings(const ShHandle han
COMPILER_EXPORT const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle);
COMPILER_EXPORT const std::vector<sh::OutputVariable> *ShGetOutputVariables(const ShHandle handle);
COMPILER_EXPORT const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle);
COMPILER_EXPORT std::array<int, 3> ShGetComputeShaderLocalGroupSize(const ShHandle handle);
typedef struct
{
......
......@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
int numCompiles = 0;
ShHandle vertexCompiler = 0;
ShHandle fragmentCompiler = 0;
ShHandle computeCompiler = 0;
ShShaderSpec spec = SH_GLES2_SPEC;
ShShaderOutput output = SH_ESSL_OUTPUT;
......@@ -244,6 +245,15 @@ int main(int argc, char *argv[])
}
compiler = fragmentCompiler;
break;
case GL_COMPUTE_SHADER:
if (computeCompiler == 0)
{
computeCompiler =
ShConstructCompiler(GL_COMPUTE_SHADER, spec, output, &resources);
}
compiler = computeCompiler;
break;
default: break;
}
if (compiler)
......@@ -282,7 +292,7 @@ int main(int argc, char *argv[])
}
}
if ((vertexCompiler == 0) && (fragmentCompiler == 0))
if ((vertexCompiler == 0) && (fragmentCompiler == 0) && (computeCompiler == 0))
failCode = EFailUsage;
if (failCode == EFailUsage)
usage();
......@@ -291,6 +301,9 @@ int main(int argc, char *argv[])
ShDestruct(vertexCompiler);
if (fragmentCompiler)
ShDestruct(fragmentCompiler);
if (computeCompiler)
ShDestruct(computeCompiler);
ShFinalize();
return failCode;
......@@ -315,6 +328,7 @@ void usage()
" -p : use precision emulation\n"
" -s=e2 : use GLES2 spec (this is by default)\n"
" -s=e3 : use GLES3 spec (in development)\n"
" -s=e31 : use GLES31 spec (in development)\n"
" -s=w : use WebGL spec\n"
" -s=w2 : use WebGL 2 spec (in development)\n"
" -s=c : use CSS Shaders spec\n"
......@@ -356,8 +370,12 @@ sh::GLenum FindShaderType(const char *fileName)
ext = strrchr(fileName, '.');
if (ext)
{
if (strncmp(ext, ".frag", 4) == 0) return GL_FRAGMENT_SHADER;
if (strncmp(ext, ".vert", 4) == 0) return GL_VERTEX_SHADER;
if (strncmp(ext, ".frag", 5) == 0)
return GL_FRAGMENT_SHADER;
if (strncmp(ext, ".vert", 5) == 0)
return GL_VERTEX_SHADER;
if (strncmp(ext, ".comp", 5) == 0)
return GL_COMPUTE_SHADER;
}
return GL_FRAGMENT_SHADER;
......
......@@ -7,6 +7,9 @@
#ifndef COMPILER_TRANSLATOR_BASETYPES_H_
#define COMPILER_TRANSLATOR_BASETYPES_H_
#include <algorithm>
#include <array>
#include "common/debug.h"
//
......@@ -346,6 +349,9 @@ enum TQualifier
EvqFlatIn,
EvqCentroidIn, // Implies smooth
// GLSL ES 3.1 compute shader special variables
EvqComputeIn,
// end of list
EvqLast
};
......@@ -365,12 +371,18 @@ enum TLayoutBlockStorage
EbsStd140
};
using TLocalSize = std::array<int, 3>;
struct TLayoutQualifier
{
int location;
TLayoutMatrixPacking matrixPacking;
TLayoutBlockStorage blockStorage;
// Compute shader layout qualifiers.
// -1 means unspecified.
TLocalSize localSize;
static TLayoutQualifier create()
{
TLayoutQualifier layoutQualifier;
......@@ -379,15 +391,66 @@ struct TLayoutQualifier
layoutQualifier.matrixPacking = EmpUnspecified;
layoutQualifier.blockStorage = EbsUnspecified;
layoutQualifier.localSize.fill(-1);
return layoutQualifier;
}
bool isEmpty() const
{
return location == -1 && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified;
return location == -1 && matrixPacking == EmpUnspecified &&
blockStorage == EbsUnspecified && localSize[0] == -1 && localSize[1] == -1 &&
localSize[2] == -1;
}
bool isGroupSizeSpecified() const
{
return std::any_of(localSize.begin(), localSize.end(),
[](int value) { return value != -1; });
}
bool isCombinationValid() const
{
bool workSizeSpecified = isGroupSizeSpecified();
bool otherLayoutQualifiersSpecified =
(location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified);
// we can have either the work group size specified, or the other layout qualifiers
return !(workSizeSpecified && otherLayoutQualifiersSpecified);
}
bool isLocalSizeEqual(const TLocalSize &localSizeIn) const
{
for (size_t i = 0u; i < localSize.size(); ++i)
{
bool result =
(localSize[i] == localSizeIn[i] || (localSize[i] == 1 && localSizeIn[i] == -1) ||
(localSize[i] == -1 && localSizeIn[i] == 1));
if (!result)
{
return false;
}
}
return true;
}
};
inline const char *getLocalSizeString(size_t dimension)
{
switch (dimension)
{
case 0u:
return "local_size_x";
case 1u:
return "local_size_y";
case 2u:
return "local_size_z";
default:
UNREACHABLE();
return "dimension out of bounds";
}
}
//
// This is just for debug print out, carried along with the definitions above.
//
......@@ -432,6 +495,7 @@ inline const char* getQualifierString(TQualifier q)
case EvqSmoothIn: return "smooth in";
case EvqFlatIn: return "flat in";
case EvqCentroidIn: return "smooth centroid in";
case EvqComputeIn: return "in";
default: UNREACHABLE(); return "unknown qualifier";
}
// clang-format on
......
......@@ -150,8 +150,10 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
builtInFunctionEmulator(),
mSourcePath(NULL),
mComputeShaderLocalSizeDeclared(false),
mTemporaryIndex(0)
{
mComputeShaderLocalSize.fill(1);
}
TCompiler::~TCompiler()
......@@ -250,6 +252,9 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mPragma = parseContext.pragma();
symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
root = parseContext.getTreeRoot();
root = intermediate.postProcess(root);
......@@ -450,6 +455,10 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
symbolTable.setDefaultPrecision(integer, EbpHigh);
symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
break;
case GL_COMPUTE_SHADER:
symbolTable.setDefaultPrecision(integer, EbpHigh);
symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
break;
default:
assert(false && "Language not supported");
}
......
......@@ -85,6 +85,9 @@ class TCompiler : public TShHandleBase
int getShaderVersion() const { return shaderVersion; }
TInfoSink& getInfoSink() { return infoSink; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
const TLocalSize &getComputeShaderLocalSize() { return mComputeShaderLocalSize; }
// Clears the results from the previous compilation.
void clearResults();
......@@ -227,6 +230,10 @@ class TCompiler : public TShHandleBase
TInfoSink infoSink; // Output sink.
const char *mSourcePath; // Path of source file or NULL
// compute shader local group size
bool mComputeShaderLocalSizeDeclared;
TLocalSize mComputeShaderLocalSize;
// name hashing.
ShHashFunction64 hashFunction;
NameMap nameMap;
......
......@@ -682,7 +682,9 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_VertexID"),
TType(EbtInt, EbpHigh, EvqVertexID, 1)));
break;
case GL_COMPUTE_SHADER:
// TODO (mradev): add compute shader built-ins
break;
default:
assert(false && "Language not supported");
}
......
......@@ -65,8 +65,10 @@ class TParseContext : angle::NonCopyable
mUsesFragColor(false),
mUsesSecondaryOutputs(false),
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset)
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
mComputeShaderLocalSizeDeclared(false)
{
mComputeShaderLocalSize.fill(-1);
}
const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
......@@ -114,6 +116,9 @@ class TParseContext : angle::NonCopyable
void incrSwitchNestingLevel() { ++mSwitchNestingLevel; }
void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
TLocalSize getComputeShaderLocalSize() const;
// This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
......@@ -149,6 +154,11 @@ class TParseContext : angle::NonCopyable
bool extensionErrorCheck(const TSourceLoc &line, const TString&);
bool singleDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &identifierLocation);
bool layoutLocationErrorCheck(const TSourceLoc &location, const TLayoutQualifier &layoutQualifier);
void layoutSupportedErrorCheck(const TSourceLoc &location,
const TString &layoutQualifierName,
int versionRequired);
bool layoutWorkGroupSizeErrorCheck(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier);
bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *);
void es3InvariantErrorCheck(const TQualifier qualifier, const TSourceLoc &invariantLocation);
void es3InputOutputTypeCheck(const TQualifier qualifier,
......@@ -279,14 +289,22 @@ class TParseContext : angle::NonCopyable
TIntermTyped *arrayIndex,
const TSourceLoc& arrayIndexLine);
void parseLocalSize(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine,
int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
size_t index,
TLocalSize *localSize);
TLayoutQualifier parseLayoutQualifier(
const TString &qualifierType, const TSourceLoc &qualifierTypeLine);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine,
const TString &intValueString,
int intValue,
const TSourceLoc &intValueLine);
TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier);
TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation);
TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
const TSourceLoc &storageLoc, TQualifier storageQualifier);
......@@ -396,6 +414,10 @@ class TParseContext : angle::NonCopyable
// gl_Secondary FragColor or both.
int mMinProgramTexelOffset;
int mMaxProgramTexelOffset;
// keep track of local group size declared in layout. It should be declared only once.
bool mComputeShaderLocalSizeDeclared;
TLocalSize mComputeShaderLocalSize;
};
int PaParseStrings(
......
......@@ -358,6 +358,17 @@ const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handl
return GetShaderVariables<sh::InterfaceBlock>(handle);
}
std::array<int, 3> ShGetComputeShaderLocalGroupSize(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getComputeShaderLocalSize();
}
bool ShCheckVariablesWithinPackingLimits(int maxVectors,
const std::vector<sh::ShaderVariable> &variables)
{
......
......@@ -77,6 +77,13 @@ void TranslatorESSL::translate(TIntermNode *root, int) {
// Write array bounds clamping emulation if needed.
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
{
const TLocalSize &localSize = getComputeShaderLocalSize();
sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
<< ", local_size_z=" << localSize[2] << ") in;\n";
}
// Write translated shader.
TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
getSymbolTable(), shaderVer, precisionEmulation);
......
......@@ -134,6 +134,13 @@ void TranslatorGLSL::translate(TIntermNode *root, int compileOptions)
}
}
if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
{
const TLocalSize &localSize = getComputeShaderLocalSize();
sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
<< ", local_size_z=" << localSize[2] << ") in;\n";
}
// Write translated shader.
TOutputGLSL outputGLSL(sink,
getArrayIndexClampingStrategy(),
......
......@@ -126,6 +126,20 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
} \
}
#define COMPUTE_ONLY(S, L) { \
if (context->getShaderType() != GL_COMPUTE_SHADER) { \
context->error(L, " supported in compute shaders only ", S); \
context->recover(); \
} \
}
#define NON_COMPUTE_ONLY(S, L) { \
if (context->getShaderType() != GL_VERTEX_SHADER && context->getShaderType() != GL_FRAGMENT_SHADER) { \
context->error(L, " supported in vertex and fragment shaders only ", S); \
context->recover(); \
} \
}
#define ES2_ONLY(S, L) { \
if (context->getShaderVersion() != 100) { \
context->error(L, " supported in GLSL ES 1.00 only ", S); \
......@@ -933,37 +947,35 @@ storage_qualifier
$$.qualifier = EvqConst;
}
| IN_QUAL {
ES3_OR_NEWER("in", @1, "storage qualifier");
if (context->getShaderType() == GL_FRAGMENT_SHADER)
{
ES3_OR_NEWER("in", @1, "storage qualifier");
$$.qualifier = EvqFragmentIn;
}
else
else if (context->getShaderType() == GL_VERTEX_SHADER)
{
ES3_OR_NEWER("in", @1, "storage qualifier");
$$.qualifier = EvqVertexIn;
}
else
{
$$.qualifier = EvqComputeIn;
}
}
| OUT_QUAL {
ES3_OR_NEWER("out", @1, "storage qualifier");
NON_COMPUTE_ONLY("out", @1);
$$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
}
| CENTROID IN_QUAL {
ES3_OR_NEWER("centroid in", @1, "storage qualifier");
if (context->getShaderType() == GL_VERTEX_SHADER)
{
context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader");
context->recover();
}
$$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
FRAG_ONLY("centroid in", @1);
$$.qualifier = EvqCentroidIn;
}
| CENTROID OUT_QUAL {
ES3_OR_NEWER("centroid out", @1, "storage qualifier");
if (context->getShaderType() == GL_FRAGMENT_SHADER)
{
context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader");
context->recover();
}
$$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
VERTEX_ONLY("centroid out", @1);
$$.qualifier = EvqCentroidOut;
}
| UNIFORM {
if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform"))
......@@ -1018,7 +1030,7 @@ layout_qualifier_id_list
$$ = $1;
}
| layout_qualifier_id_list COMMA layout_qualifier_id {
$$ = context->joinLayoutQualifiers($1, $3);
$$ = context->joinLayoutQualifiers($1, $3, @3);
}
;
......@@ -1027,10 +1039,10 @@ layout_qualifier_id
$$ = context->parseLayoutQualifier(*$1.string, @1);
}
| IDENTIFIER EQUAL INTCONSTANT {
$$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3);
$$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3);
}
| IDENTIFIER EQUAL UINTCONSTANT {
$$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3);
$$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3);
}
;
......
......@@ -370,6 +370,20 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
} \
}
#define COMPUTE_ONLY(S, L) { \
if (context->getShaderType() != GL_COMPUTE_SHADER) { \
context->error(L, " supported in compute shaders only ", S); \
context->recover(); \
} \
}
#define DRAW_ONLY(S, L) { \
if (context->getShaderType() != GL_VERTEX_SHADER && context->getShaderType() != GL_FRAGMENT_SHADER) { \
context->error(L, " supported in vertex and fragment shaders only ", S); \
context->recover(); \
} \
}
#define ES2_ONLY(S, L) { \
if (context->getShaderVersion() != 100) { \
context->error(L, " supported in GLSL ES 1.00 only ", S); \
......@@ -703,34 +717,34 @@ static const yytype_uint8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
0, 221, 221, 222, 225, 235, 238, 243, 248, 253,
258, 264, 267, 270, 273, 276, 279, 285, 293, 304,
308, 316, 319, 325, 329, 336, 342, 351, 359, 365,
372, 382, 385, 388, 391, 401, 402, 403, 404, 412,
413, 416, 419, 426, 427, 430, 436, 437, 441, 448,
449, 452, 455, 458, 464, 465, 468, 474, 475, 482,
483, 490, 491, 498, 499, 505, 506, 512, 513, 519,
520, 526, 527, 535, 536, 537, 538, 542, 543, 544,
548, 552, 556, 560, 567, 570, 576, 584, 592, 595,
601, 612, 616, 620, 624, 631, 637, 640, 647, 655,
676, 685, 695, 723, 728, 738, 743, 753, 756, 759,
762, 768, 775, 778, 782, 786, 791, 796, 803, 807,
811, 815, 820, 825, 829, 836, 846, 852, 855, 861,
867, 874, 883, 893, 901, 904, 911, 915, 919, 924,
932, 935, 946, 950, 959, 968, 976, 986, 998, 1001,
1004, 1010, 1017, 1020, 1026, 1029, 1032, 1038, 1041, 1046,
1061, 1065, 1069, 1073, 1077, 1081, 1086, 1091, 1096, 1101,
1106, 1111, 1116, 1121, 1126, 1131, 1136, 1141, 1146, 1151,
1156, 1161, 1166, 1171, 1176, 1181, 1186, 1190, 1194, 1198,
1202, 1206, 1210, 1214, 1218, 1222, 1226, 1230, 1234, 1238,
1242, 1246, 1255, 1263, 1267, 1280, 1280, 1283, 1283, 1289,
1292, 1308, 1311, 1320, 1324, 1330, 1337, 1352, 1356, 1360,
1361, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1377, 1378,
1378, 1378, 1388, 1389, 1393, 1393, 1394, 1394, 1399, 1402,
1412, 1415, 1421, 1422, 1426, 1434, 1438, 1445, 1445, 1452,
1455, 1462, 1467, 1482, 1482, 1487, 1487, 1494, 1494, 1502,
1505, 1511, 1514, 1520, 1524, 1531, 1534, 1537, 1540, 1543,
1552, 1556, 1563, 1566, 1572, 1572
0, 235, 235, 236, 239, 249, 252, 257, 262, 267,
272, 278, 281, 284, 287, 290, 293, 299, 307, 318,
322, 330, 333, 339, 343, 350, 356, 365, 373, 379,
386, 396, 399, 402, 405, 415, 416, 417, 418, 426,
427, 430, 433, 440, 441, 444, 450, 451, 455, 462,
463, 466, 469, 472, 478, 479, 482, 488, 489, 496,
497, 504, 505, 512, 513, 519, 520, 526, 527, 533,
534, 540, 541, 549, 550, 551, 552, 556, 557, 558,
562, 566, 570, 574, 581, 584, 590, 598, 606, 609,
615, 626, 630, 634, 638, 645, 651, 654, 661, 669,
690, 699, 709, 737, 742, 752, 757, 767, 770, 773,
776, 782, 789, 792, 796, 800, 805, 810, 817, 821,
825, 829, 834, 839, 843, 850, 860, 866, 869, 875,
881, 888, 897, 907, 915, 918, 925, 929, 933, 938,
946, 949, 965, 970, 975, 980, 988, 998, 1010, 1013,
1016, 1022, 1029, 1032, 1038, 1041, 1044, 1050, 1053, 1058,
1073, 1077, 1081, 1085, 1089, 1093, 1098, 1103, 1108, 1113,
1118, 1123, 1128, 1133, 1138, 1143, 1148, 1153, 1158, 1163,
1168, 1173, 1178, 1183, 1188, 1193, 1198, 1202, 1206, 1210,
1214, 1218, 1222, 1226, 1230, 1234, 1238, 1242, 1246, 1250,
1254, 1258, 1267, 1275, 1279, 1292, 1292, 1295, 1295, 1301,
1304, 1320, 1323, 1332, 1336, 1342, 1349, 1364, 1368, 1372,
1373, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1389, 1390,
1390, 1390, 1400, 1401, 1405, 1405, 1406, 1406, 1411, 1414,
1424, 1427, 1433, 1434, 1438, 1446, 1450, 1457, 1457, 1464,
1467, 1474, 1479, 1494, 1494, 1499, 1499, 1506, 1506, 1514,
1517, 1523, 1526, 1532, 1536, 1543, 1546, 1549, 1552, 1555,
1564, 1568, 1575, 1578, 1584, 1584
};
#endif
......@@ -3607,15 +3621,20 @@ yyreduce:
case 141:
{
ES3_OR_NEWER("in", (yylsp[0]), "storage qualifier");
if (context->getShaderType() == GL_FRAGMENT_SHADER)
{
ES3_OR_NEWER("in", (yylsp[0]), "storage qualifier");
(yyval.interm.type).qualifier = EvqFragmentIn;
}
else
else if (context->getShaderType() == GL_VERTEX_SHADER)
{
ES3_OR_NEWER("in", (yylsp[0]), "storage qualifier");
(yyval.interm.type).qualifier = EvqVertexIn;
}
else
{
(yyval.interm.type).qualifier = EvqComputeIn;
}
}
break;
......@@ -3624,6 +3643,7 @@ yyreduce:
{
ES3_OR_NEWER("out", (yylsp[0]), "storage qualifier");
DRAW_ONLY("out", (yylsp[0]));
(yyval.interm.type).qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
}
......@@ -3633,12 +3653,8 @@ yyreduce:
{
ES3_OR_NEWER("centroid in", (yylsp[-1]), "storage qualifier");
if (context->getShaderType() == GL_VERTEX_SHADER)
{
context->error((yylsp[-1]), "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader");
context->recover();
}
(yyval.interm.type).qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
FRAG_ONLY("centroid in", (yylsp[-1]));
(yyval.interm.type).qualifier = EvqCentroidIn;
}
break;
......@@ -3647,12 +3663,8 @@ yyreduce:
{
ES3_OR_NEWER("centroid out", (yylsp[-1]), "storage qualifier");
if (context->getShaderType() == GL_FRAGMENT_SHADER)
{
context->error((yylsp[-1]), "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader");
context->recover();
}
(yyval.interm.type).qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
VERTEX_ONLY("centroid out", (yylsp[-1]));
(yyval.interm.type).qualifier = EvqCentroidOut;
}
break;
......@@ -3740,7 +3752,7 @@ yyreduce:
case 153:
{
(yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[-2].interm.layoutQualifier), (yyvsp[0].interm.layoutQualifier));
(yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[-2].interm.layoutQualifier), (yyvsp[0].interm.layoutQualifier), (yylsp[0]));
}
break;
......@@ -3756,7 +3768,7 @@ yyreduce:
case 155:
{
(yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), *(yyvsp[0].lex).string, (yyvsp[0].lex).i, (yylsp[0]));
(yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0]));
}
break;
......@@ -3764,7 +3776,7 @@ yyreduce:
case 156:
{
(yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), *(yyvsp[0].lex).string, (yyvsp[0].lex).i, (yylsp[0]));
(yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0]));
}
break;
......
......@@ -63,6 +63,7 @@
'<(angle_path)/src/tests/compiler_tests/ShCompile_test.cpp',
'<(angle_path)/src/tests/compiler_tests/TypeTracking_test.cpp',
'<(angle_path)/src/tests/compiler_tests/VariablePacker_test.cpp',
'<(angle_path)/src/tests/compiler_tests/WorkGroupSize_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/char_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/comment_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/define_test.cpp',
......
//
// Copyright (c) 2015 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.
//
// WorkGroupSize_test.cpp:
// tests for local group size in a compute shader
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/TranslatorESSL.h"
#include "tests/test_utils/compiler_test.h"
class WorkGroupSizeTest : public testing::Test
{
public:
WorkGroupSizeTest() {}
protected:
void SetUp() override
{
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
mTranslator = new TranslatorESSL(GL_COMPUTE_SHADER, SH_GLES3_1_SPEC);
ASSERT_TRUE(mTranslator->Init(resources));
}
void TearDown() override { SafeDelete(mTranslator); }
// Return true when compilation succeeds
bool compile(const std::string &shaderString)
{
const char *shaderStrings[] = {shaderString.c_str()};
bool status = mTranslator->compile(shaderStrings, 1, SH_INTERMEDIATE_TREE | SH_VARIABLES);
TInfoSink &infoSink = mTranslator->getInfoSink();
mInfoLog = infoSink.info.c_str();
return status;
}
protected:
std::string mInfoLog;
TranslatorESSL *mTranslator = nullptr;
};
// checks whether compiler has parsed the local size layout qualifiers qcorrectly
TEST_F(WorkGroupSizeTest, OnlyLocalSizeXSpecified)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x=5) in;\n"
"void main() {\n"
"}\n";
compile(shaderString);
const TLocalSize &localSize = mTranslator->getComputeShaderLocalSize();
ASSERT_EQ(5, localSize[0]);
ASSERT_EQ(1, localSize[1]);
ASSERT_EQ(1, localSize[2]);
}
// checks whether compiler has parsed the local size layout qualifiers qcorrectly
TEST_F(WorkGroupSizeTest, LocalSizeXandZ)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x=5, local_size_z=10) in;\n"
"void main() {\n"
"}\n";
compile(shaderString);
const TLocalSize &localSize = mTranslator->getComputeShaderLocalSize();
ASSERT_EQ(5, localSize[0]);
ASSERT_EQ(1, localSize[1]);
ASSERT_EQ(10, localSize[2]);
}
// checks whether compiler has parsed the local size layout qualifiers qcorrectly
TEST_F(WorkGroupSizeTest, LocalSizeAll)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x=5, local_size_z=10, local_size_y=15) in;\n"
"void main() {\n"
"}\n";
compile(shaderString);
const TLocalSize &localSize = mTranslator->getComputeShaderLocalSize();
ASSERT_EQ(5, localSize[0]);
ASSERT_EQ(15, localSize[1]);
ASSERT_EQ(10, localSize[2]);
}
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