blob: bd90ceb44217cf0570409b09e1cbfc451adcc2ca [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{
Jamie Madill51f522f2016-12-21 15:10:55 -0500228 protected:
229 void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500230};
231
Jamie Madill51f522f2016-12-21 15:10:55 -0500232void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500233{
234 // We can't run the test if no program binary formats are supported.
235 GLint binaryFormatCount = 0;
236 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
237 if (binaryFormatCount == 0)
238 {
239 std::cout << "Test skipped because no program binary formats available." << std::endl;
240 return;
241 }
242
243 const std::string &vertexShader =
244 "#version 300 es\n"
245 "uniform block {\n"
246 " float f;\n"
247 "};\n"
248 "in vec4 position;\n"
249 "out vec4 color;\n"
250 "void main() {\n"
251 " gl_Position = position;\n"
252 " color = vec4(f, f, f, 1);\n"
253 "}";
254 const std::string &fragmentShader =
255 "#version 300 es\n"
256 "precision mediump float;\n"
257 "in vec4 color;\n"
258 "out vec4 colorOut;\n"
259 "void main() {\n"
260 " colorOut = color;\n"
261 "}";
262
263 // Init and draw with the program.
264 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
265
266 float fData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
267 GLuint bindIndex = 2;
268
269 GLBuffer ubo;
270 glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
271 glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
272 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
273
274 GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
275 ASSERT_NE(-1, blockIndex);
276
277 glUniformBlockBinding(program.get(), blockIndex, bindIndex);
278
279 glClearColor(1.0, 0.0, 0.0, 1.0);
280 glClear(GL_COLOR_BUFFER_BIT);
281 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
282
Jamie Madill51f522f2016-12-21 15:10:55 -0500283 if (drawWithProgramFirst)
284 {
285 drawQuad(program.get(), "position", 0.5f);
286 ASSERT_GL_NO_ERROR();
287 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
288 }
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500289
290 // Read back the binary.
291 GLint programLength = 0;
292 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
293 ASSERT_GL_NO_ERROR();
294
295 GLsizei readLength = 0;
296 GLenum binaryFormat = GL_NONE;
297 std::vector<uint8_t> binary(programLength);
298 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
299 ASSERT_GL_NO_ERROR();
300
301 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
302
303 // Load a new program with the binary and draw.
304 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
305
306 glClearColor(1.0, 0.0, 0.0, 1.0);
307 glClear(GL_COLOR_BUFFER_BIT);
308 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
309
310 drawQuad(binaryProgram.get(), "position", 0.5f);
311 ASSERT_GL_NO_ERROR();
312 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
313}
314
Jamie Madill51f522f2016-12-21 15:10:55 -0500315// Tests that saving and loading a program perserves uniform block binding info.
316TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
317{
318 testBinaryAndUBOBlockIndexes(true);
319}
320
321// Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
322// http://anglebug.com/1637
323TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
324{
325 testBinaryAndUBOBlockIndexes(false);
326}
327
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500328ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
329
Brandon Jones1048ea72015-10-06 15:34:52 -0700330class ProgramBinaryTransformFeedbackTest : public ANGLETest
331{
332 protected:
333 ProgramBinaryTransformFeedbackTest()
334 {
335 setWindowWidth(128);
336 setWindowHeight(128);
337 setConfigRedBits(8);
338 setConfigGreenBits(8);
339 setConfigBlueBits(8);
340 setConfigAlphaBits(8);
341 }
342
343 void SetUp() override
344 {
345 ANGLETest::SetUp();
346
347 const std::string vertexShaderSource = SHADER_SOURCE
348 ( #version 300 es\n
349 in vec4 inputAttribute;
350 out vec4 outputVarying;
351 void main()
352 {
353 outputVarying = inputAttribute;
354 }
355 );
356
357 const std::string fragmentShaderSource = SHADER_SOURCE
358 ( #version 300 es\n
359 precision highp float;
360 out vec4 outputColor;
361 void main()
362 {
363 outputColor = vec4(1,0,0,1);
364 }
365 );
366
367 std::vector<std::string> transformFeedbackVaryings;
368 transformFeedbackVaryings.push_back("outputVarying");
369
370 mProgram = CompileProgramWithTransformFeedback(
371 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
372 GL_SEPARATE_ATTRIBS);
373 if (mProgram == 0)
374 {
375 FAIL() << "shader compilation failed.";
376 }
377
378 ASSERT_GL_NO_ERROR();
379 }
380
Corentin Wallez42e9e592015-10-29 14:09:25 -0400381 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700382 {
383 glDeleteProgram(mProgram);
384
385 ANGLETest::TearDown();
386 }
387
388 GLint getAvailableProgramBinaryFormatCount() const
389 {
390 GLint formatCount;
391 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
392 return formatCount;
393 }
394
395 GLuint mProgram;
396};
397
398// This tests the assumption that float attribs of different size
399// should not internally cause a vertex shader recompile (for conversion).
400TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
401{
402 if (!extensionEnabled("GL_OES_get_program_binary"))
403 {
404 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
405 << std::endl;
406 return;
407 }
408
409 if (getAvailableProgramBinaryFormatCount() == 0)
410 {
411 std::cout << "Test skipped because no program binary formats are available." << std::endl;
412 return;
413 }
414
415 std::vector<uint8_t> binary(0);
416 GLint programLength = 0;
417 GLint writtenLength = 0;
418 GLenum binaryFormat = 0;
419
420 // Save the program binary out
421 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
422 ASSERT_GL_NO_ERROR();
423 binary.resize(programLength);
424 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
425 ASSERT_GL_NO_ERROR();
426
427 glDeleteProgram(mProgram);
428
429 // Load program binary
430 mProgram = glCreateProgram();
431 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
432
433 // Ensure the loaded binary is linked
434 GLint linkStatus;
435 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
436 EXPECT_TRUE(linkStatus != 0);
437
438 // Query information about the transform feedback varying
439 char varyingName[64];
440 GLsizei varyingSize = 0;
441 GLenum varyingType = GL_NONE;
442
443 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
444 EXPECT_GL_NO_ERROR();
445
446 EXPECT_EQ(13, writtenLength);
447 EXPECT_STREQ("outputVarying", varyingName);
448 EXPECT_EQ(1, varyingSize);
449 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
450
451 EXPECT_GL_NO_ERROR();
452}
453
454// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
455ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
456 ES3_D3D11(),
457 ES3_OPENGL());
458
Austin Kinross137b1512015-06-17 16:14:53 -0700459// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
460// - a set to save the program binary
461// - a set to load the program binary
462// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
463struct PlatformsWithLinkResult : PlatformParameters
464{
465 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
466 {
467 majorVersion = saveParams.majorVersion;
468 minorVersion = saveParams.minorVersion;
469 eglParameters = saveParams.eglParameters;
470 loadParams = loadParamsIn;
471 expectedLinkResult = expectedLinkResultIn;
472 }
473
474 PlatformParameters loadParams;
475 bool expectedLinkResult;
476};
477
Corentin Wallez33585c72015-09-03 14:41:23 -0400478// Provide a custom gtest parameter name function for PlatformsWithLinkResult
479// to avoid returning the same parameter name twice. Such a conflict would happen
480// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
481// named ES2_D3D11
482std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
483{
484 const PlatformParameters &platform1 = platform;
485 const PlatformParameters &platform2 = platform.loadParams;
486 stream << platform1 << "_to_" << platform2;
487 return stream;
488}
489
Austin Kinross137b1512015-06-17 16:14:53 -0700490class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
491{
492 public:
493 void SetUp() override
494 {
495 mOSWindow = CreateOSWindow();
496 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
497
498 if (result == false)
499 {
500 FAIL() << "Failed to create OS window";
501 }
502 }
503
504 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
505 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400506 EGLWindow *eglWindow =
507 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700508 bool result = eglWindow->initializeGL(mOSWindow);
509 if (result == false)
510 {
511 SafeDelete(eglWindow);
512 eglWindow = nullptr;
513 }
514
515 return eglWindow;
516 }
517
518 void destroyEGLWindow(EGLWindow **eglWindow)
519 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500520 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700521 (*eglWindow)->destroyGL();
522 SafeDelete(*eglWindow);
523 *eglWindow = nullptr;
524 }
525
526 GLuint createES2ProgramFromSource()
527 {
528 const std::string testVertexShaderSource = SHADER_SOURCE
529 (
530 attribute highp vec4 position;
531
532 void main(void)
533 {
534 gl_Position = position;
535 }
536 );
537
538 const std::string testFragmentShaderSource = SHADER_SOURCE
539 (
540 void main(void)
541 {
542 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
543 }
544 );
545
546 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
547 }
548
549 GLuint createES3ProgramFromSource()
550 {
551 const std::string testVertexShaderSource = SHADER_SOURCE
552 ( #version 300 es\n
553 precision highp float;
554 in highp vec4 position;
555
556 void main(void)
557 {
558 gl_Position = position;
559 }
560 );
561
562 const std::string testFragmentShaderSource = SHADER_SOURCE
563 ( #version 300 es \n
564 precision highp float;
565 out vec4 out_FragColor;
566
567 void main(void)
568 {
569 out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
570 }
571 );
572
573 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
574 }
575
576 void drawWithProgram(GLuint program)
577 {
578 glClearColor(0, 0, 0, 1);
579 glClear(GL_COLOR_BUFFER_BIT);
580
581 GLint positionLocation = glGetAttribLocation(program, "position");
582
583 glUseProgram(program);
584
585 const GLfloat vertices[] =
586 {
587 -1.0f, 1.0f, 0.5f,
588 -1.0f, -1.0f, 0.5f,
589 1.0f, -1.0f, 0.5f,
590
591 -1.0f, 1.0f, 0.5f,
592 1.0f, -1.0f, 0.5f,
593 1.0f, 1.0f, 0.5f,
594 };
595
596 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
597 glEnableVertexAttribArray(positionLocation);
598
599 glDrawArrays(GL_TRIANGLES, 0, 6);
600
601 glDisableVertexAttribArray(positionLocation);
602 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
603
604 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
605 }
606
607 void TearDown() override
608 {
609 mOSWindow->destroy();
610 SafeDelete(mOSWindow);
611 }
612
613 OSWindow *mOSWindow;
614};
615
616// Tries to create a program binary using one set of platform params, then load it using a different sent of params
617TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
618{
619 angle::PlatformParameters firstRenderer = GetParam();
620 angle::PlatformParameters secondRenderer = GetParam().loadParams;
621 bool expectedLinkResult = GetParam().expectedLinkResult;
622
623 if (!(IsPlatformAvailable(firstRenderer)))
624 {
625 std::cout << "First renderer not supported, skipping test";
626 return;
627 }
628
629 if (!(IsPlatformAvailable(secondRenderer)))
630 {
631 std::cout << "Second renderer not supported, skipping test";
632 return;
633 }
634
635 EGLWindow *eglWindow = nullptr;
636 std::vector<uint8_t> binary(0);
637 GLuint program = 0;
638
639 GLint programLength = 0;
640 GLint writtenLength = 0;
641 GLenum binaryFormat = 0;
642
643 // Create a EGL window with the first renderer
644 eglWindow = createAndInitEGLWindow(firstRenderer);
645 if (eglWindow == nullptr)
646 {
647 FAIL() << "Failed to create EGL window";
648 return;
649 }
650
651 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
652 // then our expectations for the test results will be invalid.
653 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
654 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE)
655 {
656 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
657 std::transform(rendererString.begin(), rendererString.end(), rendererString.begin(), ::tolower);
658
659 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
660 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
661
662 if (basicRenderPos != std::string::npos || softwareAdapterPos != std::string::npos)
663 {
664 // The first renderer is using WARP, even though we didn't explictly request it
665 // We should skip this test
666 std::cout << "Test skipped on when default GPU is WARP." << std::endl;
667 return;
668 }
669 }
670
671 // Create a program
672 if (firstRenderer.majorVersion == 3)
673 {
674 program = createES3ProgramFromSource();
675 }
676 else
677 {
678 program = createES2ProgramFromSource();
679 }
680
681 if (program == 0)
682 {
Austin Kinross137b1512015-06-17 16:14:53 -0700683 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700684 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700685 }
686
687 // Draw using the program to ensure it works as expected
688 drawWithProgram(program);
689 EXPECT_GL_NO_ERROR();
690
691 // Save the program binary out from this renderer
692 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
693 EXPECT_GL_NO_ERROR();
694 binary.resize(programLength);
695 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
696 EXPECT_GL_NO_ERROR();
697
698 // Destroy the first renderer
699 glDeleteProgram(program);
700 destroyEGLWindow(&eglWindow);
701
702 // Create an EGL window with the second renderer
703 eglWindow = createAndInitEGLWindow(secondRenderer);
704 if (eglWindow == nullptr)
705 {
706 FAIL() << "Failed to create EGL window";
707 return;
708 }
709
710 program = glCreateProgram();
711 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
712
713 GLint linkStatus;
714 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
715 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
716
717 if (linkStatus != 0)
718 {
719 // If the link was successful, then we should try to draw using the program to ensure it works as expected
720 drawWithProgram(program);
721 EXPECT_GL_NO_ERROR();
722 }
723
724 // Destroy the second renderer
725 glDeleteProgram(program);
726 destroyEGLWindow(&eglWindow);
727}
728
Jamie Madilla2c74982016-12-12 11:20:42 -0500729// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700730ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
731 // | Save the program | Load the program | Expected
732 // | using these params | using these params | link result
733 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
734 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
735 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
736 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
737 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
738 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
739 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500740 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400741 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500742// clang-format on