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