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