blob: 304dcca36050ac0a6886099813adc192b74850a9 [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);
61 glBufferData(GL_ARRAY_BUFFER, 128, NULL, GL_STATIC_DRAW);
62 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 Madill7a29e4a2014-05-02 10:41:48 -040082 GLuint mProgram;
83 GLuint mBuffer;
84};
85
86// This tests the assumption that float attribs of different size
87// should not internally cause a vertex shader recompile (for conversion).
Jamie Madillfa05f602015-05-07 13:47:11 -040088TEST_P(ProgramBinaryTest, FloatDynamicShaderSize)
Jamie Madill7a29e4a2014-05-02 10:41:48 -040089{
Geoff Lang90208e92015-10-05 15:40:36 -040090 if (!extensionEnabled("GL_OES_get_program_binary"))
91 {
92 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
93 << std::endl;
94 return;
95 }
96
97 if (getAvailableProgramBinaryFormatCount() == 0)
98 {
99 std::cout << "Test skipped because no program binary formats are available." << std::endl;
100 return;
101 }
102
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400103 glUseProgram(mProgram);
104 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
105
106 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, NULL);
107 glEnableVertexAttribArray(0);
108 glDrawArrays(GL_POINTS, 0, 1);
109
110 GLint programLength;
111 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
112
113 EXPECT_GL_NO_ERROR();
114
115 for (GLsizei size = 1; size <= 3; size++)
116 {
117 glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 8, NULL);
118 glEnableVertexAttribArray(0);
119 glDrawArrays(GL_POINTS, 0, 1);
120
121 GLint newProgramLength;
122 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &newProgramLength);
123 EXPECT_GL_NO_ERROR();
124 EXPECT_EQ(programLength, newProgramLength);
125 }
126}
Brandon Jones993d08d2014-10-10 14:32:57 -0700127
Jamie Madillbdec2f42016-03-02 16:35:32 -0500128// Tests that switching between signed and unsigned un-normalized data doesn't trigger a bug
129// in the D3D11 back-end.
130TEST_P(ProgramBinaryTest, DynamicShadersSignatureBug)
131{
132 glUseProgram(mProgram);
133 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
134
135 GLint attribLocation = glGetAttribLocation(mProgram, "inputAttribute");
136 ASSERT_NE(-1, attribLocation);
137 glEnableVertexAttribArray(attribLocation);
138
139 glVertexAttribPointer(attribLocation, 2, GL_BYTE, GL_FALSE, 0, nullptr);
140 glDrawArrays(GL_POINTS, 0, 1);
141
142 glVertexAttribPointer(attribLocation, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
143 glDrawArrays(GL_POINTS, 0, 1);
144}
145
Brandon Jones993d08d2014-10-10 14:32:57 -0700146// This tests the ability to successfully save and load a program binary.
Jamie Madillfa05f602015-05-07 13:47:11 -0400147TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
Brandon Jones993d08d2014-10-10 14:32:57 -0700148{
Geoff Lang90208e92015-10-05 15:40:36 -0400149 if (!extensionEnabled("GL_OES_get_program_binary"))
150 {
151 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
152 << std::endl;
153 return;
154 }
155
156 if (getAvailableProgramBinaryFormatCount() == 0)
157 {
158 std::cout << "Test skipped because no program binary formats are available." << std::endl;
159 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);
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700193 glGetProgramInfoLog(program2, static_cast<GLsizei>(infoLog.size()), NULL,
194 &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
207 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, NULL);
208 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
218// 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 -0400219ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
220 ES2_D3D9(),
221 ES2_D3D11(),
222 ES3_D3D11(),
223 ES2_OPENGL(),
224 ES3_OPENGL());
Austin Kinross137b1512015-06-17 16:14:53 -0700225
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500226class ProgramBinaryES3Test : public ANGLETest
227{
228};
229
230// Tests that saving and loading a program perserves uniform block binding info.
231TEST_P(ProgramBinaryES3Test, UniformBlockBinding)
232{
233 // We can't run the test if no program binary formats are supported.
234 GLint binaryFormatCount = 0;
235 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
236 if (binaryFormatCount == 0)
237 {
238 std::cout << "Test skipped because no program binary formats available." << std::endl;
239 return;
240 }
241
242 const std::string &vertexShader =
243 "#version 300 es\n"
244 "uniform block {\n"
245 " float f;\n"
246 "};\n"
247 "in vec4 position;\n"
248 "out vec4 color;\n"
249 "void main() {\n"
250 " gl_Position = position;\n"
251 " color = vec4(f, f, f, 1);\n"
252 "}";
253 const std::string &fragmentShader =
254 "#version 300 es\n"
255 "precision mediump float;\n"
256 "in vec4 color;\n"
257 "out vec4 colorOut;\n"
258 "void main() {\n"
259 " colorOut = color;\n"
260 "}";
261
262 // Init and draw with the program.
263 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
264
265 float fData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
266 GLuint bindIndex = 2;
267
268 GLBuffer ubo;
269 glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
270 glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
271 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
272
273 GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
274 ASSERT_NE(-1, blockIndex);
275
276 glUniformBlockBinding(program.get(), blockIndex, bindIndex);
277
278 glClearColor(1.0, 0.0, 0.0, 1.0);
279 glClear(GL_COLOR_BUFFER_BIT);
280 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
281
282 drawQuad(program.get(), "position", 0.5f);
283 ASSERT_GL_NO_ERROR();
284 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
285
286 // Read back the binary.
287 GLint programLength = 0;
288 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
289 ASSERT_GL_NO_ERROR();
290
291 GLsizei readLength = 0;
292 GLenum binaryFormat = GL_NONE;
293 std::vector<uint8_t> binary(programLength);
294 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
295 ASSERT_GL_NO_ERROR();
296
297 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
298
299 // Load a new program with the binary and draw.
300 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
301
302 glClearColor(1.0, 0.0, 0.0, 1.0);
303 glClear(GL_COLOR_BUFFER_BIT);
304 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
305
306 drawQuad(binaryProgram.get(), "position", 0.5f);
307 ASSERT_GL_NO_ERROR();
308 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
309}
310
311ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
312
Brandon Jones1048ea72015-10-06 15:34:52 -0700313class ProgramBinaryTransformFeedbackTest : public ANGLETest
314{
315 protected:
316 ProgramBinaryTransformFeedbackTest()
317 {
318 setWindowWidth(128);
319 setWindowHeight(128);
320 setConfigRedBits(8);
321 setConfigGreenBits(8);
322 setConfigBlueBits(8);
323 setConfigAlphaBits(8);
324 }
325
326 void SetUp() override
327 {
328 ANGLETest::SetUp();
329
330 const std::string vertexShaderSource = SHADER_SOURCE
331 ( #version 300 es\n
332 in vec4 inputAttribute;
333 out vec4 outputVarying;
334 void main()
335 {
336 outputVarying = inputAttribute;
337 }
338 );
339
340 const std::string fragmentShaderSource = SHADER_SOURCE
341 ( #version 300 es\n
342 precision highp float;
343 out vec4 outputColor;
344 void main()
345 {
346 outputColor = vec4(1,0,0,1);
347 }
348 );
349
350 std::vector<std::string> transformFeedbackVaryings;
351 transformFeedbackVaryings.push_back("outputVarying");
352
353 mProgram = CompileProgramWithTransformFeedback(
354 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
355 GL_SEPARATE_ATTRIBS);
356 if (mProgram == 0)
357 {
358 FAIL() << "shader compilation failed.";
359 }
360
361 ASSERT_GL_NO_ERROR();
362 }
363
Corentin Wallez42e9e592015-10-29 14:09:25 -0400364 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700365 {
366 glDeleteProgram(mProgram);
367
368 ANGLETest::TearDown();
369 }
370
371 GLint getAvailableProgramBinaryFormatCount() const
372 {
373 GLint formatCount;
374 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
375 return formatCount;
376 }
377
378 GLuint mProgram;
379};
380
381// This tests the assumption that float attribs of different size
382// should not internally cause a vertex shader recompile (for conversion).
383TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
384{
385 if (!extensionEnabled("GL_OES_get_program_binary"))
386 {
387 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
388 << std::endl;
389 return;
390 }
391
392 if (getAvailableProgramBinaryFormatCount() == 0)
393 {
394 std::cout << "Test skipped because no program binary formats are available." << std::endl;
395 return;
396 }
397
398 std::vector<uint8_t> binary(0);
399 GLint programLength = 0;
400 GLint writtenLength = 0;
401 GLenum binaryFormat = 0;
402
403 // Save the program binary out
404 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
405 ASSERT_GL_NO_ERROR();
406 binary.resize(programLength);
407 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
408 ASSERT_GL_NO_ERROR();
409
410 glDeleteProgram(mProgram);
411
412 // Load program binary
413 mProgram = glCreateProgram();
414 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
415
416 // Ensure the loaded binary is linked
417 GLint linkStatus;
418 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
419 EXPECT_TRUE(linkStatus != 0);
420
421 // Query information about the transform feedback varying
422 char varyingName[64];
423 GLsizei varyingSize = 0;
424 GLenum varyingType = GL_NONE;
425
426 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
427 EXPECT_GL_NO_ERROR();
428
429 EXPECT_EQ(13, writtenLength);
430 EXPECT_STREQ("outputVarying", varyingName);
431 EXPECT_EQ(1, varyingSize);
432 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
433
434 EXPECT_GL_NO_ERROR();
435}
436
437// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
438ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
439 ES3_D3D11(),
440 ES3_OPENGL());
441
Austin Kinross137b1512015-06-17 16:14:53 -0700442// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
443// - a set to save the program binary
444// - a set to load the program binary
445// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
446struct PlatformsWithLinkResult : PlatformParameters
447{
448 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
449 {
450 majorVersion = saveParams.majorVersion;
451 minorVersion = saveParams.minorVersion;
452 eglParameters = saveParams.eglParameters;
453 loadParams = loadParamsIn;
454 expectedLinkResult = expectedLinkResultIn;
455 }
456
457 PlatformParameters loadParams;
458 bool expectedLinkResult;
459};
460
Corentin Wallez33585c72015-09-03 14:41:23 -0400461// Provide a custom gtest parameter name function for PlatformsWithLinkResult
462// to avoid returning the same parameter name twice. Such a conflict would happen
463// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
464// named ES2_D3D11
465std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
466{
467 const PlatformParameters &platform1 = platform;
468 const PlatformParameters &platform2 = platform.loadParams;
469 stream << platform1 << "_to_" << platform2;
470 return stream;
471}
472
Austin Kinross137b1512015-06-17 16:14:53 -0700473class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
474{
475 public:
476 void SetUp() override
477 {
478 mOSWindow = CreateOSWindow();
479 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
480
481 if (result == false)
482 {
483 FAIL() << "Failed to create OS window";
484 }
485 }
486
487 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
488 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400489 EGLWindow *eglWindow =
490 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700491 bool result = eglWindow->initializeGL(mOSWindow);
492 if (result == false)
493 {
494 SafeDelete(eglWindow);
495 eglWindow = nullptr;
496 }
497
498 return eglWindow;
499 }
500
501 void destroyEGLWindow(EGLWindow **eglWindow)
502 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500503 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700504 (*eglWindow)->destroyGL();
505 SafeDelete(*eglWindow);
506 *eglWindow = nullptr;
507 }
508
509 GLuint createES2ProgramFromSource()
510 {
511 const std::string testVertexShaderSource = SHADER_SOURCE
512 (
513 attribute highp vec4 position;
514
515 void main(void)
516 {
517 gl_Position = position;
518 }
519 );
520
521 const std::string testFragmentShaderSource = SHADER_SOURCE
522 (
523 void main(void)
524 {
525 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
526 }
527 );
528
529 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
530 }
531
532 GLuint createES3ProgramFromSource()
533 {
534 const std::string testVertexShaderSource = SHADER_SOURCE
535 ( #version 300 es\n
536 precision highp float;
537 in highp vec4 position;
538
539 void main(void)
540 {
541 gl_Position = position;
542 }
543 );
544
545 const std::string testFragmentShaderSource = SHADER_SOURCE
546 ( #version 300 es \n
547 precision highp float;
548 out vec4 out_FragColor;
549
550 void main(void)
551 {
552 out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
553 }
554 );
555
556 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
557 }
558
559 void drawWithProgram(GLuint program)
560 {
561 glClearColor(0, 0, 0, 1);
562 glClear(GL_COLOR_BUFFER_BIT);
563
564 GLint positionLocation = glGetAttribLocation(program, "position");
565
566 glUseProgram(program);
567
568 const GLfloat vertices[] =
569 {
570 -1.0f, 1.0f, 0.5f,
571 -1.0f, -1.0f, 0.5f,
572 1.0f, -1.0f, 0.5f,
573
574 -1.0f, 1.0f, 0.5f,
575 1.0f, -1.0f, 0.5f,
576 1.0f, 1.0f, 0.5f,
577 };
578
579 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
580 glEnableVertexAttribArray(positionLocation);
581
582 glDrawArrays(GL_TRIANGLES, 0, 6);
583
584 glDisableVertexAttribArray(positionLocation);
585 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
586
587 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
588 }
589
590 void TearDown() override
591 {
592 mOSWindow->destroy();
593 SafeDelete(mOSWindow);
594 }
595
596 OSWindow *mOSWindow;
597};
598
599// Tries to create a program binary using one set of platform params, then load it using a different sent of params
600TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
601{
602 angle::PlatformParameters firstRenderer = GetParam();
603 angle::PlatformParameters secondRenderer = GetParam().loadParams;
604 bool expectedLinkResult = GetParam().expectedLinkResult;
605
606 if (!(IsPlatformAvailable(firstRenderer)))
607 {
608 std::cout << "First renderer not supported, skipping test";
609 return;
610 }
611
612 if (!(IsPlatformAvailable(secondRenderer)))
613 {
614 std::cout << "Second renderer not supported, skipping test";
615 return;
616 }
617
618 EGLWindow *eglWindow = nullptr;
619 std::vector<uint8_t> binary(0);
620 GLuint program = 0;
621
622 GLint programLength = 0;
623 GLint writtenLength = 0;
624 GLenum binaryFormat = 0;
625
626 // Create a EGL window with the first renderer
627 eglWindow = createAndInitEGLWindow(firstRenderer);
628 if (eglWindow == nullptr)
629 {
630 FAIL() << "Failed to create EGL window";
631 return;
632 }
633
634 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
635 // then our expectations for the test results will be invalid.
636 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
637 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE)
638 {
639 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
640 std::transform(rendererString.begin(), rendererString.end(), rendererString.begin(), ::tolower);
641
642 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
643 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
644
645 if (basicRenderPos != std::string::npos || softwareAdapterPos != std::string::npos)
646 {
647 // The first renderer is using WARP, even though we didn't explictly request it
648 // We should skip this test
649 std::cout << "Test skipped on when default GPU is WARP." << std::endl;
650 return;
651 }
652 }
653
654 // Create a program
655 if (firstRenderer.majorVersion == 3)
656 {
657 program = createES3ProgramFromSource();
658 }
659 else
660 {
661 program = createES2ProgramFromSource();
662 }
663
664 if (program == 0)
665 {
Austin Kinross137b1512015-06-17 16:14:53 -0700666 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700667 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700668 }
669
670 // Draw using the program to ensure it works as expected
671 drawWithProgram(program);
672 EXPECT_GL_NO_ERROR();
673
674 // Save the program binary out from this renderer
675 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
676 EXPECT_GL_NO_ERROR();
677 binary.resize(programLength);
678 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
679 EXPECT_GL_NO_ERROR();
680
681 // Destroy the first renderer
682 glDeleteProgram(program);
683 destroyEGLWindow(&eglWindow);
684
685 // Create an EGL window with the second renderer
686 eglWindow = createAndInitEGLWindow(secondRenderer);
687 if (eglWindow == nullptr)
688 {
689 FAIL() << "Failed to create EGL window";
690 return;
691 }
692
693 program = glCreateProgram();
694 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
695
696 GLint linkStatus;
697 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
698 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
699
700 if (linkStatus != 0)
701 {
702 // If the link was successful, then we should try to draw using the program to ensure it works as expected
703 drawWithProgram(program);
704 EXPECT_GL_NO_ERROR();
705 }
706
707 // Destroy the second renderer
708 glDeleteProgram(program);
709 destroyEGLWindow(&eglWindow);
710}
711
Jamie Madilla2c74982016-12-12 11:20:42 -0500712// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700713ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
714 // | Save the program | Load the program | Expected
715 // | using these params | using these params | link result
716 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
717 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
718 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
719 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
720 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
721 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
722 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500723 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400724 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500725// clang-format on