blob: 6ee5eb3fe02f0621bc7c750073ee1bfa2bed3794 [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
37 const std::string vertexShaderSource = SHADER_SOURCE
38 (
39 attribute vec4 inputAttribute;
40 void main()
41 {
42 gl_Position = inputAttribute;
43 }
44 );
45
46 const std::string fragmentShaderSource = SHADER_SOURCE
47 (
48 void main()
49 {
50 gl_FragColor = vec4(1,0,0,1);
51 }
52 );
53
Jamie Madill5599c8f2014-08-26 13:16:39 -040054 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040055 if (mProgram == 0)
56 {
57 FAIL() << "shader compilation failed.";
58 }
59
60 glGenBuffers(1, &mBuffer);
61 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
Yunchao Hef81ce4a2017-04-24 10:49:17 +080062 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_STATIC_DRAW);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040063 glBindBuffer(GL_ARRAY_BUFFER, 0);
64
65 ASSERT_GL_NO_ERROR();
66 }
67
Corentin Wallez42e9e592015-10-29 14:09:25 -040068 void TearDown() override
Jamie Madill7a29e4a2014-05-02 10:41:48 -040069 {
70 glDeleteProgram(mProgram);
71 glDeleteBuffers(1, &mBuffer);
72
73 ANGLETest::TearDown();
74 }
75
Geoff Lang90208e92015-10-05 15:40:36 -040076 GLint getAvailableProgramBinaryFormatCount() const
77 {
78 GLint formatCount;
79 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
80 return formatCount;
81 }
82
Jamie Madill311d9992017-05-30 15:38:54 -040083 bool supported() const
84 {
85 if (!extensionEnabled("GL_OES_get_program_binary"))
86 {
87 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
88 << std::endl;
89 return false;
90 }
91
92 if (getAvailableProgramBinaryFormatCount() == 0)
93 {
94 std::cout << "Test skipped because no program binary formats are available."
95 << std::endl;
96 return false;
97 }
98
99 return true;
100 }
101
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400102 GLuint mProgram;
103 GLuint mBuffer;
104};
105
106// This tests the assumption that float attribs of different size
107// should not internally cause a vertex shader recompile (for conversion).
Jamie Madillfa05f602015-05-07 13:47:11 -0400108TEST_P(ProgramBinaryTest, FloatDynamicShaderSize)
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400109{
Jamie Madill311d9992017-05-30 15:38:54 -0400110 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -0400111 {
Geoff Lang90208e92015-10-05 15:40:36 -0400112 return;
113 }
114
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400115 glUseProgram(mProgram);
116 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
117
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800118 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400119 glEnableVertexAttribArray(0);
120 glDrawArrays(GL_POINTS, 0, 1);
121
122 GLint programLength;
123 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
124
125 EXPECT_GL_NO_ERROR();
126
127 for (GLsizei size = 1; size <= 3; size++)
128 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800129 glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400130 glEnableVertexAttribArray(0);
131 glDrawArrays(GL_POINTS, 0, 1);
132
133 GLint newProgramLength;
134 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &newProgramLength);
135 EXPECT_GL_NO_ERROR();
136 EXPECT_EQ(programLength, newProgramLength);
137 }
138}
Brandon Jones993d08d2014-10-10 14:32:57 -0700139
Jamie Madillbdec2f42016-03-02 16:35:32 -0500140// Tests that switching between signed and unsigned un-normalized data doesn't trigger a bug
141// in the D3D11 back-end.
142TEST_P(ProgramBinaryTest, DynamicShadersSignatureBug)
143{
144 glUseProgram(mProgram);
145 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
146
147 GLint attribLocation = glGetAttribLocation(mProgram, "inputAttribute");
148 ASSERT_NE(-1, attribLocation);
149 glEnableVertexAttribArray(attribLocation);
150
151 glVertexAttribPointer(attribLocation, 2, GL_BYTE, GL_FALSE, 0, nullptr);
152 glDrawArrays(GL_POINTS, 0, 1);
153
154 glVertexAttribPointer(attribLocation, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
155 glDrawArrays(GL_POINTS, 0, 1);
156}
157
Brandon Jones993d08d2014-10-10 14:32:57 -0700158// This tests the ability to successfully save and load a program binary.
Jamie Madillfa05f602015-05-07 13:47:11 -0400159TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
Brandon Jones993d08d2014-10-10 14:32:57 -0700160{
Jamie Madill311d9992017-05-30 15:38:54 -0400161 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -0400162 {
Geoff Lang90208e92015-10-05 15:40:36 -0400163 return;
164 }
165
Brandon Jones993d08d2014-10-10 14:32:57 -0700166 GLint programLength = 0;
167 GLint writtenLength = 0;
168 GLenum binaryFormat = 0;
169
170 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
171 EXPECT_GL_NO_ERROR();
172
173 std::vector<uint8_t> binary(programLength);
174 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
175 EXPECT_GL_NO_ERROR();
176
177 // The lengths reported by glGetProgramiv and glGetProgramBinaryOES should match
178 EXPECT_EQ(programLength, writtenLength);
179
180 if (writtenLength)
181 {
182 GLuint program2 = glCreateProgram();
183 glProgramBinaryOES(program2, binaryFormat, binary.data(), writtenLength);
184
185 EXPECT_GL_NO_ERROR();
186
187 GLint linkStatus;
188 glGetProgramiv(program2, GL_LINK_STATUS, &linkStatus);
189 if (linkStatus == 0)
190 {
191 GLint infoLogLength;
192 glGetProgramiv(program2, GL_INFO_LOG_LENGTH, &infoLogLength);
193
Geoff Lang981afd72014-11-05 16:30:36 -0500194 if (infoLogLength > 0)
195 {
196 std::vector<GLchar> infoLog(infoLogLength);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800197 glGetProgramInfoLog(program2, static_cast<GLsizei>(infoLog.size()), nullptr,
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700198 &infoLog[0]);
Geoff Lang981afd72014-11-05 16:30:36 -0500199 FAIL() << "program link failed: " << &infoLog[0];
200 }
201 else
202 {
203 FAIL() << "program link failed.";
204 }
Brandon Jones993d08d2014-10-10 14:32:57 -0700205 }
206 else
207 {
208 glUseProgram(program2);
209 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
210
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800211 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Brandon Jones993d08d2014-10-10 14:32:57 -0700212 glEnableVertexAttribArray(0);
213 glDrawArrays(GL_POINTS, 0, 1);
214
215 EXPECT_GL_NO_ERROR();
216 }
217
218 glDeleteProgram(program2);
219 }
220}
Jamie Madillfa05f602015-05-07 13:47:11 -0400221
Jamie Madill311d9992017-05-30 15:38:54 -0400222// Ensures that we init the compiler before calling ProgramBinary.
223TEST_P(ProgramBinaryTest, CallProgramBinaryBeforeLink)
224{
225 if (!supported())
226 {
227 return;
228 }
229
230 // Initialize a simple program.
231 glUseProgram(mProgram);
232
233 GLsizei length = 0;
234 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH, &length);
235 ASSERT_GL_NO_ERROR();
236 ASSERT_GT(length, 0);
237
238 GLsizei readLength = 0;
239 GLenum binaryFormat = GL_NONE;
240 std::vector<uint8_t> binaryBlob(length);
241 glGetProgramBinaryOES(mProgram, length, &readLength, &binaryFormat, binaryBlob.data());
242 ASSERT_GL_NO_ERROR();
243
244 // Shutdown and restart GL entirely.
245 TearDown();
246 SetUp();
247
248 ANGLE_GL_BINARY_OES_PROGRAM(binaryProgram, binaryBlob, binaryFormat);
249 ASSERT_GL_NO_ERROR();
250
251 drawQuad(binaryProgram, "inputAttribute", 0.5f);
252 ASSERT_GL_NO_ERROR();
253}
254
Jamie Madillfa05f602015-05-07 13:47:11 -0400255// 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 -0400256ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
257 ES2_D3D9(),
258 ES2_D3D11(),
259 ES3_D3D11(),
260 ES2_OPENGL(),
261 ES3_OPENGL());
Austin Kinross137b1512015-06-17 16:14:53 -0700262
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500263class ProgramBinaryES3Test : public ANGLETest
264{
Jamie Madill51f522f2016-12-21 15:10:55 -0500265 protected:
266 void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500267};
268
Jamie Madill51f522f2016-12-21 15:10:55 -0500269void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500270{
271 // We can't run the test if no program binary formats are supported.
272 GLint binaryFormatCount = 0;
273 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
274 if (binaryFormatCount == 0)
275 {
276 std::cout << "Test skipped because no program binary formats available." << std::endl;
277 return;
278 }
279
280 const std::string &vertexShader =
281 "#version 300 es\n"
282 "uniform block {\n"
283 " float f;\n"
284 "};\n"
285 "in vec4 position;\n"
286 "out vec4 color;\n"
287 "void main() {\n"
288 " gl_Position = position;\n"
289 " color = vec4(f, f, f, 1);\n"
290 "}";
291 const std::string &fragmentShader =
292 "#version 300 es\n"
293 "precision mediump float;\n"
294 "in vec4 color;\n"
295 "out vec4 colorOut;\n"
296 "void main() {\n"
297 " colorOut = color;\n"
298 "}";
299
300 // Init and draw with the program.
301 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
302
303 float fData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
304 GLuint bindIndex = 2;
305
306 GLBuffer ubo;
307 glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
308 glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
309 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
310
311 GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
312 ASSERT_NE(-1, blockIndex);
313
314 glUniformBlockBinding(program.get(), blockIndex, bindIndex);
315
316 glClearColor(1.0, 0.0, 0.0, 1.0);
317 glClear(GL_COLOR_BUFFER_BIT);
318 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
319
Jamie Madill51f522f2016-12-21 15:10:55 -0500320 if (drawWithProgramFirst)
321 {
322 drawQuad(program.get(), "position", 0.5f);
323 ASSERT_GL_NO_ERROR();
324 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
325 }
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500326
327 // Read back the binary.
328 GLint programLength = 0;
329 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
330 ASSERT_GL_NO_ERROR();
331
332 GLsizei readLength = 0;
333 GLenum binaryFormat = GL_NONE;
334 std::vector<uint8_t> binary(programLength);
335 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
336 ASSERT_GL_NO_ERROR();
337
338 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
339
340 // Load a new program with the binary and draw.
341 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
342
343 glClearColor(1.0, 0.0, 0.0, 1.0);
344 glClear(GL_COLOR_BUFFER_BIT);
345 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
346
347 drawQuad(binaryProgram.get(), "position", 0.5f);
348 ASSERT_GL_NO_ERROR();
349 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
350}
351
Jamie Madill51f522f2016-12-21 15:10:55 -0500352// Tests that saving and loading a program perserves uniform block binding info.
353TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
354{
355 testBinaryAndUBOBlockIndexes(true);
356}
357
358// Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
359// http://anglebug.com/1637
360TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
361{
Jamie Madillb22615d2016-12-23 13:21:04 -0500362 // TODO(jmadill): Investigate Intel failure.
363 // http://anglebug.com/1637
364 if (IsWindows() && IsOpenGL() && IsIntel())
365 {
366 std::cout << "Test skipped on Windows Intel OpenGL." << std::endl;
367 return;
368 }
369
Jamie Madill51f522f2016-12-21 15:10:55 -0500370 testBinaryAndUBOBlockIndexes(false);
371}
372
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500373ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
374
Xinghua Caob1239382016-12-13 15:07:05 +0800375class ProgramBinaryES31Test : public ANGLETest
376{
377 protected:
378 ProgramBinaryES31Test()
379 {
380 setWindowWidth(128);
381 setWindowHeight(128);
382 setConfigRedBits(8);
383 setConfigGreenBits(8);
384 setConfigBlueBits(8);
385 setConfigAlphaBits(8);
386 }
387};
388
389// Tests that saving and loading a program attached with computer shader.
390TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
391{
392 // We can't run the test if no program binary formats are supported.
393 GLint binaryFormatCount = 0;
394 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
395 if (binaryFormatCount == 0)
396 {
397 std::cout << "Test skipped because no program binary formats available." << std::endl;
398 return;
399 }
400
401 const std::string &computeShader =
402 "#version 310 es\n"
403 "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
404 "uniform block {\n"
405 " vec2 f;\n"
406 "};\n"
407 "uniform vec2 g;\n"
408 "uniform highp sampler2D tex;\n"
409 "void main() {\n"
410 " vec4 color = texture(tex, f + g);\n"
411 "}";
412
413 ANGLE_GL_COMPUTE_PROGRAM(program, computeShader);
414
415 // Read back the binary.
416 GLint programLength = 0;
417 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
418 ASSERT_GL_NO_ERROR();
419
420 GLsizei readLength = 0;
421 GLenum binaryFormat = GL_NONE;
422 std::vector<uint8_t> binary(programLength);
423 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
424 ASSERT_GL_NO_ERROR();
425
426 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
427
428 // Load a new program with the binary.
429 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
430
431 // TODO(Xinghua): add dispatch support when available.
432
433 ASSERT_GL_NO_ERROR();
434}
435
436ANGLE_INSTANTIATE_TEST(ProgramBinaryES31Test, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
437
Brandon Jones1048ea72015-10-06 15:34:52 -0700438class ProgramBinaryTransformFeedbackTest : public ANGLETest
439{
440 protected:
441 ProgramBinaryTransformFeedbackTest()
442 {
443 setWindowWidth(128);
444 setWindowHeight(128);
445 setConfigRedBits(8);
446 setConfigGreenBits(8);
447 setConfigBlueBits(8);
448 setConfigAlphaBits(8);
449 }
450
451 void SetUp() override
452 {
453 ANGLETest::SetUp();
454
455 const std::string vertexShaderSource = SHADER_SOURCE
456 ( #version 300 es\n
457 in vec4 inputAttribute;
458 out vec4 outputVarying;
459 void main()
460 {
461 outputVarying = inputAttribute;
462 }
463 );
464
465 const std::string fragmentShaderSource = SHADER_SOURCE
466 ( #version 300 es\n
467 precision highp float;
468 out vec4 outputColor;
469 void main()
470 {
471 outputColor = vec4(1,0,0,1);
472 }
473 );
474
475 std::vector<std::string> transformFeedbackVaryings;
476 transformFeedbackVaryings.push_back("outputVarying");
477
478 mProgram = CompileProgramWithTransformFeedback(
479 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
480 GL_SEPARATE_ATTRIBS);
481 if (mProgram == 0)
482 {
483 FAIL() << "shader compilation failed.";
484 }
485
486 ASSERT_GL_NO_ERROR();
487 }
488
Corentin Wallez42e9e592015-10-29 14:09:25 -0400489 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700490 {
491 glDeleteProgram(mProgram);
492
493 ANGLETest::TearDown();
494 }
495
496 GLint getAvailableProgramBinaryFormatCount() const
497 {
498 GLint formatCount;
499 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
500 return formatCount;
501 }
502
503 GLuint mProgram;
504};
505
506// This tests the assumption that float attribs of different size
507// should not internally cause a vertex shader recompile (for conversion).
508TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
509{
510 if (!extensionEnabled("GL_OES_get_program_binary"))
511 {
512 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
513 << std::endl;
514 return;
515 }
516
517 if (getAvailableProgramBinaryFormatCount() == 0)
518 {
519 std::cout << "Test skipped because no program binary formats are available." << std::endl;
520 return;
521 }
522
523 std::vector<uint8_t> binary(0);
524 GLint programLength = 0;
525 GLint writtenLength = 0;
526 GLenum binaryFormat = 0;
527
528 // Save the program binary out
529 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
530 ASSERT_GL_NO_ERROR();
531 binary.resize(programLength);
532 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
533 ASSERT_GL_NO_ERROR();
534
535 glDeleteProgram(mProgram);
536
537 // Load program binary
538 mProgram = glCreateProgram();
539 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
540
541 // Ensure the loaded binary is linked
542 GLint linkStatus;
543 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
544 EXPECT_TRUE(linkStatus != 0);
545
546 // Query information about the transform feedback varying
547 char varyingName[64];
548 GLsizei varyingSize = 0;
549 GLenum varyingType = GL_NONE;
550
551 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
552 EXPECT_GL_NO_ERROR();
553
554 EXPECT_EQ(13, writtenLength);
555 EXPECT_STREQ("outputVarying", varyingName);
556 EXPECT_EQ(1, varyingSize);
557 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
558
559 EXPECT_GL_NO_ERROR();
560}
561
562// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
563ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
564 ES3_D3D11(),
565 ES3_OPENGL());
566
Austin Kinross137b1512015-06-17 16:14:53 -0700567// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
568// - a set to save the program binary
569// - a set to load the program binary
570// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
571struct PlatformsWithLinkResult : PlatformParameters
572{
573 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
574 {
575 majorVersion = saveParams.majorVersion;
576 minorVersion = saveParams.minorVersion;
577 eglParameters = saveParams.eglParameters;
578 loadParams = loadParamsIn;
579 expectedLinkResult = expectedLinkResultIn;
580 }
581
582 PlatformParameters loadParams;
583 bool expectedLinkResult;
584};
585
Corentin Wallez33585c72015-09-03 14:41:23 -0400586// Provide a custom gtest parameter name function for PlatformsWithLinkResult
587// to avoid returning the same parameter name twice. Such a conflict would happen
588// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
589// named ES2_D3D11
590std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
591{
592 const PlatformParameters &platform1 = platform;
593 const PlatformParameters &platform2 = platform.loadParams;
594 stream << platform1 << "_to_" << platform2;
595 return stream;
596}
597
Austin Kinross137b1512015-06-17 16:14:53 -0700598class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
599{
600 public:
601 void SetUp() override
602 {
603 mOSWindow = CreateOSWindow();
604 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
605
606 if (result == false)
607 {
608 FAIL() << "Failed to create OS window";
609 }
610 }
611
612 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
613 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400614 EGLWindow *eglWindow =
615 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700616 bool result = eglWindow->initializeGL(mOSWindow);
617 if (result == false)
618 {
619 SafeDelete(eglWindow);
620 eglWindow = nullptr;
621 }
622
623 return eglWindow;
624 }
625
626 void destroyEGLWindow(EGLWindow **eglWindow)
627 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500628 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700629 (*eglWindow)->destroyGL();
630 SafeDelete(*eglWindow);
631 *eglWindow = nullptr;
632 }
633
634 GLuint createES2ProgramFromSource()
635 {
636 const std::string testVertexShaderSource = SHADER_SOURCE
637 (
638 attribute highp vec4 position;
639
640 void main(void)
641 {
642 gl_Position = position;
643 }
644 );
645
646 const std::string testFragmentShaderSource = SHADER_SOURCE
647 (
648 void main(void)
649 {
650 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
651 }
652 );
653
654 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
655 }
656
657 GLuint createES3ProgramFromSource()
658 {
659 const std::string testVertexShaderSource = SHADER_SOURCE
660 ( #version 300 es\n
661 precision highp float;
662 in highp vec4 position;
663
664 void main(void)
665 {
666 gl_Position = position;
667 }
668 );
669
670 const std::string testFragmentShaderSource = SHADER_SOURCE
671 ( #version 300 es \n
672 precision highp float;
673 out vec4 out_FragColor;
674
675 void main(void)
676 {
677 out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
678 }
679 );
680
681 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
682 }
683
684 void drawWithProgram(GLuint program)
685 {
686 glClearColor(0, 0, 0, 1);
687 glClear(GL_COLOR_BUFFER_BIT);
688
689 GLint positionLocation = glGetAttribLocation(program, "position");
690
691 glUseProgram(program);
692
693 const GLfloat vertices[] =
694 {
695 -1.0f, 1.0f, 0.5f,
696 -1.0f, -1.0f, 0.5f,
697 1.0f, -1.0f, 0.5f,
698
699 -1.0f, 1.0f, 0.5f,
700 1.0f, -1.0f, 0.5f,
701 1.0f, 1.0f, 0.5f,
702 };
703
704 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
705 glEnableVertexAttribArray(positionLocation);
706
707 glDrawArrays(GL_TRIANGLES, 0, 6);
708
709 glDisableVertexAttribArray(positionLocation);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800710 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
Austin Kinross137b1512015-06-17 16:14:53 -0700711
712 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
713 }
714
715 void TearDown() override
716 {
717 mOSWindow->destroy();
718 SafeDelete(mOSWindow);
719 }
720
721 OSWindow *mOSWindow;
722};
723
724// Tries to create a program binary using one set of platform params, then load it using a different sent of params
725TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
726{
727 angle::PlatformParameters firstRenderer = GetParam();
728 angle::PlatformParameters secondRenderer = GetParam().loadParams;
729 bool expectedLinkResult = GetParam().expectedLinkResult;
730
731 if (!(IsPlatformAvailable(firstRenderer)))
732 {
733 std::cout << "First renderer not supported, skipping test";
734 return;
735 }
736
737 if (!(IsPlatformAvailable(secondRenderer)))
738 {
739 std::cout << "Second renderer not supported, skipping test";
740 return;
741 }
742
743 EGLWindow *eglWindow = nullptr;
744 std::vector<uint8_t> binary(0);
745 GLuint program = 0;
746
747 GLint programLength = 0;
748 GLint writtenLength = 0;
749 GLenum binaryFormat = 0;
750
751 // Create a EGL window with the first renderer
752 eglWindow = createAndInitEGLWindow(firstRenderer);
753 if (eglWindow == nullptr)
754 {
755 FAIL() << "Failed to create EGL window";
756 return;
757 }
758
759 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
760 // then our expectations for the test results will be invalid.
761 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
762 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE)
763 {
764 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
Jamie Madillef97c612017-09-09 23:34:18 -0400765 angle::ToLower(&rendererString);
Austin Kinross137b1512015-06-17 16:14:53 -0700766
767 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
768 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
769
770 if (basicRenderPos != std::string::npos || softwareAdapterPos != std::string::npos)
771 {
772 // The first renderer is using WARP, even though we didn't explictly request it
773 // We should skip this test
774 std::cout << "Test skipped on when default GPU is WARP." << std::endl;
775 return;
776 }
777 }
778
779 // Create a program
780 if (firstRenderer.majorVersion == 3)
781 {
782 program = createES3ProgramFromSource();
783 }
784 else
785 {
786 program = createES2ProgramFromSource();
787 }
788
789 if (program == 0)
790 {
Austin Kinross137b1512015-06-17 16:14:53 -0700791 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700792 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700793 }
794
795 // Draw using the program to ensure it works as expected
796 drawWithProgram(program);
797 EXPECT_GL_NO_ERROR();
798
799 // Save the program binary out from this renderer
800 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
801 EXPECT_GL_NO_ERROR();
802 binary.resize(programLength);
803 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
804 EXPECT_GL_NO_ERROR();
805
806 // Destroy the first renderer
807 glDeleteProgram(program);
808 destroyEGLWindow(&eglWindow);
809
810 // Create an EGL window with the second renderer
811 eglWindow = createAndInitEGLWindow(secondRenderer);
812 if (eglWindow == nullptr)
813 {
814 FAIL() << "Failed to create EGL window";
815 return;
816 }
817
818 program = glCreateProgram();
819 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
820
821 GLint linkStatus;
822 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
823 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
824
825 if (linkStatus != 0)
826 {
827 // If the link was successful, then we should try to draw using the program to ensure it works as expected
828 drawWithProgram(program);
829 EXPECT_GL_NO_ERROR();
830 }
831
832 // Destroy the second renderer
833 glDeleteProgram(program);
834 destroyEGLWindow(&eglWindow);
835}
836
Jamie Madilla2c74982016-12-12 11:20:42 -0500837// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700838ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
839 // | Save the program | Load the program | Expected
840 // | using these params | using these params | link result
841 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
842 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
843 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
844 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
845 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
846 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
847 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500848 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400849 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500850// clang-format on