blob: 6d16a6b9e73d528613d53e8b4ce4b1fd094e37e9 [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{
Jamie Madillb22615d2016-12-23 13:21:04 -0500325 // TODO(jmadill): Investigate Intel failure.
326 // http://anglebug.com/1637
327 if (IsWindows() && IsOpenGL() && IsIntel())
328 {
329 std::cout << "Test skipped on Windows Intel OpenGL." << std::endl;
330 return;
331 }
332
Jamie Madill51f522f2016-12-21 15:10:55 -0500333 testBinaryAndUBOBlockIndexes(false);
334}
335
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500336ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
337
Brandon Jones1048ea72015-10-06 15:34:52 -0700338class ProgramBinaryTransformFeedbackTest : public ANGLETest
339{
340 protected:
341 ProgramBinaryTransformFeedbackTest()
342 {
343 setWindowWidth(128);
344 setWindowHeight(128);
345 setConfigRedBits(8);
346 setConfigGreenBits(8);
347 setConfigBlueBits(8);
348 setConfigAlphaBits(8);
349 }
350
351 void SetUp() override
352 {
353 ANGLETest::SetUp();
354
355 const std::string vertexShaderSource = SHADER_SOURCE
356 ( #version 300 es\n
357 in vec4 inputAttribute;
358 out vec4 outputVarying;
359 void main()
360 {
361 outputVarying = inputAttribute;
362 }
363 );
364
365 const std::string fragmentShaderSource = SHADER_SOURCE
366 ( #version 300 es\n
367 precision highp float;
368 out vec4 outputColor;
369 void main()
370 {
371 outputColor = vec4(1,0,0,1);
372 }
373 );
374
375 std::vector<std::string> transformFeedbackVaryings;
376 transformFeedbackVaryings.push_back("outputVarying");
377
378 mProgram = CompileProgramWithTransformFeedback(
379 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
380 GL_SEPARATE_ATTRIBS);
381 if (mProgram == 0)
382 {
383 FAIL() << "shader compilation failed.";
384 }
385
386 ASSERT_GL_NO_ERROR();
387 }
388
Corentin Wallez42e9e592015-10-29 14:09:25 -0400389 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700390 {
391 glDeleteProgram(mProgram);
392
393 ANGLETest::TearDown();
394 }
395
396 GLint getAvailableProgramBinaryFormatCount() const
397 {
398 GLint formatCount;
399 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
400 return formatCount;
401 }
402
403 GLuint mProgram;
404};
405
406// This tests the assumption that float attribs of different size
407// should not internally cause a vertex shader recompile (for conversion).
408TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
409{
410 if (!extensionEnabled("GL_OES_get_program_binary"))
411 {
412 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
413 << std::endl;
414 return;
415 }
416
417 if (getAvailableProgramBinaryFormatCount() == 0)
418 {
419 std::cout << "Test skipped because no program binary formats are available." << std::endl;
420 return;
421 }
422
423 std::vector<uint8_t> binary(0);
424 GLint programLength = 0;
425 GLint writtenLength = 0;
426 GLenum binaryFormat = 0;
427
428 // Save the program binary out
429 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
430 ASSERT_GL_NO_ERROR();
431 binary.resize(programLength);
432 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
433 ASSERT_GL_NO_ERROR();
434
435 glDeleteProgram(mProgram);
436
437 // Load program binary
438 mProgram = glCreateProgram();
439 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
440
441 // Ensure the loaded binary is linked
442 GLint linkStatus;
443 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
444 EXPECT_TRUE(linkStatus != 0);
445
446 // Query information about the transform feedback varying
447 char varyingName[64];
448 GLsizei varyingSize = 0;
449 GLenum varyingType = GL_NONE;
450
451 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
452 EXPECT_GL_NO_ERROR();
453
454 EXPECT_EQ(13, writtenLength);
455 EXPECT_STREQ("outputVarying", varyingName);
456 EXPECT_EQ(1, varyingSize);
457 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
458
459 EXPECT_GL_NO_ERROR();
460}
461
462// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
463ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
464 ES3_D3D11(),
465 ES3_OPENGL());
466
Austin Kinross137b1512015-06-17 16:14:53 -0700467// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
468// - a set to save the program binary
469// - a set to load the program binary
470// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
471struct PlatformsWithLinkResult : PlatformParameters
472{
473 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
474 {
475 majorVersion = saveParams.majorVersion;
476 minorVersion = saveParams.minorVersion;
477 eglParameters = saveParams.eglParameters;
478 loadParams = loadParamsIn;
479 expectedLinkResult = expectedLinkResultIn;
480 }
481
482 PlatformParameters loadParams;
483 bool expectedLinkResult;
484};
485
Corentin Wallez33585c72015-09-03 14:41:23 -0400486// Provide a custom gtest parameter name function for PlatformsWithLinkResult
487// to avoid returning the same parameter name twice. Such a conflict would happen
488// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
489// named ES2_D3D11
490std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
491{
492 const PlatformParameters &platform1 = platform;
493 const PlatformParameters &platform2 = platform.loadParams;
494 stream << platform1 << "_to_" << platform2;
495 return stream;
496}
497
Austin Kinross137b1512015-06-17 16:14:53 -0700498class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
499{
500 public:
501 void SetUp() override
502 {
503 mOSWindow = CreateOSWindow();
504 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
505
506 if (result == false)
507 {
508 FAIL() << "Failed to create OS window";
509 }
510 }
511
512 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
513 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400514 EGLWindow *eglWindow =
515 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700516 bool result = eglWindow->initializeGL(mOSWindow);
517 if (result == false)
518 {
519 SafeDelete(eglWindow);
520 eglWindow = nullptr;
521 }
522
523 return eglWindow;
524 }
525
526 void destroyEGLWindow(EGLWindow **eglWindow)
527 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500528 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700529 (*eglWindow)->destroyGL();
530 SafeDelete(*eglWindow);
531 *eglWindow = nullptr;
532 }
533
534 GLuint createES2ProgramFromSource()
535 {
536 const std::string testVertexShaderSource = SHADER_SOURCE
537 (
538 attribute highp vec4 position;
539
540 void main(void)
541 {
542 gl_Position = position;
543 }
544 );
545
546 const std::string testFragmentShaderSource = SHADER_SOURCE
547 (
548 void main(void)
549 {
550 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
551 }
552 );
553
554 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
555 }
556
557 GLuint createES3ProgramFromSource()
558 {
559 const std::string testVertexShaderSource = SHADER_SOURCE
560 ( #version 300 es\n
561 precision highp float;
562 in highp vec4 position;
563
564 void main(void)
565 {
566 gl_Position = position;
567 }
568 );
569
570 const std::string testFragmentShaderSource = SHADER_SOURCE
571 ( #version 300 es \n
572 precision highp float;
573 out vec4 out_FragColor;
574
575 void main(void)
576 {
577 out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
578 }
579 );
580
581 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
582 }
583
584 void drawWithProgram(GLuint program)
585 {
586 glClearColor(0, 0, 0, 1);
587 glClear(GL_COLOR_BUFFER_BIT);
588
589 GLint positionLocation = glGetAttribLocation(program, "position");
590
591 glUseProgram(program);
592
593 const GLfloat vertices[] =
594 {
595 -1.0f, 1.0f, 0.5f,
596 -1.0f, -1.0f, 0.5f,
597 1.0f, -1.0f, 0.5f,
598
599 -1.0f, 1.0f, 0.5f,
600 1.0f, -1.0f, 0.5f,
601 1.0f, 1.0f, 0.5f,
602 };
603
604 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
605 glEnableVertexAttribArray(positionLocation);
606
607 glDrawArrays(GL_TRIANGLES, 0, 6);
608
609 glDisableVertexAttribArray(positionLocation);
610 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
611
612 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
613 }
614
615 void TearDown() override
616 {
617 mOSWindow->destroy();
618 SafeDelete(mOSWindow);
619 }
620
621 OSWindow *mOSWindow;
622};
623
624// Tries to create a program binary using one set of platform params, then load it using a different sent of params
625TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
626{
627 angle::PlatformParameters firstRenderer = GetParam();
628 angle::PlatformParameters secondRenderer = GetParam().loadParams;
629 bool expectedLinkResult = GetParam().expectedLinkResult;
630
631 if (!(IsPlatformAvailable(firstRenderer)))
632 {
633 std::cout << "First renderer not supported, skipping test";
634 return;
635 }
636
637 if (!(IsPlatformAvailable(secondRenderer)))
638 {
639 std::cout << "Second renderer not supported, skipping test";
640 return;
641 }
642
643 EGLWindow *eglWindow = nullptr;
644 std::vector<uint8_t> binary(0);
645 GLuint program = 0;
646
647 GLint programLength = 0;
648 GLint writtenLength = 0;
649 GLenum binaryFormat = 0;
650
651 // Create a EGL window with the first renderer
652 eglWindow = createAndInitEGLWindow(firstRenderer);
653 if (eglWindow == nullptr)
654 {
655 FAIL() << "Failed to create EGL window";
656 return;
657 }
658
659 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
660 // then our expectations for the test results will be invalid.
661 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
662 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE)
663 {
664 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
665 std::transform(rendererString.begin(), rendererString.end(), rendererString.begin(), ::tolower);
666
667 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
668 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
669
670 if (basicRenderPos != std::string::npos || softwareAdapterPos != std::string::npos)
671 {
672 // The first renderer is using WARP, even though we didn't explictly request it
673 // We should skip this test
674 std::cout << "Test skipped on when default GPU is WARP." << std::endl;
675 return;
676 }
677 }
678
679 // Create a program
680 if (firstRenderer.majorVersion == 3)
681 {
682 program = createES3ProgramFromSource();
683 }
684 else
685 {
686 program = createES2ProgramFromSource();
687 }
688
689 if (program == 0)
690 {
Austin Kinross137b1512015-06-17 16:14:53 -0700691 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700692 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700693 }
694
695 // Draw using the program to ensure it works as expected
696 drawWithProgram(program);
697 EXPECT_GL_NO_ERROR();
698
699 // Save the program binary out from this renderer
700 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
701 EXPECT_GL_NO_ERROR();
702 binary.resize(programLength);
703 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
704 EXPECT_GL_NO_ERROR();
705
706 // Destroy the first renderer
707 glDeleteProgram(program);
708 destroyEGLWindow(&eglWindow);
709
710 // Create an EGL window with the second renderer
711 eglWindow = createAndInitEGLWindow(secondRenderer);
712 if (eglWindow == nullptr)
713 {
714 FAIL() << "Failed to create EGL window";
715 return;
716 }
717
718 program = glCreateProgram();
719 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
720
721 GLint linkStatus;
722 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
723 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
724
725 if (linkStatus != 0)
726 {
727 // If the link was successful, then we should try to draw using the program to ensure it works as expected
728 drawWithProgram(program);
729 EXPECT_GL_NO_ERROR();
730 }
731
732 // Destroy the second renderer
733 glDeleteProgram(program);
734 destroyEGLWindow(&eglWindow);
735}
736
Jamie Madilla2c74982016-12-12 11:20:42 -0500737// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700738ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
739 // | Save the program | Load the program | Expected
740 // | using these params | using these params | link result
741 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
742 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
743 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
744 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
745 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
746 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
747 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500748 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400749 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500750// clang-format on