1 //
2 // Copyright 2015 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 <stdint.h>
10 #include <memory>
11
12 #include "common/string_utils.h"
13 #include "test_utils/angle_test_configs.h"
14 #include "test_utils/gl_raii.h"
15 #include "util/EGLWindow.h"
16 #include "util/OSWindow.h"
17
18 using namespace angle;
19
20 class ProgramBinaryTest : public ANGLETest<>
21 {
22 protected:
ProgramBinaryTest()23 ProgramBinaryTest()
24 {
25 setWindowWidth(128);
26 setWindowHeight(128);
27 setConfigRedBits(8);
28 setConfigGreenBits(8);
29 setConfigBlueBits(8);
30 setConfigAlphaBits(8);
31
32 // Test flakiness was noticed when reusing displays.
33 forceNewDisplay();
34 }
35
testSetUp()36 void testSetUp() override
37 {
38 mProgram = CompileProgram(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
39 if (mProgram == 0)
40 {
41 FAIL() << "shader compilation failed.";
42 }
43
44 glGenBuffers(1, &mBuffer);
45 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
46 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_STATIC_DRAW);
47 glBindBuffer(GL_ARRAY_BUFFER, 0);
48
49 ASSERT_GL_NO_ERROR();
50 }
51
testTearDown()52 void testTearDown() override
53 {
54 glDeleteProgram(mProgram);
55 glDeleteBuffers(1, &mBuffer);
56 }
57
getAvailableProgramBinaryFormatCount() const58 GLint getAvailableProgramBinaryFormatCount() const
59 {
60 GLint formatCount;
61 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
62 return formatCount;
63 }
64
supported() const65 bool supported() const
66 {
67 if (!IsGLExtensionEnabled("GL_OES_get_program_binary"))
68 {
69 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
70 << std::endl;
71 return false;
72 }
73
74 if (getAvailableProgramBinaryFormatCount() == 0)
75 {
76 std::cout << "Test skipped because no program binary formats are available."
77 << std::endl;
78 return false;
79 }
80
81 return true;
82 }
83
saveAndLoadProgram(GLuint programToSave,GLuint loadedProgram)84 void saveAndLoadProgram(GLuint programToSave, GLuint loadedProgram)
85 {
86 GLint programLength = 0;
87 GLint writtenLength = 0;
88 GLenum binaryFormat = 0;
89
90 glGetProgramiv(programToSave, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
91 EXPECT_GL_NO_ERROR();
92
93 std::vector<uint8_t> binary(programLength);
94 glGetProgramBinaryOES(programToSave, programLength, &writtenLength, &binaryFormat,
95 binary.data());
96 EXPECT_GL_NO_ERROR();
97
98 // The lengths reported by glGetProgramiv and glGetProgramBinaryOES should match
99 EXPECT_EQ(programLength, writtenLength);
100
101 if (writtenLength)
102 {
103 glProgramBinaryOES(loadedProgram, binaryFormat, binary.data(), writtenLength);
104
105 EXPECT_GL_NO_ERROR();
106
107 GLint linkStatus;
108 glGetProgramiv(loadedProgram, GL_LINK_STATUS, &linkStatus);
109 if (linkStatus == 0)
110 {
111 GLint infoLogLength;
112 glGetProgramiv(loadedProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
113
114 if (infoLogLength > 0)
115 {
116 std::vector<GLchar> infoLog(infoLogLength);
117 glGetProgramInfoLog(loadedProgram, static_cast<GLsizei>(infoLog.size()),
118 nullptr, &infoLog[0]);
119 FAIL() << "program link failed: " << &infoLog[0];
120 }
121 else
122 {
123 FAIL() << "program link failed.";
124 }
125 }
126 else
127 {
128 glUseProgram(loadedProgram);
129 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
130
131 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
132 glEnableVertexAttribArray(0);
133 glDrawArrays(GL_POINTS, 0, 1);
134
135 EXPECT_GL_NO_ERROR();
136 }
137 }
138 }
139
140 GLuint mProgram;
141 GLuint mBuffer;
142 };
143
144 // This tests the assumption that float attribs of different size
145 // should not internally cause a vertex shader recompile (for conversion).
TEST_P(ProgramBinaryTest,FloatDynamicShaderSize)146 TEST_P(ProgramBinaryTest, FloatDynamicShaderSize)
147 {
148 if (!supported())
149 {
150 return;
151 }
152
153 glUseProgram(mProgram);
154 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
155
156 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
157 glEnableVertexAttribArray(0);
158 glDrawArrays(GL_POINTS, 0, 1);
159
160 GLint programLength;
161 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
162
163 EXPECT_GL_NO_ERROR();
164
165 for (GLsizei size = 1; size <= 3; size++)
166 {
167 glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 8, nullptr);
168 glEnableVertexAttribArray(0);
169 glDrawArrays(GL_POINTS, 0, 1);
170
171 GLint newProgramLength;
172 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &newProgramLength);
173 EXPECT_GL_NO_ERROR();
174 EXPECT_EQ(programLength, newProgramLength);
175 }
176 }
177
178 // Tests that switching between signed and unsigned un-normalized data doesn't trigger a bug
179 // in the D3D11 back-end.
TEST_P(ProgramBinaryTest,DynamicShadersSignatureBug)180 TEST_P(ProgramBinaryTest, DynamicShadersSignatureBug)
181 {
182 glUseProgram(mProgram);
183 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
184
185 GLint attribLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
186 ASSERT_NE(-1, attribLocation);
187 glEnableVertexAttribArray(attribLocation);
188
189 glVertexAttribPointer(attribLocation, 2, GL_BYTE, GL_FALSE, 0, nullptr);
190 glDrawArrays(GL_POINTS, 0, 1);
191
192 glVertexAttribPointer(attribLocation, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
193 glDrawArrays(GL_POINTS, 0, 1);
194 }
195
196 // This tests the ability to successfully save and load a program binary.
TEST_P(ProgramBinaryTest,SaveAndLoadBinary)197 TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
198 {
199 if (!supported())
200 {
201 return;
202 }
203
204 GLuint programToLoad = glCreateProgram();
205
206 saveAndLoadProgram(mProgram, programToLoad);
207
208 glDeleteProgram(programToLoad);
209 EXPECT_GL_NO_ERROR();
210 }
211
212 // This tests the ability to successfully save and load a program binary and then
213 // save and load from the same program that was loaded.
TEST_P(ProgramBinaryTest,SaveAndLoadBinaryTwice)214 TEST_P(ProgramBinaryTest, SaveAndLoadBinaryTwice)
215 {
216 if (!supported())
217 {
218 return;
219 }
220
221 GLuint programToLoad = glCreateProgram();
222 GLuint programToLoad2 = glCreateProgram();
223
224 saveAndLoadProgram(mProgram, programToLoad);
225 saveAndLoadProgram(programToLoad, programToLoad2);
226
227 glDeleteProgram(programToLoad);
228 glDeleteProgram(programToLoad2);
229 EXPECT_GL_NO_ERROR();
230 }
231
232 // Ensures that we init the compiler before calling ProgramBinary.
TEST_P(ProgramBinaryTest,CallProgramBinaryBeforeLink)233 TEST_P(ProgramBinaryTest, CallProgramBinaryBeforeLink)
234 {
235 if (!supported())
236 {
237 return;
238 }
239
240 // Initialize a simple program.
241 glUseProgram(mProgram);
242
243 GLsizei length = 0;
244 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH, &length);
245 ASSERT_GL_NO_ERROR();
246 ASSERT_GT(length, 0);
247
248 GLsizei readLength = 0;
249 GLenum binaryFormat = GL_NONE;
250 std::vector<uint8_t> binaryBlob(length);
251 glGetProgramBinaryOES(mProgram, length, &readLength, &binaryFormat, binaryBlob.data());
252 ASSERT_GL_NO_ERROR();
253
254 // Shutdown and restart GL entirely.
255 recreateTestFixture();
256
257 ANGLE_GL_BINARY_OES_PROGRAM(binaryProgram, binaryBlob, binaryFormat);
258 ASSERT_GL_NO_ERROR();
259
260 drawQuad(binaryProgram, essl1_shaders::PositionAttrib(), 0.5f);
261 ASSERT_GL_NO_ERROR();
262 }
263
264 // Test that unlinked programs have a binary size of 0
TEST_P(ProgramBinaryTest,ZeroSizedUnlinkedBinary)265 TEST_P(ProgramBinaryTest, ZeroSizedUnlinkedBinary)
266 {
267 ANGLE_SKIP_TEST_IF(!supported());
268
269 ANGLE_GL_EMPTY_PROGRAM(program);
270 GLsizei length = 0;
271 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &length);
272 ASSERT_EQ(0, length);
273 }
274
275 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
276 // tests should be run against.
277 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
278 ProgramBinaryTest,
279 ES3_VULKAN().disable(Feature::EnablePipelineCacheDataCompression));
280
281 class ProgramBinaryES3Test : public ProgramBinaryTest
282 {
283 protected:
ProgramBinaryES3Test()284 ProgramBinaryES3Test()
285 {
286 // Test flakiness was noticed when reusing displays.
287 forceNewDisplay();
288 }
289
290 void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
291 };
292
293 class ProgramBinaryES31Test : public ANGLETest<>
294 {
295 protected:
ProgramBinaryES31Test()296 ProgramBinaryES31Test()
297 {
298 setWindowWidth(128);
299 setWindowHeight(128);
300 setConfigRedBits(8);
301 setConfigGreenBits(8);
302 setConfigBlueBits(8);
303 setConfigAlphaBits(8);
304
305 // Test flakiness was noticed when reusing displays.
306 forceNewDisplay();
307 }
308
getAvailableProgramBinaryFormatCount() const309 GLint getAvailableProgramBinaryFormatCount() const
310 {
311 GLint formatCount;
312 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
313 return formatCount;
314 }
315 };
316
testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)317 void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
318 {
319 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
320
321 constexpr char kVS[] = R"(#version 300 es
322 uniform block {
323 float f;
324 };
325 in vec4 position;
326 out vec4 color;
327 void main() {
328 gl_Position = position;
329 color = vec4(f, f, f, 1);
330 })";
331
332 constexpr char kFS[] = R"(#version 300 es
333 precision mediump float;
334 in vec4 color;
335 out vec4 colorOut;
336 void main() {
337 colorOut = color;
338 })";
339
340 // Init and draw with the program.
341 ANGLE_GL_PROGRAM(program, kVS, kFS);
342
343 float fData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
344 GLuint bindIndex = 2;
345
346 GLBuffer ubo;
347 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
348 glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
349 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo, 0, sizeof(fData));
350
351 GLint blockIndex = glGetUniformBlockIndex(program, "block");
352 ASSERT_NE(-1, blockIndex);
353
354 glUniformBlockBinding(program, blockIndex, bindIndex);
355
356 glClearColor(1.0, 0.0, 0.0, 1.0);
357 glClear(GL_COLOR_BUFFER_BIT);
358 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
359
360 if (drawWithProgramFirst)
361 {
362 drawQuad(program, "position", 0.5f);
363 ASSERT_GL_NO_ERROR();
364 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
365 }
366
367 // Read back the binary.
368 GLint programLength = 0;
369 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
370 ASSERT_GL_NO_ERROR();
371
372 GLsizei readLength = 0;
373 GLenum binaryFormat = GL_NONE;
374 std::vector<uint8_t> binary(programLength);
375 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
376 ASSERT_GL_NO_ERROR();
377
378 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
379
380 // Load a new program with the binary and draw.
381 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
382
383 // Reconfigure the block binding, which is reset after a call to glProgramBinary.
384 glUniformBlockBinding(binaryProgram, blockIndex, bindIndex);
385
386 glClearColor(1.0, 0.0, 0.0, 1.0);
387 glClear(GL_COLOR_BUFFER_BIT);
388 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
389
390 drawQuad(binaryProgram, "position", 0.5f);
391 ASSERT_GL_NO_ERROR();
392 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
393 }
394
395 // Tests that saving and loading a program perserves uniform block binding info.
TEST_P(ProgramBinaryES3Test,UniformBlockBindingWithDraw)396 TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
397 {
398 testBinaryAndUBOBlockIndexes(true);
399 }
400
401 // Same as UniformBlockBindingWithDraw, but does not do an initial draw with the program. Covers an
402 // ANGLE crash. http://anglebug.com/42260591
TEST_P(ProgramBinaryES3Test,UniformBlockBindingNoDraw)403 TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
404 {
405 testBinaryAndUBOBlockIndexes(false);
406 }
407
408 // Same as UniformBlockBindingWithDraw, but specifies the binding in the shader itself.
TEST_P(ProgramBinaryES31Test,UniformBlockBindingSpecifiedInShader)409 TEST_P(ProgramBinaryES31Test, UniformBlockBindingSpecifiedInShader)
410 {
411 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
412
413 constexpr char kVS[] = R"(#version 310 es
414 layout(binding = 1) uniform block {
415 vec4 v;
416 };
417 in vec4 position;
418 out vec4 color;
419 void main() {
420 gl_Position = position;
421 color = v;
422 })";
423
424 constexpr char kFS[] = R"(#version 310 es
425 precision mediump float;
426 in vec4 color;
427 out vec4 colorOut;
428 void main() {
429 colorOut = color;
430 })";
431
432 // Init and draw with the program.
433 ANGLE_GL_PROGRAM(program, kVS, kFS);
434
435 constexpr std::array<float, 4> kBlue = {0, 0, 1, 1};
436 GLBuffer blue;
437 glBindBuffer(GL_UNIFORM_BUFFER, blue);
438 glBufferData(GL_UNIFORM_BUFFER, sizeof(kBlue), kBlue.data(), GL_STATIC_DRAW);
439 glBindBufferBase(GL_UNIFORM_BUFFER, 1, blue);
440
441 GLint blockIndex = glGetUniformBlockIndex(program, "block");
442 ASSERT_NE(-1, blockIndex);
443
444 glClearColor(1.0, 0.0, 0.0, 1.0);
445 glClear(GL_COLOR_BUFFER_BIT);
446 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
447
448 drawQuad(program, "position", 0.5f);
449 ASSERT_GL_NO_ERROR();
450 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
451
452 // Read back the binary.
453 GLint programLength = 0;
454 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
455 ASSERT_GL_NO_ERROR();
456
457 GLsizei readLength = 0;
458 GLenum binaryFormat = GL_NONE;
459 std::vector<uint8_t> binary(programLength);
460 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
461 ASSERT_GL_NO_ERROR();
462
463 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
464
465 // Load a new program with the binary and draw.
466 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
467
468 glClear(GL_COLOR_BUFFER_BIT);
469 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
470
471 drawQuad(binaryProgram, "position", 0.5f);
472 ASSERT_GL_NO_ERROR();
473 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
474 }
475
476 // Ensure that uniform block bindings are reset to their original value on program binary
TEST_P(ProgramBinaryES31Test,UniformBlockBindingResetOnReload)477 TEST_P(ProgramBinaryES31Test, UniformBlockBindingResetOnReload)
478 {
479 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
480
481 constexpr char kVS[] = R"(#version 310 es
482 layout(binding = 1) uniform block {
483 vec4 v;
484 };
485 in vec4 position;
486 out vec4 color;
487 void main() {
488 gl_Position = position;
489 color = v;
490 })";
491
492 constexpr char kFS[] = R"(#version 310 es
493 precision mediump float;
494 in vec4 color;
495 out vec4 colorOut;
496 void main() {
497 colorOut = color;
498 })";
499
500 // Init and draw with the program.
501 ANGLE_GL_PROGRAM(program, kVS, kFS);
502
503 constexpr std::array<float, 4> kBlue = {0, 0, 1, 1};
504 constexpr std::array<float, 4> kGreen = {0, 1, 0, 1};
505 GLBuffer blue, green;
506 glBindBuffer(GL_UNIFORM_BUFFER, blue);
507 glBufferData(GL_UNIFORM_BUFFER, sizeof(kBlue), kBlue.data(), GL_STATIC_DRAW);
508 glBindBuffer(GL_UNIFORM_BUFFER, green);
509 glBufferData(GL_UNIFORM_BUFFER, sizeof(kGreen), kGreen.data(), GL_STATIC_DRAW);
510
511 // Bind one buffer to binding 1 and another to binding 2
512 glBindBufferBase(GL_UNIFORM_BUFFER, 1, blue);
513 glBindBufferBase(GL_UNIFORM_BUFFER, 2, green);
514
515 GLint blockIndex = glGetUniformBlockIndex(program, "block");
516 ASSERT_NE(-1, blockIndex);
517
518 // Initially, remap the block to binding 2
519 glUniformBlockBinding(program, blockIndex, 2);
520
521 glClearColor(1.0, 0.0, 0.0, 1.0);
522 glClear(GL_COLOR_BUFFER_BIT);
523 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
524
525 drawQuad(program, "position", 0.5f);
526 ASSERT_GL_NO_ERROR();
527 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
528
529 // Read back the binary.
530 GLint programLength = 0;
531 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
532 ASSERT_GL_NO_ERROR();
533
534 GLsizei readLength = 0;
535 GLenum binaryFormat = GL_NONE;
536 std::vector<uint8_t> binary(programLength);
537 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
538 ASSERT_GL_NO_ERROR();
539
540 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
541
542 // Load a new program with the binary and draw. On reset, the binding should be reset back to 1
543 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
544
545 glClear(GL_COLOR_BUFFER_BIT);
546 drawQuad(binaryProgram, "position", 0.5f);
547 ASSERT_GL_NO_ERROR();
548 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
549 }
550
551 // Test the shaders with arrays-of-struct uniforms are properly saved and restored
TEST_P(ProgramBinaryES3Test,TestArrayOfStructUniform)552 TEST_P(ProgramBinaryES3Test, TestArrayOfStructUniform)
553 {
554 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
555
556 constexpr char kVS[] =
557 "#version 300 es\n"
558 "in highp vec4 position;\n"
559 "out mediump float v_vtxOut;\n"
560 "\n"
561 "struct structType\n"
562 "{\n"
563 " mediump vec4 m0;\n"
564 " mediump vec4 m1;\n"
565 "};\n"
566 "uniform structType u_var[3];\n"
567 "\n"
568 "mediump float compare_float(mediump float a, mediump float b)\n"
569 "{\n"
570 " return abs(a - b) < 0.05 ? 1.0 : 0.0;\n"
571 "}\n"
572 "mediump float compare_vec4(mediump vec4 a, mediump vec4 b)\n"
573 "{\n"
574 " return compare_float(a.x, b.x)*compare_float(a.y, b.y)*\n"
575 " compare_float(a.z, b.z)*compare_float(a.w, b.w);\n"
576 "}\n"
577 "\n"
578 "void main (void)\n"
579 "{\n"
580 " gl_Position = position;\n"
581 " v_vtxOut = 1.0;\n"
582 " v_vtxOut *= compare_vec4(u_var[0].m0, vec4(0.15, 0.52, 0.26, 0.35));\n"
583 " v_vtxOut *= compare_vec4(u_var[0].m1, vec4(0.88, 0.09, 0.30, 0.61));\n"
584 " v_vtxOut *= compare_vec4(u_var[1].m0, vec4(0.85, 0.59, 0.33, 0.71));\n"
585 " v_vtxOut *= compare_vec4(u_var[1].m1, vec4(0.62, 0.89, 0.09, 0.99));\n"
586 " v_vtxOut *= compare_vec4(u_var[2].m0, vec4(0.53, 0.89, 0.01, 0.08));\n"
587 " v_vtxOut *= compare_vec4(u_var[2].m1, vec4(0.26, 0.72, 0.60, 0.12));\n"
588 "}";
589
590 constexpr char kFS[] =
591 "#version 300 es\n"
592 "in mediump float v_vtxOut;\n"
593 "\n"
594 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
595 "\n"
596 "void main (void)\n"
597 "{\n"
598 " mediump float result = v_vtxOut;\n"
599 " dEQP_FragColor = vec4(result, result, result, 1.0);\n"
600 "}";
601
602 // Init and draw with the program.
603 ANGLE_GL_PROGRAM(program, kVS, kFS);
604
605 glUseProgram(program);
606
607 int location = glGetUniformLocation(program, "u_var[0].m0");
608 ASSERT_NE(location, -1);
609 glUniform4f(location, 0.15, 0.52, 0.26, 0.35);
610 location = glGetUniformLocation(program, "u_var[0].m1");
611 ASSERT_NE(location, -1);
612 glUniform4f(location, 0.88, 0.09, 0.30, 0.61);
613 location = glGetUniformLocation(program, "u_var[1].m0");
614 ASSERT_NE(location, -1);
615 glUniform4f(location, 0.85, 0.59, 0.33, 0.71);
616 location = glGetUniformLocation(program, "u_var[1].m1");
617 ASSERT_NE(location, -1);
618 glUniform4f(location, 0.62, 0.89, 0.09, 0.99);
619 location = glGetUniformLocation(program, "u_var[2].m0");
620 ASSERT_NE(location, -1);
621 glUniform4f(location, 0.53, 0.89, 0.01, 0.08);
622 location = glGetUniformLocation(program, "u_var[2].m1");
623 ASSERT_NE(location, -1);
624 glUniform4f(location, 0.26, 0.72, 0.60, 0.12);
625 ASSERT_GL_NO_ERROR();
626
627 // Clear and draw with the original program:
628 glClearColor(1.0, 0.0, 0.0, 1.0);
629 glClear(GL_COLOR_BUFFER_BIT);
630 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
631 drawQuad(program, "position", 0.5f);
632 ASSERT_GL_NO_ERROR();
633 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
634
635 // Read back the binary.
636 GLint programLength = 0;
637 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
638 ASSERT_GL_NO_ERROR();
639
640 GLsizei readLength = 0;
641 GLenum binaryFormat = GL_NONE;
642 std::vector<uint8_t> binary(programLength);
643 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
644 ASSERT_GL_NO_ERROR();
645
646 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
647
648 // Load a new program with the binary and draw.
649 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
650
651 glUseProgram(binaryProgram);
652
653 location = glGetUniformLocation(binaryProgram, "u_var[0].m0");
654 ASSERT_NE(location, -1);
655 glUniform4f(location, 0.15, 0.52, 0.26, 0.35);
656 location = glGetUniformLocation(binaryProgram, "u_var[0].m1");
657 ASSERT_NE(location, -1);
658 glUniform4f(location, 0.88, 0.09, 0.30, 0.61);
659 location = glGetUniformLocation(binaryProgram, "u_var[1].m0");
660 ASSERT_NE(location, -1);
661 glUniform4f(location, 0.85, 0.59, 0.33, 0.71);
662 location = glGetUniformLocation(binaryProgram, "u_var[1].m1");
663 ASSERT_NE(location, -1);
664 glUniform4f(location, 0.62, 0.89, 0.09, 0.99);
665 location = glGetUniformLocation(binaryProgram, "u_var[2].m0");
666 ASSERT_NE(location, -1);
667 glUniform4f(location, 0.53, 0.89, 0.01, 0.08);
668 location = glGetUniformLocation(binaryProgram, "u_var[2].m1");
669 ASSERT_NE(location, -1);
670 glUniform4f(location, 0.26, 0.72, 0.60, 0.12);
671 ASSERT_GL_NO_ERROR();
672
673 // Clear and draw with the restored program:
674 glClearColor(1.0, 0.0, 0.0, 1.0);
675 glClear(GL_COLOR_BUFFER_BIT);
676 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
677 drawQuad(binaryProgram, "position", 0.5f);
678 ASSERT_GL_NO_ERROR();
679 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
680 }
681
682 // Verify that saving/loading binary with detached shaders followed by indexed
683 // drawing works.
TEST_P(ProgramBinaryES3Test,SaveAndLoadDetachedShaders)684 TEST_P(ProgramBinaryES3Test, SaveAndLoadDetachedShaders)
685 {
686 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
687
688 // We use shaders with the "flat" qualifier, to ensure that "flat" behaves
689 // across save/load. This is primarily to catch possible bugs in the Metal
690 // backend, where it needs to detect "flat" at shader link time and
691 // preserve that detection across binary save/load.
692 constexpr char kVS[] = R"(#version 300 es
693 precision highp float;
694
695 in vec4 a_position;
696 flat out vec4 v_color;
697
698 const vec4 colors[4] = vec4[](
699 vec4(0.0f, 0.0f, 1.0f, 1.0f),
700 vec4(0.0f, 0.0f, 1.0f, 1.0f),
701 vec4(0.0f, 1.0f, 0.0f, 1.0f),
702 vec4(0.0f, 1.0f, 0.0f, 1.0f)
703 );
704
705 void main()
706 {
707 v_color = colors[gl_VertexID];
708 gl_Position = a_position;
709 }
710 )";
711
712 constexpr char kFS[] = R"(#version 300 es
713 precision highp float;
714
715 flat in vec4 v_color;
716 out vec4 o_color;
717
718 void main()
719 {
720 o_color = v_color;
721 }
722 )";
723
724 const auto &vertices = GetIndexedQuadVertices();
725
726 GLBuffer vertexBuffer;
727 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
728 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
729 GL_STATIC_DRAW);
730
731 GLBuffer indexBuffer;
732 const auto &indices = GetQuadIndices();
733 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
734 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
735 GL_STATIC_DRAW);
736 ASSERT_GL_NO_ERROR();
737
738 GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, kVS);
739 GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, kFS);
740 ASSERT_NE(0u, vertexShader);
741 ASSERT_NE(0u, fragmentShader);
742
743 GLuint program = glCreateProgram();
744 glAttachShader(program, vertexShader);
745 glAttachShader(program, fragmentShader);
746
747 glLinkProgram(program);
748
749 GLint linkStatus;
750 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
751 EXPECT_EQ(GL_TRUE, linkStatus);
752
753 glDetachShader(program, vertexShader);
754 glDetachShader(program, fragmentShader);
755 glDeleteShader(vertexShader);
756 glDeleteShader(fragmentShader);
757 ASSERT_GL_NO_ERROR();
758
759 GLuint loadedProgram = glCreateProgram();
760 saveAndLoadProgram(program, loadedProgram);
761 glDeleteProgram(program);
762
763 ASSERT_EQ(glIsProgram(loadedProgram), GL_TRUE);
764 glUseProgram(loadedProgram);
765 ASSERT_GL_NO_ERROR();
766
767 GLint posLocation = glGetAttribLocation(loadedProgram, "a_position");
768 ASSERT_NE(-1, posLocation);
769
770 GLVertexArray vertexArray;
771 glBindVertexArray(vertexArray);
772 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
773 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
774 glEnableVertexAttribArray(posLocation);
775 ASSERT_GL_NO_ERROR();
776
777 glClearColor(1.0, 0.0, 0.0, 1.0);
778 glClear(GL_COLOR_BUFFER_BIT);
779 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
780
781 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
782 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
783 ASSERT_GL_NO_ERROR();
784
785 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
786
787 glDeleteProgram(loadedProgram);
788 ASSERT_GL_NO_ERROR();
789 }
790
791 // Tests the difference between uniform static and active use
TEST_P(ProgramBinaryES3Test,ActiveUniformShader)792 TEST_P(ProgramBinaryES3Test, ActiveUniformShader)
793 {
794 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
795
796 constexpr char kVS[] =
797 "#version 300 es\n"
798 "in vec4 position;\n"
799 "void main() {\n"
800 " gl_Position = position;\n"
801 "}";
802
803 constexpr char kFS[] =
804 "#version 300 es\n"
805 "precision mediump float;\n"
806 "uniform float values[2];\n"
807 "out vec4 color;\n"
808 "bool isZero(float value) {\n"
809 " return value == 0.0f;\n"
810 "}\n"
811 "void main() {\n"
812 " color = isZero(values[1]) ? vec4(1.0f,0.0f,0.0f,1.0f) : vec4(0.0f,1.0f,0.0f,1.0f);\n"
813 "}";
814
815 // Init and draw with the program.
816 ANGLE_GL_PROGRAM(program, kVS, kFS);
817
818 GLint valuesLoc = glGetUniformLocation(program, "values");
819 ASSERT_NE(-1, valuesLoc);
820
821 glUseProgram(program);
822 GLfloat values[2] = {0.5f, 1.0f};
823 glUniform1fv(valuesLoc, 2, values);
824 ASSERT_GL_NO_ERROR();
825
826 glClearColor(1.0, 0.0, 0.0, 1.0);
827 glClear(GL_COLOR_BUFFER_BIT);
828 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
829
830 drawQuad(program, "position", 0.5f);
831 ASSERT_GL_NO_ERROR();
832 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
833
834 // Read back the binary.
835 GLint programLength = 0;
836 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
837 ASSERT_GL_NO_ERROR();
838
839 GLsizei readLength = 0;
840 GLenum binaryFormat = GL_NONE;
841 std::vector<uint8_t> binary(programLength);
842 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
843 ASSERT_GL_NO_ERROR();
844
845 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
846
847 // Load a new program with the binary and draw.
848 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
849
850 valuesLoc = glGetUniformLocation(program, "values");
851 ASSERT_NE(-1, valuesLoc);
852
853 glUseProgram(binaryProgram);
854 GLfloat values2[2] = {0.1f, 1.0f};
855 glUniform1fv(valuesLoc, 2, values2);
856 ASSERT_GL_NO_ERROR();
857
858 glClearColor(1.0, 0.0, 0.0, 1.0);
859 glClear(GL_COLOR_BUFFER_BIT);
860 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
861
862 drawQuad(binaryProgram, "position", 0.5f);
863 ASSERT_GL_NO_ERROR();
864 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
865 }
866
867 // Test that uses many uniforms in the shaders
TEST_P(ProgramBinaryES3Test,BinaryWithLargeUniformCount)868 TEST_P(ProgramBinaryES3Test, BinaryWithLargeUniformCount)
869 {
870 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
871
872 constexpr char kVS[] =
873 "#version 300 es\n"
874 "uniform float redVS; \n"
875 "uniform block0 {\n"
876 " float val0;\n"
877 "};\n"
878 "uniform float greenVS; \n"
879 "uniform float blueVS; \n"
880 "in vec4 position;\n"
881 "out vec4 color;\n"
882 "void main() {\n"
883 " gl_Position = position;\n"
884 " color = vec4(redVS + val0, greenVS, blueVS, 1.0f);\n"
885 "}";
886
887 constexpr char kFS[] =
888 "#version 300 es\n"
889 "precision mediump float;\n"
890 "uniform float redFS; \n"
891 "uniform float greenFS; \n"
892 "uniform block1 {\n"
893 " float val1;\n"
894 " float val2;\n"
895 "};\n"
896 "uniform float blueFS; \n"
897 "in vec4 color;\n"
898 "out vec4 colorOut;\n"
899 "void main() {\n"
900 " colorOut = vec4(color.r + redFS,\n"
901 " color.g + greenFS + val1,\n"
902 " color.b + blueFS + val2, \n"
903 " color.a);\n"
904 "}";
905
906 // Init and draw with the program.
907 ANGLE_GL_PROGRAM(program, kVS, kFS);
908
909 float block0Data[4] = {-0.7f, 1.0f, 1.0f, 1.0f};
910 float block1Data[4] = {0.4f, -0.8f, 1.0f, 1.0f};
911 GLuint bindIndex0 = 5;
912 GLuint bindIndex1 = 2;
913
914 GLBuffer ubo0;
915 glBindBuffer(GL_UNIFORM_BUFFER, ubo0);
916 glBufferData(GL_UNIFORM_BUFFER, sizeof(block0Data), &block0Data, GL_STATIC_DRAW);
917 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex0, ubo0, 0, sizeof(block0Data));
918 ASSERT_GL_NO_ERROR();
919
920 GLBuffer ubo1;
921 glBindBuffer(GL_UNIFORM_BUFFER, ubo1);
922 glBufferData(GL_UNIFORM_BUFFER, sizeof(block1Data), &block1Data, GL_STATIC_DRAW);
923 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex1, ubo1, 0, sizeof(block1Data));
924 ASSERT_GL_NO_ERROR();
925
926 GLint block0Index = glGetUniformBlockIndex(program, "block0");
927 ASSERT_NE(-1, block0Index);
928
929 GLint block1Index = glGetUniformBlockIndex(program, "block1");
930 ASSERT_NE(-1, block1Index);
931
932 glUniformBlockBinding(program, block0Index, bindIndex0);
933 glUniformBlockBinding(program, block1Index, bindIndex1);
934 ASSERT_GL_NO_ERROR();
935
936 GLint redVSLoc = glGetUniformLocation(program, "redVS");
937 ASSERT_NE(-1, redVSLoc);
938 GLint greenVSLoc = glGetUniformLocation(program, "greenVS");
939 ASSERT_NE(-1, greenVSLoc);
940 GLint blueVSLoc = glGetUniformLocation(program, "blueVS");
941 ASSERT_NE(-1, blueVSLoc);
942 GLint redFSLoc = glGetUniformLocation(program, "redFS");
943 ASSERT_NE(-1, redFSLoc);
944 GLint greenFSLoc = glGetUniformLocation(program, "greenFS");
945 ASSERT_NE(-1, greenFSLoc);
946 GLint blueFSLoc = glGetUniformLocation(program, "blueFS");
947 ASSERT_NE(-1, blueFSLoc);
948
949 glUseProgram(program);
950 glUniform1f(redVSLoc, 0.6f);
951 glUniform1f(greenVSLoc, 0.2f);
952 glUniform1f(blueVSLoc, 1.1f);
953 glUniform1f(redFSLoc, 0.1f);
954 glUniform1f(greenFSLoc, 0.4f);
955 glUniform1f(blueFSLoc, 0.7f);
956 ASSERT_GL_NO_ERROR();
957
958 glClearColor(1.0, 0.0, 0.0, 1.0);
959 glClear(GL_COLOR_BUFFER_BIT);
960 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
961
962 drawQuad(program, "position", 0.5f);
963 ASSERT_GL_NO_ERROR();
964 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
965
966 // Read back the binary.
967 GLint programLength = 0;
968 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
969 ASSERT_GL_NO_ERROR();
970
971 GLsizei readLength = 0;
972 GLenum binaryFormat = GL_NONE;
973 std::vector<uint8_t> binary(programLength);
974 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
975 ASSERT_GL_NO_ERROR();
976
977 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
978
979 // Load a new program with the binary and draw.
980 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
981
982 glUniformBlockBinding(binaryProgram, block0Index, bindIndex0);
983 glUniformBlockBinding(binaryProgram, block1Index, bindIndex1);
984
985 redVSLoc = glGetUniformLocation(binaryProgram, "redVS");
986 ASSERT_NE(-1, redVSLoc);
987 greenVSLoc = glGetUniformLocation(binaryProgram, "greenVS");
988 ASSERT_NE(-1, greenVSLoc);
989 blueVSLoc = glGetUniformLocation(binaryProgram, "blueVS");
990 ASSERT_NE(-1, blueVSLoc);
991 redFSLoc = glGetUniformLocation(binaryProgram, "redFS");
992 ASSERT_NE(-1, redFSLoc);
993 greenFSLoc = glGetUniformLocation(binaryProgram, "greenFS");
994 ASSERT_NE(-1, greenFSLoc);
995 blueFSLoc = glGetUniformLocation(binaryProgram, "blueFS");
996 ASSERT_NE(-1, blueFSLoc);
997
998 glUseProgram(binaryProgram);
999 glUniform1f(redVSLoc, 0.2f);
1000 glUniform1f(greenVSLoc, -0.6f);
1001 glUniform1f(blueVSLoc, 1.0f);
1002 glUniform1f(redFSLoc, 1.5f);
1003 glUniform1f(greenFSLoc, 0.2f);
1004 glUniform1f(blueFSLoc, 0.8f);
1005 ASSERT_GL_NO_ERROR();
1006
1007 glClearColor(1.0, 0.0, 0.0, 1.0);
1008 glClear(GL_COLOR_BUFFER_BIT);
1009 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1010
1011 drawQuad(binaryProgram, "position", 0.5f);
1012 ASSERT_GL_NO_ERROR();
1013 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
1014 }
1015
1016 // Test that sampler texelFetch references are saved and loaded correctly
TEST_P(ProgramBinaryTest,SRGBDecodeWithSamplerAndTexelFetchTest)1017 TEST_P(ProgramBinaryTest, SRGBDecodeWithSamplerAndTexelFetchTest)
1018 {
1019 if (!supported())
1020 {
1021 return;
1022 }
1023
1024 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
1025 getClientMajorVersion() < 3);
1026
1027 // These OpenGL drivers appear not to respect the texelFetch exception
1028 // http://anglebug.com/42263564
1029 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
1030 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsWindows());
1031 ANGLE_SKIP_TEST_IF(IsOpenGL() && (IsNVIDIA() || IsARM64()) && IsMac());
1032 ANGLE_SKIP_TEST_IF(IsOpenGLES() && IsNexus5X());
1033
1034 constexpr char kVS[] =
1035 "#version 300 es\n"
1036 "precision highp float;\n"
1037 "in vec4 position;\n"
1038 "\n"
1039 "void main()\n"
1040 "{\n"
1041 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
1042 "}\n";
1043
1044 constexpr char kFS[] =
1045 "#version 300 es\n"
1046 "precision highp float;\n"
1047 "uniform sampler2D tex;\n"
1048 "in vec2 texcoord;\n"
1049 "out vec4 out_color;\n"
1050 "\n"
1051 "void main()\n"
1052 "{\n"
1053 " out_color = texelFetch(tex, ivec2(0, 0), 0);\n"
1054 "}\n";
1055
1056 GLProgram program;
1057 program.makeRaster(kVS, kFS);
1058 ASSERT_NE(0u, program);
1059
1060 GLuint reloadedProgram = glCreateProgram();
1061 saveAndLoadProgram(program, reloadedProgram);
1062
1063 GLint textureLocation = glGetUniformLocation(reloadedProgram, "tex");
1064 ASSERT_NE(-1, textureLocation);
1065
1066 GLColor linearColor(64, 127, 191, 255);
1067 GLColor srgbColor(13, 54, 133, 255);
1068
1069 GLTexture tex;
1070 glBindTexture(GL_TEXTURE_2D, tex);
1071 glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1072 &linearColor);
1073 ASSERT_GL_NO_ERROR();
1074
1075 GLSampler sampler;
1076 glBindSampler(0, sampler);
1077 glSamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
1078
1079 glUseProgram(reloadedProgram);
1080 glUniform1i(textureLocation, 0);
1081
1082 glDisable(GL_DEPTH_TEST);
1083 drawQuad(reloadedProgram, "position", 0.5f);
1084
1085 EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
1086
1087 glSamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
1088 drawQuad(reloadedProgram, "position", 0.5f);
1089
1090 EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
1091
1092 glDeleteProgram(reloadedProgram);
1093 }
1094
1095 // Test that array of structs containing array of samplers work as expected.
TEST_P(ProgramBinaryES3Test,ArrayOfStructContainingArrayOfSamplers)1096 TEST_P(ProgramBinaryES3Test, ArrayOfStructContainingArrayOfSamplers)
1097 {
1098 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1099
1100 constexpr char kFS[] =
1101 "precision mediump float;\n"
1102 "struct Data { mediump sampler2D data[2]; };\n"
1103 "uniform Data test[2];\n"
1104 "void main() {\n"
1105 " gl_FragColor = vec4(texture2D(test[1].data[1], vec2(0.0, 0.0)).r,\n"
1106 " texture2D(test[1].data[0], vec2(0.0, 0.0)).r,\n"
1107 " texture2D(test[0].data[1], vec2(0.0, 0.0)).r,\n"
1108 " texture2D(test[0].data[0], vec2(0.0, 0.0)).r);\n"
1109 "}\n";
1110
1111 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
1112 glUseProgram(program);
1113 GLTexture textures[4];
1114 GLColor expected = MakeGLColor(32, 64, 96, 255);
1115 GLubyte data[8] = {}; // 4 bytes of padding, so that texture can be initialized with 4 bytes
1116 memcpy(data, expected.data(), sizeof(expected));
1117 for (int i = 0; i < 4; i++)
1118 {
1119 int outerIdx = i % 2;
1120 int innerIdx = i / 2;
1121 glActiveTexture(GL_TEXTURE0 + i);
1122 glBindTexture(GL_TEXTURE_2D, textures[i]);
1123 // Each element provides two components.
1124 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data + i);
1125 std::stringstream uniformName;
1126 uniformName << "test[" << innerIdx << "].data[" << outerIdx << "]";
1127 // Then send it as a uniform
1128 GLint uniformLocation = glGetUniformLocation(program, uniformName.str().c_str());
1129 // The uniform should be active.
1130 EXPECT_NE(uniformLocation, -1);
1131
1132 glUniform1i(uniformLocation, 3 - i);
1133 ASSERT_GL_NO_ERROR();
1134 }
1135
1136 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
1137 ASSERT_GL_NO_ERROR();
1138 EXPECT_PIXEL_COLOR_EQ(0, 0, expected);
1139
1140 // Read back the binary.
1141 GLint programLength = 0;
1142 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1143 ASSERT_GL_NO_ERROR();
1144
1145 GLsizei readLength = 0;
1146 GLenum binaryFormat = GL_NONE;
1147 std::vector<uint8_t> binary(programLength);
1148 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
1149 ASSERT_GL_NO_ERROR();
1150
1151 // Load a new program with the binary.
1152 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1153 glUseProgram(binaryProgram);
1154
1155 for (int i = 0; i < 4; i++)
1156 {
1157 int outerIdx = i % 2;
1158 int innerIdx = i / 2;
1159 std::stringstream uniformName;
1160 uniformName << "test[" << innerIdx << "].data[" << outerIdx << "]";
1161 // Then send it as a uniform
1162 GLint uniformLocation = glGetUniformLocation(program, uniformName.str().c_str());
1163 // The uniform should be active.
1164 EXPECT_NE(uniformLocation, -1);
1165
1166 glUniform1i(uniformLocation, 3 - i);
1167 ASSERT_GL_NO_ERROR();
1168 }
1169
1170 // Verify the uniform data with the binary program.
1171 drawQuad(binaryProgram, essl1_shaders::PositionAttrib(), 0.5f);
1172 ASSERT_GL_NO_ERROR();
1173 EXPECT_PIXEL_COLOR_EQ(0, 0, expected);
1174 }
1175
1176 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryES3Test);
1177 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryES3Test);
1178
1179 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithComputeShader)1180 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
1181 {
1182 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1183
1184 constexpr char kCS[] =
1185 "#version 310 es\n"
1186 "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
1187 "uniform block {\n"
1188 " vec2 f;\n"
1189 "};\n"
1190 "uniform vec2 g;\n"
1191 "uniform highp sampler2D tex;\n"
1192 "void main() {\n"
1193 " vec4 color = texture(tex, f + g);\n"
1194 "}";
1195
1196 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1197
1198 // Read back the binary.
1199 GLint programLength = 0;
1200 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1201 ASSERT_GL_NO_ERROR();
1202
1203 GLsizei readLength = 0;
1204 GLenum binaryFormat = GL_NONE;
1205 std::vector<uint8_t> binary(programLength);
1206 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
1207 ASSERT_GL_NO_ERROR();
1208
1209 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1210
1211 // Load a new program with the binary.
1212 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1213 ASSERT_GL_NO_ERROR();
1214
1215 // Dispatch compute with the loaded binary program
1216 glUseProgram(binaryProgram);
1217 glDispatchCompute(8, 4, 2);
1218 ASSERT_GL_NO_ERROR();
1219 }
1220
1221 // Tests saving and loading a separable program that has a computer shader using a uniform and a
1222 // uniform block.
TEST_P(ProgramBinaryES31Test,SeparableProgramLinkedUniforms)1223 TEST_P(ProgramBinaryES31Test, SeparableProgramLinkedUniforms)
1224 {
1225 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1226
1227 constexpr char kComputeShader[] = R"(#version 310 es
1228 layout(local_size_x=4, local_size_y=3, local_size_z=1) in;
1229 uniform float testUint;
1230 uniform TestBlock
1231 {
1232 mat4 testMatrix;
1233 };
1234 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
1235 void main() {
1236 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(testMatrix[0][0] + testUint, 0, 0, 0));
1237 })";
1238
1239 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
1240 glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
1241
1242 // Read back the binary.
1243 GLint programLength = 0;
1244 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1245 ASSERT_GL_NO_ERROR();
1246
1247 GLsizei readLength = 0;
1248 GLenum binaryFormat = GL_NONE;
1249 std::vector<uint8_t> binary(programLength);
1250 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
1251 ASSERT_GL_NO_ERROR();
1252
1253 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1254
1255 // Load a new program with the binary.
1256 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1257 ASSERT_GL_NO_ERROR();
1258
1259 glUseProgram(binaryProgram);
1260 ASSERT_GL_NO_ERROR();
1261 }
1262
1263 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithAtomicCounterComputeShader)1264 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader)
1265 {
1266 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1267
1268 constexpr char kComputeShader[] = R"(#version 310 es
1269 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1270 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
1271 void main() {
1272 atomicCounterIncrement(ac[0]);
1273 atomicCounterDecrement(ac[1]);
1274 })";
1275
1276 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
1277
1278 // Read back the binary.
1279 GLint programLength = 0;
1280 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1281 ASSERT_GL_NO_ERROR();
1282
1283 GLsizei readLength = 0;
1284 GLenum binaryFormat = GL_NONE;
1285 std::vector<uint8_t> binary(programLength);
1286 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
1287 ASSERT_GL_NO_ERROR();
1288
1289 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1290
1291 // Load a new program with the binary.
1292 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1293 ASSERT_GL_NO_ERROR();
1294
1295 // Dispatch compute with the loaded binary program
1296 glUseProgram(binaryProgram);
1297
1298 // The initial value of 'ac[0]' is 3u, 'ac[1]' is 1u.
1299 unsigned int bufferData[3] = {11u, 3u, 1u};
1300 GLBuffer atomicCounterBuffer;
1301 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
1302 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
1303
1304 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
1305
1306 glDispatchCompute(1, 1, 1);
1307 EXPECT_GL_NO_ERROR();
1308
1309 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1310
1311 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
1312 void *mappedBuffer =
1313 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
1314 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
1315 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1316
1317 EXPECT_EQ(11u, bufferData[0]);
1318 EXPECT_EQ(4u, bufferData[1]);
1319 EXPECT_EQ(0u, bufferData[2]);
1320 ASSERT_GL_NO_ERROR();
1321 }
1322
1323 // Tests that image texture works correctly when loading a program from binary.
TEST_P(ProgramBinaryES31Test,ImageTextureBinding)1324 TEST_P(ProgramBinaryES31Test, ImageTextureBinding)
1325 {
1326 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1327
1328 const char kComputeShader[] =
1329 R"(#version 310 es
1330 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1331 layout(r32ui, binding = 1) writeonly uniform highp uimage2D writeImage;
1332 void main()
1333 {
1334 imageStore(writeImage, ivec2(gl_LocalInvocationID.xy), uvec4(200u));
1335 })";
1336
1337 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
1338
1339 // Read back the binary.
1340 GLint programLength = 0;
1341 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1342 ASSERT_GL_NO_ERROR();
1343
1344 GLsizei readLength = 0;
1345 GLenum binaryFormat = GL_NONE;
1346 std::vector<uint8_t> binary(programLength);
1347 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
1348 ASSERT_GL_NO_ERROR();
1349
1350 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1351
1352 // Load a new program with the binary.
1353 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1354 ASSERT_GL_NO_ERROR();
1355
1356 // Dispatch compute with the loaded binary program
1357 glUseProgram(binaryProgram);
1358 GLTexture texture;
1359 glBindTexture(GL_TEXTURE_2D, texture);
1360 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
1361 constexpr GLuint kInputValue = 100u;
1362 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &kInputValue);
1363 EXPECT_GL_NO_ERROR();
1364
1365 glBindImageTexture(1, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1366
1367 glDispatchCompute(1, 1, 1);
1368 EXPECT_GL_NO_ERROR();
1369
1370 GLFramebuffer framebuffer;
1371 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1372 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1373
1374 GLuint outputValue;
1375 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
1376 EXPECT_EQ(200u, outputValue);
1377 ASSERT_GL_NO_ERROR();
1378 }
1379
1380 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryES31Test);
1381 ANGLE_INSTANTIATE_TEST_ES31(ProgramBinaryES31Test);
1382
1383 class ProgramBinaryTransformFeedbackTest : public ANGLETest<>
1384 {
1385 protected:
ProgramBinaryTransformFeedbackTest()1386 ProgramBinaryTransformFeedbackTest()
1387 {
1388 setWindowWidth(128);
1389 setWindowHeight(128);
1390 setConfigRedBits(8);
1391 setConfigGreenBits(8);
1392 setConfigBlueBits(8);
1393 setConfigAlphaBits(8);
1394 }
1395
testSetUp()1396 void testSetUp() override
1397 {
1398 constexpr char kVS[] = R"(#version 300 es
1399 in vec4 inputAttribute;
1400 out vec4 outputVarying;
1401 void main()
1402 {
1403 outputVarying = inputAttribute;
1404 })";
1405
1406 constexpr char kFS[] = R"(#version 300 es
1407 precision highp float;
1408 out vec4 outputColor;
1409 void main()
1410 {
1411 outputColor = vec4(1,0,0,1);
1412 })";
1413
1414 std::vector<std::string> transformFeedbackVaryings;
1415 transformFeedbackVaryings.push_back("outputVarying");
1416
1417 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, transformFeedbackVaryings,
1418 GL_SEPARATE_ATTRIBS);
1419 if (mProgram == 0)
1420 {
1421 FAIL() << "shader compilation failed.";
1422 }
1423
1424 ASSERT_GL_NO_ERROR();
1425 }
1426
testTearDown()1427 void testTearDown() override { glDeleteProgram(mProgram); }
1428
getAvailableProgramBinaryFormatCount() const1429 GLint getAvailableProgramBinaryFormatCount() const
1430 {
1431 GLint formatCount;
1432 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
1433 return formatCount;
1434 }
1435
1436 GLuint mProgram;
1437 };
1438
1439 // This tests the assumption that float attribs of different size
1440 // should not internally cause a vertex shader recompile (for conversion).
TEST_P(ProgramBinaryTransformFeedbackTest,GetTransformFeedbackVarying)1441 TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
1442 {
1443 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_get_program_binary"));
1444
1445 ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1446
1447 // http://anglebug.com/42262347
1448 ANGLE_SKIP_TEST_IF(IsAndroid() && (IsPixel2() || IsPixel2XL()) && IsVulkan());
1449 // http://anglebug.com/40096654
1450 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
1451
1452 std::vector<uint8_t> binary(0);
1453 GLint programLength = 0;
1454 GLint writtenLength = 0;
1455 GLenum binaryFormat = 0;
1456
1457 // Save the program binary out
1458 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1459 ASSERT_GL_NO_ERROR();
1460 binary.resize(programLength);
1461 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
1462 ASSERT_GL_NO_ERROR();
1463
1464 glDeleteProgram(mProgram);
1465
1466 // Load program binary
1467 mProgram = glCreateProgram();
1468 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
1469
1470 // Ensure the loaded binary is linked
1471 GLint linkStatus;
1472 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
1473 EXPECT_TRUE(linkStatus != 0);
1474
1475 // Query information about the transform feedback varying
1476 char varyingName[64];
1477 GLsizei varyingSize = 0;
1478 GLenum varyingType = GL_NONE;
1479
1480 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType,
1481 varyingName);
1482 EXPECT_GL_NO_ERROR();
1483
1484 EXPECT_EQ(13, writtenLength);
1485 EXPECT_STREQ("outputVarying", varyingName);
1486 EXPECT_EQ(1, varyingSize);
1487 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
1488
1489 EXPECT_GL_NO_ERROR();
1490 }
1491
1492 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryTransformFeedbackTest);
1493 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryTransformFeedbackTest);
1494
1495 // For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
1496 // - a set to save the program binary
1497 // - a set to load the program binary
1498 // We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test
1499 // macros
1500 struct PlatformsWithLinkResult : PlatformParameters
1501 {
PlatformsWithLinkResultPlatformsWithLinkResult1502 PlatformsWithLinkResult(PlatformParameters saveParams,
1503 PlatformParameters loadParamsIn,
1504 bool expectedLinkResultIn)
1505 {
1506 majorVersion = saveParams.majorVersion;
1507 minorVersion = saveParams.minorVersion;
1508 eglParameters = saveParams.eglParameters;
1509 loadParams = loadParamsIn;
1510 expectedLinkResult = expectedLinkResultIn;
1511 }
1512
1513 PlatformParameters loadParams;
1514 bool expectedLinkResult;
1515 };
1516
1517 // Provide a custom gtest parameter name function for PlatformsWithLinkResult
1518 // to avoid returning the same parameter name twice. Such a conflict would happen
1519 // between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
1520 // named ES2_D3D11
operator <<(std::ostream & stream,const PlatformsWithLinkResult & platform)1521 std::ostream &operator<<(std::ostream &stream, const PlatformsWithLinkResult &platform)
1522 {
1523 const PlatformParameters &platform1 = platform;
1524 const PlatformParameters &platform2 = platform.loadParams;
1525 stream << platform1 << "_to_" << platform2;
1526 return stream;
1527 }
1528
1529 class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
1530 {
1531 public:
SetUp()1532 void SetUp() override
1533 {
1534 mOSWindow = OSWindow::New();
1535 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
1536
1537 if (result == false)
1538 {
1539 FAIL() << "Failed to create OS window";
1540 }
1541
1542 mEntryPointsLib.reset(
1543 angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ModuleDir));
1544 }
1545
createAndInitEGLWindow(angle::PlatformParameters & param)1546 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters ¶m)
1547 {
1548 EGLWindow *eglWindow = EGLWindow::New(param.majorVersion, param.minorVersion);
1549 ConfigParameters configParams;
1550 bool result = eglWindow->initializeGL(mOSWindow, mEntryPointsLib.get(), param.driver,
1551 param.eglParameters, configParams);
1552 if (!result)
1553 {
1554 EGLWindow::Delete(&eglWindow);
1555 }
1556
1557 LoadUtilGLES(eglGetProcAddress);
1558
1559 return eglWindow;
1560 }
1561
destroyEGLWindow(EGLWindow ** eglWindow)1562 void destroyEGLWindow(EGLWindow **eglWindow)
1563 {
1564 ASSERT_NE(nullptr, *eglWindow);
1565 (*eglWindow)->destroyGL();
1566 EGLWindow::Delete(eglWindow);
1567 }
1568
createES2ProgramFromSource()1569 GLuint createES2ProgramFromSource()
1570 {
1571 return CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
1572 }
1573
createES3ProgramFromSource()1574 GLuint createES3ProgramFromSource()
1575 {
1576 return CompileProgram(essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
1577 }
1578
drawWithProgram(GLuint program)1579 void drawWithProgram(GLuint program)
1580 {
1581 glClearColor(0, 0, 0, 1);
1582 glClear(GL_COLOR_BUFFER_BIT);
1583
1584 GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
1585
1586 glUseProgram(program);
1587
1588 const GLfloat vertices[] = {
1589 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
1590
1591 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
1592 };
1593
1594 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
1595 glEnableVertexAttribArray(positionLocation);
1596
1597 glDrawArrays(GL_TRIANGLES, 0, 6);
1598
1599 glDisableVertexAttribArray(positionLocation);
1600 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
1601
1602 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
1603 }
1604
TearDown()1605 void TearDown() override
1606 {
1607 mOSWindow->destroy();
1608 OSWindow::Delete(&mOSWindow);
1609 }
1610
1611 OSWindow *mOSWindow = nullptr;
1612 std::unique_ptr<angle::Library> mEntryPointsLib;
1613 };
1614
1615 // Tries to create a program binary using one set of platform params, then load it using a different
1616 // sent of params
TEST_P(ProgramBinariesAcrossPlatforms,CreateAndReloadBinary)1617 TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
1618 {
1619 angle::PlatformParameters firstRenderer = GetParam();
1620 angle::PlatformParameters secondRenderer = GetParam().loadParams;
1621 bool expectedLinkResult = GetParam().expectedLinkResult;
1622
1623 // First renderer not supported, skipping test.
1624 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(firstRenderer)));
1625
1626 // Second renderer not supported, skipping test.
1627 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(secondRenderer)));
1628
1629 EGLWindow *eglWindow = nullptr;
1630 std::vector<uint8_t> binary(0);
1631 GLuint program = 0;
1632
1633 GLint programLength = 0;
1634 GLint writtenLength = 0;
1635 GLenum binaryFormat = 0;
1636
1637 // Create a EGL window with the first renderer
1638 eglWindow = createAndInitEGLWindow(firstRenderer);
1639 if (eglWindow == nullptr)
1640 {
1641 FAIL() << "Failed to create EGL window";
1642 }
1643
1644 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
1645 // then our expectations for the test results will be invalid.
1646 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
1647 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
1648 {
1649 std::string rendererString =
1650 std::string(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
1651 angle::ToLower(&rendererString);
1652
1653 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
1654 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
1655
1656 // The first renderer is using WARP, even though we didn't explictly request it
1657 // We should skip this test
1658 ANGLE_SKIP_TEST_IF(basicRenderPos != std::string::npos ||
1659 softwareAdapterPos != std::string::npos);
1660 }
1661
1662 // Create a program
1663 if (firstRenderer.majorVersion == 3)
1664 {
1665 program = createES3ProgramFromSource();
1666 }
1667 else
1668 {
1669 program = createES2ProgramFromSource();
1670 }
1671
1672 if (program == 0)
1673 {
1674 destroyEGLWindow(&eglWindow);
1675 FAIL() << "Failed to create program from source";
1676 }
1677
1678 // Draw using the program to ensure it works as expected
1679 drawWithProgram(program);
1680 EXPECT_GL_NO_ERROR();
1681
1682 // Save the program binary out from this renderer
1683 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1684 EXPECT_GL_NO_ERROR();
1685 binary.resize(programLength);
1686 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
1687 EXPECT_GL_NO_ERROR();
1688
1689 // Destroy the first renderer
1690 glDeleteProgram(program);
1691 destroyEGLWindow(&eglWindow);
1692
1693 // Create an EGL window with the second renderer
1694 eglWindow = createAndInitEGLWindow(secondRenderer);
1695 if (eglWindow == nullptr)
1696 {
1697 FAIL() << "Failed to create EGL window";
1698 }
1699
1700 program = glCreateProgram();
1701 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
1702
1703 GLint linkStatus;
1704 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
1705 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
1706
1707 if (linkStatus != 0)
1708 {
1709 // If the link was successful, then we should try to draw using the program to ensure it
1710 // works as expected
1711 drawWithProgram(program);
1712 EXPECT_GL_NO_ERROR();
1713 }
1714
1715 // Destroy the second renderer
1716 glDeleteProgram(program);
1717 destroyEGLWindow(&eglWindow);
1718 }
1719
1720 // clang-format off
1721 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinariesAcrossPlatforms);
1722 ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
1723 // | Save the | Load the | Expected
1724 // | program in | program in | link
1725 // | this config | this config | result
1726 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
1727 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
1728 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false), // Switching from D3D11 to D3D9 shouldn't work
1729 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false), // Switching from D3D9 to D3D11 shouldn't work
1730 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false), // Switching to newer client version shouldn't work
1731 PlatformsWithLinkResult(ES2_VULKAN(), ES2_VULKAN(), true ), // Loading + reloading binary should work
1732 PlatformsWithLinkResult(ES3_VULKAN(), ES3_VULKAN(), true ), // Loading + reloading binary should work
1733 PlatformsWithLinkResult(ES31_VULKAN(), ES31_VULKAN(), true ), // Loading + reloading binary should work
1734 PlatformsWithLinkResult(ES3_VULKAN(), ES31_VULKAN(), false), // Switching to newer client version shouldn't work with Vulkan
1735 );
1736 // clang-format on
1737