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 ...@@ -511,6 +511,9 @@ enum TQualifier
// GLSL ES 3.1 memory qualifiers // GLSL ES 3.1 memory qualifiers
EvqReadOnly, EvqReadOnly,
EvqWriteOnly, EvqWriteOnly,
EvqCoherent,
EvqRestrict,
EvqVolatile,
// end of list // end of list
EvqLast EvqLast
...@@ -613,17 +616,28 @@ struct TMemoryQualifier ...@@ -613,17 +616,28 @@ struct TMemoryQualifier
// imageSize(). // imageSize().
bool readonly; bool readonly;
bool writeonly; bool writeonly;
bool coherent;
// restrict and volatile are reserved keywords in C/C++
bool restrictQualifier;
bool volatileQualifier;
static TMemoryQualifier create() static TMemoryQualifier create()
{ {
TMemoryQualifier memoryQualifier; TMemoryQualifier memoryQualifier;
memoryQualifier.readonly = false; memoryQualifier.readonly = false;
memoryQualifier.writeonly = false; memoryQualifier.writeonly = false;
memoryQualifier.coherent = false;
memoryQualifier.restrictQualifier = false;
memoryQualifier.volatileQualifier = false;
return memoryQualifier; return memoryQualifier;
} }
bool isEmpty() { return !readonly && !writeonly; } bool isEmpty()
{
return !readonly && !writeonly && !coherent && !restrictQualifier && !volatileQualifier;
}
}; };
inline const char *getWorkGroupSizeString(size_t dimension) inline const char *getWorkGroupSizeString(size_t dimension)
......
...@@ -231,6 +231,24 @@ void TOutputGLSLBase::writeVariableType(const TType &type) ...@@ -231,6 +231,24 @@ void TOutputGLSLBase::writeVariableType(const TType &type)
out << "writeonly "; 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. // Declare the struct if we have not done so already.
if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
{ {
......
...@@ -1820,6 +1820,21 @@ bool TParseContext::checkIsMemoryQualifierNotSpecified(const TMemoryQualifier &m ...@@ -1820,6 +1820,21 @@ bool TParseContext::checkIsMemoryQualifierNotSpecified(const TMemoryQualifier &m
error(location, "Only allowed with images.", "writeonly"); error(location, "Only allowed with images.", "writeonly");
return false; 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; return true;
} }
...@@ -4211,6 +4226,22 @@ void TParseContext::checkImageMemoryAccessForUserDefinedFunctions( ...@@ -4211,6 +4226,22 @@ void TParseContext::checkImageMemoryAccessForUserDefinedFunctions(
"Function call discards the 'writeonly' qualifier from image", "Function call discards the 'writeonly' qualifier from image",
arguments[i]->getAsSymbolNode()->getSymbol().c_str()); 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 ...@@ -393,6 +393,18 @@ bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier mem
case EvqWriteOnly: case EvqWriteOnly:
joinedMemoryQualifier->writeonly = true; joinedMemoryQualifier->writeonly = true;
break; 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: default:
UNREACHABLE(); UNREACHABLE();
} }
......
...@@ -77,6 +77,7 @@ static int ES2_reserved_ES3_keyword(TParseContext *context, int token); ...@@ -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_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 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);
...@@ -207,10 +208,11 @@ O [0-7] ...@@ -207,10 +208,11 @@ O [0-7]
"imageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGECUBE); } "imageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGECUBE); }
"readonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, READONLY); } "readonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, READONLY); }
"writeonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, WRITEONLY); } "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 */ /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */
"coherent" |
"restrict" |
"resource" | "resource" |
"atomic_uint" | "atomic_uint" |
"noperspective" | "noperspective" |
...@@ -285,7 +287,6 @@ O [0-7] ...@@ -285,7 +287,6 @@ O [0-7]
"inline" | "inline" |
"noinline" | "noinline" |
"volatile" |
"public" | "public" |
"static" | "static" |
"extern" | "extern" |
...@@ -503,6 +504,18 @@ int ES2_ident_ES3_keyword(TParseContext *context, int token) ...@@ -503,6 +504,18 @@ int ES2_ident_ES3_keyword(TParseContext *context, int token)
return 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) int uint_constant(TParseContext *context)
{ {
struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); 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[], ...@@ -608,4 +621,3 @@ int glslang_scan(size_t count, const char* const string[], const int length[],
return 0; return 0;
} }
...@@ -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 %token <lex> READONLY WRITEONLY COHERENT RESTRICT VOLATILE
%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
...@@ -950,6 +950,15 @@ storage_qualifier ...@@ -950,6 +950,15 @@ storage_qualifier
| WRITEONLY { | WRITEONLY {
$$ = new TMemoryQualifierWrapper(EvqWriteOnly, @1); $$ = new TMemoryQualifierWrapper(EvqWriteOnly, @1);
} }
| COHERENT {
$$ = new TMemoryQualifierWrapper(EvqCoherent, @1);
}
| RESTRICT {
$$ = new TMemoryQualifierWrapper(EvqRestrict, @1);
}
| VOLATILE {
$$ = new TMemoryQualifierWrapper(EvqVolatile, @1);
}
; ;
type_specifier 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 ...@@ -105,92 +105,95 @@ enum yytokentype
SMOOTH = 308, SMOOTH = 308,
READONLY = 309, READONLY = 309,
WRITEONLY = 310, WRITEONLY = 310,
STRUCT = 311, COHERENT = 311,
VOID_TYPE = 312, RESTRICT = 312,
WHILE = 313, VOLATILE = 313,
SAMPLER2D = 314, STRUCT = 314,
SAMPLERCUBE = 315, VOID_TYPE = 315,
SAMPLER_EXTERNAL_OES = 316, WHILE = 316,
SAMPLER2DRECT = 317, SAMPLER2D = 317,
SAMPLER2DARRAY = 318, SAMPLERCUBE = 318,
ISAMPLER2D = 319, SAMPLER_EXTERNAL_OES = 319,
ISAMPLER3D = 320, SAMPLER2DRECT = 320,
ISAMPLERCUBE = 321, SAMPLER2DARRAY = 321,
ISAMPLER2DARRAY = 322, ISAMPLER2D = 322,
USAMPLER2D = 323, ISAMPLER3D = 323,
USAMPLER3D = 324, ISAMPLERCUBE = 324,
USAMPLERCUBE = 325, ISAMPLER2DARRAY = 325,
USAMPLER2DARRAY = 326, USAMPLER2D = 326,
SAMPLER3D = 327, USAMPLER3D = 327,
SAMPLER3DRECT = 328, USAMPLERCUBE = 328,
SAMPLER2DSHADOW = 329, USAMPLER2DARRAY = 329,
SAMPLERCUBESHADOW = 330, SAMPLER3D = 330,
SAMPLER2DARRAYSHADOW = 331, SAMPLER3DRECT = 331,
IMAGE2D = 332, SAMPLER2DSHADOW = 332,
IIMAGE2D = 333, SAMPLERCUBESHADOW = 333,
UIMAGE2D = 334, SAMPLER2DARRAYSHADOW = 334,
IMAGE3D = 335, IMAGE2D = 335,
IIMAGE3D = 336, IIMAGE2D = 336,
UIMAGE3D = 337, UIMAGE2D = 337,
IMAGE2DARRAY = 338, IMAGE3D = 338,
IIMAGE2DARRAY = 339, IIMAGE3D = 339,
UIMAGE2DARRAY = 340, UIMAGE3D = 340,
IMAGECUBE = 341, IMAGE2DARRAY = 341,
IIMAGECUBE = 342, IIMAGE2DARRAY = 342,
UIMAGECUBE = 343, UIMAGE2DARRAY = 343,
LAYOUT = 344, IMAGECUBE = 344,
IDENTIFIER = 345, IIMAGECUBE = 345,
TYPE_NAME = 346, UIMAGECUBE = 346,
FLOATCONSTANT = 347, LAYOUT = 347,
INTCONSTANT = 348, IDENTIFIER = 348,
UINTCONSTANT = 349, TYPE_NAME = 349,
BOOLCONSTANT = 350, FLOATCONSTANT = 350,
FIELD_SELECTION = 351, INTCONSTANT = 351,
LEFT_OP = 352, UINTCONSTANT = 352,
RIGHT_OP = 353, BOOLCONSTANT = 353,
INC_OP = 354, FIELD_SELECTION = 354,
DEC_OP = 355, LEFT_OP = 355,
LE_OP = 356, RIGHT_OP = 356,
GE_OP = 357, INC_OP = 357,
EQ_OP = 358, DEC_OP = 358,
NE_OP = 359, LE_OP = 359,
AND_OP = 360, GE_OP = 360,
OR_OP = 361, EQ_OP = 361,
XOR_OP = 362, NE_OP = 362,
MUL_ASSIGN = 363, AND_OP = 363,
DIV_ASSIGN = 364, OR_OP = 364,
ADD_ASSIGN = 365, XOR_OP = 365,
MOD_ASSIGN = 366, MUL_ASSIGN = 366,
LEFT_ASSIGN = 367, DIV_ASSIGN = 367,
RIGHT_ASSIGN = 368, ADD_ASSIGN = 368,
AND_ASSIGN = 369, MOD_ASSIGN = 369,
XOR_ASSIGN = 370, LEFT_ASSIGN = 370,
OR_ASSIGN = 371, RIGHT_ASSIGN = 371,
SUB_ASSIGN = 372, AND_ASSIGN = 372,
LEFT_PAREN = 373, XOR_ASSIGN = 373,
RIGHT_PAREN = 374, OR_ASSIGN = 374,
LEFT_BRACKET = 375, SUB_ASSIGN = 375,
RIGHT_BRACKET = 376, LEFT_PAREN = 376,
LEFT_BRACE = 377, RIGHT_PAREN = 377,
RIGHT_BRACE = 378, LEFT_BRACKET = 378,
DOT = 379, RIGHT_BRACKET = 379,
COMMA = 380, LEFT_BRACE = 380,
COLON = 381, RIGHT_BRACE = 381,
EQUAL = 382, DOT = 382,
SEMICOLON = 383, COMMA = 383,
BANG = 384, COLON = 384,
DASH = 385, EQUAL = 385,
TILDE = 386, SEMICOLON = 386,
PLUS = 387, BANG = 387,
STAR = 388, DASH = 388,
SLASH = 389, TILDE = 389,
PERCENT = 390, PLUS = 390,
LEFT_ANGLE = 391, STAR = 391,
RIGHT_ANGLE = 392, SLASH = 392,
VERTICAL_BAR = 393, PERCENT = 393,
CARET = 394, LEFT_ANGLE = 394,
AMPERSAND = 395, RIGHT_ANGLE = 395,
QUESTION = 396 VERTICAL_BAR = 396,
CARET = 397,
AMPERSAND = 398,
QUESTION = 399
}; };
#endif #endif
......
...@@ -3076,3 +3076,83 @@ TEST_F(MalformedShaderTest, UnsizedArrayConstructorNoParameters) ...@@ -3076,3 +3076,83 @@ TEST_F(MalformedShaderTest, UnsizedArrayConstructorNoParameters)
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; 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, ...@@ -90,7 +90,10 @@ void CheckImageDeclaration(TIntermNode *astRoot,
TBasicType imageType, TBasicType imageType,
TLayoutImageInternalFormat internalFormat, TLayoutImageInternalFormat internalFormat,
bool readonly, bool readonly,
bool writeonly) bool writeonly,
bool coherent,
bool restrictQualifier,
bool volatileQualifier)
{ {
const TIntermSymbol *myImageNode = FindSymbolNode(astRoot, imageName, imageType); const TIntermSymbol *myImageNode = FindSymbolNode(astRoot, imageName, imageType);
ASSERT_NE(nullptr, myImageNode); ASSERT_NE(nullptr, myImageNode);
...@@ -101,6 +104,9 @@ void CheckImageDeclaration(TIntermNode *astRoot, ...@@ -101,6 +104,9 @@ void CheckImageDeclaration(TIntermNode *astRoot,
TMemoryQualifier myImageMemoryQualifier = myImageType.getMemoryQualifier(); TMemoryQualifier myImageMemoryQualifier = myImageType.getMemoryQualifier();
ASSERT_EQ(readonly, myImageMemoryQualifier.readonly); ASSERT_EQ(readonly, myImageMemoryQualifier.readonly);
ASSERT_EQ(writeonly, myImageMemoryQualifier.writeonly); ASSERT_EQ(writeonly, myImageMemoryQualifier.writeonly);
ASSERT_EQ(coherent, myImageMemoryQualifier.coherent);
ASSERT_EQ(restrictQualifier, myImageMemoryQualifier.restrictQualifier);
ASSERT_EQ(volatileQualifier, myImageMemoryQualifier.volatileQualifier);
} }
} // namespace } // namespace
...@@ -156,7 +162,8 @@ TEST_F(ShaderImageTest, Image2DDeclaration) ...@@ -156,7 +162,8 @@ TEST_F(ShaderImageTest, Image2DDeclaration)
} }
CheckExportedImageUniform(mTranslator->getUniforms(), 0, GL_IMAGE_2D, "myImage"); 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. // Test that an image3D is properly parsed and exported as a uniform.
...@@ -175,7 +182,8 @@ TEST_F(ShaderImageTest, Image3DDeclaration) ...@@ -175,7 +182,8 @@ TEST_F(ShaderImageTest, Image3DDeclaration)
} }
CheckExportedImageUniform(mTranslator->getUniforms(), 0, GL_UNSIGNED_INT_IMAGE_3D, "myImage"); 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. // Check that imageLoad calls get correctly parsed.
...@@ -225,3 +233,27 @@ TEST_F(ShaderImageTest, ImageStore) ...@@ -225,3 +233,27 @@ TEST_F(ShaderImageTest, ImageStore)
// imageStore call with image2DArray // imageStore call with image2DArray
CheckImageStoreCall(mASTRoot, "imageStore(uim2a1;vi3;vu4;", EbtUImage2DArray, 3, EbtUInt, 4); 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