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 // Test that sampler texelFetch references are saved and loaded correctly
TEST_P(ProgramBinaryTest,SRGBDecodeWithSamplerAndTexelFetchTest)751 TEST_P(ProgramBinaryTest, SRGBDecodeWithSamplerAndTexelFetchTest)
752 {
753 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode") ||
754 getClientMajorVersion() < 3);
755
756 // These OpenGL drivers appear not to respect the texelFetch exception
757 // http://anglebug.com/4991
758 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
759 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsWindows());
760 ANGLE_SKIP_TEST_IF(IsOpenGL() && (IsNVIDIA() || IsARM64()) && IsOSX());
761 ANGLE_SKIP_TEST_IF(IsOpenGLES() && IsNexus5X());
762
763 constexpr char kVS[] =
764 "#version 300 es\n"
765 "precision highp float;\n"
766 "in vec4 position;\n"
767 "\n"
768 "void main()\n"
769 "{\n"
770 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
771 "}\n";
772
773 constexpr char kFS[] =
774 "#version 300 es\n"
775 "precision highp float;\n"
776 "uniform sampler2D tex;\n"
777 "in vec2 texcoord;\n"
778 "out vec4 out_color;\n"
779 "\n"
780 "void main()\n"
781 "{\n"
782 " out_color = texelFetch(tex, ivec2(0, 0), 0);\n"
783 "}\n";
784
785 GLProgram program;
786 program.makeRaster(kVS, kFS);
787 ASSERT_NE(0u, program.get());
788
789 GLuint reloadedProgram = glCreateProgram();
790 saveAndLoadProgram(program.get(), reloadedProgram);
791
792 GLint textureLocation = glGetUniformLocation(reloadedProgram, "tex");
793 ASSERT_NE(-1, textureLocation);
794
795 GLColor linearColor(64, 127, 191, 255);
796 GLColor srgbColor(13, 54, 133, 255);
797
798 GLTexture tex;
799 glBindTexture(GL_TEXTURE_2D, tex.get());
800 glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
801 &linearColor);
802 ASSERT_GL_NO_ERROR();
803
804 GLSampler sampler;
805 glBindSampler(0, sampler.get());
806 glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
807
808 glUseProgram(reloadedProgram);
809 glUniform1i(textureLocation, 0);
810
811 glDisable(GL_DEPTH_TEST);
812 drawQuad(reloadedProgram, "position", 0.5f);
813
814 EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
815
816 glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
817 drawQuad(reloadedProgram, "position", 0.5f);
818
819 EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
820
821 glDeleteProgram(reloadedProgram);
822 }
823
824 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryES3Test);
825 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryES3Test);
826
827 class ProgramBinaryES31Test : public ANGLETest
828 {
829 protected:
ProgramBinaryES31Test()830 ProgramBinaryES31Test()
831 {
832 setWindowWidth(128);
833 setWindowHeight(128);
834 setConfigRedBits(8);
835 setConfigGreenBits(8);
836 setConfigBlueBits(8);
837 setConfigAlphaBits(8);
838
839 // Test flakiness was noticed when reusing displays.
840 forceNewDisplay();
841 }
842 };
843
844 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithComputeShader)845 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
846 {
847 // We can't run the test if no program binary formats are supported.
848 GLint binaryFormatCount = 0;
849 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
850 ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
851 // http://anglebug.com/4092
852 ANGLE_SKIP_TEST_IF(IsVulkan());
853
854 constexpr char kCS[] =
855 "#version 310 es\n"
856 "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
857 "uniform block {\n"
858 " vec2 f;\n"
859 "};\n"
860 "uniform vec2 g;\n"
861 "uniform highp sampler2D tex;\n"
862 "void main() {\n"
863 " vec4 color = texture(tex, f + g);\n"
864 "}";
865
866 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
867
868 // Read back the binary.
869 GLint programLength = 0;
870 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
871 ASSERT_GL_NO_ERROR();
872
873 GLsizei readLength = 0;
874 GLenum binaryFormat = GL_NONE;
875 std::vector<uint8_t> binary(programLength);
876 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
877 ASSERT_GL_NO_ERROR();
878
879 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
880
881 // Load a new program with the binary.
882 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
883 ASSERT_GL_NO_ERROR();
884
885 // Dispatch compute with the loaded binary program
886 glUseProgram(binaryProgram.get());
887 glDispatchCompute(8, 4, 2);
888 ASSERT_GL_NO_ERROR();
889 }
890
891 // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test,ProgramBinaryWithAtomicCounterComputeShader)892 TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader)
893 {
894 // We can't run the test if no program binary formats are supported.
895 GLint binaryFormatCount = 0;
896 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
897 ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
898
899 constexpr char kComputeShader[] = R"(#version 310 es
900 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
901 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
902 void main() {
903 atomicCounterIncrement(ac[0]);
904 atomicCounterDecrement(ac[1]);
905 })";
906
907 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
908
909 // Read back the binary.
910 GLint programLength = 0;
911 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programLength);
912 ASSERT_GL_NO_ERROR();
913
914 GLsizei readLength = 0;
915 GLenum binaryFormat = GL_NONE;
916 std::vector<uint8_t> binary(programLength);
917 glGetProgramBinary(program, programLength, &readLength, &binaryFormat, binary.data());
918 ASSERT_GL_NO_ERROR();
919
920 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
921
922 // Load a new program with the binary.
923 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
924 ASSERT_GL_NO_ERROR();
925
926 // Dispatch compute with the loaded binary program
927 glUseProgram(binaryProgram);
928
929 // The initial value of 'ac[0]' is 3u, 'ac[1]' is 1u.
930 unsigned int bufferData[3] = {11u, 3u, 1u};
931 GLBuffer atomicCounterBuffer;
932 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
933 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
934
935 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
936
937 glDispatchCompute(1, 1, 1);
938 EXPECT_GL_NO_ERROR();
939
940 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
941
942 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
943 void *mappedBuffer =
944 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
945 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
946 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
947
948 EXPECT_EQ(11u, bufferData[0]);
949 EXPECT_EQ(4u, bufferData[1]);
950 EXPECT_EQ(0u, bufferData[2]);
951 ASSERT_GL_NO_ERROR();
952 }
953
954 // Tests that image texture works correctly when loading a program from binary.
TEST_P(ProgramBinaryES31Test,ImageTextureBinding)955 TEST_P(ProgramBinaryES31Test, ImageTextureBinding)
956 {
957 // We can't run the test if no program binary formats are supported.
958 GLint binaryFormatCount = 0;
959 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
960 ANGLE_SKIP_TEST_IF(binaryFormatCount == 0);
961
962 const char kComputeShader[] =
963 R"(#version 310 es
964 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
965 layout(r32ui, binding = 1) writeonly uniform highp uimage2D writeImage;
966 void main()
967 {
968 imageStore(writeImage, ivec2(gl_LocalInvocationID.xy), uvec4(200u));
969 })";
970
971 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
972
973 // Read back the binary.
974 GLint programLength = 0;
975 glGetProgramiv(program.get(), 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.get(), programLength, &readLength, &binaryFormat, binary.data());
982 ASSERT_GL_NO_ERROR();
983
984 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
985
986 // Load a new program with the binary.
987 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
988 ASSERT_GL_NO_ERROR();
989
990 // Dispatch compute with the loaded binary program
991 glUseProgram(binaryProgram.get());
992 GLTexture texture;
993 glBindTexture(GL_TEXTURE_2D, texture);
994 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
995 constexpr GLuint kInputValue = 100u;
996 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &kInputValue);
997 EXPECT_GL_NO_ERROR();
998
999 glBindImageTexture(1, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1000
1001 glDispatchCompute(1, 1, 1);
1002 EXPECT_GL_NO_ERROR();
1003
1004 GLFramebuffer framebuffer;
1005 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1006 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1007
1008 GLuint outputValue;
1009 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
1010 EXPECT_EQ(200u, outputValue);
1011 ASSERT_GL_NO_ERROR();
1012 }
1013
1014 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryES31Test);
1015 ANGLE_INSTANTIATE_TEST_ES31(ProgramBinaryES31Test);
1016
1017 class ProgramBinaryTransformFeedbackTest : public ANGLETest
1018 {
1019 protected:
ProgramBinaryTransformFeedbackTest()1020 ProgramBinaryTransformFeedbackTest()
1021 {
1022 setWindowWidth(128);
1023 setWindowHeight(128);
1024 setConfigRedBits(8);
1025 setConfigGreenBits(8);
1026 setConfigBlueBits(8);
1027 setConfigAlphaBits(8);
1028 }
1029
testSetUp()1030 void testSetUp() override
1031 {
1032 constexpr char kVS[] = R"(#version 300 es
1033 in vec4 inputAttribute;
1034 out vec4 outputVarying;
1035 void main()
1036 {
1037 outputVarying = inputAttribute;
1038 })";
1039
1040 constexpr char kFS[] = R"(#version 300 es
1041 precision highp float;
1042 out vec4 outputColor;
1043 void main()
1044 {
1045 outputColor = vec4(1,0,0,1);
1046 })";
1047
1048 std::vector<std::string> transformFeedbackVaryings;
1049 transformFeedbackVaryings.push_back("outputVarying");
1050
1051 mProgram = CompileProgramWithTransformFeedback(kVS, kFS, transformFeedbackVaryings,
1052 GL_SEPARATE_ATTRIBS);
1053 if (mProgram == 0)
1054 {
1055 FAIL() << "shader compilation failed.";
1056 }
1057
1058 ASSERT_GL_NO_ERROR();
1059 }
1060
testTearDown()1061 void testTearDown() override { glDeleteProgram(mProgram); }
1062
getAvailableProgramBinaryFormatCount() const1063 GLint getAvailableProgramBinaryFormatCount() const
1064 {
1065 GLint formatCount;
1066 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
1067 return formatCount;
1068 }
1069
1070 GLuint mProgram;
1071 };
1072
1073 // This tests the assumption that float attribs of different size
1074 // should not internally cause a vertex shader recompile (for conversion).
TEST_P(ProgramBinaryTransformFeedbackTest,GetTransformFeedbackVarying)1075 TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
1076 {
1077 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_get_program_binary"));
1078
1079 ANGLE_SKIP_TEST_IF(!getAvailableProgramBinaryFormatCount());
1080
1081 // http://anglebug.com/3690
1082 ANGLE_SKIP_TEST_IF(IsAndroid() && (IsPixel2() || IsPixel2XL()) && IsVulkan());
1083 // http://anglebug.com/4092
1084 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
1085
1086 std::vector<uint8_t> binary(0);
1087 GLint programLength = 0;
1088 GLint writtenLength = 0;
1089 GLenum binaryFormat = 0;
1090
1091 // Save the program binary out
1092 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1093 ASSERT_GL_NO_ERROR();
1094 binary.resize(programLength);
1095 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
1096 ASSERT_GL_NO_ERROR();
1097
1098 glDeleteProgram(mProgram);
1099
1100 // Load program binary
1101 mProgram = glCreateProgram();
1102 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
1103
1104 // Ensure the loaded binary is linked
1105 GLint linkStatus;
1106 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
1107 EXPECT_TRUE(linkStatus != 0);
1108
1109 // Query information about the transform feedback varying
1110 char varyingName[64];
1111 GLsizei varyingSize = 0;
1112 GLenum varyingType = GL_NONE;
1113
1114 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType,
1115 varyingName);
1116 EXPECT_GL_NO_ERROR();
1117
1118 EXPECT_EQ(13, writtenLength);
1119 EXPECT_STREQ("outputVarying", varyingName);
1120 EXPECT_EQ(1, varyingSize);
1121 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
1122
1123 EXPECT_GL_NO_ERROR();
1124 }
1125
1126 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinaryTransformFeedbackTest);
1127 ANGLE_INSTANTIATE_TEST_ES3(ProgramBinaryTransformFeedbackTest);
1128
1129 // For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
1130 // - a set to save the program binary
1131 // - a set to load the program binary
1132 // We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test
1133 // macros
1134 struct PlatformsWithLinkResult : PlatformParameters
1135 {
PlatformsWithLinkResultPlatformsWithLinkResult1136 PlatformsWithLinkResult(PlatformParameters saveParams,
1137 PlatformParameters loadParamsIn,
1138 bool expectedLinkResultIn)
1139 {
1140 majorVersion = saveParams.majorVersion;
1141 minorVersion = saveParams.minorVersion;
1142 eglParameters = saveParams.eglParameters;
1143 loadParams = loadParamsIn;
1144 expectedLinkResult = expectedLinkResultIn;
1145 }
1146
1147 PlatformParameters loadParams;
1148 bool expectedLinkResult;
1149 };
1150
1151 // Provide a custom gtest parameter name function for PlatformsWithLinkResult
1152 // to avoid returning the same parameter name twice. Such a conflict would happen
1153 // between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
1154 // named ES2_D3D11
operator <<(std::ostream & stream,const PlatformsWithLinkResult & platform)1155 std::ostream &operator<<(std::ostream &stream, const PlatformsWithLinkResult &platform)
1156 {
1157 const PlatformParameters &platform1 = platform;
1158 const PlatformParameters &platform2 = platform.loadParams;
1159 stream << platform1 << "_to_" << platform2;
1160 return stream;
1161 }
1162
1163 class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
1164 {
1165 public:
SetUp()1166 void SetUp() override
1167 {
1168 mOSWindow = OSWindow::New();
1169 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
1170
1171 if (result == false)
1172 {
1173 FAIL() << "Failed to create OS window";
1174 }
1175
1176 mEntryPointsLib.reset(
1177 angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ModuleDir));
1178 }
1179
createAndInitEGLWindow(angle::PlatformParameters & param)1180 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters ¶m)
1181 {
1182 EGLWindow *eglWindow = EGLWindow::New(param.majorVersion, param.minorVersion);
1183 ConfigParameters configParams;
1184 bool result = eglWindow->initializeGL(mOSWindow, mEntryPointsLib.get(), param.driver,
1185 param.eglParameters, configParams);
1186 if (!result)
1187 {
1188 EGLWindow::Delete(&eglWindow);
1189 }
1190
1191 angle::LoadGLES(eglGetProcAddress);
1192
1193 return eglWindow;
1194 }
1195
destroyEGLWindow(EGLWindow ** eglWindow)1196 void destroyEGLWindow(EGLWindow **eglWindow)
1197 {
1198 ASSERT_NE(nullptr, *eglWindow);
1199 (*eglWindow)->destroyGL();
1200 EGLWindow::Delete(eglWindow);
1201 }
1202
createES2ProgramFromSource()1203 GLuint createES2ProgramFromSource()
1204 {
1205 return CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
1206 }
1207
createES3ProgramFromSource()1208 GLuint createES3ProgramFromSource()
1209 {
1210 return CompileProgram(essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
1211 }
1212
drawWithProgram(GLuint program)1213 void drawWithProgram(GLuint program)
1214 {
1215 glClearColor(0, 0, 0, 1);
1216 glClear(GL_COLOR_BUFFER_BIT);
1217
1218 GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
1219
1220 glUseProgram(program);
1221
1222 const GLfloat vertices[] = {
1223 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
1224
1225 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
1226 };
1227
1228 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
1229 glEnableVertexAttribArray(positionLocation);
1230
1231 glDrawArrays(GL_TRIANGLES, 0, 6);
1232
1233 glDisableVertexAttribArray(positionLocation);
1234 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
1235
1236 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
1237 }
1238
TearDown()1239 void TearDown() override
1240 {
1241 mOSWindow->destroy();
1242 OSWindow::Delete(&mOSWindow);
1243 }
1244
1245 OSWindow *mOSWindow = nullptr;
1246 std::unique_ptr<angle::Library> mEntryPointsLib;
1247 };
1248
1249 // Tries to create a program binary using one set of platform params, then load it using a different
1250 // sent of params
TEST_P(ProgramBinariesAcrossPlatforms,CreateAndReloadBinary)1251 TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
1252 {
1253 angle::PlatformParameters firstRenderer = GetParam();
1254 angle::PlatformParameters secondRenderer = GetParam().loadParams;
1255 bool expectedLinkResult = GetParam().expectedLinkResult;
1256
1257 // First renderer not supported, skipping test.
1258 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(firstRenderer)));
1259
1260 // Second renderer not supported, skipping test.
1261 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(secondRenderer)));
1262
1263 EGLWindow *eglWindow = nullptr;
1264 std::vector<uint8_t> binary(0);
1265 GLuint program = 0;
1266
1267 GLint programLength = 0;
1268 GLint writtenLength = 0;
1269 GLenum binaryFormat = 0;
1270
1271 // Create a EGL window with the first renderer
1272 eglWindow = createAndInitEGLWindow(firstRenderer);
1273 if (eglWindow == nullptr)
1274 {
1275 FAIL() << "Failed to create EGL window";
1276 }
1277
1278 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
1279 // then our expectations for the test results will be invalid.
1280 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
1281 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
1282 {
1283 std::string rendererString =
1284 std::string(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
1285 angle::ToLower(&rendererString);
1286
1287 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
1288 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
1289
1290 // The first renderer is using WARP, even though we didn't explictly request it
1291 // We should skip this test
1292 ANGLE_SKIP_TEST_IF(basicRenderPos != std::string::npos ||
1293 softwareAdapterPos != std::string::npos);
1294 }
1295
1296 // Create a program
1297 if (firstRenderer.majorVersion == 3)
1298 {
1299 program = createES3ProgramFromSource();
1300 }
1301 else
1302 {
1303 program = createES2ProgramFromSource();
1304 }
1305
1306 if (program == 0)
1307 {
1308 destroyEGLWindow(&eglWindow);
1309 FAIL() << "Failed to create program from source";
1310 }
1311
1312 // Draw using the program to ensure it works as expected
1313 drawWithProgram(program);
1314 EXPECT_GL_NO_ERROR();
1315
1316 // Save the program binary out from this renderer
1317 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
1318 EXPECT_GL_NO_ERROR();
1319 binary.resize(programLength);
1320 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
1321 EXPECT_GL_NO_ERROR();
1322
1323 // Destroy the first renderer
1324 glDeleteProgram(program);
1325 destroyEGLWindow(&eglWindow);
1326
1327 // Create an EGL window with the second renderer
1328 eglWindow = createAndInitEGLWindow(secondRenderer);
1329 if (eglWindow == nullptr)
1330 {
1331 FAIL() << "Failed to create EGL window";
1332 }
1333
1334 program = glCreateProgram();
1335 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
1336
1337 GLint linkStatus;
1338 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
1339 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
1340
1341 if (linkStatus != 0)
1342 {
1343 // If the link was successful, then we should try to draw using the program to ensure it
1344 // works as expected
1345 drawWithProgram(program);
1346 EXPECT_GL_NO_ERROR();
1347 }
1348
1349 // Destroy the second renderer
1350 glDeleteProgram(program);
1351 destroyEGLWindow(&eglWindow);
1352 }
1353
1354 // clang-format off
1355 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramBinariesAcrossPlatforms);
1356 ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
1357 // | Save the program | Load the program | Expected
1358 // | using these params | using these params | link result
1359 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
1360 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
1361 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
1362 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
1363 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
1364 PlatformsWithLinkResult(ES3_VULKAN(), ES31_VULKAN(), false ), // Switching to newer client version shouldn't work with Vulkan
1365 );
1366 // clang-format on
1367