xref: /aosp_15_r20/external/angle/src/tests/gl_tests/ProgramBinaryTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 &param)
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