blob: 7513224e41997705b34877d0ede910a4bc938c24 [file] [log] [blame]
Jamie Madillfa05f602015-05-07 13:47:11 -04001//
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
Corentin Wallezd3970de2015-05-14 11:07:48 -04007#include "test_utils/ANGLETest.h"
Jamie Madillfa05f602015-05-07 13:47:11 -04008
Brandon Jones993d08d2014-10-10 14:32:57 -07009#include <memory>
10#include <stdint.h>
Jamie Madill7a29e4a2014-05-02 10:41:48 -040011
Austin Kinross137b1512015-06-17 16:14:53 -070012#include "EGLWindow.h"
13#include "OSWindow.h"
Jamie Madillef97c612017-09-09 23:34:18 -040014#include "common/string_utils.h"
Austin Kinross137b1512015-06-17 16:14:53 -070015#include "test_utils/angle_test_configs.h"
Jamie Madilla7d12dc2016-12-13 15:08:19 -050016#include "test_utils/gl_raii.h"
Austin Kinross137b1512015-06-17 16:14:53 -070017
Jamie Madillfa05f602015-05-07 13:47:11 -040018using namespace angle;
Austin Kinross18b931d2014-09-29 12:58:31 -070019
Jamie Madill7a29e4a2014-05-02 10:41:48 -040020class ProgramBinaryTest : public ANGLETest
21{
Geoff Lang0d3683c2014-10-23 11:08:16 -040022 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040023 ProgramBinaryTest()
Jamie Madill7a29e4a2014-05-02 10:41:48 -040024 {
25 setWindowWidth(128);
26 setWindowHeight(128);
27 setConfigRedBits(8);
28 setConfigGreenBits(8);
29 setConfigBlueBits(8);
30 setConfigAlphaBits(8);
31 }
32
Corentin Wallez42e9e592015-10-29 14:09:25 -040033 void SetUp() override
Jamie Madill7a29e4a2014-05-02 10:41:48 -040034 {
35 ANGLETest::SetUp();
36
Olli Etuahoa20af6d2017-09-18 13:32:29 +030037 const std::string vertexShaderSource =
38 R"(attribute vec4 inputAttribute;
Jamie Madill7a29e4a2014-05-02 10:41:48 -040039 void main()
40 {
41 gl_Position = inputAttribute;
Olli Etuahoa20af6d2017-09-18 13:32:29 +030042 })";
Jamie Madill7a29e4a2014-05-02 10:41:48 -040043
Olli Etuahoa20af6d2017-09-18 13:32:29 +030044 const std::string fragmentShaderSource =
45 R"(void main()
Jamie Madill7a29e4a2014-05-02 10:41:48 -040046 {
47 gl_FragColor = vec4(1,0,0,1);
Olli Etuahoa20af6d2017-09-18 13:32:29 +030048 })";
Jamie Madill7a29e4a2014-05-02 10:41:48 -040049
Jamie Madill5599c8f2014-08-26 13:16:39 -040050 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040051 if (mProgram == 0)
52 {
53 FAIL() << "shader compilation failed.";
54 }
55
56 glGenBuffers(1, &mBuffer);
57 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
Yunchao Hef81ce4a2017-04-24 10:49:17 +080058 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_STATIC_DRAW);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040059 glBindBuffer(GL_ARRAY_BUFFER, 0);
60
61 ASSERT_GL_NO_ERROR();
62 }
63
Corentin Wallez42e9e592015-10-29 14:09:25 -040064 void TearDown() override
Jamie Madill7a29e4a2014-05-02 10:41:48 -040065 {
66 glDeleteProgram(mProgram);
67 glDeleteBuffers(1, &mBuffer);
68
69 ANGLETest::TearDown();
70 }
71
Geoff Lang90208e92015-10-05 15:40:36 -040072 GLint getAvailableProgramBinaryFormatCount() const
73 {
74 GLint formatCount;
75 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
76 return formatCount;
77 }
78
Jamie Madill311d9992017-05-30 15:38:54 -040079 bool supported() const
80 {
81 if (!extensionEnabled("GL_OES_get_program_binary"))
82 {
83 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
84 << std::endl;
85 return false;
86 }
87
88 if (getAvailableProgramBinaryFormatCount() == 0)
89 {
90 std::cout << "Test skipped because no program binary formats are available."
91 << std::endl;
92 return false;
93 }
94
95 return true;
96 }
97
Jamie Madill7a29e4a2014-05-02 10:41:48 -040098 GLuint mProgram;
99 GLuint mBuffer;
100};
101
102// This tests the assumption that float attribs of different size
103// should not internally cause a vertex shader recompile (for conversion).
Jamie Madillfa05f602015-05-07 13:47:11 -0400104TEST_P(ProgramBinaryTest, FloatDynamicShaderSize)
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400105{
Jamie Madill311d9992017-05-30 15:38:54 -0400106 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -0400107 {
Geoff Lang90208e92015-10-05 15:40:36 -0400108 return;
109 }
110
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400111 glUseProgram(mProgram);
112 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
113
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800114 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400115 glEnableVertexAttribArray(0);
116 glDrawArrays(GL_POINTS, 0, 1);
117
118 GLint programLength;
119 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
120
121 EXPECT_GL_NO_ERROR();
122
123 for (GLsizei size = 1; size <= 3; size++)
124 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800125 glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400126 glEnableVertexAttribArray(0);
127 glDrawArrays(GL_POINTS, 0, 1);
128
129 GLint newProgramLength;
130 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &newProgramLength);
131 EXPECT_GL_NO_ERROR();
132 EXPECT_EQ(programLength, newProgramLength);
133 }
134}
Brandon Jones993d08d2014-10-10 14:32:57 -0700135
Jamie Madillbdec2f42016-03-02 16:35:32 -0500136// Tests that switching between signed and unsigned un-normalized data doesn't trigger a bug
137// in the D3D11 back-end.
138TEST_P(ProgramBinaryTest, DynamicShadersSignatureBug)
139{
140 glUseProgram(mProgram);
141 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
142
143 GLint attribLocation = glGetAttribLocation(mProgram, "inputAttribute");
144 ASSERT_NE(-1, attribLocation);
145 glEnableVertexAttribArray(attribLocation);
146
147 glVertexAttribPointer(attribLocation, 2, GL_BYTE, GL_FALSE, 0, nullptr);
148 glDrawArrays(GL_POINTS, 0, 1);
149
150 glVertexAttribPointer(attribLocation, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
151 glDrawArrays(GL_POINTS, 0, 1);
152}
153
Brandon Jones993d08d2014-10-10 14:32:57 -0700154// This tests the ability to successfully save and load a program binary.
Jamie Madillfa05f602015-05-07 13:47:11 -0400155TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
Brandon Jones993d08d2014-10-10 14:32:57 -0700156{
Jamie Madill311d9992017-05-30 15:38:54 -0400157 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -0400158 {
Geoff Lang90208e92015-10-05 15:40:36 -0400159 return;
160 }
161
Brandon Jones993d08d2014-10-10 14:32:57 -0700162 GLint programLength = 0;
163 GLint writtenLength = 0;
164 GLenum binaryFormat = 0;
165
166 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
167 EXPECT_GL_NO_ERROR();
168
169 std::vector<uint8_t> binary(programLength);
170 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
171 EXPECT_GL_NO_ERROR();
172
173 // The lengths reported by glGetProgramiv and glGetProgramBinaryOES should match
174 EXPECT_EQ(programLength, writtenLength);
175
176 if (writtenLength)
177 {
178 GLuint program2 = glCreateProgram();
179 glProgramBinaryOES(program2, binaryFormat, binary.data(), writtenLength);
180
181 EXPECT_GL_NO_ERROR();
182
183 GLint linkStatus;
184 glGetProgramiv(program2, GL_LINK_STATUS, &linkStatus);
185 if (linkStatus == 0)
186 {
187 GLint infoLogLength;
188 glGetProgramiv(program2, GL_INFO_LOG_LENGTH, &infoLogLength);
189
Geoff Lang981afd72014-11-05 16:30:36 -0500190 if (infoLogLength > 0)
191 {
192 std::vector<GLchar> infoLog(infoLogLength);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800193 glGetProgramInfoLog(program2, static_cast<GLsizei>(infoLog.size()), nullptr,
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700194 &infoLog[0]);
Geoff Lang981afd72014-11-05 16:30:36 -0500195 FAIL() << "program link failed: " << &infoLog[0];
196 }
197 else
198 {
199 FAIL() << "program link failed.";
200 }
Brandon Jones993d08d2014-10-10 14:32:57 -0700201 }
202 else
203 {
204 glUseProgram(program2);
205 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
206
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800207 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Brandon Jones993d08d2014-10-10 14:32:57 -0700208 glEnableVertexAttribArray(0);
209 glDrawArrays(GL_POINTS, 0, 1);
210
211 EXPECT_GL_NO_ERROR();
212 }
213
214 glDeleteProgram(program2);
215 }
216}
Jamie Madillfa05f602015-05-07 13:47:11 -0400217
Jamie Madill311d9992017-05-30 15:38:54 -0400218// Ensures that we init the compiler before calling ProgramBinary.
219TEST_P(ProgramBinaryTest, CallProgramBinaryBeforeLink)
220{
221 if (!supported())
222 {
223 return;
224 }
225
226 // Initialize a simple program.
227 glUseProgram(mProgram);
228
229 GLsizei length = 0;
230 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH, &length);
231 ASSERT_GL_NO_ERROR();
232 ASSERT_GT(length, 0);
233
234 GLsizei readLength = 0;
235 GLenum binaryFormat = GL_NONE;
236 std::vector<uint8_t> binaryBlob(length);
237 glGetProgramBinaryOES(mProgram, length, &readLength, &binaryFormat, binaryBlob.data());
238 ASSERT_GL_NO_ERROR();
239
240 // Shutdown and restart GL entirely.
241 TearDown();
242 SetUp();
243
244 ANGLE_GL_BINARY_OES_PROGRAM(binaryProgram, binaryBlob, binaryFormat);
245 ASSERT_GL_NO_ERROR();
246
247 drawQuad(binaryProgram, "inputAttribute", 0.5f);
248 ASSERT_GL_NO_ERROR();
249}
250
Jamie Madillfa05f602015-05-07 13:47:11 -0400251// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
Geoff Lang90208e92015-10-05 15:40:36 -0400252ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
253 ES2_D3D9(),
254 ES2_D3D11(),
255 ES3_D3D11(),
256 ES2_OPENGL(),
257 ES3_OPENGL());
Austin Kinross137b1512015-06-17 16:14:53 -0700258
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500259class ProgramBinaryES3Test : public ANGLETest
260{
Jamie Madill51f522f2016-12-21 15:10:55 -0500261 protected:
262 void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500263};
264
Jamie Madill51f522f2016-12-21 15:10:55 -0500265void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500266{
267 // We can't run the test if no program binary formats are supported.
268 GLint binaryFormatCount = 0;
269 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
270 if (binaryFormatCount == 0)
271 {
272 std::cout << "Test skipped because no program binary formats available." << std::endl;
273 return;
274 }
275
276 const std::string &vertexShader =
277 "#version 300 es\n"
278 "uniform block {\n"
279 " float f;\n"
280 "};\n"
281 "in vec4 position;\n"
282 "out vec4 color;\n"
283 "void main() {\n"
284 " gl_Position = position;\n"
285 " color = vec4(f, f, f, 1);\n"
286 "}";
287 const std::string &fragmentShader =
288 "#version 300 es\n"
289 "precision mediump float;\n"
290 "in vec4 color;\n"
291 "out vec4 colorOut;\n"
292 "void main() {\n"
293 " colorOut = color;\n"
294 "}";
295
296 // Init and draw with the program.
297 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
298
299 float fData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
300 GLuint bindIndex = 2;
301
302 GLBuffer ubo;
303 glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
304 glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
305 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
306
307 GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
308 ASSERT_NE(-1, blockIndex);
309
310 glUniformBlockBinding(program.get(), blockIndex, bindIndex);
311
312 glClearColor(1.0, 0.0, 0.0, 1.0);
313 glClear(GL_COLOR_BUFFER_BIT);
314 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
315
Jamie Madill51f522f2016-12-21 15:10:55 -0500316 if (drawWithProgramFirst)
317 {
318 drawQuad(program.get(), "position", 0.5f);
319 ASSERT_GL_NO_ERROR();
320 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
321 }
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500322
323 // Read back the binary.
324 GLint programLength = 0;
325 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
326 ASSERT_GL_NO_ERROR();
327
328 GLsizei readLength = 0;
329 GLenum binaryFormat = GL_NONE;
330 std::vector<uint8_t> binary(programLength);
331 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
332 ASSERT_GL_NO_ERROR();
333
334 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
335
336 // Load a new program with the binary and draw.
337 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
338
339 glClearColor(1.0, 0.0, 0.0, 1.0);
340 glClear(GL_COLOR_BUFFER_BIT);
341 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
342
343 drawQuad(binaryProgram.get(), "position", 0.5f);
344 ASSERT_GL_NO_ERROR();
345 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
346}
347
Jamie Madill51f522f2016-12-21 15:10:55 -0500348// Tests that saving and loading a program perserves uniform block binding info.
349TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
350{
351 testBinaryAndUBOBlockIndexes(true);
352}
353
354// Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
355// http://anglebug.com/1637
356TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
357{
Jamie Madillb22615d2016-12-23 13:21:04 -0500358 // TODO(jmadill): Investigate Intel failure.
359 // http://anglebug.com/1637
360 if (IsWindows() && IsOpenGL() && IsIntel())
361 {
362 std::cout << "Test skipped on Windows Intel OpenGL." << std::endl;
363 return;
364 }
365
Jamie Madill51f522f2016-12-21 15:10:55 -0500366 testBinaryAndUBOBlockIndexes(false);
367}
368
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500369ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
370
Xinghua Caob1239382016-12-13 15:07:05 +0800371class ProgramBinaryES31Test : public ANGLETest
372{
373 protected:
374 ProgramBinaryES31Test()
375 {
376 setWindowWidth(128);
377 setWindowHeight(128);
378 setConfigRedBits(8);
379 setConfigGreenBits(8);
380 setConfigBlueBits(8);
381 setConfigAlphaBits(8);
382 }
383};
384
385// Tests that saving and loading a program attached with computer shader.
386TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
387{
388 // We can't run the test if no program binary formats are supported.
389 GLint binaryFormatCount = 0;
390 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
391 if (binaryFormatCount == 0)
392 {
393 std::cout << "Test skipped because no program binary formats available." << std::endl;
394 return;
395 }
396
397 const std::string &computeShader =
398 "#version 310 es\n"
399 "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
400 "uniform block {\n"
401 " vec2 f;\n"
402 "};\n"
403 "uniform vec2 g;\n"
404 "uniform highp sampler2D tex;\n"
405 "void main() {\n"
406 " vec4 color = texture(tex, f + g);\n"
407 "}";
408
409 ANGLE_GL_COMPUTE_PROGRAM(program, computeShader);
410
411 // Read back the binary.
412 GLint programLength = 0;
413 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
414 ASSERT_GL_NO_ERROR();
415
416 GLsizei readLength = 0;
417 GLenum binaryFormat = GL_NONE;
418 std::vector<uint8_t> binary(programLength);
419 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
420 ASSERT_GL_NO_ERROR();
421
422 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
423
424 // Load a new program with the binary.
425 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
426
427 // TODO(Xinghua): add dispatch support when available.
428
429 ASSERT_GL_NO_ERROR();
430}
431
432ANGLE_INSTANTIATE_TEST(ProgramBinaryES31Test, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
433
Brandon Jones1048ea72015-10-06 15:34:52 -0700434class ProgramBinaryTransformFeedbackTest : public ANGLETest
435{
436 protected:
437 ProgramBinaryTransformFeedbackTest()
438 {
439 setWindowWidth(128);
440 setWindowHeight(128);
441 setConfigRedBits(8);
442 setConfigGreenBits(8);
443 setConfigBlueBits(8);
444 setConfigAlphaBits(8);
445 }
446
447 void SetUp() override
448 {
449 ANGLETest::SetUp();
450
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300451 const std::string vertexShaderSource =
452 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700453 in vec4 inputAttribute;
454 out vec4 outputVarying;
455 void main()
456 {
457 outputVarying = inputAttribute;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300458 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700459
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300460 const std::string fragmentShaderSource =
461 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700462 precision highp float;
463 out vec4 outputColor;
464 void main()
465 {
466 outputColor = vec4(1,0,0,1);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300467 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700468
469 std::vector<std::string> transformFeedbackVaryings;
470 transformFeedbackVaryings.push_back("outputVarying");
471
472 mProgram = CompileProgramWithTransformFeedback(
473 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
474 GL_SEPARATE_ATTRIBS);
475 if (mProgram == 0)
476 {
477 FAIL() << "shader compilation failed.";
478 }
479
480 ASSERT_GL_NO_ERROR();
481 }
482
Corentin Wallez42e9e592015-10-29 14:09:25 -0400483 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700484 {
485 glDeleteProgram(mProgram);
486
487 ANGLETest::TearDown();
488 }
489
490 GLint getAvailableProgramBinaryFormatCount() const
491 {
492 GLint formatCount;
493 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
494 return formatCount;
495 }
496
497 GLuint mProgram;
498};
499
500// This tests the assumption that float attribs of different size
501// should not internally cause a vertex shader recompile (for conversion).
502TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
503{
504 if (!extensionEnabled("GL_OES_get_program_binary"))
505 {
506 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
507 << std::endl;
508 return;
509 }
510
511 if (getAvailableProgramBinaryFormatCount() == 0)
512 {
513 std::cout << "Test skipped because no program binary formats are available." << std::endl;
514 return;
515 }
516
517 std::vector<uint8_t> binary(0);
518 GLint programLength = 0;
519 GLint writtenLength = 0;
520 GLenum binaryFormat = 0;
521
522 // Save the program binary out
523 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
524 ASSERT_GL_NO_ERROR();
525 binary.resize(programLength);
526 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
527 ASSERT_GL_NO_ERROR();
528
529 glDeleteProgram(mProgram);
530
531 // Load program binary
532 mProgram = glCreateProgram();
533 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
534
535 // Ensure the loaded binary is linked
536 GLint linkStatus;
537 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
538 EXPECT_TRUE(linkStatus != 0);
539
540 // Query information about the transform feedback varying
541 char varyingName[64];
542 GLsizei varyingSize = 0;
543 GLenum varyingType = GL_NONE;
544
545 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
546 EXPECT_GL_NO_ERROR();
547
548 EXPECT_EQ(13, writtenLength);
549 EXPECT_STREQ("outputVarying", varyingName);
550 EXPECT_EQ(1, varyingSize);
551 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
552
553 EXPECT_GL_NO_ERROR();
554}
555
556// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
557ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
558 ES3_D3D11(),
559 ES3_OPENGL());
560
Austin Kinross137b1512015-06-17 16:14:53 -0700561// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
562// - a set to save the program binary
563// - a set to load the program binary
564// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
565struct PlatformsWithLinkResult : PlatformParameters
566{
567 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
568 {
569 majorVersion = saveParams.majorVersion;
570 minorVersion = saveParams.minorVersion;
571 eglParameters = saveParams.eglParameters;
572 loadParams = loadParamsIn;
573 expectedLinkResult = expectedLinkResultIn;
574 }
575
576 PlatformParameters loadParams;
577 bool expectedLinkResult;
578};
579
Corentin Wallez33585c72015-09-03 14:41:23 -0400580// Provide a custom gtest parameter name function for PlatformsWithLinkResult
581// to avoid returning the same parameter name twice. Such a conflict would happen
582// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
583// named ES2_D3D11
584std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
585{
586 const PlatformParameters &platform1 = platform;
587 const PlatformParameters &platform2 = platform.loadParams;
588 stream << platform1 << "_to_" << platform2;
589 return stream;
590}
591
Austin Kinross137b1512015-06-17 16:14:53 -0700592class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
593{
594 public:
595 void SetUp() override
596 {
597 mOSWindow = CreateOSWindow();
598 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
599
600 if (result == false)
601 {
602 FAIL() << "Failed to create OS window";
603 }
604 }
605
606 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
607 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400608 EGLWindow *eglWindow =
609 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700610 bool result = eglWindow->initializeGL(mOSWindow);
611 if (result == false)
612 {
613 SafeDelete(eglWindow);
614 eglWindow = nullptr;
615 }
616
617 return eglWindow;
618 }
619
620 void destroyEGLWindow(EGLWindow **eglWindow)
621 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500622 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700623 (*eglWindow)->destroyGL();
624 SafeDelete(*eglWindow);
625 *eglWindow = nullptr;
626 }
627
628 GLuint createES2ProgramFromSource()
629 {
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300630 const std::string testVertexShaderSource =
631 R"(attribute highp vec4 position;
Austin Kinross137b1512015-06-17 16:14:53 -0700632
633 void main(void)
634 {
635 gl_Position = position;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300636 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700637
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300638 const std::string testFragmentShaderSource =
639 R"(void main(void)
Austin Kinross137b1512015-06-17 16:14:53 -0700640 {
641 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300642 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700643
644 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
645 }
646
647 GLuint createES3ProgramFromSource()
648 {
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300649 const std::string testVertexShaderSource =
650 R"(#version 300 es
Austin Kinross137b1512015-06-17 16:14:53 -0700651 precision highp float;
652 in highp vec4 position;
653
654 void main(void)
655 {
656 gl_Position = position;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300657 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700658
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300659 const std::string testFragmentShaderSource =
660 R"(#version 300 es
Austin Kinross137b1512015-06-17 16:14:53 -0700661 precision highp float;
662 out vec4 out_FragColor;
663
664 void main(void)
665 {
666 out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300667 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700668
669 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
670 }
671
672 void drawWithProgram(GLuint program)
673 {
674 glClearColor(0, 0, 0, 1);
675 glClear(GL_COLOR_BUFFER_BIT);
676
677 GLint positionLocation = glGetAttribLocation(program, "position");
678
679 glUseProgram(program);
680
681 const GLfloat vertices[] =
682 {
683 -1.0f, 1.0f, 0.5f,
684 -1.0f, -1.0f, 0.5f,
685 1.0f, -1.0f, 0.5f,
686
687 -1.0f, 1.0f, 0.5f,
688 1.0f, -1.0f, 0.5f,
689 1.0f, 1.0f, 0.5f,
690 };
691
692 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
693 glEnableVertexAttribArray(positionLocation);
694
695 glDrawArrays(GL_TRIANGLES, 0, 6);
696
697 glDisableVertexAttribArray(positionLocation);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800698 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
Austin Kinross137b1512015-06-17 16:14:53 -0700699
700 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
701 }
702
703 void TearDown() override
704 {
705 mOSWindow->destroy();
706 SafeDelete(mOSWindow);
707 }
708
709 OSWindow *mOSWindow;
710};
711
712// Tries to create a program binary using one set of platform params, then load it using a different sent of params
713TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
714{
715 angle::PlatformParameters firstRenderer = GetParam();
716 angle::PlatformParameters secondRenderer = GetParam().loadParams;
717 bool expectedLinkResult = GetParam().expectedLinkResult;
718
719 if (!(IsPlatformAvailable(firstRenderer)))
720 {
721 std::cout << "First renderer not supported, skipping test";
722 return;
723 }
724
725 if (!(IsPlatformAvailable(secondRenderer)))
726 {
727 std::cout << "Second renderer not supported, skipping test";
728 return;
729 }
730
731 EGLWindow *eglWindow = nullptr;
732 std::vector<uint8_t> binary(0);
733 GLuint program = 0;
734
735 GLint programLength = 0;
736 GLint writtenLength = 0;
737 GLenum binaryFormat = 0;
738
739 // Create a EGL window with the first renderer
740 eglWindow = createAndInitEGLWindow(firstRenderer);
741 if (eglWindow == nullptr)
742 {
743 FAIL() << "Failed to create EGL window";
744 return;
745 }
746
747 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
748 // then our expectations for the test results will be invalid.
749 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
750 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE)
751 {
752 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
Jamie Madillef97c612017-09-09 23:34:18 -0400753 angle::ToLower(&rendererString);
Austin Kinross137b1512015-06-17 16:14:53 -0700754
755 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
756 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
757
758 if (basicRenderPos != std::string::npos || softwareAdapterPos != std::string::npos)
759 {
760 // The first renderer is using WARP, even though we didn't explictly request it
761 // We should skip this test
762 std::cout << "Test skipped on when default GPU is WARP." << std::endl;
763 return;
764 }
765 }
766
767 // Create a program
768 if (firstRenderer.majorVersion == 3)
769 {
770 program = createES3ProgramFromSource();
771 }
772 else
773 {
774 program = createES2ProgramFromSource();
775 }
776
777 if (program == 0)
778 {
Austin Kinross137b1512015-06-17 16:14:53 -0700779 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700780 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700781 }
782
783 // Draw using the program to ensure it works as expected
784 drawWithProgram(program);
785 EXPECT_GL_NO_ERROR();
786
787 // Save the program binary out from this renderer
788 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
789 EXPECT_GL_NO_ERROR();
790 binary.resize(programLength);
791 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
792 EXPECT_GL_NO_ERROR();
793
794 // Destroy the first renderer
795 glDeleteProgram(program);
796 destroyEGLWindow(&eglWindow);
797
798 // Create an EGL window with the second renderer
799 eglWindow = createAndInitEGLWindow(secondRenderer);
800 if (eglWindow == nullptr)
801 {
802 FAIL() << "Failed to create EGL window";
803 return;
804 }
805
806 program = glCreateProgram();
807 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
808
809 GLint linkStatus;
810 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
811 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
812
813 if (linkStatus != 0)
814 {
815 // If the link was successful, then we should try to draw using the program to ensure it works as expected
816 drawWithProgram(program);
817 EXPECT_GL_NO_ERROR();
818 }
819
820 // Destroy the second renderer
821 glDeleteProgram(program);
822 destroyEGLWindow(&eglWindow);
823}
824
Jamie Madilla2c74982016-12-12 11:20:42 -0500825// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700826ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
827 // | Save the program | Load the program | Expected
828 // | using these params | using these params | link result
829 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
830 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
831 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
832 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
833 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
834 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
835 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500836 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400837 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500838// clang-format on