1 //
2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // BufferVariables_test.cpp:
7 //   Tests for buffer variables in GLSL ES 3.10 section 4.3.7.
8 //
9 
10 #include "gtest/gtest.h"
11 
12 #include "GLSLANG/ShaderLang.h"
13 #include "angle_gl.h"
14 #include "gtest/gtest.h"
15 #include "tests/test_utils/ShaderCompileTreeTest.h"
16 #include "tests/test_utils/compiler_test.h"
17 
18 using namespace sh;
19 
20 class BufferVariablesTest : public ShaderCompileTreeTest
21 {
22   public:
BufferVariablesTest()23     BufferVariablesTest() {}
24 
25   protected:
getShaderType() const26     ::GLenum getShaderType() const override { return GL_VERTEX_SHADER; }
getShaderSpec() const27     ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
initResources(ShBuiltInResources * resources)28     void initResources(ShBuiltInResources *resources) override
29     {
30         resources->MaxShaderStorageBufferBindings = 8;
31     }
32 };
33 
34 class BufferVariablesMatchTest : public MatchOutputCodeTest
35 {
36   public:
BufferVariablesMatchTest()37     BufferVariablesMatchTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, 0, SH_ESSL_OUTPUT)
38     {
39         getResources()->MaxShaderStorageBufferBindings = 8;
40     }
41 };
42 
43 // Test that the buffer qualifier described in GLSL ES 3.10 section 4.3.7 can be successfully
44 // compiled.
TEST_F(BufferVariablesTest,BasicShaderStorageBlockDeclaration)45 TEST_F(BufferVariablesTest, BasicShaderStorageBlockDeclaration)
46 {
47     const std::string &source =
48         "#version 310 es\n"
49         "layout(binding = 3) buffer buf {\n"
50         "    int b1;\n"
51         "    buffer int b2;\n"
52         "};\n"
53         "void main()\n"
54         "{\n"
55         "}\n";
56     if (!compile(source))
57     {
58         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
59     }
60 }
61 
62 // Test that shader storage block layout qualifiers can be declared for global scope.
TEST_F(BufferVariablesTest,LayoutQualifiersDeclaredInGlobal)63 TEST_F(BufferVariablesTest, LayoutQualifiersDeclaredInGlobal)
64 {
65     const std::string &source =
66         "#version 310 es\n"
67         "layout(shared, column_major) buffer;\n"
68         "void main()\n"
69         "{\n"
70         "}\n";
71     if (!compile(source))
72     {
73         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
74     }
75 }
76 
77 // Test that shader storage block can be used with one or more memory qualifiers.
TEST_F(BufferVariablesTest,ShaderStorageBlockWithMemoryQualifier)78 TEST_F(BufferVariablesTest, ShaderStorageBlockWithMemoryQualifier)
79 {
80     const std::string &source =
81         "#version 310 es\n"
82         "layout(binding = 3) writeonly buffer buf {\n"
83         "    int b1;\n"
84         "    buffer int b2;\n"
85         "};\n"
86         "void main()\n"
87         "{\n"
88         "}\n";
89     if (!compile(source))
90     {
91         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
92     }
93 }
94 
95 // Test that buffer variables can be used with one or more memory qualifiers.
TEST_F(BufferVariablesTest,BufferVariablesWithMemoryQualifier)96 TEST_F(BufferVariablesTest, BufferVariablesWithMemoryQualifier)
97 {
98     const std::string &source =
99         "#version 310 es\n"
100         "layout(binding = 3) buffer buf {\n"
101         "    writeonly int b1;\n"
102         "    writeonly buffer int b2;\n"
103         "};\n"
104         "void main()\n"
105         "{\n"
106         "}\n";
107     if (!compile(source))
108     {
109         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
110     }
111 }
112 
113 // Test that it is a compile-time error to declare buffer variables at global scope (outside a
114 // block).
TEST_F(BufferVariablesTest,DeclareBufferVariableAtGlobal)115 TEST_F(BufferVariablesTest, DeclareBufferVariableAtGlobal)
116 {
117     const std::string &source =
118         "#version 310 es\n"
119         "layout(binding = 3) buffer int a;\n"
120         "void main()\n"
121         "{\n"
122         "}\n";
123     if (compile(source))
124     {
125         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
126     }
127 }
128 
129 // Test that the buffer variable can't be opaque type.
TEST_F(BufferVariablesTest,BufferVariableWithOpaqueType)130 TEST_F(BufferVariablesTest, BufferVariableWithOpaqueType)
131 {
132     const std::string &source =
133         "#version 310 es\n"
134         "layout(binding = 3) buffer buf {\n"
135         "    int b1;\n"
136         "    atomic_uint b2;\n"
137         "};\n"
138         "void main()\n"
139         "{\n"
140         "}\n";
141     if (compile(source))
142     {
143         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
144     }
145 }
146 
147 // Test that the uniform variable can't be in shader storage block.
TEST_F(BufferVariablesTest,UniformVariableInShaderStorageBlock)148 TEST_F(BufferVariablesTest, UniformVariableInShaderStorageBlock)
149 {
150     const std::string &source =
151         "#version 310 es\n"
152         "layout(binding = 3) buffer buf {\n"
153         "    uniform int a;\n"
154         "};\n"
155         "void main()\n"
156         "{\n"
157         "}\n";
158     if (compile(source))
159     {
160         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
161     }
162 }
163 
164 // Test that buffer qualifier is not supported in verson lower than GLSL ES 3.10.
TEST_F(BufferVariablesTest,BufferQualifierInESSL3)165 TEST_F(BufferVariablesTest, BufferQualifierInESSL3)
166 {
167     const std::string &source =
168         "#version 300 es\n"
169         "layout(binding = 3) buffer buf {\n"
170         "    int b1;\n"
171         "    buffer int b2;\n"
172         "};\n"
173         "void main()\n"
174         "{\n"
175         "}\n";
176     if (compile(source))
177     {
178         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
179     }
180 }
181 
182 // Test that can't assign to a readonly buffer variable.
TEST_F(BufferVariablesTest,AssignToReadonlyBufferVariable)183 TEST_F(BufferVariablesTest, AssignToReadonlyBufferVariable)
184 {
185     const std::string &source =
186         "#version 310 es\n"
187         "layout(binding = 3) buffer buf {\n"
188         "    readonly int b1;\n"
189         "};\n"
190         "void main()\n"
191         "{\n"
192         "    b1 = 5;\n"
193         "}\n";
194     if (compile(source))
195     {
196         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
197     }
198 }
199 
200 // Test that can't assign to a buffer variable declared within shader storage block with readonly.
TEST_F(BufferVariablesTest,AssignToBufferVariableWithinReadonlyBlock)201 TEST_F(BufferVariablesTest, AssignToBufferVariableWithinReadonlyBlock)
202 {
203     const std::string &source =
204         "#version 310 es\n"
205         "layout(binding = 3) readonly buffer buf {\n"
206         "    int b1;\n"
207         "};\n"
208         "void main()\n"
209         "{\n"
210         "    b1 = 5;\n"
211         "}\n";
212     if (compile(source))
213     {
214         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
215     }
216 }
217 
218 // Test that can't assign to a readonly buffer variable through an instance name.
TEST_F(BufferVariablesTest,AssignToReadonlyBufferVariableByInstanceName)219 TEST_F(BufferVariablesTest, AssignToReadonlyBufferVariableByInstanceName)
220 {
221     const std::string &source =
222         R"(#version 310 es
223         layout(binding = 3) buffer buf {
224             readonly float f;
225         } instanceBuffer;
226         void main()
227         {
228             instanceBuffer.f += 0.2;
229         })";
230     if (compile(source))
231     {
232         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
233     }
234 }
235 
236 // Test that can't assign to a readonly struct buffer variable.
TEST_F(BufferVariablesTest,AssignToReadonlyStructBufferVariable)237 TEST_F(BufferVariablesTest, AssignToReadonlyStructBufferVariable)
238 {
239     const std::string &source =
240         R"(#version 310 es
241         struct S {
242             float f;
243         };
244         layout(binding = 3) buffer buf {
245             readonly S s;
246         };
247         void main()
248         {
249             s.f += 0.2;
250         })";
251     if (compile(source))
252     {
253         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
254     }
255 }
256 
257 // Test that can't assign to a readonly struct buffer variable through an instance name.
TEST_F(BufferVariablesTest,AssignToReadonlyStructBufferVariableByInstanceName)258 TEST_F(BufferVariablesTest, AssignToReadonlyStructBufferVariableByInstanceName)
259 {
260     const std::string &source =
261         R"(#version 310 es
262         struct S {
263             float f;
264         };
265         layout(binding = 3) buffer buf {
266             readonly S s;
267         } instanceBuffer;
268         void main()
269         {
270             instanceBuffer.s.f += 0.2;
271         })";
272     if (compile(source))
273     {
274         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
275     }
276 }
277 
278 // Test that a readonly and writeonly buffer variable should neither read or write.
TEST_F(BufferVariablesTest,AccessReadonlyWriteonlyBufferVariable)279 TEST_F(BufferVariablesTest, AccessReadonlyWriteonlyBufferVariable)
280 {
281     const std::string &source =
282         "#version 310 es\n"
283         "layout(binding = 3) buffer buf {\n"
284         "    readonly writeonly int b1;\n"
285         "};\n"
286         "void main()\n"
287         "{\n"
288         "    b1 = 5;\n"
289         "    int test = b1;\n"
290         "}\n";
291     if (compile(source))
292     {
293         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
294     }
295 }
296 
297 // Test that accessing a writeonly buffer variable should be error.
TEST_F(BufferVariablesTest,AccessWriteonlyBufferVariable)298 TEST_F(BufferVariablesTest, AccessWriteonlyBufferVariable)
299 {
300     const std::string &source =
301         "#version 310 es\n"
302         "layout(binding = 3) buffer buf {\n"
303         "    writeonly int b1;\n"
304         "};\n"
305         "void main()\n"
306         "{\n"
307         "    int test = b1;\n"
308         "}\n";
309     if (compile(source))
310     {
311         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
312     }
313 }
314 
315 // Test that accessing a buffer variable through an instance name is ok.
TEST_F(BufferVariablesTest,AccessReadonlyBufferVariableByInstanceName)316 TEST_F(BufferVariablesTest, AccessReadonlyBufferVariableByInstanceName)
317 {
318     const std::string &source =
319         "#version 310 es\n"
320         "layout(binding = 3) buffer buf {\n"
321         "    readonly float f;\n"
322         "} instanceBuffer;\n"
323         "void main()\n"
324         "{\n"
325         "    gl_Position.x = instanceBuffer.f;\n"
326         "}\n";
327     if (!compile(source))
328     {
329         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
330     }
331 }
332 
333 // Test that accessing a buffer variable through an instance name inherits the writeonly qualifier
334 // and generates errors.
TEST_F(BufferVariablesTest,AccessWriteonlyBufferVariableByInstanceName)335 TEST_F(BufferVariablesTest, AccessWriteonlyBufferVariableByInstanceName)
336 {
337     const std::string &source =
338         "#version 310 es\n"
339         "layout(binding = 3) writeonly buffer buf {\n"
340         "    float f;\n"
341         "} instanceBuffer;\n"
342         "void main()\n"
343         "{\n"
344         "    float test = instanceBuffer.f;\n"
345         "}\n";
346     if (compile(source))
347     {
348         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
349     }
350 }
351 
352 // Test that writeonly buffer variable as the argument of a unary operator should be error.
TEST_F(BufferVariablesTest,UnaryOperatorWithWriteonlyBufferVariable)353 TEST_F(BufferVariablesTest, UnaryOperatorWithWriteonlyBufferVariable)
354 {
355     const std::string &source =
356         "#version 310 es\n"
357         "layout(binding = 3) buffer buf {\n"
358         "    writeonly int b1;\n"
359         "};\n"
360         "void main()\n"
361         "{\n"
362         "    ++b1;\n"
363         "}\n";
364     if (compile(source))
365     {
366         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
367     }
368 }
369 
370 // Test that writeonly buffer variable on the left-hand side of compound assignment should be error.
TEST_F(BufferVariablesTest,CompoundAssignmentToWriteonlyBufferVariable)371 TEST_F(BufferVariablesTest, CompoundAssignmentToWriteonlyBufferVariable)
372 {
373     const std::string &source =
374         "#version 310 es\n"
375         "layout(binding = 3) buffer buf {\n"
376         "    writeonly int b1;\n"
377         "};\n"
378         "void main()\n"
379         "{\n"
380         "    b1 += 5;\n"
381         "}\n";
382     if (compile(source))
383     {
384         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
385     }
386 }
387 
388 // Test that writeonly buffer variable as ternary op argument should be error.
TEST_F(BufferVariablesTest,TernarySelectionWithWriteonlyBufferVariable)389 TEST_F(BufferVariablesTest, TernarySelectionWithWriteonlyBufferVariable)
390 {
391     const std::string &source =
392         "#version 310 es\n"
393         "layout(binding = 3) buffer buf {\n"
394         "    writeonly bool b1;\n"
395         "};\n"
396         "void main()\n"
397         "{\n"
398         "    int test = b1 ? 1 : 0;\n"
399         "}\n";
400     if (compile(source))
401     {
402         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
403     }
404 }
405 
406 // Test that writeonly buffer variable as array constructor argument should be error.
TEST_F(BufferVariablesTest,ArrayConstructorWithWriteonlyBufferVariable)407 TEST_F(BufferVariablesTest, ArrayConstructorWithWriteonlyBufferVariable)
408 {
409     const std::string &source =
410         "#version 310 es\n"
411         "layout(binding = 3) buffer buf {\n"
412         "    writeonly float f;\n"
413         "};\n"
414         "void main()\n"
415         "{\n"
416         "    float a[3] = float[3](f, f, f);\n"
417         "}\n";
418     if (compile(source))
419     {
420         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
421     }
422 }
423 
424 // Test that writeonly buffer variable as structure constructor argument should be error.
TEST_F(BufferVariablesTest,StructureConstructorWithWriteonlyBufferVariable)425 TEST_F(BufferVariablesTest, StructureConstructorWithWriteonlyBufferVariable)
426 {
427     const std::string &source =
428         "#version 310 es\n"
429         "struct S {\n"
430         "    int a;\n"
431         "};\n"
432         "struct T {\n"
433         "    S b;\n"
434         "};\n"
435         "layout(binding = 3) buffer buf {\n"
436         "    writeonly S c;\n"
437         "};\n"
438         "void main()\n"
439         "{\n"
440         "    T t = T(c);\n"
441         "}\n";
442     if (compile(source))
443     {
444         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
445     }
446 }
447 
448 // Test that writeonly buffer variable as built-in function argument should be error.
TEST_F(BufferVariablesTest,BuildInFunctionWithWriteonlyBufferVariable)449 TEST_F(BufferVariablesTest, BuildInFunctionWithWriteonlyBufferVariable)
450 {
451     const std::string &source =
452         "#version 310 es\n"
453         "layout(binding = 3) buffer buf {\n"
454         "    writeonly int a;\n"
455         "};\n"
456         "void main()\n"
457         "{\n"
458         "    int test = min(a, 1);\n"
459         "}\n";
460     if (compile(source))
461     {
462         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
463     }
464 }
465 
466 // Test that readonly buffer variable as user-defined function in argument should be ok.
TEST_F(BufferVariablesTest,UserDefinedFunctionWithReadonlyBufferVariableInArgument)467 TEST_F(BufferVariablesTest, UserDefinedFunctionWithReadonlyBufferVariableInArgument)
468 {
469     const std::string &source =
470         "#version 310 es\n"
471         "layout(binding = 3) buffer buf {\n"
472         "    readonly float f;\n"
473         "};\n"
474         "void foo(float a) {}\n"
475         "void main()\n"
476         "{\n"
477         "    foo(f);\n"
478         "}\n";
479     if (!compile(source))
480     {
481         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
482     }
483 }
484 
485 // Test that writeonly buffer variable as user-defined function in argument should be error.
TEST_F(BufferVariablesTest,UserDefinedFunctionWithWriteonlyBufferVariableInArgument)486 TEST_F(BufferVariablesTest, UserDefinedFunctionWithWriteonlyBufferVariableInArgument)
487 {
488     const std::string &source =
489         "#version 310 es\n"
490         "layout(binding = 3) buffer buf {\n"
491         "    writeonly float f;\n"
492         "};\n"
493         "void foo(float a) {}\n"
494         "void main()\n"
495         "{\n"
496         "    foo(f);\n"
497         "}\n";
498     if (compile(source))
499     {
500         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
501     }
502 }
503 
504 // Test that writeonly buffer variable as user-defined function out argument should be ok.
TEST_F(BufferVariablesTest,UserDefinedFunctionWithWriteonlyBufferVariableOutArgument)505 TEST_F(BufferVariablesTest, UserDefinedFunctionWithWriteonlyBufferVariableOutArgument)
506 {
507     const std::string &source =
508         "#version 310 es\n"
509         "layout(binding = 3) buffer buf {\n"
510         "    writeonly float f;\n"
511         "};\n"
512         "void foo(out float a) {}\n"
513         "void main()\n"
514         "{\n"
515         "    foo(f);\n"
516         "}\n";
517     if (!compile(source))
518     {
519         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
520     }
521 }
522 
523 // Test that readonly buffer variable as user-defined function out argument should be error.
TEST_F(BufferVariablesTest,UserDefinedFunctionWithReadonlyBufferVariableOutArgument)524 TEST_F(BufferVariablesTest, UserDefinedFunctionWithReadonlyBufferVariableOutArgument)
525 {
526     const std::string &source =
527         "#version 310 es\n"
528         "layout(binding = 3) buffer buf {\n"
529         "    readonly float f;\n"
530         "};\n"
531         "void foo(out float a) {}\n"
532         "void main()\n"
533         "{\n"
534         "    foo(f);\n"
535         "}\n";
536     if (compile(source))
537     {
538         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
539     }
540 }
541 
542 // Test that buffer qualifier can't modify a function parameter.
TEST_F(BufferVariablesTest,BufferQualifierOnFunctionParameter)543 TEST_F(BufferVariablesTest, BufferQualifierOnFunctionParameter)
544 {
545     const std::string &source =
546         "#version 310 es\n"
547         "void foo(buffer float a) {}\n"
548         "void main()\n"
549         "{\n"
550         "}\n";
551     if (compile(source))
552     {
553         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
554     }
555 }
556 
557 // Test that std430 qualifier is supported for shader storage blocks.
TEST_F(BufferVariablesTest,ShaderStorageBlockWithStd430)558 TEST_F(BufferVariablesTest, ShaderStorageBlockWithStd430)
559 {
560     const std::string &source =
561         "#version 310 es\n"
562         "layout(std430) buffer buf {\n"
563         "    int b1;\n"
564         "    int b2;\n"
565         "};\n"
566         "void main()\n"
567         "{\n"
568         "}\n";
569     if (!compile(source))
570     {
571         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
572     }
573 }
574 
575 // Test that using std430 qualifier on a uniform block will fail to compile.
TEST_F(BufferVariablesTest,UniformBlockWithStd430)576 TEST_F(BufferVariablesTest, UniformBlockWithStd430)
577 {
578     const std::string &source =
579         "#version 310 es\n"
580         "layout(std430) uniform buf {\n"
581         "    int b1;\n"
582         "    int b2;\n"
583         "};\n"
584         "void main()\n"
585         "{\n"
586         "}\n";
587     if (compile(source))
588     {
589         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
590     }
591 }
592 
593 // Test that indexing a runtime-sized array with a positive index compiles.
TEST_F(BufferVariablesTest,IndexRuntimeSizedArray)594 TEST_F(BufferVariablesTest, IndexRuntimeSizedArray)
595 {
596     const std::string &source =
597         R"(#version 310 es
598 
599         layout(std430) buffer buf
600         {
601             int arr[];
602         };
603 
604         void main()
605         {
606             arr[100];
607         })";
608     if (!compile(source))
609     {
610         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
611     }
612 }
613 
614 // Test that indexing a runtime-sized array with a negative constant index does not compile.
TEST_F(BufferVariablesTest,IndexRuntimeSizedArrayWithNegativeIndex)615 TEST_F(BufferVariablesTest, IndexRuntimeSizedArrayWithNegativeIndex)
616 {
617     const std::string &source =
618         R"(#version 310 es
619 
620         layout(std430) buffer buf
621         {
622             int arr[];
623         };
624 
625         void main()
626         {
627             arr[-1];
628         })";
629     if (compile(source))
630     {
631         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
632     }
633 }
634 
635 // Test that only the last member of a buffer can be runtime-sized.
TEST_F(BufferVariablesTest,RuntimeSizedVariableInNotLastInBuffer)636 TEST_F(BufferVariablesTest, RuntimeSizedVariableInNotLastInBuffer)
637 {
638     const std::string &source =
639         R"(#version 310 es
640 
641         layout(std430) buffer buf
642         {
643             int arr[];
644             int i;
645         };
646 
647         void main()
648         {
649         })";
650     if (compile(source))
651     {
652         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
653     }
654 }
655 
656 // Test that memory qualifiers are output.
TEST_F(BufferVariablesMatchTest,MemoryQualifiers)657 TEST_F(BufferVariablesMatchTest, MemoryQualifiers)
658 {
659     const std::string &source =
660         R"(#version 310 es
661 
662         layout(std430) coherent buffer buf
663         {
664             int defaultCoherent;
665             coherent ivec2 specifiedCoherent;
666             volatile ivec3 specifiedVolatile;
667             restrict ivec4 specifiedRestrict;
668             readonly float specifiedReadOnly;
669             writeonly vec2 specifiedWriteOnly;
670             volatile readonly vec3 specifiedMultiple;
671         };
672 
673         void main()
674         {
675         })";
676     compile(source);
677     ASSERT_TRUE(foundInESSLCode("coherent highp int"));
678     ASSERT_TRUE(foundInESSLCode("coherent highp ivec2"));
679     ASSERT_TRUE(foundInESSLCode("coherent volatile highp ivec3"));
680     ASSERT_TRUE(foundInESSLCode("coherent restrict highp ivec4"));
681     ASSERT_TRUE(foundInESSLCode("readonly coherent highp float"));
682     ASSERT_TRUE(foundInESSLCode("writeonly coherent highp vec2"));
683     ASSERT_TRUE(foundInESSLCode("readonly coherent volatile highp vec3"));
684 }
685