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