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