• 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::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 
testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)293 void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
294 {
295     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
296 
297     constexpr char kVS[] =
298         "#version 300 es\n"
299         "uniform block {\n"
300         "    float f;\n"
301         "};\n"
302         "in vec4 position;\n"
303         "out vec4 color;\n"
304         "void main() {\n"
305         "    gl_Position = position;\n"
306         "    color = vec4(f, f, f, 1);\n"
307         "}";
308 
309     constexpr char kFS[] =
310         "#version 300 es\n"
311         "precision mediump float;\n"
312         "in vec4 color;\n"
313         "out vec4 colorOut;\n"
314         "void main() {\n"
315         "    colorOut = color;\n"
316         "}";
317 
318     // Init and draw with the program.
319     ANGLE_GL_PROGRAM(program, kVS, kFS);
320 
321     float fData[4]   = {1.0f, 1.0f, 1.0f, 1.0f};
322     GLuint bindIndex = 2;
323 
324     GLBuffer ubo;
325     glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
326     glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
327     glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
328 
329     GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
330     ASSERT_NE(-1, blockIndex);
331 
332     glUniformBlockBinding(program.get(), blockIndex, bindIndex);
333 
334     glClearColor(1.0, 0.0, 0.0, 1.0);
335     glClear(GL_COLOR_BUFFER_BIT);
336     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
337 
338     if (drawWithProgramFirst)
339     {
340         drawQuad(program.get(), "position", 0.5f);
341         ASSERT_GL_NO_ERROR();
342         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
343     }
344 
345     // Read back the binary.
346     GLint programLength = 0;
347     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
348     ASSERT_GL_NO_ERROR();
349 
350     GLsizei readLength  = 0;
351     GLenum binaryFormat = GL_NONE;
352     std::vector<uint8_t> binary(programLength);
353     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
354     ASSERT_GL_NO_ERROR();
355 
356     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
357 
358     // Load a new program with the binary and draw.
359     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
360 
361     glClearColor(1.0, 0.0, 0.0, 1.0);
362     glClear(GL_COLOR_BUFFER_BIT);
363     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
364 
365     drawQuad(binaryProgram.get(), "position", 0.5f);
366     ASSERT_GL_NO_ERROR();
367     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
368 }
369 
370 // Tests that saving and loading a program perserves uniform block binding info.
TEST_P(ProgramBinaryES3Test,UniformBlockBindingWithDraw)371 TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
372 {
373     testBinaryAndUBOBlockIndexes(true);
374 }
375 
376 // Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
377 // http://anglebug.com/1637
TEST_P(ProgramBinaryES3Test,UniformBlockBindingNoDraw)378 TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
379 {
380     testBinaryAndUBOBlockIndexes(false);
381 }
382 
383 // Test the shaders with arrays-of-struct uniforms are properly saved and restored
TEST_P(ProgramBinaryES3Test,TestArrayOfStructUniform)384 TEST_P(ProgramBinaryES3Test, TestArrayOfStructUniform)
385 {
386     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
387 
388     constexpr char kVS[] =
389         "#version 300 es\n"
390         "in highp vec4 position;\n"
391         "out mediump float v_vtxOut;\n"
392         "\n"
393         "struct structType\n"
394         "{\n"
395         "    mediump vec4 m0;\n"
396         "    mediump vec4 m1;\n"
397         "};\n"
398         "uniform structType u_var[3];\n"
399         "\n"
400         "mediump float compare_float(mediump float a, mediump float b)\n"
401         "{\n"
402         "    return abs(a - b) < 0.05 ? 1.0 : 0.0;\n"
403         "}\n"
404         "mediump float compare_vec4(mediump vec4 a, mediump vec4 b)\n"
405         "{\n"
406         "    return compare_float(a.x, b.x)*compare_float(a.y, b.y)*\n"
407         "           compare_float(a.z, b.z)*compare_float(a.w, b.w);\n"
408         "}\n"
409         "\n"
410         "void main (void)\n"
411         "{\n"
412         "    gl_Position = position;\n"
413         "    v_vtxOut = 1.0;\n"
414         "    v_vtxOut *= compare_vec4(u_var[0].m0, vec4(0.15, 0.52, 0.26, 0.35));\n"
415         "    v_vtxOut *= compare_vec4(u_var[0].m1, vec4(0.88, 0.09, 0.30, 0.61));\n"
416         "    v_vtxOut *= compare_vec4(u_var[1].m0, vec4(0.85, 0.59, 0.33, 0.71));\n"
417         "    v_vtxOut *= compare_vec4(u_var[1].m1, vec4(0.62, 0.89, 0.09, 0.99));\n"
418         "    v_vtxOut *= compare_vec4(u_var[2].m0, vec4(0.53, 0.89, 0.01, 0.08));\n"
419         "    v_vtxOut *= compare_vec4(u_var[2].m1, vec4(0.26, 0.72, 0.60, 0.12));\n"
420         "}";
421 
422     constexpr char kFS[] =
423         "#version 300 es\n"
424         "in mediump float v_vtxOut;\n"
425         "\n"
426         "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
427         "\n"
428         "void main (void)\n"
429         "{\n"
430         "    mediump float result = v_vtxOut;\n"
431         "    dEQP_FragColor = vec4(result, result, result, 1.0);\n"
432         "}";
433 
434     // Init and draw with the program.
435     ANGLE_GL_PROGRAM(program, kVS, kFS);
436 
437     glUseProgram(program.get());
438 
439     int location = glGetUniformLocation(program.get(), "u_var[0].m0");
440     ASSERT_NE(location, -1);
441     glUniform4f(location, 0.15, 0.52, 0.26, 0.35);
442     location = glGetUniformLocation(program.get(), "u_var[0].m1");
443     ASSERT_NE(location, -1);
444     glUniform4f(location, 0.88, 0.09, 0.30, 0.61);
445     location = glGetUniformLocation(program.get(), "u_var[1].m0");
446     ASSERT_NE(location, -1);
447     glUniform4f(location, 0.85, 0.59, 0.33, 0.71);
448     location = glGetUniformLocation(program.get(), "u_var[1].m1");
449     ASSERT_NE(location, -1);
450     glUniform4f(location, 0.62, 0.89, 0.09, 0.99);
451     location = glGetUniformLocation(program.get(), "u_var[2].m0");
452     ASSERT_NE(location, -1);
453     glUniform4f(location, 0.53, 0.89, 0.01, 0.08);
454     location = glGetUniformLocation(program.get(), "u_var[2].m1");
455     ASSERT_NE(location, -1);
456     glUniform4f(location, 0.26, 0.72, 0.60, 0.12);
457     ASSERT_GL_NO_ERROR();
458 
459     // Clear and draw with the original program:
460     glClearColor(1.0, 0.0, 0.0, 1.0);
461     glClear(GL_COLOR_BUFFER_BIT);
462     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
463     drawQuad(program.get(), "position", 0.5f);
464     ASSERT_GL_NO_ERROR();
465     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
466 
467     // Read back the binary.
468     GLint programLength = 0;
469     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
470     ASSERT_GL_NO_ERROR();
471 
472     GLsizei readLength  = 0;
473     GLenum binaryFormat = GL_NONE;
474     std::vector<uint8_t> binary(programLength);
475     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
476     ASSERT_GL_NO_ERROR();
477 
478     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
479 
480     // Load a new program with the binary and draw.
481     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
482 
483     glUseProgram(binaryProgram.get());
484 
485     location = glGetUniformLocation(binaryProgram.get(), "u_var[0].m0");
486     ASSERT_NE(location, -1);
487     glUniform4f(location, 0.15, 0.52, 0.26, 0.35);
488     location = glGetUniformLocation(binaryProgram.get(), "u_var[0].m1");
489     ASSERT_NE(location, -1);
490     glUniform4f(location, 0.88, 0.09, 0.30, 0.61);
491     location = glGetUniformLocation(binaryProgram.get(), "u_var[1].m0");
492     ASSERT_NE(location, -1);
493     glUniform4f(location, 0.85, 0.59, 0.33, 0.71);
494     location = glGetUniformLocation(binaryProgram.get(), "u_var[1].m1");
495     ASSERT_NE(location, -1);
496     glUniform4f(location, 0.62, 0.89, 0.09, 0.99);
497     location = glGetUniformLocation(binaryProgram.get(), "u_var[2].m0");
498     ASSERT_NE(location, -1);
499     glUniform4f(location, 0.53, 0.89, 0.01, 0.08);
500     location = glGetUniformLocation(binaryProgram.get(), "u_var[2].m1");
501     ASSERT_NE(location, -1);
502     glUniform4f(location, 0.26, 0.72, 0.60, 0.12);
503     ASSERT_GL_NO_ERROR();
504 
505     // Clear and draw with the restored program:
506     glClearColor(1.0, 0.0, 0.0, 1.0);
507     glClear(GL_COLOR_BUFFER_BIT);
508     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
509     drawQuad(binaryProgram.get(), "position", 0.5f);
510     ASSERT_GL_NO_ERROR();
511     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
512 }
513 
514 // Verify that saving/loading binary with detached shaders followed by indexed
515 // drawing works.
TEST_P(ProgramBinaryES3Test,SaveAndLoadDetachedShaders)516 TEST_P(ProgramBinaryES3Test, SaveAndLoadDetachedShaders)
517 {
518     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
519 
520     // We use shaders with the "flat" qualifier, to ensure that "flat" behaves
521     // across save/load. This is primarily to catch possible bugs in the Metal
522     // backend, where it needs to detect "flat" at shader link time and
523     // preserve that detection across binary save/load.
524     constexpr char kVS[] = R"(#version 300 es
525 precision highp float;
526 
527 in vec4 a_position;
528 flat out vec4 v_color;
529 
530 const vec4 colors[4] = vec4[](
531     vec4(0.0f, 0.0f, 1.0f, 1.0f),
532     vec4(0.0f, 0.0f, 1.0f, 1.0f),
533     vec4(0.0f, 1.0f, 0.0f, 1.0f),
534     vec4(0.0f, 1.0f, 0.0f, 1.0f)
535 );
536 
537 void main()
538 {
539     v_color = colors[gl_VertexID];
540     gl_Position = a_position;
541 }
542 )";
543 
544     constexpr char kFS[] = R"(#version 300 es
545 precision highp float;
546 
547 flat in vec4 v_color;
548 out vec4 o_color;
549 
550 void main()
551 {
552     o_color = v_color;
553 }
554 )";
555 
556     const auto &vertices = GetIndexedQuadVertices();
557 
558     GLBuffer vertexBuffer;
559     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
560     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
561                  GL_STATIC_DRAW);
562 
563     GLBuffer indexBuffer;
564     const auto &indices = GetQuadIndices();
565     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
566     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
567                  GL_STATIC_DRAW);
568     ASSERT_GL_NO_ERROR();
569 
570     GLuint vertexShader   = CompileShader(GL_VERTEX_SHADER, kVS);
571     GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, kFS);
572     ASSERT_NE(0u, vertexShader);
573     ASSERT_NE(0u, fragmentShader);
574 
575     GLuint program = glCreateProgram();
576     glAttachShader(program, vertexShader);
577     glAttachShader(program, fragmentShader);
578 
579     glLinkProgram(program);
580 
581     GLint linkStatus;
582     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
583     EXPECT_EQ(GL_TRUE, linkStatus);
584 
585     glDetachShader(program, vertexShader);
586     glDetachShader(program, fragmentShader);
587     glDeleteShader(vertexShader);
588     glDeleteShader(fragmentShader);
589     ASSERT_GL_NO_ERROR();
590 
591     GLuint loadedProgram = glCreateProgram();
592     saveAndLoadProgram(program, loadedProgram);
593     glDeleteProgram(program);
594 
595     ASSERT_EQ(glIsProgram(loadedProgram), GL_TRUE);
596     glUseProgram(loadedProgram);
597     ASSERT_GL_NO_ERROR();
598 
599     GLint posLocation = glGetAttribLocation(loadedProgram, "a_position");
600     ASSERT_NE(-1, posLocation);
601 
602     GLVertexArray vertexArray;
603     glBindVertexArray(vertexArray);
604     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
605     glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
606     glEnableVertexAttribArray(posLocation);
607     ASSERT_GL_NO_ERROR();
608 
609     glClearColor(1.0, 0.0, 0.0, 1.0);
610     glClear(GL_COLOR_BUFFER_BIT);
611     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
612 
613     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
614     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
615     ASSERT_GL_NO_ERROR();
616 
617     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
618 
619     glDeleteProgram(loadedProgram);
620     ASSERT_GL_NO_ERROR();
621 }
622 
623 // Tests the difference between uniform static and active use
TEST_P(ProgramBinaryES3Test,ActiveUniformShader)624 TEST_P(ProgramBinaryES3Test, ActiveUniformShader)
625 {
626     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
627 
628     constexpr char kVS[] =
629         "#version 300 es\n"
630         "in vec4 position;\n"
631         "void main() {\n"
632         "    gl_Position = position;\n"
633         "}";
634 
635     constexpr char kFS[] =
636         "#version 300 es\n"
637         "precision mediump float;\n"
638         "uniform float values[2];\n"
639         "out vec4 color;\n"
640         "bool isZero(float value) {\n"
641         "    return value == 0.0f;\n"
642         "}\n"
643         "void main() {\n"
644         "    color = isZero(values[1]) ? vec4(1.0f,0.0f,0.0f,1.0f) : vec4(0.0f,1.0f,0.0f,1.0f);\n"
645         "}";
646 
647     // Init and draw with the program.
648     ANGLE_GL_PROGRAM(program, kVS, kFS);
649 
650     GLint valuesLoc = glGetUniformLocation(program.get(), "values");
651     ASSERT_NE(-1, valuesLoc);
652 
653     glUseProgram(program.get());
654     GLfloat values[2] = {0.5f, 1.0f};
655     glUniform1fv(valuesLoc, 2, values);
656     ASSERT_GL_NO_ERROR();
657 
658     glClearColor(1.0, 0.0, 0.0, 1.0);
659     glClear(GL_COLOR_BUFFER_BIT);
660     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
661 
662     drawQuad(program.get(), "position", 0.5f);
663     ASSERT_GL_NO_ERROR();
664     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
665 
666     // Read back the binary.
667     GLint programLength = 0;
668     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
669     ASSERT_GL_NO_ERROR();
670 
671     GLsizei readLength  = 0;
672     GLenum binaryFormat = GL_NONE;
673     std::vector<uint8_t> binary(programLength);
674     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
675     ASSERT_GL_NO_ERROR();
676 
677     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
678 
679     // Load a new program with the binary and draw.
680     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
681 
682     valuesLoc = glGetUniformLocation(program.get(), "values");
683     ASSERT_NE(-1, valuesLoc);
684 
685     glUseProgram(binaryProgram.get());
686     GLfloat values2[2] = {0.1f, 1.0f};
687     glUniform1fv(valuesLoc, 2, values2);
688     ASSERT_GL_NO_ERROR();
689 
690     glClearColor(1.0, 0.0, 0.0, 1.0);
691     glClear(GL_COLOR_BUFFER_BIT);
692     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
693 
694     drawQuad(binaryProgram.get(), "position", 0.5f);
695     ASSERT_GL_NO_ERROR();
696     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
697 }
698 
699 // Test that uses many uniforms in the shaders
TEST_P(ProgramBinaryES3Test,BinaryWithLargeUniformCount)700 TEST_P(ProgramBinaryES3Test, BinaryWithLargeUniformCount)
701 {
702     // Suspecting AMD driver bug - failure seen on bots running on ATI GPU on Windows.
703     // http://anglebug.com/3721
704     ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && IsWindows());
705 
706     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
707 
708     constexpr char kVS[] =
709         "#version 300 es\n"
710         "uniform float redVS; \n"
711         "uniform block0 {\n"
712         "    float val0;\n"
713         "};\n"
714         "uniform float greenVS; \n"
715         "uniform float blueVS; \n"
716         "in vec4 position;\n"
717         "out vec4 color;\n"
718         "void main() {\n"
719         "    gl_Position = position;\n"
720         "    color = vec4(redVS + val0, greenVS, blueVS, 1.0f);\n"
721         "}";
722 
723     constexpr char kFS[] =
724         "#version 300 es\n"
725         "precision mediump float;\n"
726         "uniform float redFS; \n"
727         "uniform float greenFS; \n"
728         "uniform block1 {\n"
729         "    float val1;\n"
730         "    float val2;\n"
731         "};\n"
732         "uniform float blueFS; \n"
733         "in vec4 color;\n"
734         "out vec4 colorOut;\n"
735         "void main() {\n"
736         "    colorOut = vec4(color.r + redFS,\n"
737         "                    color.g + greenFS + val1,\n"
738         "                    color.b + blueFS + val2, \n"
739         "                    color.a);\n"
740         "}";
741 
742     // Init and draw with the program.
743     ANGLE_GL_PROGRAM(program, kVS, kFS);
744 
745     float block0Data[4] = {-0.7f, 1.0f, 1.0f, 1.0f};
746     float block1Data[4] = {0.4f, -0.8f, 1.0f, 1.0f};
747     GLuint bindIndex0   = 5;
748     GLuint bindIndex1   = 2;
749 
750     GLBuffer ubo0;
751     glBindBuffer(GL_UNIFORM_BUFFER, ubo0.get());
752     glBufferData(GL_UNIFORM_BUFFER, sizeof(block0Data), &block0Data, GL_STATIC_DRAW);
753     glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex0, ubo0.get(), 0, sizeof(block0Data));
754     ASSERT_GL_NO_ERROR();
755 
756     GLBuffer ubo1;
757     glBindBuffer(GL_UNIFORM_BUFFER, ubo1.get());
758     glBufferData(GL_UNIFORM_BUFFER, sizeof(block1Data), &block1Data, GL_STATIC_DRAW);
759     glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex1, ubo1.get(), 0, sizeof(block1Data));
760     ASSERT_GL_NO_ERROR();
761 
762     GLint block0Index = glGetUniformBlockIndex(program.get(), "block0");
763     ASSERT_NE(-1, block0Index);
764 
765     GLint block1Index = glGetUniformBlockIndex(program.get(), "block1");
766     ASSERT_NE(-1, block1Index);
767 
768     glUniformBlockBinding(program.get(), block0Index, bindIndex0);
769     glUniformBlockBinding(program.get(), block1Index, bindIndex1);
770     ASSERT_GL_NO_ERROR();
771 
772     GLint redVSLoc = glGetUniformLocation(program.get(), "redVS");
773     ASSERT_NE(-1, redVSLoc);
774     GLint greenVSLoc = glGetUniformLocation(program.get(), "greenVS");
775     ASSERT_NE(-1, greenVSLoc);
776     GLint blueVSLoc = glGetUniformLocation(program.get(), "blueVS");
777     ASSERT_NE(-1, blueVSLoc);
778     GLint redFSLoc = glGetUniformLocation(program.get(), "redFS");
779     ASSERT_NE(-1, redFSLoc);
780     GLint greenFSLoc = glGetUniformLocation(program.get(), "greenFS");
781     ASSERT_NE(-1, greenFSLoc);
782     GLint blueFSLoc = glGetUniformLocation(program.get(), "blueFS");
783     ASSERT_NE(-1, blueFSLoc);
784 
785     glUseProgram(program.get());
786     glUniform1f(redVSLoc, 0.6f);
787     glUniform1f(greenVSLoc, 0.2f);
788     glUniform1f(blueVSLoc, 1.1f);
789     glUniform1f(redFSLoc, 0.1f);
790     glUniform1f(greenFSLoc, 0.4f);
791     glUniform1f(blueFSLoc, 0.7f);
792     ASSERT_GL_NO_ERROR();
793 
794     glClearColor(1.0, 0.0, 0.0, 1.0);
795     glClear(GL_COLOR_BUFFER_BIT);
796     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
797 
798     drawQuad(program.get(), "position", 0.5f);
799     ASSERT_GL_NO_ERROR();
800     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
801 
802     // Read back the binary.
803     GLint programLength = 0;
804     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
805     ASSERT_GL_NO_ERROR();
806 
807     GLsizei readLength  = 0;
808     GLenum binaryFormat = GL_NONE;
809     std::vector<uint8_t> binary(programLength);
810     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
811     ASSERT_GL_NO_ERROR();
812 
813     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
814 
815     // Load a new program with the binary and draw.
816     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
817 
818     redVSLoc = glGetUniformLocation(program.get(), "redVS");
819     ASSERT_NE(-1, redVSLoc);
820     greenVSLoc = glGetUniformLocation(program.get(), "greenVS");
821     ASSERT_NE(-1, greenVSLoc);
822     blueVSLoc = glGetUniformLocation(program.get(), "blueVS");
823     ASSERT_NE(-1, blueVSLoc);
824     redFSLoc = glGetUniformLocation(program.get(), "redFS");
825     ASSERT_NE(-1, redFSLoc);
826     greenFSLoc = glGetUniformLocation(program.get(), "greenFS");
827     ASSERT_NE(-1, greenFSLoc);
828     blueFSLoc = glGetUniformLocation(program.get(), "blueFS");
829     ASSERT_NE(-1, blueFSLoc);
830 
831     glUseProgram(binaryProgram.get());
832     glUniform1f(redVSLoc, 0.2f);
833     glUniform1f(greenVSLoc, -0.6f);
834     glUniform1f(blueVSLoc, 1.0f);
835     glUniform1f(redFSLoc, 1.5f);
836     glUniform1f(greenFSLoc, 0.2f);
837     glUniform1f(blueFSLoc, 0.8f);
838     ASSERT_GL_NO_ERROR();
839 
840     glClearColor(1.0, 0.0, 0.0, 1.0);
841     glClear(GL_COLOR_BUFFER_BIT);
842     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
843 
844     drawQuad(binaryProgram.get(), "position", 0.5f);
845     ASSERT_GL_NO_ERROR();
846     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
847 }
848 
849 // Test that sampler texelFetch references are saved and loaded correctly
TEST_P(ProgramBinaryTest,SRGBDecodeWithSamplerAndTexelFetchTest)850 TEST_P(ProgramBinaryTest, SRGBDecodeWithSamplerAndTexelFetchTest)
851 {
852     if (!supported())
853     {
854         return;
855     }
856 
857     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
858                        getClientMajorVersion() < 3);
859 
860     // These OpenGL drivers appear not to respect the texelFetch exception
861     // http://anglebug.com/4991
862     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
863     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsWindows());
864     ANGLE_SKIP_TEST_IF(IsOpenGL() && (IsNVIDIA() || IsARM64()) && IsMac());
865     ANGLE_SKIP_TEST_IF(IsOpenGLES() && IsNexus5X());
866 
867     constexpr char kVS[] =
868         "#version 300 es\n"
869         "precision highp float;\n"
870         "in vec4 position;\n"
871         "\n"
872         "void main()\n"
873         "{\n"
874         "   gl_Position = vec4(position.xy, 0.0, 1.0);\n"
875         "}\n";
876 
877     constexpr char kFS[] =
878         "#version 300 es\n"
879         "precision highp float;\n"
880         "uniform sampler2D tex;\n"
881         "in vec2 texcoord;\n"
882         "out vec4 out_color;\n"
883         "\n"
884         "void main()\n"
885         "{\n"
886         "   out_color = texelFetch(tex, ivec2(0, 0), 0);\n"
887         "}\n";
888 
889     GLProgram program;
890     program.makeRaster(kVS, kFS);
891     ASSERT_NE(0u, program.get());
892 
893     GLuint reloadedProgram = glCreateProgram();
894     saveAndLoadProgram(program.get(), reloadedProgram);
895 
896     GLint textureLocation = glGetUniformLocation(reloadedProgram, "tex");
897     ASSERT_NE(-1, textureLocation);
898 
899     GLColor linearColor(64, 127, 191, 255);
900     GLColor srgbColor(13, 54, 133, 255);
901 
902     GLTexture tex;
903     glBindTexture(GL_TEXTURE_2D, tex.get());
904     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
905                  &linearColor);
906     ASSERT_GL_NO_ERROR();
907 
908     GLSampler sampler;
909     glBindSampler(0, sampler.get());
910     glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
911 
912     glUseProgram(reloadedProgram);
913     glUniform1i(textureLocation, 0);
914 
915     glDisable(GL_DEPTH_TEST);
916     drawQuad(reloadedProgram, "position", 0.5f);
917 
918     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
919 
920     glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
921     drawQuad(reloadedProgram, "position", 0.5f);
922 
923     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
924 
925     glDeleteProgram(reloadedProgram);
926 }
927 
928 // Test that array of structs containing array of samplers work as expected.
TEST_P(ProgramBinaryES3Test,ArrayOfStructContainingArrayOfSamplers)929 TEST_P(ProgramBinaryES3Test, ArrayOfStructContainingArrayOfSamplers)
930 {
931     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
932 
933     constexpr char kFS[] =
934         "precision mediump float;\n"
935         "struct Data { mediump sampler2D data[2]; };\n"
936         "uniform Data test[2];\n"
937         "void main() {\n"
938         "    gl_FragColor = vec4(texture2D(test[1].data[1], vec2(0.0, 0.0)).r,\n"
939         "                        texture2D(test[1].data[0], vec2(0.0, 0.0)).r,\n"
940         "                        texture2D(test[0].data[1], vec2(0.0, 0.0)).r,\n"
941         "                        texture2D(test[0].data[0], vec2(0.0, 0.0)).r);\n"
942         "}\n";
943 
944     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
945     glUseProgram(program.get());
946     GLTexture textures[4];
947     GLColor expected = MakeGLColor(32, 64, 96, 255);
948     GLubyte data[8]  = {};  // 4 bytes of padding, so that texture can be initialized with 4 bytes
949     memcpy(data, expected.data(), sizeof(expected));
950     for (int i = 0; i < 4; i++)
951     {
952         int outerIdx = i % 2;
953         int innerIdx = i / 2;
954         glActiveTexture(GL_TEXTURE0 + i);
955         glBindTexture(GL_TEXTURE_2D, textures[i]);
956         // Each element provides two components.
957         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data + i);
958         std::stringstream uniformName;
959         uniformName << "test[" << innerIdx << "].data[" << outerIdx << "]";
960         // Then send it as a uniform
961         GLint uniformLocation = glGetUniformLocation(program.get(), uniformName.str().c_str());
962         // The uniform should be active.
963         EXPECT_NE(uniformLocation, -1);
964 
965         glUniform1i(uniformLocation, 3 - i);
966         ASSERT_GL_NO_ERROR();
967     }
968 
969     drawQuad(program.get(), essl1_shaders::PositionAttrib(), 0.5f);
970     ASSERT_GL_NO_ERROR();
971     EXPECT_PIXEL_COLOR_EQ(0, 0, expected);
972 
973     // Read back the binary.
974     GLint programLength = 0;
975     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
976     ASSERT_GL_NO_ERROR();
977 
978     GLsizei readLength  = 0;
979     GLenum binaryFormat = GL_NONE;
980     std::vector<uint8_t> binary(programLength);
981     glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
982     ASSERT_GL_NO_ERROR();
983 
984     // Load a new program with the binary.
985     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
986     glUseProgram(binaryProgram);
987 
988     for (int i = 0; i < 4; i++)
989     {
990         int outerIdx = i % 2;
991         int innerIdx = i / 2;
992         std::stringstream uniformName;
993         uniformName << "test[" << innerIdx << "].data[" << outerIdx << "]";
994         // Then send it as a uniform
995         GLint uniformLocation = glGetUniformLocation(program, uniformName.str().c_str());
996         // The uniform should be active.
997         EXPECT_NE(uniformLocation, -1);
998 
999         glUniform1i(uniformLocation, 3 - i);
1000         ASSERT_GL_NO_ERROR();
1001     }
1002 
1003     // Verify the uniform data with the binary program.
1004     drawQuad(binaryProgram, essl1_shaders::PositionAttrib(), 0.5f);
1005     ASSERT_GL_NO_ERROR();
1006     EXPECT_PIXEL_COLOR_EQ(0, 0, expected);
1007 }
1008 
1009 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryES3Test);
1010 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryES3Test);
1011 
1012 class ProgramBinaryES31Test : public ANGLETest<>
1013 {
1014   protected:
ProgramBinaryES31Test()1015     ProgramBinaryES31Test()
1016     {
1017         setWindowWidth(128);
1018         setWindowHeight(128);
1019         setConfigRedBits(8);
1020         setConfigGreenBits(8);
1021         setConfigBlueBits(8);
1022         setConfigAlphaBits(8);
1023 
1024         // Test flakiness was noticed when reusing displays.
1025         forceNewDisplay();
1026     }
1027 
getAvailableProgramBinaryFormatCount() const1028     GLint getAvailableProgramBinaryFormatCount() const
1029     {
1030         GLint formatCount;
1031         glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
1032         return formatCount;
1033     }
1034 };
1035 
1036 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithComputeShader)1037 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
1038 {
1039     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1040 
1041     // http://anglebug.com/4092
1042     ANGLE_SKIP_TEST_IF(IsVulkan());
1043 
1044     constexpr char kCS[] =
1045         "#version 310 es\n"
1046         "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
1047         "uniform block {\n"
1048         "    vec2 f;\n"
1049         "};\n"
1050         "uniform vec2 g;\n"
1051         "uniform highp sampler2D tex;\n"
1052         "void main() {\n"
1053         "    vec4 color = texture(tex, f + g);\n"
1054         "}";
1055 
1056     ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1057 
1058     // Read back the binary.
1059     GLint programLength = 0;
1060     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
1061     ASSERT_GL_NO_ERROR();
1062 
1063     GLsizei readLength  = 0;
1064     GLenum binaryFormat = GL_NONE;
1065     std::vector<uint8_t> binary(programLength);
1066     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
1067     ASSERT_GL_NO_ERROR();
1068 
1069     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1070 
1071     // Load a new program with the binary.
1072     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1073     ASSERT_GL_NO_ERROR();
1074 
1075     // Dispatch compute with the loaded binary program
1076     glUseProgram(binaryProgram.get());
1077     glDispatchCompute(8, 4, 2);
1078     ASSERT_GL_NO_ERROR();
1079 }
1080 
1081 // Tests saving and loading a separable program that has a computer shader using a uniform and a
1082 // uniform block.
TEST_P(ProgramBinaryES31Test,SeparableProgramLinkedUniforms)1083 TEST_P(ProgramBinaryES31Test, SeparableProgramLinkedUniforms)
1084 {
1085     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1086 
1087     constexpr char kComputeShader[] = R"(#version 310 es
1088 layout(local_size_x=4, local_size_y=3, local_size_z=1) in;
1089 uniform float testUint;
1090 uniform TestBlock
1091 {
1092     mat4 testMatrix;
1093 };
1094 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
1095 void main() {
1096     imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(testMatrix[0][0] + testUint, 0, 0, 0));
1097 })";
1098 
1099     ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
1100     glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
1101 
1102     // Read back the binary.
1103     GLint programLength = 0;
1104     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1105     ASSERT_GL_NO_ERROR();
1106 
1107     GLsizei readLength  = 0;
1108     GLenum binaryFormat = GL_NONE;
1109     std::vector<uint8_t> binary(programLength);
1110     glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
1111     ASSERT_GL_NO_ERROR();
1112 
1113     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1114 
1115     // Load a new program with the binary.
1116     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1117     ASSERT_GL_NO_ERROR();
1118 
1119     glUseProgram(binaryProgram);
1120     ASSERT_GL_NO_ERROR();
1121 }
1122 
1123 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithAtomicCounterComputeShader)1124 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader)
1125 {
1126     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1127 
1128     constexpr char kComputeShader[] = R"(#version 310 es
1129 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1130 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
1131 void main() {
1132     atomicCounterIncrement(ac[0]);
1133     atomicCounterDecrement(ac[1]);
1134 })";
1135 
1136     ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
1137 
1138     // Read back the binary.
1139     GLint programLength = 0;
1140     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1141     ASSERT_GL_NO_ERROR();
1142 
1143     GLsizei readLength  = 0;
1144     GLenum binaryFormat = GL_NONE;
1145     std::vector<uint8_t> binary(programLength);
1146     glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
1147     ASSERT_GL_NO_ERROR();
1148 
1149     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1150 
1151     // Load a new program with the binary.
1152     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1153     ASSERT_GL_NO_ERROR();
1154 
1155     // Dispatch compute with the loaded binary program
1156     glUseProgram(binaryProgram);
1157 
1158     // The initial value of 'ac[0]' is 3u, 'ac[1]' is 1u.
1159     unsigned int bufferData[3] = {11u, 3u, 1u};
1160     GLBuffer atomicCounterBuffer;
1161     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
1162     glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
1163 
1164     glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
1165 
1166     glDispatchCompute(1, 1, 1);
1167     EXPECT_GL_NO_ERROR();
1168 
1169     glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1170 
1171     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
1172     void *mappedBuffer =
1173         glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
1174     memcpy(bufferData, mappedBuffer, sizeof(bufferData));
1175     glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1176 
1177     EXPECT_EQ(11u, bufferData[0]);
1178     EXPECT_EQ(4u, bufferData[1]);
1179     EXPECT_EQ(0u, bufferData[2]);
1180     ASSERT_GL_NO_ERROR();
1181 }
1182 
1183 // Tests that image texture works correctly when loading a program from binary.
TEST_P(ProgramBinaryES31Test,ImageTextureBinding)1184 TEST_P(ProgramBinaryES31Test, ImageTextureBinding)
1185 {
1186     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1187 
1188     const char kComputeShader[] =
1189         R"(#version 310 es
1190         layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1191         layout(r32ui, binding = 1) writeonly uniform highp uimage2D writeImage;
1192         void main()
1193         {
1194             imageStore(writeImage, ivec2(gl_LocalInvocationID.xy), uvec4(200u));
1195         })";
1196 
1197     ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
1198 
1199     // Read back the binary.
1200     GLint programLength = 0;
1201     glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
1202     ASSERT_GL_NO_ERROR();
1203 
1204     GLsizei readLength  = 0;
1205     GLenum binaryFormat = GL_NONE;
1206     std::vector<uint8_t> binary(programLength);
1207     glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
1208     ASSERT_GL_NO_ERROR();
1209 
1210     EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
1211 
1212     // Load a new program with the binary.
1213     ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
1214     ASSERT_GL_NO_ERROR();
1215 
1216     // Dispatch compute with the loaded binary program
1217     glUseProgram(binaryProgram.get());
1218     GLTexture texture;
1219     glBindTexture(GL_TEXTURE_2D, texture);
1220     glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
1221     constexpr GLuint kInputValue = 100u;
1222     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &kInputValue);
1223     EXPECT_GL_NO_ERROR();
1224 
1225     glBindImageTexture(1, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1226 
1227     glDispatchCompute(1, 1, 1);
1228     EXPECT_GL_NO_ERROR();
1229 
1230     GLFramebuffer framebuffer;
1231     glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1232     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1233 
1234     GLuint outputValue;
1235     glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
1236     EXPECT_EQ(200u, outputValue);
1237     ASSERT_GL_NO_ERROR();
1238 }
1239 
1240 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryES31Test);
1241 ANGLE_INSTANTIATE_TEST_ES31(ProgramBinaryES31Test);
1242 
1243 class ProgramBinaryTransformFeedbackTest : public ANGLETest<>
1244 {
1245   protected:
ProgramBinaryTransformFeedbackTest()1246     ProgramBinaryTransformFeedbackTest()
1247     {
1248         setWindowWidth(128);
1249         setWindowHeight(128);
1250         setConfigRedBits(8);
1251         setConfigGreenBits(8);
1252         setConfigBlueBits(8);
1253         setConfigAlphaBits(8);
1254     }
1255 
testSetUp()1256     void testSetUp() override
1257     {
1258         constexpr char kVS[] = R"(#version 300 es
1259 in vec4 inputAttribute;
1260 out vec4 outputVarying;
1261 void main()
1262 {
1263     outputVarying = inputAttribute;
1264 })";
1265 
1266         constexpr char kFS[] = R"(#version 300 es
1267 precision highp float;
1268 out vec4 outputColor;
1269 void main()
1270 {
1271     outputColor = vec4(1,0,0,1);
1272 })";
1273 
1274         std::vector<std::string> transformFeedbackVaryings;
1275         transformFeedbackVaryings.push_back("outputVarying");
1276 
1277         mProgram = CompileProgramWithTransformFeedback(kVS, kFS, transformFeedbackVaryings,
1278                                                        GL_SEPARATE_ATTRIBS);
1279         if (mProgram == 0)
1280         {
1281             FAIL() << "shader compilation failed.";
1282         }
1283 
1284         ASSERT_GL_NO_ERROR();
1285     }
1286 
testTearDown()1287     void testTearDown() override { glDeleteProgram(mProgram); }
1288 
getAvailableProgramBinaryFormatCount() const1289     GLint getAvailableProgramBinaryFormatCount() const
1290     {
1291         GLint formatCount;
1292         glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
1293         return formatCount;
1294     }
1295 
1296     GLuint mProgram;
1297 };
1298 
1299 // This tests the assumption that float attribs of different size
1300 // should not internally cause a vertex shader recompile (for conversion).
TEST_P(ProgramBinaryTransformFeedbackTest,GetTransformFeedbackVarying)1301 TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
1302 {
1303     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_get_program_binary"));
1304 
1305     ANGLE_SKIP_TEST_IF(getAvailableProgramBinaryFormatCount() == 0);
1306 
1307     // http://anglebug.com/3690
1308     ANGLE_SKIP_TEST_IF(IsAndroid() && (IsPixel2() || IsPixel2XL()) && IsVulkan());
1309     // http://anglebug.com/4092
1310     ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
1311 
1312     std::vector<uint8_t> binary(0);
1313     GLint programLength = 0;
1314     GLint writtenLength = 0;
1315     GLenum binaryFormat = 0;
1316 
1317     // Save the program binary out
1318     glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1319     ASSERT_GL_NO_ERROR();
1320     binary.resize(programLength);
1321     glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
1322     ASSERT_GL_NO_ERROR();
1323 
1324     glDeleteProgram(mProgram);
1325 
1326     // Load program binary
1327     mProgram = glCreateProgram();
1328     glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
1329 
1330     // Ensure the loaded binary is linked
1331     GLint linkStatus;
1332     glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
1333     EXPECT_TRUE(linkStatus != 0);
1334 
1335     // Query information about the transform feedback varying
1336     char varyingName[64];
1337     GLsizei varyingSize = 0;
1338     GLenum varyingType  = GL_NONE;
1339 
1340     glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType,
1341                                   varyingName);
1342     EXPECT_GL_NO_ERROR();
1343 
1344     EXPECT_EQ(13, writtenLength);
1345     EXPECT_STREQ("outputVarying", varyingName);
1346     EXPECT_EQ(1, varyingSize);
1347     EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
1348 
1349     EXPECT_GL_NO_ERROR();
1350 }
1351 
1352 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryTransformFeedbackTest);
1353 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryTransformFeedbackTest);
1354 
1355 // For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
1356 // - a set to save the program binary
1357 // - a set to load the program binary
1358 // We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test
1359 // macros
1360 struct PlatformsWithLinkResult : PlatformParameters
1361 {
PlatformsWithLinkResultPlatformsWithLinkResult1362     PlatformsWithLinkResult(PlatformParameters saveParams,
1363                             PlatformParameters loadParamsIn,
1364                             bool expectedLinkResultIn)
1365     {
1366         majorVersion       = saveParams.majorVersion;
1367         minorVersion       = saveParams.minorVersion;
1368         eglParameters      = saveParams.eglParameters;
1369         loadParams         = loadParamsIn;
1370         expectedLinkResult = expectedLinkResultIn;
1371     }
1372 
1373     PlatformParameters loadParams;
1374     bool expectedLinkResult;
1375 };
1376 
1377 // Provide a custom gtest parameter name function for PlatformsWithLinkResult
1378 // to avoid returning the same parameter name twice. Such a conflict would happen
1379 // between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
1380 // named ES2_D3D11
operator <<(std::ostream & stream,const PlatformsWithLinkResult & platform)1381 std::ostream &operator<<(std::ostream &stream, const PlatformsWithLinkResult &platform)
1382 {
1383     const PlatformParameters &platform1 = platform;
1384     const PlatformParameters &platform2 = platform.loadParams;
1385     stream << platform1 << "_to_" << platform2;
1386     return stream;
1387 }
1388 
1389 class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
1390 {
1391   public:
SetUp()1392     void SetUp() override
1393     {
1394         mOSWindow   = OSWindow::New();
1395         bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
1396 
1397         if (result == false)
1398         {
1399             FAIL() << "Failed to create OS window";
1400         }
1401 
1402         mEntryPointsLib.reset(
1403             angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ModuleDir));
1404     }
1405 
createAndInitEGLWindow(angle::PlatformParameters & param)1406     EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
1407     {
1408         EGLWindow *eglWindow = EGLWindow::New(param.clientType, param.majorVersion,
1409                                               param.minorVersion, param.profileMask);
1410         ConfigParameters configParams;
1411         bool result = eglWindow->initializeGL(mOSWindow, mEntryPointsLib.get(), param.driver,
1412                                               param.eglParameters, configParams);
1413         if (!result)
1414         {
1415             EGLWindow::Delete(&eglWindow);
1416         }
1417 
1418         LoadUtilGLES(eglGetProcAddress);
1419 
1420         return eglWindow;
1421     }
1422 
destroyEGLWindow(EGLWindow ** eglWindow)1423     void destroyEGLWindow(EGLWindow **eglWindow)
1424     {
1425         ASSERT_NE(nullptr, *eglWindow);
1426         (*eglWindow)->destroyGL();
1427         EGLWindow::Delete(eglWindow);
1428     }
1429 
createES2ProgramFromSource()1430     GLuint createES2ProgramFromSource()
1431     {
1432         return CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
1433     }
1434 
createES3ProgramFromSource()1435     GLuint createES3ProgramFromSource()
1436     {
1437         return CompileProgram(essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
1438     }
1439 
drawWithProgram(GLuint program)1440     void drawWithProgram(GLuint program)
1441     {
1442         glClearColor(0, 0, 0, 1);
1443         glClear(GL_COLOR_BUFFER_BIT);
1444 
1445         GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
1446 
1447         glUseProgram(program);
1448 
1449         const GLfloat vertices[] = {
1450             -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
1451 
1452             -1.0f, 1.0f, 0.5f, 1.0f,  -1.0f, 0.5f, 1.0f, 1.0f,  0.5f,
1453         };
1454 
1455         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
1456         glEnableVertexAttribArray(positionLocation);
1457 
1458         glDrawArrays(GL_TRIANGLES, 0, 6);
1459 
1460         glDisableVertexAttribArray(positionLocation);
1461         glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
1462 
1463         EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
1464     }
1465 
TearDown()1466     void TearDown() override
1467     {
1468         mOSWindow->destroy();
1469         OSWindow::Delete(&mOSWindow);
1470     }
1471 
1472     OSWindow *mOSWindow = nullptr;
1473     std::unique_ptr<angle::Library> mEntryPointsLib;
1474 };
1475 
1476 // Tries to create a program binary using one set of platform params, then load it using a different
1477 // sent of params
TEST_P(ProgramBinariesAcrossPlatforms,CreateAndReloadBinary)1478 TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
1479 {
1480     angle::PlatformParameters firstRenderer  = GetParam();
1481     angle::PlatformParameters secondRenderer = GetParam().loadParams;
1482     bool expectedLinkResult                  = GetParam().expectedLinkResult;
1483 
1484     // First renderer not supported, skipping test.
1485     ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(firstRenderer)));
1486 
1487     // Second renderer not supported, skipping test.
1488     ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(secondRenderer)));
1489 
1490     EGLWindow *eglWindow = nullptr;
1491     std::vector<uint8_t> binary(0);
1492     GLuint program = 0;
1493 
1494     GLint programLength = 0;
1495     GLint writtenLength = 0;
1496     GLenum binaryFormat = 0;
1497 
1498     // Create a EGL window with the first renderer
1499     eglWindow = createAndInitEGLWindow(firstRenderer);
1500     if (eglWindow == nullptr)
1501     {
1502         FAIL() << "Failed to create EGL window";
1503     }
1504 
1505     // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
1506     // then our expectations for the test results will be invalid.
1507     if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
1508         secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
1509     {
1510         std::string rendererString =
1511             std::string(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
1512         angle::ToLower(&rendererString);
1513 
1514         auto basicRenderPos     = rendererString.find(std::string("microsoft basic render"));
1515         auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
1516 
1517         // The first renderer is using WARP, even though we didn't explictly request it
1518         // We should skip this test
1519         ANGLE_SKIP_TEST_IF(basicRenderPos != std::string::npos ||
1520                            softwareAdapterPos != std::string::npos);
1521     }
1522 
1523     // Create a program
1524     if (firstRenderer.majorVersion == 3)
1525     {
1526         program = createES3ProgramFromSource();
1527     }
1528     else
1529     {
1530         program = createES2ProgramFromSource();
1531     }
1532 
1533     if (program == 0)
1534     {
1535         destroyEGLWindow(&eglWindow);
1536         FAIL() << "Failed to create program from source";
1537     }
1538 
1539     // Draw using the program to ensure it works as expected
1540     drawWithProgram(program);
1541     EXPECT_GL_NO_ERROR();
1542 
1543     // Save the program binary out from this renderer
1544     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1545     EXPECT_GL_NO_ERROR();
1546     binary.resize(programLength);
1547     glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
1548     EXPECT_GL_NO_ERROR();
1549 
1550     // Destroy the first renderer
1551     glDeleteProgram(program);
1552     destroyEGLWindow(&eglWindow);
1553 
1554     // Create an EGL window with the second renderer
1555     eglWindow = createAndInitEGLWindow(secondRenderer);
1556     if (eglWindow == nullptr)
1557     {
1558         FAIL() << "Failed to create EGL window";
1559     }
1560 
1561     program = glCreateProgram();
1562     glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
1563 
1564     GLint linkStatus;
1565     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
1566     EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
1567 
1568     if (linkStatus != 0)
1569     {
1570         // If the link was successful, then we should try to draw using the program to ensure it
1571         // works as expected
1572         drawWithProgram(program);
1573         EXPECT_GL_NO_ERROR();
1574     }
1575 
1576     // Destroy the second renderer
1577     glDeleteProgram(program);
1578     destroyEGLWindow(&eglWindow);
1579 }
1580 
1581 // clang-format off
1582 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinariesAcrossPlatforms);
1583 ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
1584                        //                     | Save the     | Load the     | Expected
1585                        //                     | program in   | program in   | link
1586                        //                     | this config  | this config  | result
1587                        PlatformsWithLinkResult(ES2_D3D11(),   ES2_D3D11(),   true ), // Loading + reloading binary should work
1588                        PlatformsWithLinkResult(ES3_D3D11(),   ES3_D3D11(),   true ), // Loading + reloading binary should work
1589                        PlatformsWithLinkResult(ES2_D3D11(),   ES2_D3D9(),    false), // Switching from D3D11 to D3D9 shouldn't work
1590                        PlatformsWithLinkResult(ES2_D3D9(),    ES2_D3D11(),   false), // Switching from D3D9 to D3D11 shouldn't work
1591                        PlatformsWithLinkResult(ES2_D3D11(),   ES3_D3D11(),   false), // Switching to newer client version shouldn't work
1592                        PlatformsWithLinkResult(ES2_VULKAN(),  ES2_VULKAN(),  true ), // Loading + reloading binary should work
1593                        PlatformsWithLinkResult(ES3_VULKAN(),  ES3_VULKAN(),  true ), // Loading + reloading binary should work
1594                        PlatformsWithLinkResult(ES31_VULKAN(), ES31_VULKAN(), true ), // Loading + reloading binary should work
1595                        PlatformsWithLinkResult(ES3_VULKAN(),  ES31_VULKAN(), false), // Switching to newer client version shouldn't work with Vulkan
1596                       );
1597 // clang-format on
1598