blob: 1f32f6b5f00da8a16aef9e759c731b7d7c0e4eae [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"
15
Jamie Madillfa05f602015-05-07 13:47:11 -040016using namespace angle;
Austin Kinross18b931d2014-09-29 12:58:31 -070017
Jamie Madill7a29e4a2014-05-02 10:41:48 -040018class ProgramBinaryTest : public ANGLETest
19{
Geoff Lang0d3683c2014-10-23 11:08:16 -040020 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040021 ProgramBinaryTest()
Jamie Madill7a29e4a2014-05-02 10:41:48 -040022 {
23 setWindowWidth(128);
24 setWindowHeight(128);
25 setConfigRedBits(8);
26 setConfigGreenBits(8);
27 setConfigBlueBits(8);
28 setConfigAlphaBits(8);
29 }
30
31 virtual void SetUp()
32 {
33 ANGLETest::SetUp();
34
35 const std::string vertexShaderSource = SHADER_SOURCE
36 (
37 attribute vec4 inputAttribute;
38 void main()
39 {
40 gl_Position = inputAttribute;
41 }
42 );
43
44 const std::string fragmentShaderSource = SHADER_SOURCE
45 (
46 void main()
47 {
48 gl_FragColor = vec4(1,0,0,1);
49 }
50 );
51
Jamie Madill5599c8f2014-08-26 13:16:39 -040052 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
Jamie Madill7a29e4a2014-05-02 10:41:48 -040053 if (mProgram == 0)
54 {
55 FAIL() << "shader compilation failed.";
56 }
57
58 glGenBuffers(1, &mBuffer);
59 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
60 glBufferData(GL_ARRAY_BUFFER, 128, NULL, GL_STATIC_DRAW);
61 glBindBuffer(GL_ARRAY_BUFFER, 0);
62
63 ASSERT_GL_NO_ERROR();
64 }
65
66 virtual void TearDown()
67 {
68 glDeleteProgram(mProgram);
69 glDeleteBuffers(1, &mBuffer);
70
71 ANGLETest::TearDown();
72 }
73
Geoff Lang90208e92015-10-05 15:40:36 -040074 GLint getAvailableProgramBinaryFormatCount() const
75 {
76 GLint formatCount;
77 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &formatCount);
78 return formatCount;
79 }
80
Jamie Madill7a29e4a2014-05-02 10:41:48 -040081 GLuint mProgram;
82 GLuint mBuffer;
83};
84
85// This tests the assumption that float attribs of different size
86// should not internally cause a vertex shader recompile (for conversion).
Jamie Madillfa05f602015-05-07 13:47:11 -040087TEST_P(ProgramBinaryTest, FloatDynamicShaderSize)
Jamie Madill7a29e4a2014-05-02 10:41:48 -040088{
Geoff Lang90208e92015-10-05 15:40:36 -040089 if (!extensionEnabled("GL_OES_get_program_binary"))
90 {
91 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
92 << std::endl;
93 return;
94 }
95
96 if (getAvailableProgramBinaryFormatCount() == 0)
97 {
98 std::cout << "Test skipped because no program binary formats are available." << std::endl;
99 return;
100 }
101
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400102 glUseProgram(mProgram);
103 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
104
105 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, NULL);
106 glEnableVertexAttribArray(0);
107 glDrawArrays(GL_POINTS, 0, 1);
108
109 GLint programLength;
110 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
111
112 EXPECT_GL_NO_ERROR();
113
114 for (GLsizei size = 1; size <= 3; size++)
115 {
116 glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 8, NULL);
117 glEnableVertexAttribArray(0);
118 glDrawArrays(GL_POINTS, 0, 1);
119
120 GLint newProgramLength;
121 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &newProgramLength);
122 EXPECT_GL_NO_ERROR();
123 EXPECT_EQ(programLength, newProgramLength);
124 }
125}
Brandon Jones993d08d2014-10-10 14:32:57 -0700126
127// This tests the ability to successfully save and load a program binary.
Jamie Madillfa05f602015-05-07 13:47:11 -0400128TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
Brandon Jones993d08d2014-10-10 14:32:57 -0700129{
Geoff Lang90208e92015-10-05 15:40:36 -0400130 if (!extensionEnabled("GL_OES_get_program_binary"))
131 {
132 std::cout << "Test skipped because GL_OES_get_program_binary is not available."
133 << std::endl;
134 return;
135 }
136
137 if (getAvailableProgramBinaryFormatCount() == 0)
138 {
139 std::cout << "Test skipped because no program binary formats are available." << std::endl;
140 return;
141 }
142
Brandon Jones993d08d2014-10-10 14:32:57 -0700143 GLint programLength = 0;
144 GLint writtenLength = 0;
145 GLenum binaryFormat = 0;
146
147 glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
148 EXPECT_GL_NO_ERROR();
149
150 std::vector<uint8_t> binary(programLength);
151 glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
152 EXPECT_GL_NO_ERROR();
153
154 // The lengths reported by glGetProgramiv and glGetProgramBinaryOES should match
155 EXPECT_EQ(programLength, writtenLength);
156
157 if (writtenLength)
158 {
159 GLuint program2 = glCreateProgram();
160 glProgramBinaryOES(program2, binaryFormat, binary.data(), writtenLength);
161
162 EXPECT_GL_NO_ERROR();
163
164 GLint linkStatus;
165 glGetProgramiv(program2, GL_LINK_STATUS, &linkStatus);
166 if (linkStatus == 0)
167 {
168 GLint infoLogLength;
169 glGetProgramiv(program2, GL_INFO_LOG_LENGTH, &infoLogLength);
170
Geoff Lang981afd72014-11-05 16:30:36 -0500171 if (infoLogLength > 0)
172 {
173 std::vector<GLchar> infoLog(infoLogLength);
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700174 glGetProgramInfoLog(program2, static_cast<GLsizei>(infoLog.size()), NULL,
175 &infoLog[0]);
Geoff Lang981afd72014-11-05 16:30:36 -0500176 FAIL() << "program link failed: " << &infoLog[0];
177 }
178 else
179 {
180 FAIL() << "program link failed.";
181 }
Brandon Jones993d08d2014-10-10 14:32:57 -0700182 }
183 else
184 {
185 glUseProgram(program2);
186 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
187
188 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, NULL);
189 glEnableVertexAttribArray(0);
190 glDrawArrays(GL_POINTS, 0, 1);
191
192 EXPECT_GL_NO_ERROR();
193 }
194
195 glDeleteProgram(program2);
196 }
197}
Jamie Madillfa05f602015-05-07 13:47:11 -0400198
199// 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 -0400200ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
201 ES2_D3D9(),
202 ES2_D3D11(),
203 ES3_D3D11(),
204 ES2_OPENGL(),
205 ES3_OPENGL());
Austin Kinross137b1512015-06-17 16:14:53 -0700206
207// For the ProgramBinariesAcrossPlatforms tests, we need two sets of params:
208// - a set to save the program binary
209// - a set to load the program binary
210// We combine these into one struct extending PlatformParameters so we can reuse existing ANGLE test macros
211struct PlatformsWithLinkResult : PlatformParameters
212{
213 PlatformsWithLinkResult(PlatformParameters saveParams, PlatformParameters loadParamsIn, bool expectedLinkResultIn)
214 {
215 majorVersion = saveParams.majorVersion;
216 minorVersion = saveParams.minorVersion;
217 eglParameters = saveParams.eglParameters;
218 loadParams = loadParamsIn;
219 expectedLinkResult = expectedLinkResultIn;
220 }
221
222 PlatformParameters loadParams;
223 bool expectedLinkResult;
224};
225
Corentin Wallez33585c72015-09-03 14:41:23 -0400226// Provide a custom gtest parameter name function for PlatformsWithLinkResult
227// to avoid returning the same parameter name twice. Such a conflict would happen
228// between ES2_D3D11_to_ES2D3D11 and ES2_D3D11_to_ES3D3D11 as they were both
229// named ES2_D3D11
230std::ostream &operator<<(std::ostream& stream, const PlatformsWithLinkResult &platform)
231{
232 const PlatformParameters &platform1 = platform;
233 const PlatformParameters &platform2 = platform.loadParams;
234 stream << platform1 << "_to_" << platform2;
235 return stream;
236}
237
Austin Kinross137b1512015-06-17 16:14:53 -0700238class ProgramBinariesAcrossPlatforms : public testing::TestWithParam<PlatformsWithLinkResult>
239{
240 public:
241 void SetUp() override
242 {
243 mOSWindow = CreateOSWindow();
244 bool result = mOSWindow->initialize("ProgramBinariesAcrossRenderersTests", 100, 100);
245
246 if (result == false)
247 {
248 FAIL() << "Failed to create OS window";
249 }
250 }
251
252 EGLWindow *createAndInitEGLWindow(angle::PlatformParameters &param)
253 {
Geoff Lang5ade8452015-09-02 11:00:30 -0400254 EGLWindow *eglWindow =
255 new EGLWindow(param.majorVersion, param.minorVersion, param.eglParameters);
Austin Kinross137b1512015-06-17 16:14:53 -0700256 bool result = eglWindow->initializeGL(mOSWindow);
257 if (result == false)
258 {
259 SafeDelete(eglWindow);
260 eglWindow = nullptr;
261 }
262
263 return eglWindow;
264 }
265
266 void destroyEGLWindow(EGLWindow **eglWindow)
267 {
268 ASSERT(*eglWindow != nullptr);
269 (*eglWindow)->destroyGL();
270 SafeDelete(*eglWindow);
271 *eglWindow = nullptr;
272 }
273
274 GLuint createES2ProgramFromSource()
275 {
276 const std::string testVertexShaderSource = SHADER_SOURCE
277 (
278 attribute highp vec4 position;
279
280 void main(void)
281 {
282 gl_Position = position;
283 }
284 );
285
286 const std::string testFragmentShaderSource = SHADER_SOURCE
287 (
288 void main(void)
289 {
290 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
291 }
292 );
293
294 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
295 }
296
297 GLuint createES3ProgramFromSource()
298 {
299 const std::string testVertexShaderSource = SHADER_SOURCE
300 ( #version 300 es\n
301 precision highp float;
302 in highp vec4 position;
303
304 void main(void)
305 {
306 gl_Position = position;
307 }
308 );
309
310 const std::string testFragmentShaderSource = SHADER_SOURCE
311 ( #version 300 es \n
312 precision highp float;
313 out vec4 out_FragColor;
314
315 void main(void)
316 {
317 out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
318 }
319 );
320
321 return CompileProgram(testVertexShaderSource, testFragmentShaderSource);
322 }
323
324 void drawWithProgram(GLuint program)
325 {
326 glClearColor(0, 0, 0, 1);
327 glClear(GL_COLOR_BUFFER_BIT);
328
329 GLint positionLocation = glGetAttribLocation(program, "position");
330
331 glUseProgram(program);
332
333 const GLfloat vertices[] =
334 {
335 -1.0f, 1.0f, 0.5f,
336 -1.0f, -1.0f, 0.5f,
337 1.0f, -1.0f, 0.5f,
338
339 -1.0f, 1.0f, 0.5f,
340 1.0f, -1.0f, 0.5f,
341 1.0f, 1.0f, 0.5f,
342 };
343
344 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
345 glEnableVertexAttribArray(positionLocation);
346
347 glDrawArrays(GL_TRIANGLES, 0, 6);
348
349 glDisableVertexAttribArray(positionLocation);
350 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
351
352 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
353 }
354
355 void TearDown() override
356 {
357 mOSWindow->destroy();
358 SafeDelete(mOSWindow);
359 }
360
361 OSWindow *mOSWindow;
362};
363
364// Tries to create a program binary using one set of platform params, then load it using a different sent of params
365TEST_P(ProgramBinariesAcrossPlatforms, CreateAndReloadBinary)
366{
367 angle::PlatformParameters firstRenderer = GetParam();
368 angle::PlatformParameters secondRenderer = GetParam().loadParams;
369 bool expectedLinkResult = GetParam().expectedLinkResult;
370
371 if (!(IsPlatformAvailable(firstRenderer)))
372 {
373 std::cout << "First renderer not supported, skipping test";
374 return;
375 }
376
377 if (!(IsPlatformAvailable(secondRenderer)))
378 {
379 std::cout << "Second renderer not supported, skipping test";
380 return;
381 }
382
383 EGLWindow *eglWindow = nullptr;
384 std::vector<uint8_t> binary(0);
385 GLuint program = 0;
386
387 GLint programLength = 0;
388 GLint writtenLength = 0;
389 GLenum binaryFormat = 0;
390
391 // Create a EGL window with the first renderer
392 eglWindow = createAndInitEGLWindow(firstRenderer);
393 if (eglWindow == nullptr)
394 {
395 FAIL() << "Failed to create EGL window";
396 return;
397 }
398
399 // If the test is trying to use both the default GPU and WARP, but the default GPU *IS* WARP,
400 // then our expectations for the test results will be invalid.
401 if (firstRenderer.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
402 secondRenderer.eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE)
403 {
404 std::string rendererString = std::string(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
405 std::transform(rendererString.begin(), rendererString.end(), rendererString.begin(), ::tolower);
406
407 auto basicRenderPos = rendererString.find(std::string("microsoft basic render"));
408 auto softwareAdapterPos = rendererString.find(std::string("software adapter"));
409
410 if (basicRenderPos != std::string::npos || softwareAdapterPos != std::string::npos)
411 {
412 // The first renderer is using WARP, even though we didn't explictly request it
413 // We should skip this test
414 std::cout << "Test skipped on when default GPU is WARP." << std::endl;
415 return;
416 }
417 }
418
419 // Create a program
420 if (firstRenderer.majorVersion == 3)
421 {
422 program = createES3ProgramFromSource();
423 }
424 else
425 {
426 program = createES2ProgramFromSource();
427 }
428
429 if (program == 0)
430 {
Austin Kinross137b1512015-06-17 16:14:53 -0700431 destroyEGLWindow(&eglWindow);
Corentin Wallezefb6ac62015-09-02 08:10:09 -0700432 FAIL() << "Failed to create program from source";
Austin Kinross137b1512015-06-17 16:14:53 -0700433 }
434
435 // Draw using the program to ensure it works as expected
436 drawWithProgram(program);
437 EXPECT_GL_NO_ERROR();
438
439 // Save the program binary out from this renderer
440 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
441 EXPECT_GL_NO_ERROR();
442 binary.resize(programLength);
443 glGetProgramBinaryOES(program, programLength, &writtenLength, &binaryFormat, binary.data());
444 EXPECT_GL_NO_ERROR();
445
446 // Destroy the first renderer
447 glDeleteProgram(program);
448 destroyEGLWindow(&eglWindow);
449
450 // Create an EGL window with the second renderer
451 eglWindow = createAndInitEGLWindow(secondRenderer);
452 if (eglWindow == nullptr)
453 {
454 FAIL() << "Failed to create EGL window";
455 return;
456 }
457
458 program = glCreateProgram();
459 glProgramBinaryOES(program, binaryFormat, binary.data(), writtenLength);
460
461 GLint linkStatus;
462 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
463 EXPECT_EQ(expectedLinkResult, (linkStatus != 0));
464
465 if (linkStatus != 0)
466 {
467 // If the link was successful, then we should try to draw using the program to ensure it works as expected
468 drawWithProgram(program);
469 EXPECT_GL_NO_ERROR();
470 }
471
472 // Destroy the second renderer
473 glDeleteProgram(program);
474 destroyEGLWindow(&eglWindow);
475}
476
477ANGLE_INSTANTIATE_TEST(ProgramBinariesAcrossPlatforms,
478 // | Save the program | Load the program | Expected
479 // | using these params | using these params | link result
480 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11(), true ), // Loading + reloading binary should work
481 PlatformsWithLinkResult(ES3_D3D11(), ES3_D3D11(), true ), // Loading + reloading binary should work
482 PlatformsWithLinkResult(ES2_D3D11_FL11_0(), ES2_D3D11_FL9_3(), false ), // Switching feature level shouldn't work
483 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D11_WARP(), false ), // Switching from hardware to software shouldn't work
484 PlatformsWithLinkResult(ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3_WARP(), false ), // Switching from hardware to software shouldn't work for FL9 either
485 PlatformsWithLinkResult(ES2_D3D11(), ES2_D3D9(), false ), // Switching from D3D11 to D3D9 shouldn't work
486 PlatformsWithLinkResult(ES2_D3D9(), ES2_D3D11(), false ), // Switching from D3D9 to D3D11 shouldn't work
487 PlatformsWithLinkResult(ES2_D3D11(), ES3_D3D11(), true ) // Switching to newer client version should work
488
489 // TODO: ANGLE issue 523
490 // Compiling a program with client version 3, saving the binary, then loading it with client version 2 should not work
491 // PlatformsWithLinkResult(ES3_D3D11(), ES2_D3D11(), false )
Corentin Wallezf3357ee2015-07-22 14:10:19 -0400492 );