xref: /aosp_15_r20/external/angle/src/tests/gl_tests/ShaderBinaryTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2022 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 
7 #include "test_utils/ANGLETest.h"
8 
9 #include <vector>
10 
11 #include "GLSLANG/ShaderLang.h"
12 #include "test_utils/gl_raii.h"
13 
14 using namespace angle;
15 
16 class ShaderBinaryTest : public ANGLETest<>
17 {
18   protected:
ShaderBinaryTest()19     ShaderBinaryTest()
20     {
21         setWindowWidth(128);
22         setWindowHeight(128);
23         setConfigRedBits(8);
24         setConfigGreenBits(8);
25         setConfigBlueBits(8);
26         setConfigAlphaBits(8);
27 
28         // Test flakiness was noticed when reusing displays.
29         forceNewDisplay();
30     }
31 
testSetUp()32     void testSetUp() override
33     {
34         ASSERT_EQ(sh::Initialize(), true);
35 
36         if (!supported())
37         {
38             // Must return early because the initialization below will crash otherwise.
39             // Individal tests will skip themselves as well.
40             return;
41         }
42 
43         mCompileOptions.objectCode                    = true;
44         mCompileOptions.emulateGLDrawID               = true;
45         mCompileOptions.initializeUninitializedLocals = true;
46 
47         sh::InitBuiltInResources(&mResources);
48 
49         // Generate a shader binary:
50         ShShaderSpec spec     = SH_GLES2_SPEC;
51         ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
52 
53         // Vertex shader:
54         const char *source = essl1_shaders::vs::Simple();
55         ShHandle vertexCompiler =
56             sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &mResources);
57         bool compileResult =
58             sh::GetShaderBinary(vertexCompiler, &source, 1, mCompileOptions, &mVertexShaderBinary);
59         ASSERT_TRUE(compileResult);
60 
61         if (mVertexShaderBinary.size() == 0)
62         {
63             FAIL() << "Creating vertex shader binary failed.";
64         }
65 
66         // Fragment shader:
67         source = essl1_shaders::fs::Red();
68         ShHandle fragmentCompiler =
69             sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
70         compileResult = sh::GetShaderBinary(fragmentCompiler, &source, 1, mCompileOptions,
71                                             &mFragmentShaderBinary);
72         ASSERT_TRUE(compileResult);
73 
74         if (mFragmentShaderBinary.size() == 0)
75         {
76             FAIL() << "Creating fragment shader binary failed.";
77         }
78     }
79 
testTearDown()80     void testTearDown() override
81     {
82         sh::Finalize();
83 
84         if (!supported())
85         {
86             // Return early because the initialization didn't complete.
87             return;
88         }
89 
90         glDeleteBuffers(1, &mBuffer);
91     }
92 
supported() const93     bool supported() const
94     {
95         GLint formatCount;
96         glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &formatCount);
97         if (formatCount == 0)
98         {
99             std::cout << "Test skipped because no program binary formats are available."
100                       << std::endl;
101             return false;
102         }
103         std::vector<GLint> formats(formatCount);
104         glGetIntegerv(GL_SHADER_BINARY_FORMATS, formats.data());
105 
106         ASSERT(formats[0] == GL_SHADER_BINARY_ANGLE);
107 
108         return true;
109     }
110 
111     ShCompileOptions mCompileOptions = {};
112     ShBuiltInResources mResources;
113     GLuint mBuffer;
114     sh::ShaderBinaryBlob mVertexShaderBinary;
115     sh::ShaderBinaryBlob mFragmentShaderBinary;
116 };
117 
118 // This tests the ability to successfully create and load a shader binary.
TEST_P(ShaderBinaryTest,CreateAndLoadBinary)119 TEST_P(ShaderBinaryTest, CreateAndLoadBinary)
120 {
121     ANGLE_SKIP_TEST_IF(!supported());
122 
123     GLint compileResult;
124     // Create vertex shader and load binary
125     GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
126     glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
127                    mVertexShaderBinary.size());
128     glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
129     ASSERT_GL_TRUE(compileResult);
130 
131     // Create fragment shader and load binary
132     GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
133     glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, mFragmentShaderBinary.data(),
134                    mFragmentShaderBinary.size());
135     glGetShaderiv(fragShader, GL_COMPILE_STATUS, &compileResult);
136     ASSERT_GL_TRUE(compileResult);
137 
138     // Create program from the shaders
139     GLuint newProgram = glCreateProgram();
140     glAttachShader(newProgram, vertShader);
141     glAttachShader(newProgram, fragShader);
142     glLinkProgram(newProgram);
143     newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
144 
145     // Test with a basic draw
146     drawQuad(newProgram, "a_position", 0.5f);
147     ASSERT_GL_NO_ERROR();
148     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
149 }
150 
151 // Check invalid gl call parameters, such as providing a GL type when a shader handle is expected.
TEST_P(ShaderBinaryTest,InvalidCallParams)152 TEST_P(ShaderBinaryTest, InvalidCallParams)
153 {
154     ANGLE_SKIP_TEST_IF(!supported());
155 
156     GLuint vertShader[2];
157     vertShader[0]     = glCreateShader(GL_VERTEX_SHADER);
158     GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
159 
160     // Invalid shader
161     vertShader[1] = -1;
162     glShaderBinary(1, &vertShader[1], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
163                    mVertexShaderBinary.size());
164     EXPECT_GL_ERROR(GL_INVALID_VALUE);
165 
166     // GL_INVALID_ENUM is generated if binaryFormat is not an accepted value.
167     glShaderBinary(1, &vertShader[0], GL_INVALID_ENUM, mVertexShaderBinary.data(),
168                    mVertexShaderBinary.size());
169     EXPECT_GL_ERROR(GL_INVALID_ENUM);
170 
171     // GL_INVALID_VALUE is generated if n or length is negative
172     glShaderBinary(-1, &vertShader[0], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
173                    mVertexShaderBinary.size());
174     EXPECT_GL_ERROR(GL_INVALID_VALUE);
175     glShaderBinary(1, &vertShader[0], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(), -1);
176     EXPECT_GL_ERROR(GL_INVALID_VALUE);
177 
178     // GL_INVALID_OPERATION is generated if any value in shaders is not a shader object.
179     GLuint program = glCreateProgram();
180     glShaderBinary(1, &program, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
181                    mVertexShaderBinary.size());
182     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
183 
184     // GL_INVALID_OPERATION is generated if more than one of the handles in shaders refers to the
185     // same shader object.
186     vertShader[1] = vertShader[0];
187     glShaderBinary(2, &vertShader[0], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
188                    mVertexShaderBinary.size());
189     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
190 
191     // GL_INVALID_VALUE is generated if the data pointed to by binary does not match the format
192     // specified by binaryFormat.
193     std::string invalid("Invalid Shader Blob.");
194     glShaderBinary(1, &vertShader[0], GL_SHADER_BINARY_ANGLE, invalid.data(), invalid.size());
195     EXPECT_GL_ERROR(GL_INVALID_VALUE);
196 
197     // Try loading vertex shader binary into fragment shader
198     glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
199                    mVertexShaderBinary.size());
200     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
201 }
202 
203 // Check attempting to get source code from a shader that was loaded with glShaderBinary.
TEST_P(ShaderBinaryTest,GetSourceFromBinaryShader)204 TEST_P(ShaderBinaryTest, GetSourceFromBinaryShader)
205 {
206     ANGLE_SKIP_TEST_IF(!supported());
207 
208     GLint compileResult;
209     // Create vertex shader and load binary
210     GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
211     glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
212                    mVertexShaderBinary.size());
213     glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
214     ASSERT_GL_TRUE(compileResult);
215 
216     GLsizei length = 0;
217     glGetShaderSource(vertShader, 0, &length, nullptr);
218 
219     EXPECT_EQ(length, 0);
220 }
221 
222 // Create a program from both shader source code and a binary blob.
TEST_P(ShaderBinaryTest,CombineSourceAndBinaryShaders)223 TEST_P(ShaderBinaryTest, CombineSourceAndBinaryShaders)
224 {
225     ANGLE_SKIP_TEST_IF(!supported());
226 
227     GLint compileResult;
228     // Create vertex shader and load binary
229     GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
230     glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
231                    mVertexShaderBinary.size());
232     glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
233     ASSERT_GL_TRUE(compileResult);
234 
235     // Create fragment shader
236     GLuint fragShader = CompileShader(GL_FRAGMENT_SHADER, essl1_shaders::fs::Red());
237 
238     GLuint newProgram = glCreateProgram();
239     glAttachShader(newProgram, vertShader);
240     glAttachShader(newProgram, fragShader);
241     glLinkProgram(newProgram);
242     newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
243 
244     // Test with a basic draw
245     drawQuad(newProgram, "a_position", 0.5f);
246     ASSERT_GL_NO_ERROR();
247     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
248 }
249 
250 // Test that shaders loaded with glShaderBinary do not cause false hits in the program cache.
TEST_P(ShaderBinaryTest,ProgramCacheWithShaderBinary)251 TEST_P(ShaderBinaryTest, ProgramCacheWithShaderBinary)
252 {
253     ANGLE_SKIP_TEST_IF(!supported());
254     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_get_program_binary"));
255 
256     GLint compileResult;
257     // Create vertex shader that will be shared between the programs
258     GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
259     glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
260                    mVertexShaderBinary.size());
261     glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
262     ASSERT_GL_TRUE(compileResult);
263 
264     // Create a program with a red vertex shader
265     GLuint fragShaderRed = glCreateShader(GL_FRAGMENT_SHADER);
266     glShaderBinary(1, &fragShaderRed, GL_SHADER_BINARY_ANGLE, mFragmentShaderBinary.data(),
267                    mFragmentShaderBinary.size());
268     glGetShaderiv(fragShaderRed, GL_COMPILE_STATUS, &compileResult);
269     ASSERT_GL_TRUE(compileResult);
270 
271     GLuint programRed = glCreateProgram();
272     glAttachShader(programRed, vertShader);
273     glAttachShader(programRed, fragShaderRed);
274     glLinkProgram(programRed);
275     programRed = CheckLinkStatusAndReturnProgram(programRed, true);
276 
277     // Test with a basic draw
278     drawQuad(programRed, "a_position", 0.5f);
279     ASSERT_GL_NO_ERROR();
280     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
281 
282     // Create a program with a blue fragment shader, also loaded from a binary
283     ShShaderSpec spec     = SH_GLES2_SPEC;
284     ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
285 
286     const char *source = essl1_shaders::fs::Blue();
287     sh::ShaderBinaryBlob fragShaderBlueData;
288     ShHandle fragmentCompiler =
289         sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
290     bool binaryCompileResult =
291         sh::GetShaderBinary(fragmentCompiler, &source, 1, mCompileOptions, &fragShaderBlueData);
292     ASSERT_TRUE(binaryCompileResult);
293     if (fragShaderBlueData.size() == 0)
294     {
295         FAIL() << "Creating fragment shader binary failed.";
296     }
297 
298     GLuint fragShaderBlue = glCreateShader(GL_FRAGMENT_SHADER);
299     glShaderBinary(1, &fragShaderBlue, GL_SHADER_BINARY_ANGLE, fragShaderBlueData.data(),
300                    fragShaderBlueData.size());
301     glGetShaderiv(fragShaderBlue, GL_COMPILE_STATUS, &compileResult);
302     ASSERT_GL_TRUE(compileResult);
303 
304     GLuint programBlue = glCreateProgram();
305     glAttachShader(programBlue, vertShader);
306     glAttachShader(programBlue, fragShaderBlue);
307     glLinkProgram(programBlue);
308     programBlue = CheckLinkStatusAndReturnProgram(programBlue, true);
309 
310     // The program cache should miss and create a new program
311     drawQuad(programBlue, "a_position", 0.5f);
312     ASSERT_GL_NO_ERROR();
313     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
314 }
315 
316 class ShaderBinaryTestES31 : public ShaderBinaryTest
317 {
318   protected:
testSetUp()319     void testSetUp() override
320     {
321         ASSERT_EQ(sh::Initialize(), true);
322 
323         mCompileOptions.objectCode                    = true;
324         mCompileOptions.emulateGLDrawID               = true;
325         mCompileOptions.initializeUninitializedLocals = true;
326 
327         sh::InitBuiltInResources(&mResources);
328         mResources.EXT_geometry_shader     = 1;
329         mResources.EXT_tessellation_shader = 1;
330 
331         // Generate a shader binary:
332         ShShaderSpec spec     = SH_GLES3_1_SPEC;
333         ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
334 
335         // Vertex shader:
336         const char *source = essl31_shaders::vs::Simple();
337         ShHandle vertexCompiler =
338             sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &mResources);
339         bool compileResult =
340             sh::GetShaderBinary(vertexCompiler, &source, 1, mCompileOptions, &mVertexShaderBinary);
341         ASSERT_TRUE(compileResult);
342 
343         if (mVertexShaderBinary.size() == 0)
344         {
345             FAIL() << "Creating vertex shader binary failed.";
346         }
347 
348         // Fragment shader:
349         source = essl31_shaders::fs::Red();
350         ShHandle fragmentCompiler =
351             sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
352         compileResult = sh::GetShaderBinary(fragmentCompiler, &source, 1, mCompileOptions,
353                                             &mFragmentShaderBinary);
354         ASSERT_TRUE(compileResult);
355 
356         if (mFragmentShaderBinary.size() == 0)
357         {
358             FAIL() << "Creating fragment shader binary failed.";
359         }
360     }
361 };
362 
363 // Test all shader stages
TEST_P(ShaderBinaryTestES31,AllShaderStages)364 TEST_P(ShaderBinaryTestES31, AllShaderStages)
365 {
366     ANGLE_SKIP_TEST_IF(!supported());
367     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
368     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_tessellation_shader"));
369 
370     const char *kGS = R"(#version 310 es
371 #extension GL_EXT_geometry_shader : require
372 precision mediump float;
373 
374 layout (triangles) in;
375 layout (triangle_strip, max_vertices = 3) out;
376 
377 void main() {
378     gl_Position = gl_in[0].gl_Position;
379     EmitVertex();
380 
381     gl_Position = gl_in[1].gl_Position;
382     EmitVertex();
383 
384     gl_Position = gl_in[2].gl_Position;
385     EmitVertex();
386 
387     EndPrimitive();
388 }
389 )";
390 
391     const char *kTCS = R"(#version 310 es
392 #extension GL_EXT_tessellation_shader : require
393 precision mediump float;
394 
395 layout (vertices = 1) out;
396 
397 void main()
398 {
399     gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
400     gl_TessLevelInner[0] = 1.0;
401     gl_TessLevelInner[1] = 1.0;
402     gl_TessLevelOuter[0] = 1.0;
403     gl_TessLevelOuter[1] = 1.0;
404     gl_TessLevelOuter[2] = 1.0;
405     gl_TessLevelOuter[3] = 1.0;
406 }
407 
408 )";
409 
410     const char *kTES = R"(#version 310 es
411 #extension GL_EXT_tessellation_shader : require
412 precision mediump float;
413 
414 layout (quads, cw, fractional_odd_spacing) in;
415 
416 void main()
417 {
418     gl_Position = vec4(gl_TessCoord.xy * 2. - 1., 0, 1);
419 }
420 )";
421 
422     // Generate a shader binary for geo, tcs, tes:
423     ShShaderSpec spec                  = SH_GLES3_1_SPEC;
424     ShShaderOutput output              = SH_SPIRV_VULKAN_OUTPUT;
425     mResources.EXT_geometry_shader     = 1;
426     mResources.EXT_tessellation_shader = 1;
427 
428     // Geometry shader:
429     sh::ShaderBinaryBlob geometryShaderBinary;
430     ShHandle geometryCompiler =
431         sh::ConstructCompiler(GL_GEOMETRY_SHADER, spec, output, &mResources);
432     bool compileResult =
433         sh::GetShaderBinary(geometryCompiler, &kGS, 1, mCompileOptions, &geometryShaderBinary);
434     ASSERT_TRUE(compileResult);
435     if (geometryShaderBinary.size() == 0)
436     {
437         FAIL() << "Creating geometry shader binary failed.";
438     }
439 
440     // tesselation control shader:
441     sh::ShaderBinaryBlob tessControlShaderBinary;
442     ShHandle tessControlCompiler =
443         sh::ConstructCompiler(GL_TESS_CONTROL_SHADER, spec, output, &mResources);
444     compileResult = sh::GetShaderBinary(tessControlCompiler, &kTCS, 1, mCompileOptions,
445                                         &tessControlShaderBinary);
446     ASSERT_TRUE(compileResult);
447     if (tessControlShaderBinary.size() == 0)
448     {
449         FAIL() << "Creating tesselation control shader binary failed.";
450     }
451 
452     // tesselation evaluation shader:
453     sh::ShaderBinaryBlob tessEvaluationShaderBinary;
454     ShHandle tessEvaluationCompiler =
455         sh::ConstructCompiler(GL_TESS_EVALUATION_SHADER, spec, output, &mResources);
456     compileResult = sh::GetShaderBinary(tessEvaluationCompiler, &kTES, 1, mCompileOptions,
457                                         &tessEvaluationShaderBinary);
458     ASSERT_TRUE(compileResult);
459     if (tessEvaluationShaderBinary.size() == 0)
460     {
461         FAIL() << "Creating tesselation evaluation shader binary failed.";
462     }
463 
464     GLint loadResult;
465     // Create vertex shader and load binary
466     GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
467     glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
468                    mVertexShaderBinary.size());
469     glGetShaderiv(vertShader, GL_COMPILE_STATUS, &loadResult);
470     ASSERT_GL_TRUE(loadResult);
471 
472     // Create geometry shader and load binary
473     GLuint geoShader = glCreateShader(GL_GEOMETRY_SHADER);
474     glShaderBinary(1, &geoShader, GL_SHADER_BINARY_ANGLE, geometryShaderBinary.data(),
475                    geometryShaderBinary.size());
476     glGetShaderiv(geoShader, GL_COMPILE_STATUS, &loadResult);
477     ASSERT_GL_TRUE(loadResult);
478 
479     // Create tesselation control shader and load binary
480     GLuint tcShader = glCreateShader(GL_TESS_CONTROL_SHADER);
481     glShaderBinary(1, &tcShader, GL_SHADER_BINARY_ANGLE, tessControlShaderBinary.data(),
482                    tessControlShaderBinary.size());
483     glGetShaderiv(tcShader, GL_COMPILE_STATUS, &loadResult);
484     ASSERT_GL_TRUE(loadResult);
485 
486     // Create tesselation evaluation and load binary
487     GLuint teShader = glCreateShader(GL_TESS_EVALUATION_SHADER);
488     glShaderBinary(1, &teShader, GL_SHADER_BINARY_ANGLE, tessEvaluationShaderBinary.data(),
489                    tessEvaluationShaderBinary.size());
490     glGetShaderiv(teShader, GL_COMPILE_STATUS, &loadResult);
491     ASSERT_GL_TRUE(loadResult);
492 
493     // Create fragment shader and load binary
494     GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
495     glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, mFragmentShaderBinary.data(),
496                    mFragmentShaderBinary.size());
497     glGetShaderiv(fragShader, GL_COMPILE_STATUS, &loadResult);
498     ASSERT_GL_TRUE(loadResult);
499 
500     // Create program from the shaders
501     GLuint newProgram = glCreateProgram();
502     glAttachShader(newProgram, vertShader);
503     glAttachShader(newProgram, geoShader);
504     glAttachShader(newProgram, tcShader);
505     glAttachShader(newProgram, teShader);
506     glAttachShader(newProgram, fragShader);
507     glLinkProgram(newProgram);
508     newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
509 
510     // Test with a basic draw
511     drawPatches(newProgram, "a_position", 0.5f, 1.0f, GL_FALSE);
512     ASSERT_GL_NO_ERROR();
513     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
514 }
515 
516 // Test glShaderBinary with complex shaders
TEST_P(ShaderBinaryTestES31,ComplexShader)517 TEST_P(ShaderBinaryTestES31, ComplexShader)
518 {
519     ANGLE_SKIP_TEST_IF(!supported());
520 
521     const char *kVertexShader = R"(#version 310 es
522 uniform vec2 table[4];
523 
524 in vec2 position;
525 in vec4 aTest;
526 
527 out vec2 texCoord;
528 out vec4 vTest;
529 
530 void main()
531 {
532     gl_Position = vec4(position + table[gl_InstanceID], 0, 1);
533     vTest       = aTest;
534     texCoord    = gl_Position.xy * 0.5 + vec2(0.5);
535 })";
536 
537     const char *kFragmentShader = R"(#version 310 es
538 precision mediump float;
539 
540 struct S { sampler2D sampler; };
541 uniform S uStruct;
542 
543 layout (binding = 0, std430) buffer Input {
544     float sampledInput;
545 };
546 
547 in vec2 texCoord;
548 in vec4 vTest;
549 out vec4 my_FragColor;
550 
551 void main()
552 {
553     if (sampledInput == 1.0)
554     {
555         my_FragColor = texture(uStruct.sampler, texCoord);
556     }
557     else
558     {
559         my_FragColor = vTest;
560     }
561 })";
562 
563     // Generate shader binaries:
564     ShShaderSpec spec     = SH_GLES3_1_SPEC;
565     ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
566 
567     // Vertex shader:
568     sh::ShaderBinaryBlob vertexShaderBinary;
569     ShHandle vertexCompiler = sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &mResources);
570     bool compileResult = sh::GetShaderBinary(vertexCompiler, &kVertexShader, 1, mCompileOptions,
571                                              &vertexShaderBinary);
572     ASSERT_TRUE(compileResult);
573 
574     if (vertexShaderBinary.size() == 0)
575     {
576         FAIL() << "Creating vertex shader binary failed.";
577     }
578 
579     // Fragment shader:
580     sh::ShaderBinaryBlob fragmentShaderBinary;
581     ShHandle fragmentCompiler =
582         sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
583     compileResult = sh::GetShaderBinary(fragmentCompiler, &kFragmentShader, 1, mCompileOptions,
584                                         &fragmentShaderBinary);
585     ASSERT_TRUE(compileResult);
586 
587     if (fragmentShaderBinary.size() == 0)
588     {
589         FAIL() << "Creating fragment shader binary failed.";
590     }
591 
592     GLint loadResult;
593     // Create vertex shader and load binary
594     GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
595     glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, vertexShaderBinary.data(),
596                    vertexShaderBinary.size());
597     glGetShaderiv(vertShader, GL_COMPILE_STATUS, &loadResult);
598     ASSERT_GL_TRUE(loadResult);
599 
600     // Create fragment shader and load binary
601     GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
602     glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, fragmentShaderBinary.data(),
603                    fragmentShaderBinary.size());
604     glGetShaderiv(fragShader, GL_COMPILE_STATUS, &loadResult);
605     ASSERT_GL_TRUE(loadResult);
606 
607     // Create program from the shaders
608     GLuint newProgram = glCreateProgram();
609     glAttachShader(newProgram, vertShader);
610     glAttachShader(newProgram, fragShader);
611     glLinkProgram(newProgram);
612     newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
613     glUseProgram(newProgram);
614     ASSERT_GL_NO_ERROR();
615 
616     // Setup instance offset table
617     constexpr GLfloat table[] = {-1, -1, -1, 1, 1, -1, 1, 1};
618     GLint tableMemberLoc      = glGetUniformLocation(newProgram, "table");
619     ASSERT_NE(-1, tableMemberLoc);
620     glUniform2fv(tableMemberLoc, 4, table);
621     ASSERT_GL_NO_ERROR();
622 
623     // Setup red testure and sampler uniform
624     GLTexture tex;
625     glActiveTexture(GL_TEXTURE0);
626     glBindTexture(GL_TEXTURE_2D, tex);
627     GLubyte texData[] = {255u, 0u, 0u, 255u};
628     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData);
629 
630     GLint samplerMemberLoc = glGetUniformLocation(newProgram, "uStruct.sampler");
631     ASSERT_NE(-1, samplerMemberLoc);
632     glUniform1i(samplerMemberLoc, 0);
633     ASSERT_GL_NO_ERROR();
634 
635     // Setup the `aTest` attribute to blue
636     std::vector<Vector4> kInputAttribute(6, Vector4(0.0f, 0.0f, 1.0f, 1.0f));
637     GLint positionLocation = glGetAttribLocation(newProgram, "aTest");
638     glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, kInputAttribute.data());
639     glEnableVertexAttribArray(positionLocation);
640 
641     // Setup 'sampledInput' storage buffer to 1
642     constexpr GLfloat kInputDataOne = 1.0f;
643     GLBuffer input;
644     glBindBuffer(GL_SHADER_STORAGE_BUFFER, input);
645     glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat), &kInputDataOne, GL_STATIC_COPY);
646     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, input);
647     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
648     ASSERT_GL_NO_ERROR();
649 
650     // Test sampling texture with an instanced draw
651     drawQuadInstanced(newProgram, "position", 0.5f, 0.5f, GL_FALSE, 4);
652     ASSERT_GL_NO_ERROR();
653     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
654 
655     // Setup 'sampledInput' storage buffer to 0
656     constexpr GLfloat kInputDataZero = 0.0f;
657     glBindBuffer(GL_SHADER_STORAGE_BUFFER, input);
658     glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat), &kInputDataZero, GL_STATIC_COPY);
659     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, input);
660     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
661     ASSERT_GL_NO_ERROR();
662 
663     // Test color attribute with an instanced draw
664     drawQuadInstanced(newProgram, "position", 0.5f, 0.5f, GL_FALSE, 4);
665     ASSERT_GL_NO_ERROR();
666     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
667 }
668 
669 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
670 // tests should be run against.
671 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(ShaderBinaryTest);
672 
673 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ShaderBinaryTestES31);
674 ANGLE_INSTANTIATE_TEST_ES31(ShaderBinaryTestES31);
675