blob: e1a7aa53f6ebdf1781f81c938a60f35ea14a8f49 [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 Etuaho5804dc82018-04-13 14:11:46 +030037 mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
Jamie Madill7a29e4a2014-05-02 10:41:48 -040038 if (mProgram == 0)
39 {
40 FAIL() << "shader compilation failed.";
41 }
42
43 glGenBuffers(1, &mBuffer);
44 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
Yunchao Hef81ce4a2017-04-24 10:49:17 +080045 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_STATIC_DRAW);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040046 glBindBuffer(GL_ARRAY_BUFFER, 0);
47
48 ASSERT_GL_NO_ERROR();
49 }
50
Corentin Wallez42e9e592015-10-29 14:09:25 -040051 void TearDown() override
Jamie Madill7a29e4a2014-05-02 10:41:48 -040052 {
53 glDeleteProgram(mProgram);
54 glDeleteBuffers(1, &mBuffer);
55
56 ANGLETest::TearDown();
57 }
58
Geoff Lang90208e92015-10-05 15:40:36 -040059 GLint getAvailableProgramBinaryFormatCount() const
60 {
61 GLint formatCount;
62 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
63 return formatCount;
64 }
65
Jamie Madill311d9992017-05-30 15:38:54 -040066 bool supported() const
67 {
68 if (!extensionEnabled("GL_OES_get_program_binary"))
69 {
70 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
71 << std::endl;
72 return false;
73 }
74
75 if (getAvailableProgramBinaryFormatCount() == 0)
76 {
77 std::cout << "Test skipped because no program binary formats are available."
78 << std::endl;
79 return false;
80 }
81
82 return true;
83 }
84
Jamie Madill7a29e4a2014-05-02 10:41:48 -040085 GLuint mProgram;
86 GLuint mBuffer;
87};
88
89// This tests the assumption that float attribs of different size
90// should not internally cause a vertex shader recompile (for conversion).
Jamie Madillfa05f602015-05-07 13:47:11 -040091TEST_P(ProgramBinaryTest, FloatDynamicShaderSize)
Jamie Madill7a29e4a2014-05-02 10:41:48 -040092{
Jamie Madill311d9992017-05-30 15:38:54 -040093 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -040094 {
Geoff Lang90208e92015-10-05 15:40:36 -040095 return;
96 }
97
Jamie Madill7a29e4a2014-05-02 10:41:48 -040098 glUseProgram(mProgram);
99 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
100
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800101 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400102 glEnableVertexAttribArray(0);
103 glDrawArrays(GL_POINTS, 0, 1);
104
105 GLint programLength;
106 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
107
108 EXPECT_GL_NO_ERROR();
109
110 for (GLsizei size = 1; size <= 3; size++)
111 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800112 glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 8, nullptr);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400113 glEnableVertexAttribArray(0);
114 glDrawArrays(GL_POINTS, 0, 1);
115
116 GLint newProgramLength;
117 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &newProgramLength);
118 EXPECT_GL_NO_ERROR();
119 EXPECT_EQ(programLength, newProgramLength);
120 }
121}
Brandon Jones993d08d2014-10-10 14:32:57 -0700122
Jamie Madillbdec2f42016-03-02 16:35:32 -0500123// Tests that switching between signed and unsigned un-normalized data doesn't trigger a bug
124// in the D3D11 back-end.
125TEST_P(ProgramBinaryTest, DynamicShadersSignatureBug)
126{
127 glUseProgram(mProgram);
128 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
129
Olli Etuaho5804dc82018-04-13 14:11:46 +0300130 GLint attribLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
Jamie Madillbdec2f42016-03-02 16:35:32 -0500131 ASSERT_NE(-1, attribLocation);
132 glEnableVertexAttribArray(attribLocation);
133
134 glVertexAttribPointer(attribLocation, 2, GL_BYTE, GL_FALSE, 0, nullptr);
135 glDrawArrays(GL_POINTS, 0, 1);
136
137 glVertexAttribPointer(attribLocation, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
138 glDrawArrays(GL_POINTS, 0, 1);
139}
140
Brandon Jones993d08d2014-10-10 14:32:57 -0700141// This tests the ability to successfully save and load a program binary.
Jamie Madillfa05f602015-05-07 13:47:11 -0400142TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
Brandon Jones993d08d2014-10-10 14:32:57 -0700143{
Jamie Madill311d9992017-05-30 15:38:54 -0400144 if (!supported())
Geoff Lang90208e92015-10-05 15:40:36 -0400145 {
Geoff Lang90208e92015-10-05 15:40:36 -0400146 return;
147 }
148
Brandon Jones993d08d2014-10-10 14:32:57 -0700149 GLint programLength = 0;
150 GLint writtenLength = 0;
151 GLenum binaryFormat = 0;
152
153 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
154 EXPECT_GL_NO_ERROR();
155
156 std::vector<uint8_t> binary(programLength);
157 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
158 EXPECT_GL_NO_ERROR();
159
160 // The lengths reported by glGetProgramiv and glGetProgramBinaryOES should match
161 EXPECT_EQ(programLength, writtenLength);
162
163 if (writtenLength)
164 {
165 GLuint program2 = glCreateProgram();
166 glProgramBinaryOES(program2, binaryFormat, binary.data(), writtenLength);
167
168 EXPECT_GL_NO_ERROR();
169
170 GLint linkStatus;
171 glGetProgramiv(program2, GL_LINK_STATUS, &linkStatus);
172 if (linkStatus == 0)
173 {
174 GLint infoLogLength;
175 glGetProgramiv(program2, GL_INFO_LOG_LENGTH, &infoLogLength);
176
Geoff Lang981afd72014-11-05 16:30:36 -0500177 if (infoLogLength > 0)
178 {
179 std::vector<GLchar> infoLog(infoLogLength);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800180 glGetProgramInfoLog(program2, static_cast<GLsizei>(infoLog.size()), nullptr,
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700181 &infoLog[0]);
Geoff Lang981afd72014-11-05 16:30:36 -0500182 FAIL() << "program link failed: " << &infoLog[0];
183 }
184 else
185 {
186 FAIL() << "program link failed.";
187 }
Brandon Jones993d08d2014-10-10 14:32:57 -0700188 }
189 else
190 {
191 glUseProgram(program2);
192 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
193
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800194 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
Brandon Jones993d08d2014-10-10 14:32:57 -0700195 glEnableVertexAttribArray(0);
196 glDrawArrays(GL_POINTS, 0, 1);
197
198 EXPECT_GL_NO_ERROR();
199 }
200
201 glDeleteProgram(program2);
202 }
203}
Jamie Madillfa05f602015-05-07 13:47:11 -0400204
Jamie Madill311d9992017-05-30 15:38:54 -0400205// Ensures that we init the compiler before calling ProgramBinary.
206TEST_P(ProgramBinaryTest, CallProgramBinaryBeforeLink)
207{
208 if (!supported())
209 {
210 return;
211 }
212
213 // Initialize a simple program.
214 glUseProgram(mProgram);
215
216 GLsizei length = 0;
217 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH, &length);
218 ASSERT_GL_NO_ERROR();
219 ASSERT_GT(length, 0);
220
221 GLsizei readLength = 0;
222 GLenum binaryFormat = GL_NONE;
223 std::vector<uint8_t> binaryBlob(length);
224 glGetProgramBinaryOES(mProgram, length, &readLength, &binaryFormat, binaryBlob.data());
225 ASSERT_GL_NO_ERROR();
226
227 // Shutdown and restart GL entirely.
228 TearDown();
229 SetUp();
230
231 ANGLE_GL_BINARY_OES_PROGRAM(binaryProgram, binaryBlob, binaryFormat);
232 ASSERT_GL_NO_ERROR();
233
Olli Etuaho5804dc82018-04-13 14:11:46 +0300234 drawQuad(binaryProgram, essl1_shaders::PositionAttrib(), 0.5f);
Jamie Madill311d9992017-05-30 15:38:54 -0400235 ASSERT_GL_NO_ERROR();
236}
237
Geoff Langb26ab822018-05-29 11:19:00 -0400238// Test that unlinked programs have a binary size of 0
239TEST_P(ProgramBinaryTest, ZeroSizedUnlinkedBinary)
240{
241 ANGLE_SKIP_TEST_IF(!supported());
242
243 ANGLE_GL_EMPTY_PROGRAM(program);
244 GLsizei length = 0;
245 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &length);
246 ASSERT_EQ(0, length);
247}
248
Jamie Madillfa05f602015-05-07 13:47:11 -0400249// 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 -0400250ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
251 ES2_D3D9(),
252 ES2_D3D11(),
253 ES3_D3D11(),
254 ES2_OPENGL(),
255 ES3_OPENGL());
Austin Kinross137b1512015-06-17 16:14:53 -0700256
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500257class ProgramBinaryES3Test : public ANGLETest
258{
Jamie Madill51f522f2016-12-21 15:10:55 -0500259 protected:
260 void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500261};
262
Jamie Madill51f522f2016-12-21 15:10:55 -0500263void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500264{
265 // We can't run the test if no program binary formats are supported.
266 GLint binaryFormatCount = 0;
267 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
Yunchao He9550c602018-02-13 14:47:05 +0800268 ANGLE_SKIP_TEST_IF(!binaryFormatCount);
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500269
270 const std::string &vertexShader =
271 "#version 300 es\n"
272 "uniform block {\n"
273 " float f;\n"
274 "};\n"
275 "in vec4 position;\n"
276 "out vec4 color;\n"
277 "void main() {\n"
278 " gl_Position = position;\n"
279 " color = vec4(f, f, f, 1);\n"
280 "}";
281 const std::string &fragmentShader =
282 "#version 300 es\n"
283 "precision mediump float;\n"
284 "in vec4 color;\n"
285 "out vec4 colorOut;\n"
286 "void main() {\n"
287 " colorOut = color;\n"
288 "}";
289
290 // Init and draw with the program.
291 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
292
293 float fData[4] = {1.0f, 1.0f, 1.0f, 1.0f};
294 GLuint bindIndex = 2;
295
296 GLBuffer ubo;
297 glBindBuffer(GL_UNIFORM_BUFFER, ubo.get());
298 glBufferData(GL_UNIFORM_BUFFER, sizeof(fData), &fData, GL_STATIC_DRAW);
299 glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex, ubo.get(), 0, sizeof(fData));
300
301 GLint blockIndex = glGetUniformBlockIndex(program.get(), "block");
302 ASSERT_NE(-1, blockIndex);
303
304 glUniformBlockBinding(program.get(), blockIndex, bindIndex);
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
Jamie Madill51f522f2016-12-21 15:10:55 -0500310 if (drawWithProgramFirst)
311 {
312 drawQuad(program.get(), "position", 0.5f);
313 ASSERT_GL_NO_ERROR();
314 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
315 }
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500316
317 // Read back the binary.
318 GLint programLength = 0;
319 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
320 ASSERT_GL_NO_ERROR();
321
322 GLsizei readLength = 0;
323 GLenum binaryFormat = GL_NONE;
324 std::vector<uint8_t> binary(programLength);
325 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
326 ASSERT_GL_NO_ERROR();
327
328 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
329
330 // Load a new program with the binary and draw.
331 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
332
333 glClearColor(1.0, 0.0, 0.0, 1.0);
334 glClear(GL_COLOR_BUFFER_BIT);
335 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
336
337 drawQuad(binaryProgram.get(), "position", 0.5f);
338 ASSERT_GL_NO_ERROR();
339 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
340}
341
Jamie Madill51f522f2016-12-21 15:10:55 -0500342// Tests that saving and loading a program perserves uniform block binding info.
343TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
344{
345 testBinaryAndUBOBlockIndexes(true);
346}
347
348// Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
349// http://anglebug.com/1637
350TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
351{
352 testBinaryAndUBOBlockIndexes(false);
353}
354
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500355ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
356
Xinghua Caob1239382016-12-13 15:07:05 +0800357class ProgramBinaryES31Test : public ANGLETest
358{
359 protected:
360 ProgramBinaryES31Test()
361 {
362 setWindowWidth(128);
363 setWindowHeight(128);
364 setConfigRedBits(8);
365 setConfigGreenBits(8);
366 setConfigBlueBits(8);
367 setConfigAlphaBits(8);
368 }
369};
370
371// Tests that saving and loading a program attached with computer shader.
372TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
373{
374 // We can't run the test if no program binary formats are supported.
375 GLint binaryFormatCount = 0;
376 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
Yunchao He9550c602018-02-13 14:47:05 +0800377 ANGLE_SKIP_TEST_IF(!binaryFormatCount);
Xinghua Caob1239382016-12-13 15:07:05 +0800378
379 const std::string &computeShader =
380 "#version 310 es\n"
381 "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
382 "uniform block {\n"
383 " vec2 f;\n"
384 "};\n"
385 "uniform vec2 g;\n"
386 "uniform highp sampler2D tex;\n"
387 "void main() {\n"
388 " vec4 color = texture(tex, f + g);\n"
389 "}";
390
391 ANGLE_GL_COMPUTE_PROGRAM(program, computeShader);
392
393 // Read back the binary.
394 GLint programLength = 0;
395 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
396 ASSERT_GL_NO_ERROR();
397
398 GLsizei readLength = 0;
399 GLenum binaryFormat = GL_NONE;
400 std::vector<uint8_t> binary(programLength);
401 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
402 ASSERT_GL_NO_ERROR();
403
404 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
405
406 // Load a new program with the binary.
407 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
Yunchao He85072e82017-11-14 15:43:28 +0800408 ASSERT_GL_NO_ERROR();
Xinghua Caob1239382016-12-13 15:07:05 +0800409
Yunchao He85072e82017-11-14 15:43:28 +0800410 // Dispatch compute with the loaded binary program
411 glUseProgram(binaryProgram.get());
412 glDispatchCompute(8, 4, 2);
Xinghua Caob1239382016-12-13 15:07:05 +0800413 ASSERT_GL_NO_ERROR();
414}
415
416ANGLE_INSTANTIATE_TEST(ProgramBinaryES31Test, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
417
Brandon Jones1048ea72015-10-06 15:34:52 -0700418class ProgramBinaryTransformFeedbackTest : public ANGLETest
419{
420 protected:
421 ProgramBinaryTransformFeedbackTest()
422 {
423 setWindowWidth(128);
424 setWindowHeight(128);
425 setConfigRedBits(8);
426 setConfigGreenBits(8);
427 setConfigBlueBits(8);
428 setConfigAlphaBits(8);
429 }
430
431 void SetUp() override
432 {
433 ANGLETest::SetUp();
434
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300435 const std::string vertexShaderSource =
436 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700437 in vec4 inputAttribute;
438 out vec4 outputVarying;
439 void main()
440 {
441 outputVarying = inputAttribute;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300442 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700443
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300444 const std::string fragmentShaderSource =
445 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700446 precision highp float;
447 out vec4 outputColor;
448 void main()
449 {
450 outputColor = vec4(1,0,0,1);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300451 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700452
453 std::vector<std::string> transformFeedbackVaryings;
454 transformFeedbackVaryings.push_back("outputVarying");
455
456 mProgram = CompileProgramWithTransformFeedback(
457 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
458 GL_SEPARATE_ATTRIBS);
459 if (mProgram == 0)
460 {
461 FAIL() << "shader compilation failed.";
462 }
463
464 ASSERT_GL_NO_ERROR();
465 }
466
Corentin Wallez42e9e592015-10-29 14:09:25 -0400467 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700468 {
469 glDeleteProgram(mProgram);
470
471 ANGLETest::TearDown();
472 }
473
474 GLint getAvailableProgramBinaryFormatCount() const
475 {
476 GLint formatCount;
477 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
478 return formatCount;
479 }
480
481 GLuint mProgram;
482};
483
484// This tests the assumption that float attribs of different size
485// should not internally cause a vertex shader recompile (for conversion).
486TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
487{
Yunchao He9550c602018-02-13 14:47:05 +0800488 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_get_program_binary"));
Brandon Jones1048ea72015-10-06 15:34:52 -0700489
Yunchao He9550c602018-02-13 14:47:05 +0800490 ANGLE_SKIP_TEST_IF(!getAvailableProgramBinaryFormatCount());
Brandon Jones1048ea72015-10-06 15:34:52 -0700491
492 std::vector<uint8_t> binary(0);
493 GLint programLength = 0;
494 GLint writtenLength = 0;
495 GLenum binaryFormat = 0;
496
497 // Save the program binary out
498 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
499 ASSERT_GL_NO_ERROR();
500 binary.resize(programLength);
501 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
502 ASSERT_GL_NO_ERROR();
503
504 glDeleteProgram(mProgram);
505
506 // Load program binary
507 mProgram = glCreateProgram();
508 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
509
510 // Ensure the loaded binary is linked
511 GLint linkStatus;
512 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
513 EXPECT_TRUE(linkStatus != 0);
514
515 // Query information about the transform feedback varying
516 char varyingName[64];
517 GLsizei varyingSize = 0;
518 GLenum varyingType = GL_NONE;
519
520 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
521 EXPECT_GL_NO_ERROR();
522
523 EXPECT_EQ(13, writtenLength);
524 EXPECT_STREQ("outputVarying", varyingName);
525 EXPECT_EQ(1, varyingSize);
526 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
527
528 EXPECT_GL_NO_ERROR();
529}
530
531// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
532ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
533 ES3_D3D11(),
534 ES3_OPENGL());
535
Austin Kinross137b1512015-06-17 16:14:53 -0700536// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
537// - a set to save the program binary
538// - a set to load the program binary
539// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
540struct PlatformsWithLinkResult : PlatformParameters
541{
542 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
543 {
544 majorVersion = saveParams.majorVersion;
545 minorVersion = saveParams.minorVersion;
546 eglParameters = saveParams.eglParameters;
547 loadParams = loadParamsIn;
548 expectedLinkResult = expectedLinkResultIn;
549 }
550
551 PlatformParameters loadParams;
552 bool expectedLinkResult;
553};
554
Corentin Wallez33585c72015-09-03 14:41:23 -0400555// Provide a custom gtest parameter name function for PlatformsWithLinkResult
556// to avoid returning the same parameter name twice. Such a conflict would happen
557// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
558// named ES2_D3D11
559std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
560{
561 const PlatformParameters &platform1 = platform;
562 const PlatformParameters &platform2 = platform.loadParams;
563 stream << platform1 << "_to_" << platform2;
564 return stream;
565}
566
Austin Kinross137b1512015-06-17 16:14:53 -0700567class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
568{
569 public:
570 void SetUp() override
571 {
572 mOSWindow = CreateOSWindow();
573 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
574
575 if (result == false)
576 {
577 FAIL() << "Failed to create OS window";
578 }
579 }
580
581 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
582 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400583 EGLWindow *eglWindow =
584 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700585 bool result = eglWindow->initializeGL(mOSWindow);
586 if (result == false)
587 {
588 SafeDelete(eglWindow);
589 eglWindow = nullptr;
590 }
591
592 return eglWindow;
593 }
594
595 void destroyEGLWindow(EGLWindow **eglWindow)
596 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500597 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700598 (*eglWindow)->destroyGL();
599 SafeDelete(*eglWindow);
600 *eglWindow = nullptr;
601 }
602
603 GLuint createES2ProgramFromSource()
604 {
Olli Etuaho5804dc82018-04-13 14:11:46 +0300605 return CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
Austin Kinross137b1512015-06-17 16:14:53 -0700606 }
607
608 GLuint createES3ProgramFromSource()
609 {
Olli Etuaho5804dc82018-04-13 14:11:46 +0300610 return CompileProgram(essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
Austin Kinross137b1512015-06-17 16:14:53 -0700611 }
612
613 void drawWithProgram(GLuint program)
614 {
615 glClearColor(0, 0, 0, 1);
616 glClear(GL_COLOR_BUFFER_BIT);
617
Olli Etuaho5804dc82018-04-13 14:11:46 +0300618 GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
Austin Kinross137b1512015-06-17 16:14:53 -0700619
620 glUseProgram(program);
621
622 const GLfloat vertices[] =
623 {
624 -1.0f, 1.0f, 0.5f,
625 -1.0f, -1.0f, 0.5f,
626 1.0f, -1.0f, 0.5f,
627
628 -1.0f, 1.0f, 0.5f,
629 1.0f, -1.0f, 0.5f,
630 1.0f, 1.0f, 0.5f,
631 };
632
633 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
634 glEnableVertexAttribArray(positionLocation);
635
636 glDrawArrays(GL_TRIANGLES, 0, 6);
637
638 glDisableVertexAttribArray(positionLocation);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800639 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
Austin Kinross137b1512015-06-17 16:14:53 -0700640
641 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
642 }
643
644 void TearDown() override
645 {
646 mOSWindow->destroy();
647 SafeDelete(mOSWindow);
648 }
649
650 OSWindow *mOSWindow;
651};
652
653// Tries to create a program binary using one set of platform params, then load it using a different sent of params
654TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
655{
656 angle::PlatformParameters firstRenderer = GetParam();
657 angle::PlatformParameters secondRenderer = GetParam().loadParams;
658 bool expectedLinkResult = GetParam().expectedLinkResult;
659
Yunchao He9550c602018-02-13 14:47:05 +0800660 // First renderer not supported, skipping test.
661 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(firstRenderer)));
Austin Kinross137b1512015-06-17 16:14:53 -0700662
Yunchao He9550c602018-02-13 14:47:05 +0800663 // Second renderer not supported, skipping test.
664 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(secondRenderer)));
Austin Kinross137b1512015-06-17 16:14:53 -0700665
666 EGLWindow *eglWindow = nullptr;
667 std::vector<uint8_t> binary(0);
668 GLuint program = 0;
669
670 GLint programLength = 0;
671 GLint writtenLength = 0;
672 GLenum binaryFormat = 0;
673
674 // Create a EGL window with the first renderer
675 eglWindow = createAndInitEGLWindow(firstRenderer);
676 if (eglWindow == nullptr)
677 {
678 FAIL() << "Failed to create EGL window";
679 return;
680 }
681
682 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
683 // then our expectations for the test results will be invalid.
Jamie Madillf3e23292018-01-04 18:19:21 -0500684 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
685 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
Austin Kinross137b1512015-06-17 16:14:53 -0700686 {
687 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
Jamie Madillef97c612017-09-09 23:34:18 -0400688 angle::ToLower(&rendererString);
Austin Kinross137b1512015-06-17 16:14:53 -0700689
690 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
691 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
692
Yunchao He9550c602018-02-13 14:47:05 +0800693 // The first renderer is using WARP, even though we didn't explictly request it
694 // We should skip this test
695 ANGLE_SKIP_TEST_IF(basicRenderPos != std::string::npos ||
696 softwareAdapterPos != std::string::npos);
Austin Kinross137b1512015-06-17 16:14:53 -0700697 }
698
699 // Create a program
700 if (firstRenderer.majorVersion == 3)
701 {
702 program = createES3ProgramFromSource();
703 }
704 else
705 {
706 program = createES2ProgramFromSource();
707 }
708
709 if (program == 0)
710 {
Austin Kinross137b1512015-06-17 16:14:53 -0700711 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700712 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700713 }
714
715 // Draw using the program to ensure it works as expected
716 drawWithProgram(program);
717 EXPECT_GL_NO_ERROR();
718
719 // Save the program binary out from this renderer
720 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
721 EXPECT_GL_NO_ERROR();
722 binary.resize(programLength);
723 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
724 EXPECT_GL_NO_ERROR();
725
726 // Destroy the first renderer
727 glDeleteProgram(program);
728 destroyEGLWindow(&eglWindow);
729
730 // Create an EGL window with the second renderer
731 eglWindow = createAndInitEGLWindow(secondRenderer);
732 if (eglWindow == nullptr)
733 {
734 FAIL() << "Failed to create EGL window";
735 return;
736 }
737
738 program = glCreateProgram();
739 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
740
741 GLint linkStatus;
742 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
743 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
744
745 if (linkStatus != 0)
746 {
747 // If the link was successful, then we should try to draw using the program to ensure it works as expected
748 drawWithProgram(program);
749 EXPECT_GL_NO_ERROR();
750 }
751
752 // Destroy the second renderer
753 glDeleteProgram(program);
754 destroyEGLWindow(&eglWindow);
755}
756
Jamie Madilla2c74982016-12-12 11:20:42 -0500757// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700758ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
759 // | Save the program | Load the program | Expected
760 // | using these params | using these params | link result
761 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
762 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
763 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
764 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
765 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
766 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
767 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500768 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400769 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500770// clang-format on