Commit b8b0122f by Martin Radev Committed by Commit Bot

Add compiler support for shared memory

The patch adds handling of the 'shared' qualifier in the shader compiler. BUG=angleproject:1442 TEST=angle_unittests Change-Id: Iaa288026af0faf2a30e40495faa6ea1f5ff02323 Reviewed-on: https://chromium-review.googlesource.com/413200 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent c31b7411
...@@ -504,6 +504,7 @@ enum TQualifier ...@@ -504,6 +504,7 @@ enum TQualifier
EvqCentroidIn, // Implies smooth EvqCentroidIn, // Implies smooth
// GLSL ES 3.1 compute shader special variables // GLSL ES 3.1 compute shader special variables
EvqShared,
EvqComputeIn, EvqComputeIn,
EvqNumWorkGroups, EvqNumWorkGroups,
EvqWorkGroupSize, EvqWorkGroupSize,
...@@ -707,6 +708,7 @@ inline const char *getQualifierString(TQualifier q) ...@@ -707,6 +708,7 @@ inline const char *getQualifierString(TQualifier q)
case EvqCentroid: return "centroid"; case EvqCentroid: return "centroid";
case EvqFlat: return "flat"; case EvqFlat: return "flat";
case EvqSmooth: return "smooth"; case EvqSmooth: return "smooth";
case EvqShared: return "shared";
case EvqComputeIn: return "in"; case EvqComputeIn: return "in";
case EvqNumWorkGroups: return "NumWorkGroups"; case EvqNumWorkGroups: return "NumWorkGroups";
case EvqWorkGroupSize: return "WorkGroupSize"; case EvqWorkGroupSize: return "WorkGroupSize";
......
...@@ -1099,6 +1099,21 @@ bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString & ...@@ -1099,6 +1099,21 @@ bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &
return true; return true;
} }
void TParseContext::emptyDeclarationErrorCheck(const TPublicType &publicType,
const TSourceLoc &location)
{
if (publicType.isUnsizedArray())
{
// ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
// error. It is assumed that this applies to empty declarations as well.
error(location, "empty array declaration needs to specify a size", "");
}
if (publicType.qualifier == EvqShared && !publicType.layoutQualifier.isEmpty())
{
error(location, "Shared memory declarations cannot have layout specified", "layout");
}
}
// These checks are common for all declarations starting a declarator list, and declarators that // These checks are common for all declarations starting a declarator list, and declarators that
// follow an empty declaration. // follow an empty declaration.
void TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, void TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
...@@ -1900,13 +1915,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration( ...@@ -1900,13 +1915,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
if (emptyDeclaration) if (emptyDeclaration)
{ {
if (publicType.isUnsizedArray()) emptyDeclarationErrorCheck(publicType, identifierOrTypeLocation);
{
// ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
// error. It is assumed that this applies to empty declarations as well.
error(identifierOrTypeLocation, "empty array declaration needs to specify a size",
identifier.c_str());
}
} }
else else
{ {
......
...@@ -145,6 +145,7 @@ class TParseContext : angle::NonCopyable ...@@ -145,6 +145,7 @@ class TParseContext : angle::NonCopyable
bool checkCanUseExtension(const TSourceLoc &line, const TString &extension); bool checkCanUseExtension(const TSourceLoc &line, const TString &extension);
void singleDeclarationErrorCheck(const TPublicType &publicType, void singleDeclarationErrorCheck(const TPublicType &publicType,
const TSourceLoc &identifierLocation); const TSourceLoc &identifierLocation);
void emptyDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &location);
void checkLayoutQualifierSupported(const TSourceLoc &location, void checkLayoutQualifierSupported(const TSourceLoc &location,
const TString &layoutQualifierName, const TString &layoutQualifierName,
int versionRequired); int versionRequired);
......
...@@ -78,6 +78,7 @@ static int ES2_keyword_ES3_reserved(TParseContext *context, int token); ...@@ -78,6 +78,7 @@ static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
static int ES2_ident_ES3_keyword(TParseContext *context, int token); static int ES2_ident_ES3_keyword(TParseContext *context, int token);
static int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token); static int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token);
static int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token); static int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token);
static int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token);
static int uint_constant(TParseContext *context); static int uint_constant(TParseContext *context);
static int int_constant(TParseContext *context); static int int_constant(TParseContext *context);
static int float_constant(yyscan_t yyscanner); static int float_constant(yyscan_t yyscanner);
...@@ -131,6 +132,7 @@ O [0-7] ...@@ -131,6 +132,7 @@ O [0-7]
"in" { return IN_QUAL; } "in" { return IN_QUAL; }
"out" { return OUT_QUAL; } "out" { return OUT_QUAL; }
"inout" { return INOUT_QUAL; } "inout" { return INOUT_QUAL; }
"shared" { return ES2_and_ES3_ident_ES3_1_keyword(context, SHARED); }
"float" { return FLOAT_TYPE; } "float" { return FLOAT_TYPE; }
"int" { return INT_TYPE; } "int" { return INT_TYPE; }
...@@ -516,6 +518,21 @@ int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token) ...@@ -516,6 +518,21 @@ int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token)
return token; return token;
} }
int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token)
{
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
yyscan_t yyscanner = (yyscan_t) context->getScanner();
// not a reserved word in GLSL ES 1.00 and GLSL ES 3.00, so could be used as an identifier/type name
if (context->getShaderVersion() < 310)
{
yylval->lex.string = NewPoolTString(yytext);
return check_type(yyscanner);
}
return token;
}
int uint_constant(TParseContext *context) int uint_constant(TParseContext *context)
{ {
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
......
...@@ -169,7 +169,7 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons ...@@ -169,7 +169,7 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING %token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
%token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3 %token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3
%token <lex> CENTROID FLAT SMOOTH %token <lex> CENTROID FLAT SMOOTH
%token <lex> READONLY WRITEONLY COHERENT RESTRICT VOLATILE %token <lex> READONLY WRITEONLY COHERENT RESTRICT VOLATILE SHARED
%token <lex> STRUCT VOID_TYPE WHILE %token <lex> STRUCT VOID_TYPE WHILE
%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY %token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY
%token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY %token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY
...@@ -959,6 +959,11 @@ storage_qualifier ...@@ -959,6 +959,11 @@ storage_qualifier
| VOLATILE { | VOLATILE {
$$ = new TMemoryQualifierWrapper(EvqVolatile, @1); $$ = new TMemoryQualifierWrapper(EvqVolatile, @1);
} }
| SHARED {
context->checkIsAtGlobalLevel(@1, "shared");
COMPUTE_ONLY("shared", @1);
$$ = new TStorageQualifierWrapper(EvqShared, @1);
}
; ;
type_specifier type_specifier
...@@ -1006,6 +1011,9 @@ layout_qualifier_id ...@@ -1006,6 +1011,9 @@ layout_qualifier_id
| IDENTIFIER EQUAL UINTCONSTANT { | IDENTIFIER EQUAL UINTCONSTANT {
$$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3); $$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3);
} }
| SHARED {
$$ = context->parseLayoutQualifier("shared", @1);
}
; ;
type_specifier_no_prec type_specifier_no_prec
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -105,92 +105,93 @@ enum yytokentype ...@@ -105,92 +105,93 @@ enum yytokentype
COHERENT = 311, COHERENT = 311,
RESTRICT = 312, RESTRICT = 312,
VOLATILE = 313, VOLATILE = 313,
STRUCT = 314, SHARED = 314,
VOID_TYPE = 315, STRUCT = 315,
WHILE = 316, VOID_TYPE = 316,
SAMPLER2D = 317, WHILE = 317,
SAMPLERCUBE = 318, SAMPLER2D = 318,
SAMPLER_EXTERNAL_OES = 319, SAMPLERCUBE = 319,
SAMPLER2DRECT = 320, SAMPLER_EXTERNAL_OES = 320,
SAMPLER2DARRAY = 321, SAMPLER2DRECT = 321,
ISAMPLER2D = 322, SAMPLER2DARRAY = 322,
ISAMPLER3D = 323, ISAMPLER2D = 323,
ISAMPLERCUBE = 324, ISAMPLER3D = 324,
ISAMPLER2DARRAY = 325, ISAMPLERCUBE = 325,
USAMPLER2D = 326, ISAMPLER2DARRAY = 326,
USAMPLER3D = 327, USAMPLER2D = 327,
USAMPLERCUBE = 328, USAMPLER3D = 328,
USAMPLER2DARRAY = 329, USAMPLERCUBE = 329,
SAMPLER3D = 330, USAMPLER2DARRAY = 330,
SAMPLER3DRECT = 331, SAMPLER3D = 331,
SAMPLER2DSHADOW = 332, SAMPLER3DRECT = 332,
SAMPLERCUBESHADOW = 333, SAMPLER2DSHADOW = 333,
SAMPLER2DARRAYSHADOW = 334, SAMPLERCUBESHADOW = 334,
IMAGE2D = 335, SAMPLER2DARRAYSHADOW = 335,
IIMAGE2D = 336, IMAGE2D = 336,
UIMAGE2D = 337, IIMAGE2D = 337,
IMAGE3D = 338, UIMAGE2D = 338,
IIMAGE3D = 339, IMAGE3D = 339,
UIMAGE3D = 340, IIMAGE3D = 340,
IMAGE2DARRAY = 341, UIMAGE3D = 341,
IIMAGE2DARRAY = 342, IMAGE2DARRAY = 342,
UIMAGE2DARRAY = 343, IIMAGE2DARRAY = 343,
IMAGECUBE = 344, UIMAGE2DARRAY = 344,
IIMAGECUBE = 345, IMAGECUBE = 345,
UIMAGECUBE = 346, IIMAGECUBE = 346,
LAYOUT = 347, UIMAGECUBE = 347,
IDENTIFIER = 348, LAYOUT = 348,
TYPE_NAME = 349, IDENTIFIER = 349,
FLOATCONSTANT = 350, TYPE_NAME = 350,
INTCONSTANT = 351, FLOATCONSTANT = 351,
UINTCONSTANT = 352, INTCONSTANT = 352,
BOOLCONSTANT = 353, UINTCONSTANT = 353,
FIELD_SELECTION = 354, BOOLCONSTANT = 354,
LEFT_OP = 355, FIELD_SELECTION = 355,
RIGHT_OP = 356, LEFT_OP = 356,
INC_OP = 357, RIGHT_OP = 357,
DEC_OP = 358, INC_OP = 358,
LE_OP = 359, DEC_OP = 359,
GE_OP = 360, LE_OP = 360,
EQ_OP = 361, GE_OP = 361,
NE_OP = 362, EQ_OP = 362,
AND_OP = 363, NE_OP = 363,
OR_OP = 364, AND_OP = 364,
XOR_OP = 365, OR_OP = 365,
MUL_ASSIGN = 366, XOR_OP = 366,
DIV_ASSIGN = 367, MUL_ASSIGN = 367,
ADD_ASSIGN = 368, DIV_ASSIGN = 368,
MOD_ASSIGN = 369, ADD_ASSIGN = 369,
LEFT_ASSIGN = 370, MOD_ASSIGN = 370,
RIGHT_ASSIGN = 371, LEFT_ASSIGN = 371,
AND_ASSIGN = 372, RIGHT_ASSIGN = 372,
XOR_ASSIGN = 373, AND_ASSIGN = 373,
OR_ASSIGN = 374, XOR_ASSIGN = 374,
SUB_ASSIGN = 375, OR_ASSIGN = 375,
LEFT_PAREN = 376, SUB_ASSIGN = 376,
RIGHT_PAREN = 377, LEFT_PAREN = 377,
LEFT_BRACKET = 378, RIGHT_PAREN = 378,
RIGHT_BRACKET = 379, LEFT_BRACKET = 379,
LEFT_BRACE = 380, RIGHT_BRACKET = 380,
RIGHT_BRACE = 381, LEFT_BRACE = 381,
DOT = 382, RIGHT_BRACE = 382,
COMMA = 383, DOT = 383,
COLON = 384, COMMA = 384,
EQUAL = 385, COLON = 385,
SEMICOLON = 386, EQUAL = 386,
BANG = 387, SEMICOLON = 387,
DASH = 388, BANG = 388,
TILDE = 389, DASH = 389,
PLUS = 390, TILDE = 390,
STAR = 391, PLUS = 391,
SLASH = 392, STAR = 392,
PERCENT = 393, SLASH = 393,
LEFT_ANGLE = 394, PERCENT = 394,
RIGHT_ANGLE = 395, LEFT_ANGLE = 395,
VERTICAL_BAR = 396, RIGHT_ANGLE = 396,
CARET = 397, VERTICAL_BAR = 397,
AMPERSAND = 398, CARET = 398,
QUESTION = 399 AMPERSAND = 399,
QUESTION = 400
}; };
#endif #endif
......
...@@ -3130,3 +3130,202 @@ TEST_F(MalformedComputeShaderTest, WorkGroupSizeAsArraySize) ...@@ -3130,3 +3130,202 @@ TEST_F(MalformedComputeShaderTest, WorkGroupSizeAsArraySize)
FAIL() << "Shader compilation failed, expecting success " << mInfoLog; FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
} }
} }
// Shared memory variables cannot be used inside a vertex shader.
// GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
TEST_F(MalformedVertexShaderGLES31Test, VertexShaderSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 i;\n"
"shared float myShared[10];\n"
"void main() {\n"
" gl_Position = i;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Shared memory variables cannot be used inside a fragment shader.
// GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
TEST_F(MalformedFragmentShaderGLES31Test, FragmentShaderSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"shared float myShared[10];\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Shared memory cannot be combined with any other storage qualifier.
TEST_F(MalformedComputeShaderTest, UniformSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"uniform shared float myShared[100];\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Correct usage of shared memory variables.
TEST_F(MalformedComputeShaderTest, CorrectUsageOfSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"shared float myShared[100];\n"
"void main() {\n"
" myShared[gl_LocalInvocationID.x] = 1.0;\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
// Shared memory variables cannot be initialized.
// GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
TEST_F(MalformedComputeShaderTest, SharedVariableInitialization)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"shared int myShared = 0;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Local variables cannot be qualified as shared.
// GLSL ES 3.10 Revision 4, 4.3 Storage Qualifiers
TEST_F(MalformedComputeShaderTest, SharedMemoryInFunctionBody)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"void func() {\n"
" shared int myShared;\n"
"}\n"
"void main() {\n"
" func();\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Struct members cannot be qualified as shared.
TEST_F(MalformedComputeShaderTest, SharedMemoryInStruct)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"struct MyStruct {\n"
" shared int myShared;\n"
"};\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Interface block members cannot be qualified as shared.
TEST_F(MalformedComputeShaderTest, SharedMemoryInInterfaceBlock)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"uniform Myblock {\n"
" shared int myShared;\n"
"};\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// The shared qualifier cannot be used with any other qualifier.
TEST_F(MalformedComputeShaderTest, SharedWithInvariant)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"invariant shared int myShared;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// The shared qualifier cannot be used with any other qualifier.
TEST_F(MalformedComputeShaderTest, SharedWithMemoryQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"readonly shared int myShared;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// The shared qualifier cannot be used with any other qualifier.
TEST_F(MalformedComputeShaderTest, SharedGlobalLayoutDeclaration)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"layout(row_major) shared mat4;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
\ No newline at end of file
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