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