blob: b6de1e9a51bff804130710e00fdc40e7446f5904 [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{
Jamie Madillb22615d2016-12-23 13:21:04 -0500352 // TODO(jmadill): Investigate Intel failure.
353 // http://anglebug.com/1637
Yunchao He9550c602018-02-13 14:47:05 +0800354 ANGLE_SKIP_TEST_IF(IsWindows() && IsOpenGL() && IsIntel());
Jamie Madillb22615d2016-12-23 13:21:04 -0500355
Jamie Madill51f522f2016-12-21 15:10:55 -0500356 testBinaryAndUBOBlockIndexes(false);
357}
358
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500359ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
360
Xinghua Caob1239382016-12-13 15:07:05 +0800361class ProgramBinaryES31Test : public ANGLETest
362{
363 protected:
364 ProgramBinaryES31Test()
365 {
366 setWindowWidth(128);
367 setWindowHeight(128);
368 setConfigRedBits(8);
369 setConfigGreenBits(8);
370 setConfigBlueBits(8);
371 setConfigAlphaBits(8);
372 }
373};
374
375// Tests that saving and loading a program attached with computer shader.
376TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
377{
378 // We can't run the test if no program binary formats are supported.
379 GLint binaryFormatCount = 0;
380 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
Yunchao He9550c602018-02-13 14:47:05 +0800381 ANGLE_SKIP_TEST_IF(!binaryFormatCount);
Xinghua Caob1239382016-12-13 15:07:05 +0800382
383 const std::string &computeShader =
384 "#version 310 es\n"
385 "layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
386 "uniform block {\n"
387 " vec2 f;\n"
388 "};\n"
389 "uniform vec2 g;\n"
390 "uniform highp sampler2D tex;\n"
391 "void main() {\n"
392 " vec4 color = texture(tex, f + g);\n"
393 "}";
394
395 ANGLE_GL_COMPUTE_PROGRAM(program, computeShader);
396
397 // Read back the binary.
398 GLint programLength = 0;
399 glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
400 ASSERT_GL_NO_ERROR();
401
402 GLsizei readLength = 0;
403 GLenum binaryFormat = GL_NONE;
404 std::vector<uint8_t> binary(programLength);
405 glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
406 ASSERT_GL_NO_ERROR();
407
408 EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
409
410 // Load a new program with the binary.
411 ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
Yunchao He85072e82017-11-14 15:43:28 +0800412 ASSERT_GL_NO_ERROR();
Xinghua Caob1239382016-12-13 15:07:05 +0800413
Yunchao He85072e82017-11-14 15:43:28 +0800414 // Dispatch compute with the loaded binary program
415 glUseProgram(binaryProgram.get());
416 glDispatchCompute(8, 4, 2);
Xinghua Caob1239382016-12-13 15:07:05 +0800417 ASSERT_GL_NO_ERROR();
418}
419
420ANGLE_INSTANTIATE_TEST(ProgramBinaryES31Test, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
421
Brandon Jones1048ea72015-10-06 15:34:52 -0700422class ProgramBinaryTransformFeedbackTest : public ANGLETest
423{
424 protected:
425 ProgramBinaryTransformFeedbackTest()
426 {
427 setWindowWidth(128);
428 setWindowHeight(128);
429 setConfigRedBits(8);
430 setConfigGreenBits(8);
431 setConfigBlueBits(8);
432 setConfigAlphaBits(8);
433 }
434
435 void SetUp() override
436 {
437 ANGLETest::SetUp();
438
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300439 const std::string vertexShaderSource =
440 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700441 in vec4 inputAttribute;
442 out vec4 outputVarying;
443 void main()
444 {
445 outputVarying = inputAttribute;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300446 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700447
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300448 const std::string fragmentShaderSource =
449 R"(#version 300 es
Brandon Jones1048ea72015-10-06 15:34:52 -0700450 precision highp float;
451 out vec4 outputColor;
452 void main()
453 {
454 outputColor = vec4(1,0,0,1);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300455 })";
Brandon Jones1048ea72015-10-06 15:34:52 -0700456
457 std::vector<std::string> transformFeedbackVaryings;
458 transformFeedbackVaryings.push_back("outputVarying");
459
460 mProgram = CompileProgramWithTransformFeedback(
461 vertexShaderSource, fragmentShaderSource, transformFeedbackVaryings,
462 GL_SEPARATE_ATTRIBS);
463 if (mProgram == 0)
464 {
465 FAIL() << "shader compilation failed.";
466 }
467
468 ASSERT_GL_NO_ERROR();
469 }
470
Corentin Wallez42e9e592015-10-29 14:09:25 -0400471 void TearDown() override
Brandon Jones1048ea72015-10-06 15:34:52 -0700472 {
473 glDeleteProgram(mProgram);
474
475 ANGLETest::TearDown();
476 }
477
478 GLint getAvailableProgramBinaryFormatCount() const
479 {
480 GLint formatCount;
481 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
482 return formatCount;
483 }
484
485 GLuint mProgram;
486};
487
488// This tests the assumption that float attribs of different size
489// should not internally cause a vertex shader recompile (for conversion).
490TEST_P(ProgramBinaryTransformFeedbackTest, GetTransformFeedbackVarying)
491{
Yunchao He9550c602018-02-13 14:47:05 +0800492 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_get_program_binary"));
Brandon Jones1048ea72015-10-06 15:34:52 -0700493
Yunchao He9550c602018-02-13 14:47:05 +0800494 ANGLE_SKIP_TEST_IF(!getAvailableProgramBinaryFormatCount());
Brandon Jones1048ea72015-10-06 15:34:52 -0700495
496 std::vector<uint8_t> binary(0);
497 GLint programLength = 0;
498 GLint writtenLength = 0;
499 GLenum binaryFormat = 0;
500
501 // Save the program binary out
502 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
503 ASSERT_GL_NO_ERROR();
504 binary.resize(programLength);
505 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
506 ASSERT_GL_NO_ERROR();
507
508 glDeleteProgram(mProgram);
509
510 // Load program binary
511 mProgram = glCreateProgram();
512 glProgramBinaryOES(mProgram, binaryFormat, binary.data(), writtenLength);
513
514 // Ensure the loaded binary is linked
515 GLint linkStatus;
516 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
517 EXPECT_TRUE(linkStatus != 0);
518
519 // Query information about the transform feedback varying
520 char varyingName[64];
521 GLsizei varyingSize = 0;
522 GLenum varyingType = GL_NONE;
523
524 glGetTransformFeedbackVarying(mProgram, 0, 64, &writtenLength, &varyingSize, &varyingType, varyingName);
525 EXPECT_GL_NO_ERROR();
526
527 EXPECT_EQ(13, writtenLength);
528 EXPECT_STREQ("outputVarying", varyingName);
529 EXPECT_EQ(1, varyingSize);
530 EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varyingType);
531
532 EXPECT_GL_NO_ERROR();
533}
534
535// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
536ANGLE_INSTANTIATE_TEST(ProgramBinaryTransformFeedbackTest,
537 ES3_D3D11(),
538 ES3_OPENGL());
539
Austin Kinross137b1512015-06-17 16:14:53 -0700540// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
541// - a set to save the program binary
542// - a set to load the program binary
543// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
544struct PlatformsWithLinkResult : PlatformParameters
545{
546 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
547 {
548 majorVersion = saveParams.majorVersion;
549 minorVersion = saveParams.minorVersion;
550 eglParameters = saveParams.eglParameters;
551 loadParams = loadParamsIn;
552 expectedLinkResult = expectedLinkResultIn;
553 }
554
555 PlatformParameters loadParams;
556 bool expectedLinkResult;
557};
558
Corentin Wallez33585c72015-09-03 14:41:23 -0400559// Provide a custom gtest parameter name function for PlatformsWithLinkResult
560// to avoid returning the same parameter name twice. Such a conflict would happen
561// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
562// named ES2_D3D11
563std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
564{
565 const PlatformParameters &platform1 = platform;
566 const PlatformParameters &platform2 = platform.loadParams;
567 stream << platform1 << "_to_" << platform2;
568 return stream;
569}
570
Austin Kinross137b1512015-06-17 16:14:53 -0700571class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
572{
573 public:
574 void SetUp() override
575 {
576 mOSWindow = CreateOSWindow();
577 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
578
579 if (result == false)
580 {
581 FAIL() << "Failed to create OS window";
582 }
583 }
584
585 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
586 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400587 EGLWindow *eglWindow =
588 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700589 bool result = eglWindow->initializeGL(mOSWindow);
590 if (result == false)
591 {
592 SafeDelete(eglWindow);
593 eglWindow = nullptr;
594 }
595
596 return eglWindow;
597 }
598
599 void destroyEGLWindow(EGLWindow **eglWindow)
600 {
Jamie Madille1faacb2016-12-13 12:42:14 -0500601 ASSERT_NE(nullptr, *eglWindow);
Austin Kinross137b1512015-06-17 16:14:53 -0700602 (*eglWindow)->destroyGL();
603 SafeDelete(*eglWindow);
604 *eglWindow = nullptr;
605 }
606
607 GLuint createES2ProgramFromSource()
608 {
Olli Etuaho5804dc82018-04-13 14:11:46 +0300609 return CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
Austin Kinross137b1512015-06-17 16:14:53 -0700610 }
611
612 GLuint createES3ProgramFromSource()
613 {
Olli Etuaho5804dc82018-04-13 14:11:46 +0300614 return CompileProgram(essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
Austin Kinross137b1512015-06-17 16:14:53 -0700615 }
616
617 void drawWithProgram(GLuint program)
618 {
619 glClearColor(0, 0, 0, 1);
620 glClear(GL_COLOR_BUFFER_BIT);
621
Olli Etuaho5804dc82018-04-13 14:11:46 +0300622 GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
Austin Kinross137b1512015-06-17 16:14:53 -0700623
624 glUseProgram(program);
625
626 const GLfloat vertices[] =
627 {
628 -1.0f, 1.0f, 0.5f,
629 -1.0f, -1.0f, 0.5f,
630 1.0f, -1.0f, 0.5f,
631
632 -1.0f, 1.0f, 0.5f,
633 1.0f, -1.0f, 0.5f,
634 1.0f, 1.0f, 0.5f,
635 };
636
637 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
638 glEnableVertexAttribArray(positionLocation);
639
640 glDrawArrays(GL_TRIANGLES, 0, 6);
641
642 glDisableVertexAttribArray(positionLocation);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800643 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
Austin Kinross137b1512015-06-17 16:14:53 -0700644
645 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
646 }
647
648 void TearDown() override
649 {
650 mOSWindow->destroy();
651 SafeDelete(mOSWindow);
652 }
653
654 OSWindow *mOSWindow;
655};
656
657// Tries to create a program binary using one set of platform params, then load it using a different sent of params
658TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
659{
660 angle::PlatformParameters firstRenderer = GetParam();
661 angle::PlatformParameters secondRenderer = GetParam().loadParams;
662 bool expectedLinkResult = GetParam().expectedLinkResult;
663
Yunchao He9550c602018-02-13 14:47:05 +0800664 // First renderer not supported, skipping test.
665 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(firstRenderer)));
Austin Kinross137b1512015-06-17 16:14:53 -0700666
Yunchao He9550c602018-02-13 14:47:05 +0800667 // Second renderer not supported, skipping test.
668 ANGLE_SKIP_TEST_IF(!(IsPlatformAvailable(secondRenderer)));
Austin Kinross137b1512015-06-17 16:14:53 -0700669
670 EGLWindow *eglWindow = nullptr;
671 std::vector<uint8_t> binary(0);
672 GLuint program = 0;
673
674 GLint programLength = 0;
675 GLint writtenLength = 0;
676 GLenum binaryFormat = 0;
677
678 // Create a EGL window with the first renderer
679 eglWindow = createAndInitEGLWindow(firstRenderer);
680 if (eglWindow == nullptr)
681 {
682 FAIL() << "Failed to create EGL window";
683 return;
684 }
685
686 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
687 // then our expectations for the test results will be invalid.
Jamie Madillf3e23292018-01-04 18:19:21 -0500688 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
689 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
Austin Kinross137b1512015-06-17 16:14:53 -0700690 {
691 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
Jamie Madillef97c612017-09-09 23:34:18 -0400692 angle::ToLower(&rendererString);
Austin Kinross137b1512015-06-17 16:14:53 -0700693
694 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
695 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
696
Yunchao He9550c602018-02-13 14:47:05 +0800697 // The first renderer is using WARP, even though we didn't explictly request it
698 // We should skip this test
699 ANGLE_SKIP_TEST_IF(basicRenderPos != std::string::npos ||
700 softwareAdapterPos != std::string::npos);
Austin Kinross137b1512015-06-17 16:14:53 -0700701 }
702
703 // Create a program
704 if (firstRenderer.majorVersion == 3)
705 {
706 program = createES3ProgramFromSource();
707 }
708 else
709 {
710 program = createES2ProgramFromSource();
711 }
712
713 if (program == 0)
714 {
Austin Kinross137b1512015-06-17 16:14:53 -0700715 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700716 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700717 }
718
719 // Draw using the program to ensure it works as expected
720 drawWithProgram(program);
721 EXPECT_GL_NO_ERROR();
722
723 // Save the program binary out from this renderer
724 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
725 EXPECT_GL_NO_ERROR();
726 binary.resize(programLength);
727 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
728 EXPECT_GL_NO_ERROR();
729
730 // Destroy the first renderer
731 glDeleteProgram(program);
732 destroyEGLWindow(&eglWindow);
733
734 // Create an EGL window with the second renderer
735 eglWindow = createAndInitEGLWindow(secondRenderer);
736 if (eglWindow == nullptr)
737 {
738 FAIL() << "Failed to create EGL window";
739 return;
740 }
741
742 program = glCreateProgram();
743 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
744
745 GLint linkStatus;
746 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
747 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
748
749 if (linkStatus != 0)
750 {
751 // If the link was successful, then we should try to draw using the program to ensure it works as expected
752 drawWithProgram(program);
753 EXPECT_GL_NO_ERROR();
754 }
755
756 // Destroy the second renderer
757 glDeleteProgram(program);
758 destroyEGLWindow(&eglWindow);
759}
760
Jamie Madilla2c74982016-12-12 11:20:42 -0500761// clang-format off
Austin Kinross137b1512015-06-17 16:14:53 -0700762ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
763 // | Save the program | Load the program | Expected
764 // | using these params | using these params | link result
765 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
766 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
767 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
768 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
769 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
770 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
771 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
Jamie Madilla2c74982016-12-12 11:20:42 -0500772 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), false ), // Switching to newer client version shouldn't work
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400773 );
Jamie Madilla2c74982016-12-12 11:20:42 -0500774// clang-format on