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