blob: 298c9b1c1677f5f54744e89bde93f616e3aad855 [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"
Jamie Madillef97c612017-09-09 23:34:18 -040014#include "common/string_utils.h"
Austin Kinross137b1512015-06-17 16:14:53 -070015#include "test_utils/angle_test_configs.h"
Jamie Madilla7d12dc2016-12-13 15:08:19 -050016#include "test_utils/gl_raii.h"
Austin Kinross137b1512015-06-17 16:14:53 -070017
Jamie Madillfa05f602015-05-07 13:47:11 -040018using namespace angle;
Austin Kinross18b931d2014-09-29 12:58:31 -070019
Jamie Madill7a29e4a2014-05-02 10:41:48 -040020class ProgramBinaryTest : public ANGLETest
21{
Geoff Lang0d3683c2014-10-23 11:08:16 -040022 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040023 ProgramBinaryTest()
Jamie Madill7a29e4a2014-05-02 10:41:48 -040024 {
25 setWindowWidth(128);
26 setWindowHeight(128);
27 setConfigRedBits(8);
28 setConfigGreenBits(8);
29 setConfigBlueBits(8);
30 setConfigAlphaBits(8);
31 }
32
Corentin Wallez42e9e592015-10-29 14:09:25 -040033 void SetUp() override
Jamie Madill7a29e4a2014-05-02 10:41:48 -040034 {
35 ANGLETest::SetUp();
36
Olli Etuahoa20af6d2017-09-18 13:32:29 +030037 const std::string vertexShaderSource =
38 R"(attribute vec4 inputAttribute;
Jamie Madill7a29e4a2014-05-02 10:41:48 -040039 void main()
40 {
41 gl_Position = inputAttribute;
Olli Etuahoa20af6d2017-09-18 13:32:29 +030042 })";
Jamie Madill7a29e4a2014-05-02 10:41:48 -040043
Olli Etuahoa20af6d2017-09-18 13:32:29 +030044 const std::string fragmentShaderSource =
45 R"(void main()
Jamie Madill7a29e4a2014-05-02 10:41:48 -040046 {
47 gl_FragColor = vec4(1,0,0,1);
Olli Etuahoa20af6d2017-09-18 13:32:29 +030048 })";
Jamie Madill7a29e4a2014-05-02 10:41:48 -040049
Jamie Madill5599c8f2014-08-26 13:16:39 -040050 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040051 if (mProgram == 0)
52 {
53 FAIL() << "shader compilation failed.";
54 }
55
56 glGenBuffers(1, &mBuffer);
57 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
Yunchao Hef81ce4a2017-04-24 10:49:17 +080058 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_STATIC_DRAW);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040059 glBindBuffer(GL_ARRAY_BUFFER, 0);
60
61 ASSERT_GL_NO_ERROR();
62 }
63
Corentin Wallez42e9e592015-10-29 14:09:25 -040064 void TearDown() override
Jamie Madill7a29e4a2014-05-02 10:41:48 -040065 {
66 glDeleteProgram(mProgram);
67 glDeleteBuffers(1, &mBuffer);
68
69 ANGLETest::TearDown();
70 }
71
Geoff Lang90208e92015-10-05 15:40:36 -040072 GLint getAvailableProgramBinaryFormatCount() const
73 {
74 GLint formatCount;
75 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
76 return formatCount;
77 }
78
Jamie Madill311d9992017-05-30 15:38:54 -040079 bool supported() const
80 {
81 if (!extensionEnabled("GL_OES_get_program_binary"))
82 {
83 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
84 << std::endl;
85 return false;
86 }
87
88 if (getAvailableProgramBinaryFormatCount() == 0)
89 {
90 std::cout << "Test skipped because no program binary formats are available."
91 << std::endl;
92 return false;
93 }
94
95 return true;
96 }
97
Jamie Madill7a29e4a2014-05-02 10:41:48 -040098 GLuint mProgram;
99 GLuint mBuffer;
100};
101
102// This tests the assumption that float attribs of different size
103// should not internally cause a vertex shader recompile (for conversion).
Jamie Madillfa05f602015-05-07 13:47:11 -0400104TEST_P(ProgramBinaryTest, FloatDynamicShaderSize)
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400105{
Jamie Madill311d9992017-05-30 15:38:54 -0400106 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -0400107 {
Geoff Lang90208e92015-10-05 15:40:36 -0400108 return;
109 }
110
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400111 glUseProgram(mProgram);
112 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
113
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800114 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400115 glEnableVertexAttribArray(0);
116 glDrawArrays(GL_POINTS, 0, 1);
117
118 GLint programLength;
119 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
120
121 EXPECT_GL_NO_ERROR();
122
123 for (GLsizei size = 1; size <= 3; size++)
124 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800125 glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400126 glEnableVertexAttribArray(0);
127 glDrawArrays(GL_POINTS, 0, 1);
128
129 GLint newProgramLength;
130 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &newProgramLength);
131 EXPECT_GL_NO_ERROR();
132 EXPECT_EQ(programLength, newProgramLength);
133 }
134}
Brandon Jones993d08d2014-10-10 14:32:57 -0700135
Jamie Madillbdec2f42016-03-02 16:35:32 -0500136// Tests that switching between signed and unsigned un-normalized data doesn't trigger a bug
137// in the D3D11 back-end.
138TEST_P(ProgramBinaryTest, DynamicShadersSignatureBug)
139{
140 glUseProgram(mProgram);
141 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
142
143 GLint attribLocation = glGetAttribLocation(mProgram, "inputAttribute");
144 ASSERT_NE(-1, attribLocation);
145 glEnableVertexAttribArray(attribLocation);
146
147 glVertexAttribPointer(attribLocation, 2, GL_BYTE, GL_FALSE, 0, nullptr);
148 glDrawArrays(GL_POINTS, 0, 1);
149
150 glVertexAttribPointer(attribLocation, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
151 glDrawArrays(GL_POINTS, 0, 1);
152}
153
Brandon Jones993d08d2014-10-10 14:32:57 -0700154// This tests the ability to successfully save and load a program binary.
Jamie Madillfa05f602015-05-07 13:47:11 -0400155TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
Brandon Jones993d08d2014-10-10 14:32:57 -0700156{
Jamie Madill311d9992017-05-30 15:38:54 -0400157 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -0400158 {
Geoff Lang90208e92015-10-05 15:40:36 -0400159 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);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800193 glGetProgramInfoLog(program2, static_cast<GLsizei>(infoLog.size()), nullptr,
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700194 &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
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800207 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Brandon Jones993d08d2014-10-10 14:32:57 -0700208 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
Jamie Madill311d9992017-05-30 15:38:54 -0400218// Ensures that we init the compiler before calling ProgramBinary.
219TEST_P(ProgramBinaryTest, CallProgramBinaryBeforeLink)
220{
221 if (!supported())
222 {
223 return;
224 }
225
226 // Initialize a simple program.
227 glUseProgram(mProgram);
228
229 GLsizei length = 0;
230 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH, &length);
231 ASSERT_GL_NO_ERROR();
232 ASSERT_GT(length, 0);
233
234 GLsizei readLength = 0;
235 GLenum binaryFormat = GL_NONE;
236 std::vector<uint8_t> binaryBlob(length);
237 glGetProgramBinaryOES(mProgram, length, &readLength, &binaryFormat, binaryBlob.data());
238 ASSERT_GL_NO_ERROR();
239
240 // Shutdown and restart GL entirely.
241 TearDown();
242 SetUp();
243
244 ANGLE_GL_BINARY_OES_PROGRAM(binaryProgram, binaryBlob, binaryFormat);
245 ASSERT_GL_NO_ERROR();
246
247 drawQuad(binaryProgram, "inputAttribute", 0.5f);
248 ASSERT_GL_NO_ERROR();
249}
250
Jamie Madillfa05f602015-05-07 13:47:11 -0400251// 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 -0400252ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
253 ES2_D3D9(),
254 ES2_D3D11(),
255 ES3_D3D11(),
256 ES2_OPENGL(),
257 ES3_OPENGL());
Austin Kinross137b1512015-06-17 16:14:53 -0700258
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500259class ProgramBinaryES3Test : public ANGLETest
260{
Jamie Madill51f522f2016-12-21 15:10:55 -0500261 protected:
262 void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500263};
264
Jamie Madill51f522f2016-12-21 15:10:55 -0500265void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500266{
267 // We can't run the test if no program binary formats are supported.
268 GLint binaryFormatCount = 0;
269 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
270 if (binaryFormatCount == 0)
271 {
272 std::cout << "Test skipped because no program binary formats available." << std::endl;
273 return;
274 }
275
276 const std::string &vertexShader =
277 "#version 300 es\n"
278 "uniform block {\n"
279 " float f;\n"
280 "};\n"
281 "in vec4 position;\n"
282 "out vec4 color;\n"
283 "void main() {\n"
284 " gl_Position = position;\n"
285 " color = vec4(f, f, f, 1);\n"
286 "}";
287 const std::string &fragmentShader =
288 "#version 300 es\n"
289 "precision mediump float;\n"
290 "in vec4 color;\n"
291 "out vec4 colorOut;\n"
292 "void main() {\n"
293 " colorOut = color;\n"
294 "}";
295
296 // Init and draw with the program.
297 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
298
299 float fData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
300 GLuint bindIndex = 2;
301
302 GLBuffer ubo;
303 glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
304 glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
305 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
306
307 GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
308 ASSERT_NE(-1, blockIndex);
309
310 glUniformBlockBinding(program.get(), blockIndex, bindIndex);
311
312 glClearColor(1.0, 0.0, 0.0, 1.0);
313 glClear(GL_COLOR_BUFFER_BIT);
314 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
315
Jamie Madill51f522f2016-12-21 15:10:55 -0500316 if (drawWithProgramFirst)
317 {
318 drawQuad(program.get(), "position", 0.5f);
319 ASSERT_GL_NO_ERROR();
320 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
321 }
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500322
323 // Read back the binary.
324 GLint programLength = 0;
325 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
326 ASSERT_GL_NO_ERROR();
327
328 GLsizei readLength = 0;
329 GLenum binaryFormat = GL_NONE;
330 std::vector<uint8_t> binary(programLength);
331 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
332 ASSERT_GL_NO_ERROR();
333
334 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
335
336 // Load a new program with the binary and draw.
337 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
338
339 glClearColor(1.0, 0.0, 0.0, 1.0);
340 glClear(GL_COLOR_BUFFER_BIT);
341 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
342
343 drawQuad(binaryProgram.get(), "position", 0.5f);
344 ASSERT_GL_NO_ERROR();
345 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
346}
347
Jamie Madill51f522f2016-12-21 15:10:55 -0500348// Tests that saving and loading a program perserves uniform block binding info.
349TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
350{
351 testBinaryAndUBOBlockIndexes(true);
352}
353
354// Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
355// http://anglebug.com/1637
356TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
357{
Jamie Madillb22615d2016-12-23 13:21:04 -0500358 // TODO(jmadill): Investigate Intel failure.
359 // http://anglebug.com/1637
360 if (IsWindows() && IsOpenGL() && IsIntel())
361 {
362 std::cout << "Test skipped on Windows Intel OpenGL." << std::endl;
363 return;
364 }
365
Jamie Madill51f522f2016-12-21 15:10:55 -0500366 testBinaryAndUBOBlockIndexes(false);
367}
368
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500369ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
370
Xinghua Caob1239382016-12-13 15:07:05 +0800371class ProgramBinaryES31Test : public ANGLETest
372{
373 protected:
374 ProgramBinaryES31Test()
375 {
376 setWindowWidth(128);
377 setWindowHeight(128);
378 setConfigRedBits(8);
379 setConfigGreenBits(8);
380 setConfigBlueBits(8);
381 setConfigAlphaBits(8);
382 }
383};
384
385// Tests that saving and loading a program attached with computer shader.
386TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
387{
388 // We can't run the test if no program binary formats are supported.
389 GLint binaryFormatCount = 0;
390 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
391 if (binaryFormatCount == 0)
392 {
393 std::cout << "Test skipped because no program binary formats available." << std::endl;
394 return;
395 }
396
397 const std::string &computeShader =
398 "#version 310 es\n"
399 "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
400 "uniform block {\n"
401 " vec2 f;\n"
402 "};\n"
403 "uniform vec2 g;\n"
404 "uniform highp sampler2D tex;\n"
405 "void main() {\n"
406 " vec4 color = texture(tex, f + g);\n"
407 "}";
408
409 ANGLE_GL_COMPUTE_PROGRAM(program, computeShader);
410
411 // Read back the binary.
412 GLint programLength = 0;
413 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
414 ASSERT_GL_NO_ERROR();
415
416 GLsizei readLength = 0;
417 GLenum binaryFormat = GL_NONE;
418 std::vector<uint8_t> binary(programLength);
419 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
420 ASSERT_GL_NO_ERROR();
421
422 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
423
424 // Load a new program with the binary.
425 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
Yunchao He85072e82017-11-14 15:43:28 +0800426 ASSERT_GL_NO_ERROR();
Xinghua Caob1239382016-12-13 15:07:05 +0800427
Yunchao He85072e82017-11-14 15:43:28 +0800428 // Dispatch compute with the loaded binary program
429 glUseProgram(binaryProgram.get());
430 glDispatchCompute(8, 4, 2);
Xinghua Caob1239382016-12-13 15:07:05 +0800431 ASSERT_GL_NO_ERROR();
432}
433
434ANGLE_INSTANTIATE_TEST(ProgramBinaryES31Test, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
435
Brandon Jones1048ea72015-10-06 15:34:52 -0700436class ProgramBinaryTransformFeedbackTest : public ANGLETest
437{
438 protected:
439 ProgramBinaryTransformFeedbackTest()
440 {
441 setWindowWidth(128);
442 setWindowHeight(128);
443 setConfigRedBits(8);
444 setConfigGreenBits(8);
445 setConfigBlueBits(8);
446 setConfigAlphaBits(8);
447 }
448
449 void SetUp() override
450 {
451 ANGLETest::SetUp();
452
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300453 const std::string vertexShaderSource =
454 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700455 in vec4 inputAttribute;
456 out vec4 outputVarying;
457 void main()
458 {
459 outputVarying = inputAttribute;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300460 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700461
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300462 const std::string fragmentShaderSource =
463 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700464 precision highp float;
465 out vec4 outputColor;
466 void main()
467 {
468 outputColor = vec4(1,0,0,1);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300469 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700470
471 std::vector<std::string> transformFeedbackVaryings;
472 transformFeedbackVaryings.push_back("outputVarying");
473
474 mProgram = CompileProgramWithTransformFeedback(
475 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
476 GL_SEPARATE_ATTRIBS);
477 if (mProgram == 0)
478 {
479 FAIL() << "shader compilation failed.";
480 }
481
482 ASSERT_GL_NO_ERROR();
483 }
484
Corentin Wallez42e9e592015-10-29 14:09:25 -0400485 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700486 {
487 glDeleteProgram(mProgram);
488
489 ANGLETest::TearDown();
490 }
491
492 GLint getAvailableProgramBinaryFormatCount() const
493 {
494 GLint formatCount;
495 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
496 return formatCount;
497 }
498
499 GLuint mProgram;
500};
501
502// This tests the assumption that float attribs of different size
503// should not internally cause a vertex shader recompile (for conversion).
504TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
505{
506 if (!extensionEnabled("GL_OES_get_program_binary"))
507 {
508 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
509 << std::endl;
510 return;
511 }
512
513 if (getAvailableProgramBinaryFormatCount() == 0)
514 {
515 std::cout << "Test skipped because no program binary formats are available." << std::endl;
516 return;
517 }
518
519 std::vector<uint8_t> binary(0);
520 GLint programLength = 0;
521 GLint writtenLength = 0;
522 GLenum binaryFormat = 0;
523
524 // Save the program binary out
525 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
526 ASSERT_GL_NO_ERROR();
527 binary.resize(programLength);
528 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
529 ASSERT_GL_NO_ERROR();
530
531 glDeleteProgram(mProgram);
532
533 // Load program binary
534 mProgram = glCreateProgram();
535 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
536
537 // Ensure the loaded binary is linked
538 GLint linkStatus;
539 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
540 EXPECT_TRUE(linkStatus != 0);
541
542 // Query information about the transform feedback varying
543 char varyingName[64];
544 GLsizei varyingSize = 0;
545 GLenum varyingType = GL_NONE;
546
547 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
548 EXPECT_GL_NO_ERROR();
549
550 EXPECT_EQ(13, writtenLength);
551 EXPECT_STREQ("outputVarying", varyingName);
552 EXPECT_EQ(1, varyingSize);
553 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
554
555 EXPECT_GL_NO_ERROR();
556}
557
558// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
559ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
560 ES3_D3D11(),
561 ES3_OPENGL());
562
Austin Kinross137b1512015-06-17 16:14:53 -0700563// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
564// - a set to save the program binary
565// - a set to load the program binary
566// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
567struct PlatformsWithLinkResult : PlatformParameters
568{
569 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
570 {
571 majorVersion = saveParams.majorVersion;
572 minorVersion = saveParams.minorVersion;
573 eglParameters = saveParams.eglParameters;
574 loadParams = loadParamsIn;
575 expectedLinkResult = expectedLinkResultIn;
576 }
577
578 PlatformParameters loadParams;
579 bool expectedLinkResult;
580};
581
Corentin Wallez33585c72015-09-03 14:41:23 -0400582// Provide a custom gtest parameter name function for PlatformsWithLinkResult
583// to avoid returning the same parameter name twice. Such a conflict would happen
584// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
585// named ES2_D3D11
586std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
587{
588 const PlatformParameters &platform1 = platform;
589 const PlatformParameters &platform2 = platform.loadParams;
590 stream << platform1 << "_to_" << platform2;
591 return stream;
592}
593
Austin Kinross137b1512015-06-17 16:14:53 -0700594class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
595{
596 public:
597 void SetUp() override
598 {
599 mOSWindow = CreateOSWindow();
600 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
601
602 if (result == false)
603 {
604 FAIL() << "Failed to create OS window";
605 }
606 }
607
608 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
609 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400610 EGLWindow *eglWindow =
611 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700612 bool result = eglWindow->initializeGL(mOSWindow);
613 if (result == false)
614 {
615 SafeDelete(eglWindow);
616 eglWindow = nullptr;
617 }
618
619 return eglWindow;
620 }
621
622 void destroyEGLWindow(EGLWindow **eglWindow)
623 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500624 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700625 (*eglWindow)->destroyGL();
626 SafeDelete(*eglWindow);
627 *eglWindow = nullptr;
628 }
629
630 GLuint createES2ProgramFromSource()
631 {
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300632 const std::string testVertexShaderSource =
633 R"(attribute highp vec4 position;
Austin Kinross137b1512015-06-17 16:14:53 -0700634
635 void main(void)
636 {
637 gl_Position = position;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300638 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700639
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300640 const std::string testFragmentShaderSource =
641 R"(void main(void)
Austin Kinross137b1512015-06-17 16:14:53 -0700642 {
643 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300644 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700645
646 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
647 }
648
649 GLuint createES3ProgramFromSource()
650 {
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300651 const std::string testVertexShaderSource =
652 R"(#version 300 es
Austin Kinross137b1512015-06-17 16:14:53 -0700653 precision highp float;
654 in highp vec4 position;
655
656 void main(void)
657 {
658 gl_Position = position;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300659 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700660
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300661 const std::string testFragmentShaderSource =
662 R"(#version 300 es
Austin Kinross137b1512015-06-17 16:14:53 -0700663 precision highp float;
664 out vec4 out_FragColor;
665
666 void main(void)
667 {
668 out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300669 })";
Austin Kinross137b1512015-06-17 16:14:53 -0700670
671 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
672 }
673
674 void drawWithProgram(GLuint program)
675 {
676 glClearColor(0, 0, 0, 1);
677 glClear(GL_COLOR_BUFFER_BIT);
678
679 GLint positionLocation = glGetAttribLocation(program, "position");
680
681 glUseProgram(program);
682
683 const GLfloat vertices[] =
684 {
685 -1.0f, 1.0f, 0.5f,
686 -1.0f, -1.0f, 0.5f,
687 1.0f, -1.0f, 0.5f,
688
689 -1.0f, 1.0f, 0.5f,
690 1.0f, -1.0f, 0.5f,
691 1.0f, 1.0f, 0.5f,
692 };
693
694 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
695 glEnableVertexAttribArray(positionLocation);
696
697 glDrawArrays(GL_TRIANGLES, 0, 6);
698
699 glDisableVertexAttribArray(positionLocation);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800700 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
Austin Kinross137b1512015-06-17 16:14:53 -0700701
702 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
703 }
704
705 void TearDown() override
706 {
707 mOSWindow->destroy();
708 SafeDelete(mOSWindow);
709 }
710
711 OSWindow *mOSWindow;
712};
713
714// Tries to create a program binary using one set of platform params, then load it using a different sent of params
715TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
716{
717 angle::PlatformParameters firstRenderer = GetParam();
718 angle::PlatformParameters secondRenderer = GetParam().loadParams;
719 bool expectedLinkResult = GetParam().expectedLinkResult;
720
721 if (!(IsPlatformAvailable(firstRenderer)))
722 {
723 std::cout << "First renderer not supported, skipping test";
724 return;
725 }
726
727 if (!(IsPlatformAvailable(secondRenderer)))
728 {
729 std::cout << "Second renderer not supported, skipping test";
730 return;
731 }
732
733 EGLWindow *eglWindow = nullptr;
734 std::vector<uint8_t> binary(0);
735 GLuint program = 0;
736
737 GLint programLength = 0;
738 GLint writtenLength = 0;
739 GLenum binaryFormat = 0;
740
741 // Create a EGL window with the first renderer
742 eglWindow = createAndInitEGLWindow(firstRenderer);
743 if (eglWindow == nullptr)
744 {
745 FAIL() << "Failed to create EGL window";
746 return;
747 }
748
749 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
750 // then our expectations for the test results will be invalid.
751 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
752 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE)
753 {
754 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
Jamie Madillef97c612017-09-09 23:34:18 -0400755 angle::ToLower(&rendererString);
Austin Kinross137b1512015-06-17 16:14:53 -0700756
757 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
758 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
759
760 if (basicRenderPos != std::string::npos || softwareAdapterPos != std::string::npos)
761 {
762 // The first renderer is using WARP, even though we didn't explictly request it
763 // We should skip this test
764 std::cout << "Test skipped on when default GPU is WARP." << std::endl;
765 return;
766 }
767 }
768
769 // Create a program
770 if (firstRenderer.majorVersion == 3)
771 {
772 program = createES3ProgramFromSource();
773 }
774 else
775 {
776 program = createES2ProgramFromSource();
777 }
778
779 if (program == 0)
780 {
Austin Kinross137b1512015-06-17 16:14:53 -0700781 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700782 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700783 }
784
785 // Draw using the program to ensure it works as expected
786 drawWithProgram(program);
787 EXPECT_GL_NO_ERROR();
788
789 // Save the program binary out from this renderer
790 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
791 EXPECT_GL_NO_ERROR();
792 binary.resize(programLength);
793 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
794 EXPECT_GL_NO_ERROR();
795
796 // Destroy the first renderer
797 glDeleteProgram(program);
798 destroyEGLWindow(&eglWindow);
799
800 // Create an EGL window with the second renderer
801 eglWindow = createAndInitEGLWindow(secondRenderer);
802 if (eglWindow == nullptr)
803 {
804 FAIL() << "Failed to create EGL window";
805 return;
806 }
807
808 program = glCreateProgram();
809 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
810
811 GLint linkStatus;
812 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
813 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
814
815 if (linkStatus != 0)
816 {
817 // If the link was successful, then we should try to draw using the program to ensure it works as expected
818 drawWithProgram(program);
819 EXPECT_GL_NO_ERROR();
820 }
821
822 // Destroy the second renderer
823 glDeleteProgram(program);
824 destroyEGLWindow(&eglWindow);
825}
826
Jamie Madilla2c74982016-12-12 11:20:42 -0500827// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700828ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
829 // | Save the program | Load the program | Expected
830 // | using these params | using these params | link result
831 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
832 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
833 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
834 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
835 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
836 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
837 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500838 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400839 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500840// clang-format on