• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::Simple(), essl1_shaders::fs::Red());
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(ProgramBinaryTest);
278 
279 class ProgramBinaryES3Test : public ANGLETest
280 {
281   protected:
ProgramBinaryES3Test()282     ProgramBinaryES3Test()
283     {
284         // Test flakiness was noticed when reusing displays.
285         forceNewDisplay();
286     }
287 
288     void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
289 };
290 
testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)291 void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
292 {
293     // We can't run the test if no program binary formats are supported.
294     GLint binaryFormatCount = 0;
295     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
296     ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
297 
298     constexpr char kVS[] =
299         "#version 300 es\n"
300         "uniform block {\n"
301         "    float f;\n"
302         "};\n"
303         "in vec4 position;\n"
304         "out vec4 color;\n"
305         "void main() {\n"
306         "    gl_Position = position;\n"
307         "    color = vec4(f, f, f, 1);\n"
308         "}";
309 
310     constexpr char kFS[] =
311         "#version 300 es\n"
312         "precision mediump float;\n"
313         "in vec4 color;\n"
314         "out vec4 colorOut;\n"
315         "void main() {\n"
316         "    colorOut = color;\n"
317         "}";
318 
319     // Init and draw with the program.
320     ANGLE_GL_PROGRAM(program, kVS, kFS);
321 
322     float fData[4]   = {1.0f, 1.0f, 1.0f, 1.0f};
323     GLuint bindIndex = 2;
324 
325     GLBuffer ubo;
326     glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
327     glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
328     glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
329 
330     GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
331     ASSERT_NE(-1, blockIndex);
332 
333     glUniformBlockBinding(program.get(), blockIndex, bindIndex);
334 
335     glClearColor(1.0, 0.0, 0.0, 1.0);
336     glClear(GL_COLOR_BUFFER_BIT);
337     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
338 
339     if (drawWithProgramFirst)
340     {
341         drawQuad(program.get(), "position", 0.5f);
342         ASSERT_GL_NO_ERROR();
343         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
344     }
345 
346     // Read back the binary.
347     GLint programLength = 0;
348     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
349     ASSERT_GL_NO_ERROR();
350 
351     GLsizei readLength  = 0;
352     GLenum binaryFormat = GL_NONE;
353     std::vector<uint8_t> binary(programLength);
354     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
355     ASSERT_GL_NO_ERROR();
356 
357     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
358 
359     // Load a new program with the binary and draw.
360     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
361 
362     glClearColor(1.0, 0.0, 0.0, 1.0);
363     glClear(GL_COLOR_BUFFER_BIT);
364     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
365 
366     drawQuad(binaryProgram.get(), "position", 0.5f);
367     ASSERT_GL_NO_ERROR();
368     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
369 }
370 
371 // Tests that saving and loading a program perserves uniform block binding info.
TEST_P(ProgramBinaryES3Test,UniformBlockBindingWithDraw)372 TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
373 {
374     testBinaryAndUBOBlockIndexes(true);
375 }
376 
377 // Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
378 // http://anglebug.com/1637
TEST_P(ProgramBinaryES3Test,UniformBlockBindingNoDraw)379 TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
380 {
381     testBinaryAndUBOBlockIndexes(false);
382 }
383 
384 // Test the shaders with arrays-of-struct uniforms are properly saved and restored
TEST_P(ProgramBinaryES3Test,TestArrayOfStructUniform)385 TEST_P(ProgramBinaryES3Test, TestArrayOfStructUniform)
386 {
387     // We can't run the test if no program binary formats are supported.
388     GLint binaryFormatCount = 0;
389     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
390     ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
391 
392     constexpr char kVS[] =
393         "#version 300 es\n"
394         "in highp vec4 position;\n"
395         "out mediump float v_vtxOut;\n"
396         "\n"
397         "struct structType\n"
398         "{\n"
399         "    mediump vec4 m0;\n"
400         "    mediump vec4 m1;\n"
401         "};\n"
402         "uniform structType u_var[3];\n"
403         "\n"
404         "mediump float compare_float(mediump float a, mediump float b)\n"
405         "{\n"
406         "    return abs(a - b) < 0.05 ? 1.0 : 0.0;\n"
407         "}\n"
408         "mediump float compare_vec4(mediump vec4 a, mediump vec4 b)\n"
409         "{\n"
410         "    return compare_float(a.x, b.x)*compare_float(a.y, b.y)*\n"
411         "           compare_float(a.z, b.z)*compare_float(a.w, b.w);\n"
412         "}\n"
413         "\n"
414         "void main (void)\n"
415         "{\n"
416         "    gl_Position = position;\n"
417         "    v_vtxOut = 1.0;\n"
418         "    v_vtxOut *= compare_vec4(u_var[0].m0, vec4(0.15, 0.52, 0.26, 0.35));\n"
419         "    v_vtxOut *= compare_vec4(u_var[0].m1, vec4(0.88, 0.09, 0.30, 0.61));\n"
420         "    v_vtxOut *= compare_vec4(u_var[1].m0, vec4(0.85, 0.59, 0.33, 0.71));\n"
421         "    v_vtxOut *= compare_vec4(u_var[1].m1, vec4(0.62, 0.89, 0.09, 0.99));\n"
422         "    v_vtxOut *= compare_vec4(u_var[2].m0, vec4(0.53, 0.89, 0.01, 0.08));\n"
423         "    v_vtxOut *= compare_vec4(u_var[2].m1, vec4(0.26, 0.72, 0.60, 0.12));\n"
424         "}";
425 
426     constexpr char kFS[] =
427         "#version 300 es\n"
428         "in mediump float v_vtxOut;\n"
429         "\n"
430         "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
431         "\n"
432         "void main (void)\n"
433         "{\n"
434         "    mediump float result = v_vtxOut;\n"
435         "    dEQP_FragColor = vec4(result, result, result, 1.0);\n"
436         "}";
437 
438     // Init and draw with the program.
439     ANGLE_GL_PROGRAM(program, kVS, kFS);
440 
441     glUseProgram(program.get());
442 
443     int location = glGetUniformLocation(program.get(), "u_var[0].m0");
444     ASSERT_NE(location, -1);
445     glUniform4f(location, 0.15, 0.52, 0.26, 0.35);
446     location = glGetUniformLocation(program.get(), "u_var[0].m1");
447     ASSERT_NE(location, -1);
448     glUniform4f(location, 0.88, 0.09, 0.30, 0.61);
449     location = glGetUniformLocation(program.get(), "u_var[1].m0");
450     ASSERT_NE(location, -1);
451     glUniform4f(location, 0.85, 0.59, 0.33, 0.71);
452     location = glGetUniformLocation(program.get(), "u_var[1].m1");
453     ASSERT_NE(location, -1);
454     glUniform4f(location, 0.62, 0.89, 0.09, 0.99);
455     location = glGetUniformLocation(program.get(), "u_var[2].m0");
456     ASSERT_NE(location, -1);
457     glUniform4f(location, 0.53, 0.89, 0.01, 0.08);
458     location = glGetUniformLocation(program.get(), "u_var[2].m1");
459     ASSERT_NE(location, -1);
460     glUniform4f(location, 0.26, 0.72, 0.60, 0.12);
461     ASSERT_GL_NO_ERROR();
462 
463     // Clear and draw with the original program:
464     glClearColor(1.0, 0.0, 0.0, 1.0);
465     glClear(GL_COLOR_BUFFER_BIT);
466     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
467     drawQuad(program.get(), "position", 0.5f);
468     ASSERT_GL_NO_ERROR();
469     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
470 
471     // Read back the binary.
472     GLint programLength = 0;
473     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
474     ASSERT_GL_NO_ERROR();
475 
476     GLsizei readLength  = 0;
477     GLenum binaryFormat = GL_NONE;
478     std::vector<uint8_t> binary(programLength);
479     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
480     ASSERT_GL_NO_ERROR();
481 
482     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
483 
484     // Load a new program with the binary and draw.
485     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
486 
487     glUseProgram(binaryProgram.get());
488 
489     location = glGetUniformLocation(binaryProgram.get(), "u_var[0].m0");
490     ASSERT_NE(location, -1);
491     glUniform4f(location, 0.15, 0.52, 0.26, 0.35);
492     location = glGetUniformLocation(binaryProgram.get(), "u_var[0].m1");
493     ASSERT_NE(location, -1);
494     glUniform4f(location, 0.88, 0.09, 0.30, 0.61);
495     location = glGetUniformLocation(binaryProgram.get(), "u_var[1].m0");
496     ASSERT_NE(location, -1);
497     glUniform4f(location, 0.85, 0.59, 0.33, 0.71);
498     location = glGetUniformLocation(binaryProgram.get(), "u_var[1].m1");
499     ASSERT_NE(location, -1);
500     glUniform4f(location, 0.62, 0.89, 0.09, 0.99);
501     location = glGetUniformLocation(binaryProgram.get(), "u_var[2].m0");
502     ASSERT_NE(location, -1);
503     glUniform4f(location, 0.53, 0.89, 0.01, 0.08);
504     location = glGetUniformLocation(binaryProgram.get(), "u_var[2].m1");
505     ASSERT_NE(location, -1);
506     glUniform4f(location, 0.26, 0.72, 0.60, 0.12);
507     ASSERT_GL_NO_ERROR();
508 
509     // Clear and draw with the restored program:
510     glClearColor(1.0, 0.0, 0.0, 1.0);
511     glClear(GL_COLOR_BUFFER_BIT);
512     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
513     drawQuad(binaryProgram.get(), "position", 0.5f);
514     ASSERT_GL_NO_ERROR();
515     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
516 }
517 
518 // Tests the difference between uniform static and active use
TEST_P(ProgramBinaryES3Test,ActiveUniformShader)519 TEST_P(ProgramBinaryES3Test, ActiveUniformShader)
520 {
521     // We can't run the test if no program binary formats are supported.
522     GLint binaryFormatCount = 0;
523     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
524     ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
525 
526     constexpr char kVS[] =
527         "#version 300 es\n"
528         "in vec4 position;\n"
529         "void main() {\n"
530         "    gl_Position = position;\n"
531         "}";
532 
533     constexpr char kFS[] =
534         "#version 300 es\n"
535         "precision mediump float;\n"
536         "uniform float values[2];\n"
537         "out vec4 color;\n"
538         "bool isZero(float value) {\n"
539         "    return value == 0.0f;\n"
540         "}\n"
541         "void main() {\n"
542         "    color = isZero(values[1]) ? vec4(1.0f,0.0f,0.0f,1.0f) : vec4(0.0f,1.0f,0.0f,1.0f);\n"
543         "}";
544 
545     // Init and draw with the program.
546     ANGLE_GL_PROGRAM(program, kVS, kFS);
547 
548     GLint valuesLoc = glGetUniformLocation(program.get(), "values");
549     ASSERT_NE(-1, valuesLoc);
550 
551     glUseProgram(program.get());
552     GLfloat values[2] = {0.5f, 1.0f};
553     glUniform1fv(valuesLoc, 2, values);
554     ASSERT_GL_NO_ERROR();
555 
556     glClearColor(1.0, 0.0, 0.0, 1.0);
557     glClear(GL_COLOR_BUFFER_BIT);
558     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
559 
560     drawQuad(program.get(), "position", 0.5f);
561     ASSERT_GL_NO_ERROR();
562     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
563 
564     // Read back the binary.
565     GLint programLength = 0;
566     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
567     ASSERT_GL_NO_ERROR();
568 
569     GLsizei readLength  = 0;
570     GLenum binaryFormat = GL_NONE;
571     std::vector<uint8_t> binary(programLength);
572     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
573     ASSERT_GL_NO_ERROR();
574 
575     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
576 
577     // Load a new program with the binary and draw.
578     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
579 
580     valuesLoc = glGetUniformLocation(program.get(), "values");
581     ASSERT_NE(-1, valuesLoc);
582 
583     glUseProgram(binaryProgram.get());
584     GLfloat values2[2] = {0.1f, 1.0f};
585     glUniform1fv(valuesLoc, 2, values2);
586     ASSERT_GL_NO_ERROR();
587 
588     glClearColor(1.0, 0.0, 0.0, 1.0);
589     glClear(GL_COLOR_BUFFER_BIT);
590     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
591 
592     drawQuad(binaryProgram.get(), "position", 0.5f);
593     ASSERT_GL_NO_ERROR();
594     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
595 }
596 
597 // Test that uses many uniforms in the shaders
TEST_P(ProgramBinaryES3Test,BinaryWithLargeUniformCount)598 TEST_P(ProgramBinaryES3Test, BinaryWithLargeUniformCount)
599 {
600     // Suspecting AMD driver bug - failure seen on bots running on ATI GPU on Windows.
601     // http://anglebug.com/3721
602     ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && IsWindows());
603 
604     // We can't run the test if no program binary formats are supported.
605     GLint binaryFormatCount = 0;
606     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
607     ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
608 
609     constexpr char kVS[] =
610         "#version 300 es\n"
611         "uniform float redVS; \n"
612         "uniform block0 {\n"
613         "    float val0;\n"
614         "};\n"
615         "uniform float greenVS; \n"
616         "uniform float blueVS; \n"
617         "in vec4 position;\n"
618         "out vec4 color;\n"
619         "void main() {\n"
620         "    gl_Position = position;\n"
621         "    color = vec4(redVS + val0, greenVS, blueVS, 1.0f);\n"
622         "}";
623 
624     constexpr char kFS[] =
625         "#version 300 es\n"
626         "precision mediump float;\n"
627         "uniform float redFS; \n"
628         "uniform float greenFS; \n"
629         "uniform block1 {\n"
630         "    float val1;\n"
631         "    float val2;\n"
632         "};\n"
633         "uniform float blueFS; \n"
634         "in vec4 color;\n"
635         "out vec4 colorOut;\n"
636         "void main() {\n"
637         "    colorOut = vec4(color.r + redFS,\n"
638         "                    color.g + greenFS + val1,\n"
639         "                    color.b + blueFS + val2, \n"
640         "                    color.a);\n"
641         "}";
642 
643     // Init and draw with the program.
644     ANGLE_GL_PROGRAM(program, kVS, kFS);
645 
646     float block0Data[4] = {-0.7f, 1.0f, 1.0f, 1.0f};
647     float block1Data[4] = {0.4f, -0.8f, 1.0f, 1.0f};
648     GLuint bindIndex0   = 5;
649     GLuint bindIndex1   = 2;
650 
651     GLBuffer ubo0;
652     glBindBuffer(GL_UNIFORM_BUFFER, ubo0.get());
653     glBufferData(GL_UNIFORM_BUFFER, sizeof(block0Data), &block0Data, GL_STATIC_DRAW);
654     glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex0, ubo0.get(), 0, sizeof(block0Data));
655     ASSERT_GL_NO_ERROR();
656 
657     GLBuffer ubo1;
658     glBindBuffer(GL_UNIFORM_BUFFER, ubo1.get());
659     glBufferData(GL_UNIFORM_BUFFER, sizeof(block1Data), &block1Data, GL_STATIC_DRAW);
660     glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex1, ubo1.get(), 0, sizeof(block1Data));
661     ASSERT_GL_NO_ERROR();
662 
663     GLint block0Index = glGetUniformBlockIndex(program.get(), "block0");
664     ASSERT_NE(-1, block0Index);
665 
666     GLint block1Index = glGetUniformBlockIndex(program.get(), "block1");
667     ASSERT_NE(-1, block1Index);
668 
669     glUniformBlockBinding(program.get(), block0Index, bindIndex0);
670     glUniformBlockBinding(program.get(), block1Index, bindIndex1);
671     ASSERT_GL_NO_ERROR();
672 
673     GLint redVSLoc = glGetUniformLocation(program.get(), "redVS");
674     ASSERT_NE(-1, redVSLoc);
675     GLint greenVSLoc = glGetUniformLocation(program.get(), "greenVS");
676     ASSERT_NE(-1, greenVSLoc);
677     GLint blueVSLoc = glGetUniformLocation(program.get(), "blueVS");
678     ASSERT_NE(-1, blueVSLoc);
679     GLint redFSLoc = glGetUniformLocation(program.get(), "redFS");
680     ASSERT_NE(-1, redFSLoc);
681     GLint greenFSLoc = glGetUniformLocation(program.get(), "greenFS");
682     ASSERT_NE(-1, greenFSLoc);
683     GLint blueFSLoc = glGetUniformLocation(program.get(), "blueFS");
684     ASSERT_NE(-1, blueFSLoc);
685 
686     glUseProgram(program.get());
687     glUniform1f(redVSLoc, 0.6f);
688     glUniform1f(greenVSLoc, 0.2f);
689     glUniform1f(blueVSLoc, 1.1f);
690     glUniform1f(redFSLoc, 0.1f);
691     glUniform1f(greenFSLoc, 0.4f);
692     glUniform1f(blueFSLoc, 0.7f);
693     ASSERT_GL_NO_ERROR();
694 
695     glClearColor(1.0, 0.0, 0.0, 1.0);
696     glClear(GL_COLOR_BUFFER_BIT);
697     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
698 
699     drawQuad(program.get(), "position", 0.5f);
700     ASSERT_GL_NO_ERROR();
701     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
702 
703     // Read back the binary.
704     GLint programLength = 0;
705     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
706     ASSERT_GL_NO_ERROR();
707 
708     GLsizei readLength  = 0;
709     GLenum binaryFormat = GL_NONE;
710     std::vector<uint8_t> binary(programLength);
711     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
712     ASSERT_GL_NO_ERROR();
713 
714     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
715 
716     // Load a new program with the binary and draw.
717     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
718 
719     redVSLoc = glGetUniformLocation(program.get(), "redVS");
720     ASSERT_NE(-1, redVSLoc);
721     greenVSLoc = glGetUniformLocation(program.get(), "greenVS");
722     ASSERT_NE(-1, greenVSLoc);
723     blueVSLoc = glGetUniformLocation(program.get(), "blueVS");
724     ASSERT_NE(-1, blueVSLoc);
725     redFSLoc = glGetUniformLocation(program.get(), "redFS");
726     ASSERT_NE(-1, redFSLoc);
727     greenFSLoc = glGetUniformLocation(program.get(), "greenFS");
728     ASSERT_NE(-1, greenFSLoc);
729     blueFSLoc = glGetUniformLocation(program.get(), "blueFS");
730     ASSERT_NE(-1, blueFSLoc);
731 
732     glUseProgram(binaryProgram.get());
733     glUniform1f(redVSLoc, 0.2f);
734     glUniform1f(greenVSLoc, -0.6f);
735     glUniform1f(blueVSLoc, 1.0f);
736     glUniform1f(redFSLoc, 1.5f);
737     glUniform1f(greenFSLoc, 0.2f);
738     glUniform1f(blueFSLoc, 0.8f);
739     ASSERT_GL_NO_ERROR();
740 
741     glClearColor(1.0, 0.0, 0.0, 1.0);
742     glClear(GL_COLOR_BUFFER_BIT);
743     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
744 
745     drawQuad(binaryProgram.get(), "position", 0.5f);
746     ASSERT_GL_NO_ERROR();
747     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
748 }
749 
750 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryES3Test);
751 
752 class ProgramBinaryES31Test : public ANGLETest
753 {
754   protected:
ProgramBinaryES31Test()755     ProgramBinaryES31Test()
756     {
757         setWindowWidth(128);
758         setWindowHeight(128);
759         setConfigRedBits(8);
760         setConfigGreenBits(8);
761         setConfigBlueBits(8);
762         setConfigAlphaBits(8);
763 
764         // Test flakiness was noticed when reusing displays.
765         forceNewDisplay();
766     }
767 };
768 
769 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithComputeShader)770 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
771 {
772     // We can't run the test if no program binary formats are supported.
773     GLint binaryFormatCount = 0;
774     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
775     ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
776     // http://anglebug.com/4092
777     ANGLE_SKIP_TEST_IF(IsVulkan());
778 
779     constexpr char kCS[] =
780         "#version 310 es\n"
781         "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
782         "uniform block {\n"
783         "    vec2 f;\n"
784         "};\n"
785         "uniform vec2 g;\n"
786         "uniform highp sampler2D tex;\n"
787         "void main() {\n"
788         "    vec4 color = texture(tex, f + g);\n"
789         "}";
790 
791     ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
792 
793     // Read back the binary.
794     GLint programLength = 0;
795     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
796     ASSERT_GL_NO_ERROR();
797 
798     GLsizei readLength  = 0;
799     GLenum binaryFormat = GL_NONE;
800     std::vector<uint8_t> binary(programLength);
801     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
802     ASSERT_GL_NO_ERROR();
803 
804     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
805 
806     // Load a new program with the binary.
807     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
808     ASSERT_GL_NO_ERROR();
809 
810     // Dispatch compute with the loaded binary program
811     glUseProgram(binaryProgram.get());
812     glDispatchCompute(8, 4, 2);
813     ASSERT_GL_NO_ERROR();
814 }
815 
816 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithAtomicCounterComputeShader)817 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader)
818 {
819     // http://anglebug.com/4092
820     ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
821     // We can't run the test if no program binary formats are supported.
822     GLint binaryFormatCount = 0;
823     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
824     ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
825 
826     constexpr char kComputeShader[] = R"(#version 310 es
827 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
828 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
829 void main() {
830     atomicCounterIncrement(ac[0]);
831     atomicCounterDecrement(ac[1]);
832 })";
833 
834     ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
835 
836     // Read back the binary.
837     GLint programLength = 0;
838     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
839     ASSERT_GL_NO_ERROR();
840 
841     GLsizei readLength  = 0;
842     GLenum binaryFormat = GL_NONE;
843     std::vector<uint8_t> binary(programLength);
844     glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
845     ASSERT_GL_NO_ERROR();
846 
847     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
848 
849     // Load a new program with the binary.
850     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
851     ASSERT_GL_NO_ERROR();
852 
853     // Dispatch compute with the loaded binary program
854     glUseProgram(binaryProgram);
855 
856     // The initial value of 'ac[0]' is 3u, 'ac[1]' is 1u.
857     unsigned int bufferData[3] = {11u, 3u, 1u};
858     GLBuffer atomicCounterBuffer;
859     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
860     glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
861 
862     glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
863 
864     glDispatchCompute(1, 1, 1);
865     EXPECT_GL_NO_ERROR();
866 
867     glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
868 
869     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
870     void *mappedBuffer =
871         glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
872     memcpy(bufferData, mappedBuffer, sizeof(bufferData));
873     glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
874 
875     EXPECT_EQ(11u, bufferData[0]);
876     EXPECT_EQ(4u, bufferData[1]);
877     EXPECT_EQ(0u, bufferData[2]);
878     ASSERT_GL_NO_ERROR();
879 }
880 
881 // Tests that image texture works correctly when loading a program from binary.
TEST_P(ProgramBinaryES31Test,ImageTextureBinding)882 TEST_P(ProgramBinaryES31Test, ImageTextureBinding)
883 {
884     // We can't run the test if no program binary formats are supported.
885     GLint binaryFormatCount = 0;
886     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
887     ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
888 
889     const char kComputeShader[] =
890         R"(#version 310 es
891         layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
892         layout(r32ui, binding = 1) writeonly uniform highp uimage2D writeImage;
893         void main()
894         {
895             imageStore(writeImage, ivec2(gl_LocalInvocationID.xy), uvec4(200u));
896         })";
897 
898     ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
899 
900     // Read back the binary.
901     GLint programLength = 0;
902     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
903     ASSERT_GL_NO_ERROR();
904 
905     GLsizei readLength  = 0;
906     GLenum binaryFormat = GL_NONE;
907     std::vector<uint8_t> binary(programLength);
908     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
909     ASSERT_GL_NO_ERROR();
910 
911     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
912 
913     // Load a new program with the binary.
914     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
915     ASSERT_GL_NO_ERROR();
916 
917     // Dispatch compute with the loaded binary program
918     glUseProgram(binaryProgram.get());
919     GLTexture texture;
920     glBindTexture(GL_TEXTURE_2D, texture);
921     glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
922     constexpr GLuint kInputValue = 100u;
923     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &kInputValue);
924     EXPECT_GL_NO_ERROR();
925 
926     glBindImageTexture(1, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
927 
928     glDispatchCompute(1, 1, 1);
929     EXPECT_GL_NO_ERROR();
930 
931     GLFramebuffer framebuffer;
932     glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
933     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
934 
935     GLuint outputValue;
936     glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
937     EXPECT_EQ(200u, outputValue);
938     ASSERT_GL_NO_ERROR();
939 }
940 
941 ANGLE_INSTANTIATE_TEST_ES31(ProgramBinaryES31Test);
942 
943 class ProgramBinaryTransformFeedbackTest : public ANGLETest
944 {
945   protected:
ProgramBinaryTransformFeedbackTest()946     ProgramBinaryTransformFeedbackTest()
947     {
948         setWindowWidth(128);
949         setWindowHeight(128);
950         setConfigRedBits(8);
951         setConfigGreenBits(8);
952         setConfigBlueBits(8);
953         setConfigAlphaBits(8);
954     }
955 
testSetUp()956     void testSetUp() override
957     {
958         constexpr char kVS[] = R"(#version 300 es
959 in vec4 inputAttribute;
960 out vec4 outputVarying;
961 void main()
962 {
963     outputVarying = inputAttribute;
964 })";
965 
966         constexpr char kFS[] = R"(#version 300 es
967 precision highp float;
968 out vec4 outputColor;
969 void main()
970 {
971     outputColor = vec4(1,0,0,1);
972 })";
973 
974         std::vector<std::string> transformFeedbackVaryings;
975         transformFeedbackVaryings.push_back("outputVarying");
976 
977         mProgram = CompileProgramWithTransformFeedback(kVS, kFS, transformFeedbackVaryings,
978                                                        GL_SEPARATE_ATTRIBS);
979         if (mProgram == 0)
980         {
981             FAIL() << "shader compilation failed.";
982         }
983 
984         ASSERT_GL_NO_ERROR();
985     }
986 
testTearDown()987     void testTearDown() override { glDeleteProgram(mProgram); }
988 
getAvailableProgramBinaryFormatCount() const989     GLint getAvailableProgramBinaryFormatCount() const
990     {
991         GLint formatCount;
992         glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
993         return formatCount;
994     }
995 
996     GLuint mProgram;
997 };
998 
999 // This tests the assumption that float attribs of different size
1000 // should not internally cause a vertex shader recompile (for conversion).
TEST_P(ProgramBinaryTransformFeedbackTest,GetTransformFeedbackVarying)1001 TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
1002 {
1003     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_get_program_binary"));
1004 
1005     ANGLE_SKIP_TEST_IF(!getAvailableProgramBinaryFormatCount());
1006 
1007     // http://anglebug.com/3690
1008     ANGLE_SKIP_TEST_IF(IsAndroid() && (IsPixel2() || IsPixel2XL()) && IsVulkan());
1009     // http://anglebug.com/4092
1010     ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
1011 
1012     std::vector<uint8_t> binary(0);
1013     GLint programLength = 0;
1014     GLint writtenLength = 0;
1015     GLenum binaryFormat = 0;
1016 
1017     // Save the program binary out
1018     glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1019     ASSERT_GL_NO_ERROR();
1020     binary.resize(programLength);
1021     glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
1022     ASSERT_GL_NO_ERROR();
1023 
1024     glDeleteProgram(mProgram);
1025 
1026     // Load program binary
1027     mProgram = glCreateProgram();
1028     glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
1029 
1030     // Ensure the loaded binary is linked
1031     GLint linkStatus;
1032     glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
1033     EXPECT_TRUE(linkStatus != 0);
1034 
1035     // Query information about the transform feedback varying
1036     char varyingName[64];
1037     GLsizei varyingSize = 0;
1038     GLenum varyingType  = GL_NONE;
1039 
1040     glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType,
1041                                   varyingName);
1042     EXPECT_GL_NO_ERROR();
1043 
1044     EXPECT_EQ(13, writtenLength);
1045     EXPECT_STREQ("outputVarying", varyingName);
1046     EXPECT_EQ(1, varyingSize);
1047     EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
1048 
1049     EXPECT_GL_NO_ERROR();
1050 }
1051 
1052 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
1053 // tests should be run against.
1054 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryTransformFeedbackTest);
1055 
1056 // For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
1057 // - a set to save the program binary
1058 // - a set to load the program binary
1059 // We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test
1060 // macros
1061 struct PlatformsWithLinkResult : PlatformParameters
1062 {
PlatformsWithLinkResultPlatformsWithLinkResult1063     PlatformsWithLinkResult(PlatformParameters saveParams,
1064                             PlatformParameters loadParamsIn,
1065                             bool expectedLinkResultIn)
1066     {
1067         majorVersion       = saveParams.majorVersion;
1068         minorVersion       = saveParams.minorVersion;
1069         eglParameters      = saveParams.eglParameters;
1070         loadParams         = loadParamsIn;
1071         expectedLinkResult = expectedLinkResultIn;
1072     }
1073 
1074     PlatformParameters loadParams;
1075     bool expectedLinkResult;
1076 };
1077 
1078 // Provide a custom gtest parameter name function for PlatformsWithLinkResult
1079 // to avoid returning the same parameter name twice. Such a conflict would happen
1080 // between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
1081 // named ES2_D3D11
operator <<(std::ostream & stream,const PlatformsWithLinkResult & platform)1082 std::ostream &operator<<(std::ostream &stream, const PlatformsWithLinkResult &platform)
1083 {
1084     const PlatformParameters &platform1 = platform;
1085     const PlatformParameters &platform2 = platform.loadParams;
1086     stream << platform1 << "_to_" << platform2;
1087     return stream;
1088 }
1089 
1090 class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
1091 {
1092   public:
SetUp()1093     void SetUp() override
1094     {
1095         mOSWindow   = OSWindow::New();
1096         bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
1097 
1098         if (result == false)
1099         {
1100             FAIL() << "Failed to create OS window";
1101         }
1102 
1103         mEntryPointsLib.reset(
1104             angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir));
1105     }
1106 
createAndInitEGLWindow(angle::PlatformParameters & param)1107     EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
1108     {
1109         EGLWindow *eglWindow = EGLWindow::New(param.majorVersion, param.minorVersion);
1110         ConfigParameters configParams;
1111         bool result = eglWindow->initializeGL(mOSWindow, mEntryPointsLib.get(), param.eglParameters,
1112                                               configParams);
1113         if (!result)
1114         {
1115             EGLWindow::Delete(&eglWindow);
1116         }
1117 
1118         angle::LoadGLES(eglGetProcAddress);
1119 
1120         return eglWindow;
1121     }
1122 
destroyEGLWindow(EGLWindow ** eglWindow)1123     void destroyEGLWindow(EGLWindow **eglWindow)
1124     {
1125         ASSERT_NE(nullptr, *eglWindow);
1126         (*eglWindow)->destroyGL();
1127         EGLWindow::Delete(eglWindow);
1128     }
1129 
createES2ProgramFromSource()1130     GLuint createES2ProgramFromSource()
1131     {
1132         return CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
1133     }
1134 
createES3ProgramFromSource()1135     GLuint createES3ProgramFromSource()
1136     {
1137         return CompileProgram(essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
1138     }
1139 
drawWithProgram(GLuint program)1140     void drawWithProgram(GLuint program)
1141     {
1142         glClearColor(0, 0, 0, 1);
1143         glClear(GL_COLOR_BUFFER_BIT);
1144 
1145         GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
1146 
1147         glUseProgram(program);
1148 
1149         const GLfloat vertices[] = {
1150             -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
1151 
1152             -1.0f, 1.0f, 0.5f, 1.0f,  -1.0f, 0.5f, 1.0f, 1.0f,  0.5f,
1153         };
1154 
1155         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
1156         glEnableVertexAttribArray(positionLocation);
1157 
1158         glDrawArrays(GL_TRIANGLES, 0, 6);
1159 
1160         glDisableVertexAttribArray(positionLocation);
1161         glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
1162 
1163         EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
1164     }
1165 
TearDown()1166     void TearDown() override
1167     {
1168         mOSWindow->destroy();
1169         OSWindow::Delete(&mOSWindow);
1170     }
1171 
1172     OSWindow *mOSWindow = nullptr;
1173     std::unique_ptr<angle::Library> mEntryPointsLib;
1174 };
1175 
1176 // Tries to create a program binary using one set of platform params, then load it using a different
1177 // sent of params
TEST_P(ProgramBinariesAcrossPlatforms,CreateAndReloadBinary)1178 TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
1179 {
1180     angle::PlatformParameters firstRenderer  = GetParam();
1181     angle::PlatformParameters secondRenderer = GetParam().loadParams;
1182     bool expectedLinkResult                  = GetParam().expectedLinkResult;
1183 
1184     // First renderer not supported, skipping test.
1185     ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(firstRenderer)));
1186 
1187     // Second renderer not supported, skipping test.
1188     ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(secondRenderer)));
1189 
1190     EGLWindow *eglWindow = nullptr;
1191     std::vector<uint8_t> binary(0);
1192     GLuint program = 0;
1193 
1194     GLint programLength = 0;
1195     GLint writtenLength = 0;
1196     GLenum binaryFormat = 0;
1197 
1198     // Create a EGL window with the first renderer
1199     eglWindow = createAndInitEGLWindow(firstRenderer);
1200     if (eglWindow == nullptr)
1201     {
1202         FAIL() << "Failed to create EGL window";
1203         return;
1204     }
1205 
1206     // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
1207     // then our expectations for the test results will be invalid.
1208     if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
1209         secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
1210     {
1211         std::string rendererString =
1212             std::string(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
1213         angle::ToLower(&rendererString);
1214 
1215         auto basicRenderPos     = rendererString.find(std::string("microsoft basic render"));
1216         auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
1217 
1218         // The first renderer is using WARP, even though we didn't explictly request it
1219         // We should skip this test
1220         ANGLE_SKIP_TEST_IF(basicRenderPos != std::string::npos ||
1221                            softwareAdapterPos != std::string::npos);
1222     }
1223 
1224     // Create a program
1225     if (firstRenderer.majorVersion == 3)
1226     {
1227         program = createES3ProgramFromSource();
1228     }
1229     else
1230     {
1231         program = createES2ProgramFromSource();
1232     }
1233 
1234     if (program == 0)
1235     {
1236         destroyEGLWindow(&eglWindow);
1237         FAIL() << "Failed to create program from source";
1238     }
1239 
1240     // Draw using the program to ensure it works as expected
1241     drawWithProgram(program);
1242     EXPECT_GL_NO_ERROR();
1243 
1244     // Save the program binary out from this renderer
1245     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1246     EXPECT_GL_NO_ERROR();
1247     binary.resize(programLength);
1248     glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
1249     EXPECT_GL_NO_ERROR();
1250 
1251     // Destroy the first renderer
1252     glDeleteProgram(program);
1253     destroyEGLWindow(&eglWindow);
1254 
1255     // Create an EGL window with the second renderer
1256     eglWindow = createAndInitEGLWindow(secondRenderer);
1257     if (eglWindow == nullptr)
1258     {
1259         FAIL() << "Failed to create EGL window";
1260         return;
1261     }
1262 
1263     program = glCreateProgram();
1264     glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
1265 
1266     GLint linkStatus;
1267     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
1268     EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
1269 
1270     if (linkStatus != 0)
1271     {
1272         // If the link was successful, then we should try to draw using the program to ensure it
1273         // works as expected
1274         drawWithProgram(program);
1275         EXPECT_GL_NO_ERROR();
1276     }
1277 
1278     // Destroy the second renderer
1279     glDeleteProgram(program);
1280     destroyEGLWindow(&eglWindow);
1281 }
1282 
1283 // clang-format off
1284 ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
1285                        //                     | Save the program   | Load the program      | Expected
1286                        //                     | using these params | using these params    | link result
1287                        PlatformsWithLinkResult(ES2_D3D11(),         ES2_D3D11(),            true         ), // Loading + reloading binary should work
1288                        PlatformsWithLinkResult(ES3_D3D11(),         ES3_D3D11(),            true         ), // Loading + reloading binary should work
1289                        PlatformsWithLinkResult(ES2_D3D11(),         ES2_D3D9(),             false        ), // Switching from D3D11 to D3D9 shouldn't work
1290                        PlatformsWithLinkResult(ES2_D3D9(),          ES2_D3D11(),            false        ), // Switching from D3D9 to D3D11 shouldn't work
1291                        PlatformsWithLinkResult(ES2_D3D11(),         ES3_D3D11(),            false        ), // Switching to newer client version shouldn't work
1292                        );
1293 // clang-format on
1294