Commit 049edfa2 by Martin Radev Committed by Commit Bot

Add volatile, coherent and restrict memory qualifiers

The patch adds support for the three remaining memory qualifiers: volatile, coherent and restrict. BUG=angleproject:1442 TEST=angle_unittests TEST=angle_end2end_tests Change-Id: Ie662d304af2399468df1d976e04c38dada1e2cec Reviewed-on: https://chromium-review.googlesource.com/385876 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 7b8f3c9b
......@@ -511,6 +511,9 @@ enum TQualifier
// GLSL ES 3.1 memory qualifiers
EvqReadOnly,
EvqWriteOnly,
EvqCoherent,
EvqRestrict,
EvqVolatile,
// end of list
EvqLast
......@@ -613,17 +616,28 @@ struct TMemoryQualifier
// imageSize().
bool readonly;
bool writeonly;
bool coherent;
// restrict and volatile are reserved keywords in C/C++
bool restrictQualifier;
bool volatileQualifier;
static TMemoryQualifier create()
{
TMemoryQualifier memoryQualifier;
memoryQualifier.readonly = false;
memoryQualifier.writeonly = false;
memoryQualifier.readonly = false;
memoryQualifier.writeonly = false;
memoryQualifier.coherent = false;
memoryQualifier.restrictQualifier = false;
memoryQualifier.volatileQualifier = false;
return memoryQualifier;
}
bool isEmpty() { return !readonly && !writeonly; }
bool isEmpty()
{
return !readonly && !writeonly && !coherent && !restrictQualifier && !volatileQualifier;
}
};
inline const char *getWorkGroupSizeString(size_t dimension)
......
......@@ -231,6 +231,24 @@ void TOutputGLSLBase::writeVariableType(const TType &type)
out << "writeonly ";
}
if (memoryQualifier.coherent)
{
ASSERT(IsImage(type.getBasicType()));
out << "coherent ";
}
if (memoryQualifier.restrictQualifier)
{
ASSERT(IsImage(type.getBasicType()));
out << "restrict ";
}
if (memoryQualifier.volatileQualifier)
{
ASSERT(IsImage(type.getBasicType()));
out << "volatile ";
}
// Declare the struct if we have not done so already.
if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
{
......
......@@ -1820,6 +1820,21 @@ bool TParseContext::checkIsMemoryQualifierNotSpecified(const TMemoryQualifier &m
error(location, "Only allowed with images.", "writeonly");
return false;
}
if (memoryQualifier.coherent)
{
error(location, "Only allowed with images.", "coherent");
return false;
}
if (memoryQualifier.restrictQualifier)
{
error(location, "Only allowed with images.", "restrict");
return false;
}
if (memoryQualifier.volatileQualifier)
{
error(location, "Only allowed with images.", "volatile");
return false;
}
return true;
}
......@@ -4211,6 +4226,22 @@ void TParseContext::checkImageMemoryAccessForUserDefinedFunctions(
"Function call discards the 'writeonly' qualifier from image",
arguments[i]->getAsSymbolNode()->getSymbol().c_str());
}
if (functionArgumentMemoryQualifier.coherent &&
!functionParameterMemoryQualifier.coherent)
{
error(functionCall->getLine(),
"Function call discards the 'coherent' qualifier from image",
arguments[i]->getAsSymbolNode()->getSymbol().c_str());
}
if (functionArgumentMemoryQualifier.volatileQualifier &&
!functionParameterMemoryQualifier.volatileQualifier)
{
error(functionCall->getLine(),
"Function call discards the 'volatile' qualifier from image",
arguments[i]->getAsSymbolNode()->getSymbol().c_str());
}
}
}
}
......
......@@ -393,6 +393,18 @@ bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier mem
case EvqWriteOnly:
joinedMemoryQualifier->writeonly = true;
break;
case EvqCoherent:
joinedMemoryQualifier->coherent = true;
break;
case EvqRestrict:
joinedMemoryQualifier->restrictQualifier = true;
break;
case EvqVolatile:
// Variables having the volatile qualifier are automatcally treated as coherent as well.
// GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
joinedMemoryQualifier->volatileQualifier = true;
joinedMemoryQualifier->coherent = true;
break;
default:
UNREACHABLE();
}
......
......@@ -77,6 +77,7 @@ static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
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_reserved_ES3_1_keyword(TParseContext *context, int token);
static int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token);
static int uint_constant(TParseContext *context);
static int int_constant(TParseContext *context);
static int float_constant(yyscan_t yyscanner);
......@@ -207,10 +208,11 @@ O [0-7]
"imageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGECUBE); }
"readonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, READONLY); }
"writeonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, WRITEONLY); }
"coherent" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, COHERENT); }
"restrict" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, RESTRICT); }
"volatile" { return ES2_and_ES3_reserved_ES3_1_keyword(context, VOLATILE); }
/* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
"coherent" |
"restrict" |
"resource" |
"atomic_uint" |
"noperspective" |
......@@ -285,7 +287,6 @@ O [0-7]
"inline" |
"noinline" |
"volatile" |
"public" |
"static" |
"extern" |
......@@ -503,6 +504,18 @@ int ES2_ident_ES3_keyword(TParseContext *context, int token)
return token;
}
int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token)
{
yyscan_t yyscanner = (yyscan_t) context->getScanner();
if (context->getShaderVersion() < 310)
{
return reserved_word(yyscanner);
}
return token;
}
int uint_constant(TParseContext *context)
{
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
......@@ -608,4 +621,3 @@ int glslang_scan(size_t count, const char* const string[], const int length[],
return 0;
}
......@@ -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> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3
%token <lex> CENTROID FLAT SMOOTH
%token <lex> READONLY WRITEONLY
%token <lex> READONLY WRITEONLY COHERENT RESTRICT VOLATILE
%token <lex> STRUCT VOID_TYPE WHILE
%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY
%token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY
......@@ -950,6 +950,15 @@ storage_qualifier
| WRITEONLY {
$$ = new TMemoryQualifierWrapper(EvqWriteOnly, @1);
}
| COHERENT {
$$ = new TMemoryQualifierWrapper(EvqCoherent, @1);
}
| RESTRICT {
$$ = new TMemoryQualifierWrapper(EvqRestrict, @1);
}
| VOLATILE {
$$ = new TMemoryQualifierWrapper(EvqVolatile, @1);
}
;
type_specifier
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -105,92 +105,95 @@ enum yytokentype
SMOOTH = 308,
READONLY = 309,
WRITEONLY = 310,
STRUCT = 311,
VOID_TYPE = 312,
WHILE = 313,
SAMPLER2D = 314,
SAMPLERCUBE = 315,
SAMPLER_EXTERNAL_OES = 316,
SAMPLER2DRECT = 317,
SAMPLER2DARRAY = 318,
ISAMPLER2D = 319,
ISAMPLER3D = 320,
ISAMPLERCUBE = 321,
ISAMPLER2DARRAY = 322,
USAMPLER2D = 323,
USAMPLER3D = 324,
USAMPLERCUBE = 325,
USAMPLER2DARRAY = 326,
SAMPLER3D = 327,
SAMPLER3DRECT = 328,
SAMPLER2DSHADOW = 329,
SAMPLERCUBESHADOW = 330,
SAMPLER2DARRAYSHADOW = 331,
IMAGE2D = 332,
IIMAGE2D = 333,
UIMAGE2D = 334,
IMAGE3D = 335,
IIMAGE3D = 336,
UIMAGE3D = 337,
IMAGE2DARRAY = 338,
IIMAGE2DARRAY = 339,
UIMAGE2DARRAY = 340,
IMAGECUBE = 341,
IIMAGECUBE = 342,
UIMAGECUBE = 343,
LAYOUT = 344,
IDENTIFIER = 345,
TYPE_NAME = 346,
FLOATCONSTANT = 347,
INTCONSTANT = 348,
UINTCONSTANT = 349,
BOOLCONSTANT = 350,
FIELD_SELECTION = 351,
LEFT_OP = 352,
RIGHT_OP = 353,
INC_OP = 354,
DEC_OP = 355,
LE_OP = 356,
GE_OP = 357,
EQ_OP = 358,
NE_OP = 359,
AND_OP = 360,
OR_OP = 361,
XOR_OP = 362,
MUL_ASSIGN = 363,
DIV_ASSIGN = 364,
ADD_ASSIGN = 365,
MOD_ASSIGN = 366,
LEFT_ASSIGN = 367,
RIGHT_ASSIGN = 368,
AND_ASSIGN = 369,
XOR_ASSIGN = 370,
OR_ASSIGN = 371,
SUB_ASSIGN = 372,
LEFT_PAREN = 373,
RIGHT_PAREN = 374,
LEFT_BRACKET = 375,
RIGHT_BRACKET = 376,
LEFT_BRACE = 377,
RIGHT_BRACE = 378,
DOT = 379,
COMMA = 380,
COLON = 381,
EQUAL = 382,
SEMICOLON = 383,
BANG = 384,
DASH = 385,
TILDE = 386,
PLUS = 387,
STAR = 388,
SLASH = 389,
PERCENT = 390,
LEFT_ANGLE = 391,
RIGHT_ANGLE = 392,
VERTICAL_BAR = 393,
CARET = 394,
AMPERSAND = 395,
QUESTION = 396
COHERENT = 311,
RESTRICT = 312,
VOLATILE = 313,
STRUCT = 314,
VOID_TYPE = 315,
WHILE = 316,
SAMPLER2D = 317,
SAMPLERCUBE = 318,
SAMPLER_EXTERNAL_OES = 319,
SAMPLER2DRECT = 320,
SAMPLER2DARRAY = 321,
ISAMPLER2D = 322,
ISAMPLER3D = 323,
ISAMPLERCUBE = 324,
ISAMPLER2DARRAY = 325,
USAMPLER2D = 326,
USAMPLER3D = 327,
USAMPLERCUBE = 328,
USAMPLER2DARRAY = 329,
SAMPLER3D = 330,
SAMPLER3DRECT = 331,
SAMPLER2DSHADOW = 332,
SAMPLERCUBESHADOW = 333,
SAMPLER2DARRAYSHADOW = 334,
IMAGE2D = 335,
IIMAGE2D = 336,
UIMAGE2D = 337,
IMAGE3D = 338,
IIMAGE3D = 339,
UIMAGE3D = 340,
IMAGE2DARRAY = 341,
IIMAGE2DARRAY = 342,
UIMAGE2DARRAY = 343,
IMAGECUBE = 344,
IIMAGECUBE = 345,
UIMAGECUBE = 346,
LAYOUT = 347,
IDENTIFIER = 348,
TYPE_NAME = 349,
FLOATCONSTANT = 350,
INTCONSTANT = 351,
UINTCONSTANT = 352,
BOOLCONSTANT = 353,
FIELD_SELECTION = 354,
LEFT_OP = 355,
RIGHT_OP = 356,
INC_OP = 357,
DEC_OP = 358,
LE_OP = 359,
GE_OP = 360,
EQ_OP = 361,
NE_OP = 362,
AND_OP = 363,
OR_OP = 364,
XOR_OP = 365,
MUL_ASSIGN = 366,
DIV_ASSIGN = 367,
ADD_ASSIGN = 368,
MOD_ASSIGN = 369,
LEFT_ASSIGN = 370,
RIGHT_ASSIGN = 371,
AND_ASSIGN = 372,
XOR_ASSIGN = 373,
OR_ASSIGN = 374,
SUB_ASSIGN = 375,
LEFT_PAREN = 376,
RIGHT_PAREN = 377,
LEFT_BRACKET = 378,
RIGHT_BRACKET = 379,
LEFT_BRACE = 380,
RIGHT_BRACE = 381,
DOT = 382,
COMMA = 383,
COLON = 384,
EQUAL = 385,
SEMICOLON = 386,
BANG = 387,
DASH = 388,
TILDE = 389,
PLUS = 390,
STAR = 391,
SLASH = 392,
PERCENT = 393,
LEFT_ANGLE = 394,
RIGHT_ANGLE = 395,
VERTICAL_BAR = 396,
CARET = 397,
AMPERSAND = 398,
QUESTION = 399
};
#endif
......
......@@ -3076,3 +3076,83 @@ TEST_F(MalformedShaderTest, UnsizedArrayConstructorNoParameters)
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Passing an image parameter as an argument to another function should not be able to discard the
// coherent qualifier.
TEST_F(MalformedFragmentShaderGLES31Test, CoherentQualifierMissingInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform coherent image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Passing an image parameter as an argument to another function should not be able to discard the
// volatile qualifier.
TEST_F(MalformedFragmentShaderGLES31Test, VolatileQualifierMissingInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform volatile image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// The restrict qualifier can be discarded from a function argument.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(MalformedFragmentShaderGLES31Test, RestrictQualifierDiscardedInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform restrict image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
// Function image arguments can be overqualified.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(MalformedFragmentShaderGLES31Test, OverqualifyingImageParameter)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform image2D myImage;\n"
"void myFunc(in coherent volatile image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
\ No newline at end of file
......@@ -90,7 +90,10 @@ void CheckImageDeclaration(TIntermNode *astRoot,
TBasicType imageType,
TLayoutImageInternalFormat internalFormat,
bool readonly,
bool writeonly)
bool writeonly,
bool coherent,
bool restrictQualifier,
bool volatileQualifier)
{
const TIntermSymbol *myImageNode = FindSymbolNode(astRoot, imageName, imageType);
ASSERT_NE(nullptr, myImageNode);
......@@ -101,6 +104,9 @@ void CheckImageDeclaration(TIntermNode *astRoot,
TMemoryQualifier myImageMemoryQualifier = myImageType.getMemoryQualifier();
ASSERT_EQ(readonly, myImageMemoryQualifier.readonly);
ASSERT_EQ(writeonly, myImageMemoryQualifier.writeonly);
ASSERT_EQ(coherent, myImageMemoryQualifier.coherent);
ASSERT_EQ(restrictQualifier, myImageMemoryQualifier.restrictQualifier);
ASSERT_EQ(volatileQualifier, myImageMemoryQualifier.volatileQualifier);
}
} // namespace
......@@ -156,7 +162,8 @@ TEST_F(ShaderImageTest, Image2DDeclaration)
}
CheckExportedImageUniform(mTranslator->getUniforms(), 0, GL_IMAGE_2D, "myImage");
CheckImageDeclaration(mASTRoot, "myImage", EbtImage2D, EiifRGBA32F, true, false);
CheckImageDeclaration(mASTRoot, "myImage", EbtImage2D, EiifRGBA32F, true, false, false, false,
false);
}
// Test that an image3D is properly parsed and exported as a uniform.
......@@ -175,7 +182,8 @@ TEST_F(ShaderImageTest, Image3DDeclaration)
}
CheckExportedImageUniform(mTranslator->getUniforms(), 0, GL_UNSIGNED_INT_IMAGE_3D, "myImage");
CheckImageDeclaration(mASTRoot, "myImage", EbtUImage3D, EiifRGBA32UI, true, true);
CheckImageDeclaration(mASTRoot, "myImage", EbtUImage3D, EiifRGBA32UI, true, true, false, false,
false);
}
// Check that imageLoad calls get correctly parsed.
......@@ -225,3 +233,27 @@ TEST_F(ShaderImageTest, ImageStore)
// imageStore call with image2DArray
CheckImageStoreCall(mASTRoot, "imageStore(uim2a1;vi3;vu4;", EbtUImage2DArray, 3, EbtUInt, 4);
}
// Check that memory qualifiers are correctly parsed.
TEST_F(ShaderImageTest, ImageMemoryQualifiers)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 4) in;"
"layout(rgba32f) uniform highp coherent readonly image2D image1;\n"
"layout(rgba32f) uniform highp volatile writeonly image2D image2;\n"
"layout(rgba32f) uniform highp volatile restrict readonly writeonly image2D image3;\n"
"void main() {\n"
"}";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed" << mInfoLog;
}
CheckImageDeclaration(mASTRoot, "image1", EbtImage2D, EiifRGBA32F, true, false, true, false,
false);
CheckImageDeclaration(mASTRoot, "image2", EbtImage2D, EiifRGBA32F, false, true, true, false,
true);
CheckImageDeclaration(mASTRoot, "image3", EbtImage2D, EiifRGBA32F, true, true, true, true,
true);
}
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