1 //
2 // Copyright 2020 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 // ContextNoErrorTest:
7 // Tests pertaining to GL_KHR_no_error
8 //
9
10 #include <gtest/gtest.h>
11
12 #include "common/platform.h"
13 #include "test_utils/ANGLETest.h"
14 #include "test_utils/gl_raii.h"
15
16 using namespace angle;
17
18 class ContextNoErrorTest : public ANGLETest<>
19 {
20 protected:
ContextNoErrorTest()21 ContextNoErrorTest() : mNaughtyTexture(0) { setNoErrorEnabled(true); }
22
testTearDown()23 void testTearDown() override
24 {
25 if (mNaughtyTexture != 0)
26 {
27 glDeleteTextures(1, &mNaughtyTexture);
28 }
29 }
30
bindNaughtyTexture()31 void bindNaughtyTexture()
32 {
33 glGenTextures(1, &mNaughtyTexture);
34 ASSERT_GL_NO_ERROR();
35 glBindTexture(GL_TEXTURE_CUBE_MAP, mNaughtyTexture);
36 ASSERT_GL_NO_ERROR();
37
38 // mNaughtyTexture should now be a GL_TEXTURE_CUBE_MAP texture, so rebinding it to
39 // GL_TEXTURE_2D is an error
40 glBindTexture(GL_TEXTURE_2D, mNaughtyTexture);
41 }
42
43 GLuint mNaughtyTexture = 0;
44 };
45
46 class ContextNoErrorTestES3 : public ContextNoErrorTest
47 {};
48
49 class ContextNoErrorPPOTest31 : public ContextNoErrorTest
50 {
51 protected:
testTearDown()52 void testTearDown() override
53 {
54 glDeleteProgram(mVertProg);
55 glDeleteProgram(mFragProg);
56 glDeleteProgramPipelines(1, &mPipeline);
57 }
58
59 void bindProgramPipeline(const GLchar *vertString, const GLchar *fragString);
60 void drawQuadWithPPO(const std::string &positionAttribName,
61 const GLfloat positionAttribZ,
62 const GLfloat positionAttribXYScale);
63
64 GLuint mVertProg = 0;
65 GLuint mFragProg = 0;
66 GLuint mPipeline = 0;
67 };
68
bindProgramPipeline(const GLchar * vertString,const GLchar * fragString)69 void ContextNoErrorPPOTest31::bindProgramPipeline(const GLchar *vertString,
70 const GLchar *fragString)
71 {
72 mVertProg = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
73 ASSERT_NE(mVertProg, 0u);
74 mFragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
75 ASSERT_NE(mFragProg, 0u);
76
77 // Generate a program pipeline and attach the programs to their respective stages
78 glGenProgramPipelines(1, &mPipeline);
79 EXPECT_GL_NO_ERROR();
80 glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
81 EXPECT_GL_NO_ERROR();
82 glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
83 EXPECT_GL_NO_ERROR();
84 glBindProgramPipeline(mPipeline);
85 EXPECT_GL_NO_ERROR();
86 }
87
drawQuadWithPPO(const std::string & positionAttribName,const GLfloat positionAttribZ,const GLfloat positionAttribXYScale)88 void ContextNoErrorPPOTest31::drawQuadWithPPO(const std::string &positionAttribName,
89 const GLfloat positionAttribZ,
90 const GLfloat positionAttribXYScale)
91 {
92 glUseProgram(0);
93
94 std::array<Vector3, 6> quadVertices = ANGLETestBase::GetQuadVertices();
95
96 for (Vector3 &vertex : quadVertices)
97 {
98 vertex.x() *= positionAttribXYScale;
99 vertex.y() *= positionAttribXYScale;
100 vertex.z() = positionAttribZ;
101 }
102
103 GLint positionLocation = glGetAttribLocation(mVertProg, positionAttribName.c_str());
104
105 glBindBuffer(GL_ARRAY_BUFFER, 0);
106 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
107 glEnableVertexAttribArray(positionLocation);
108
109 glDrawArrays(GL_TRIANGLES, 0, 6);
110
111 glDisableVertexAttribArray(positionLocation);
112 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
113 }
114
115 // Tests that error reporting is suppressed when GL_KHR_no_error is enabled
TEST_P(ContextNoErrorTest,NoError)116 TEST_P(ContextNoErrorTest, NoError)
117 {
118 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
119
120 bindNaughtyTexture();
121 EXPECT_GL_NO_ERROR();
122 }
123
124 // Test glDetachShader to make sure it resolves linking with a no error context and doesn't assert
TEST_P(ContextNoErrorTest,DetachAfterLink)125 TEST_P(ContextNoErrorTest, DetachAfterLink)
126 {
127 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
128
129 GLuint vs = CompileShader(GL_VERTEX_SHADER, essl1_shaders::vs::Simple());
130 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, essl1_shaders::fs::Red());
131 GLuint program = glCreateProgram();
132 glAttachShader(program, vs);
133 glAttachShader(program, fs);
134 glLinkProgram(program);
135
136 glDetachShader(program, vs);
137 glDetachShader(program, fs);
138
139 glDeleteShader(vs);
140 glDeleteShader(fs);
141 glDeleteProgram(program);
142 EXPECT_GL_NO_ERROR();
143 }
144
145 // Tests that we can draw with a program pipeline when GL_KHR_no_error is enabled.
TEST_P(ContextNoErrorPPOTest31,DrawWithPPO)146 TEST_P(ContextNoErrorPPOTest31, DrawWithPPO)
147 {
148 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
149
150 // Only the Vulkan backend supports PPOs
151 ANGLE_SKIP_TEST_IF(!IsVulkan());
152
153 // Create two separable program objects from a
154 // single source string respectively (vertSrc and fragSrc)
155 const GLchar *vertString = essl31_shaders::vs::Simple();
156 const GLchar *fragString = essl31_shaders::fs::Red();
157
158 bindProgramPipeline(vertString, fragString);
159
160 drawQuadWithPPO("a_position", 0.5f, 1.0f);
161 ASSERT_GL_NO_ERROR();
162 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
163 }
164
165 // Test drawing with program and then with PPO to make sure it resolves linking of both the program
166 // and the PPO with a no error context.
TEST_P(ContextNoErrorPPOTest31,DrawWithProgramThenPPO)167 TEST_P(ContextNoErrorPPOTest31, DrawWithProgramThenPPO)
168 {
169 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
170
171 // Only the Vulkan backend supports PPOs
172 ANGLE_SKIP_TEST_IF(!IsVulkan());
173
174 ANGLE_GL_PROGRAM(simpleProgram, essl31_shaders::vs::Simple(), essl31_shaders::fs::Red());
175 ASSERT_NE(simpleProgram, 0u);
176 EXPECT_GL_NO_ERROR();
177
178 // Create two separable program objects from a
179 // single source string respectively (vertSrc and fragSrc)
180 const GLchar *vertString = essl31_shaders::vs::Simple();
181 const GLchar *fragString = essl31_shaders::fs::Green();
182
183 // Bind the PPO
184 bindProgramPipeline(vertString, fragString);
185
186 // Bind the program
187 glUseProgram(simpleProgram);
188 EXPECT_GL_NO_ERROR();
189
190 // Draw and expect red since program overrides PPO
191 drawQuad(simpleProgram, essl31_shaders::PositionAttrib(), 0.5f);
192 EXPECT_GL_NO_ERROR();
193 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
194
195 // Unbind the program
196 glUseProgram(0);
197 EXPECT_GL_NO_ERROR();
198
199 // Draw and expect green
200 drawQuadWithPPO("a_position", 0.5f, 1.0f);
201 EXPECT_GL_NO_ERROR();
202 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
203 }
204
205 // Test glUseProgramStages with different programs
TEST_P(ContextNoErrorPPOTest31,UseProgramStagesWithDifferentPrograms)206 TEST_P(ContextNoErrorPPOTest31, UseProgramStagesWithDifferentPrograms)
207 {
208 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
209
210 // Only the Vulkan backend supports PPOs
211 ANGLE_SKIP_TEST_IF(!IsVulkan());
212
213 // Create two separable program objects from a
214 // single source string respectively (vertSrc and fragSrc)
215 const GLchar *vertString = essl31_shaders::vs::Simple();
216 const GLchar *fragString1 = R"(#version 310 es
217 precision highp float;
218 uniform float redColorIn;
219 uniform float greenColorIn;
220 out vec4 my_FragColor;
221 void main()
222 {
223 my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
224 })";
225 const GLchar *fragString2 = R"(#version 310 es
226 precision highp float;
227 uniform float greenColorIn;
228 uniform float blueColorIn;
229 out vec4 my_FragColor;
230 void main()
231 {
232 my_FragColor = vec4(0.0, greenColorIn, blueColorIn, 1.0);
233 })";
234
235 bindProgramPipeline(vertString, fragString1);
236
237 // Set the output color to red
238 GLint location = glGetUniformLocation(mFragProg, "redColorIn");
239 glActiveShaderProgram(mPipeline, mFragProg);
240 glUniform1f(location, 1.0);
241 location = glGetUniformLocation(mFragProg, "greenColorIn");
242 glActiveShaderProgram(mPipeline, mFragProg);
243 glUniform1f(location, 0.0);
244
245 drawQuadWithPPO("a_position", 0.5f, 1.0f);
246 ASSERT_GL_NO_ERROR();
247 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
248
249 GLuint fragProg;
250 fragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString2);
251 ASSERT_NE(fragProg, 0u);
252 EXPECT_GL_NO_ERROR();
253
254 glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, fragProg);
255 EXPECT_GL_NO_ERROR();
256
257 glClearColor(0.0, 0.0, 0.0, 0.0);
258 glClear(GL_COLOR_BUFFER_BIT);
259
260 // Set the output color to blue
261 location = glGetUniformLocation(fragProg, "greenColorIn");
262 glActiveShaderProgram(mPipeline, fragProg);
263 glUniform1f(location, 0.0);
264 location = glGetUniformLocation(fragProg, "blueColorIn");
265 glActiveShaderProgram(mPipeline, fragProg);
266 glUniform1f(location, 1.0);
267
268 drawQuadWithPPO("a_position", 0.5f, 1.0f);
269 ASSERT_GL_NO_ERROR();
270 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
271
272 glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
273 EXPECT_GL_NO_ERROR();
274
275 glClearColor(0.0, 0.0, 0.0, 0.0);
276 glClear(GL_COLOR_BUFFER_BIT);
277
278 drawQuadWithPPO("a_position", 0.5f, 1.0f);
279 ASSERT_GL_NO_ERROR();
280 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
281
282 glDeleteProgram(mVertProg);
283 glDeleteProgram(mFragProg);
284 glDeleteProgram(fragProg);
285 }
286
287 // Test glUseProgramStages with repeated calls to glUseProgramStages with the same programs.
TEST_P(ContextNoErrorPPOTest31,RepeatedCallToUseProgramStagesWithSamePrograms)288 TEST_P(ContextNoErrorPPOTest31, RepeatedCallToUseProgramStagesWithSamePrograms)
289 {
290 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
291
292 // Only the Vulkan backend supports PPOs
293 ANGLE_SKIP_TEST_IF(!IsVulkan());
294
295 // Create two separable program objects from a
296 // single source string respectively (vertSrc and fragSrc)
297 const GLchar *vertString = essl31_shaders::vs::Simple();
298 const GLchar *fragString = R"(#version 310 es
299 precision highp float;
300 uniform float redColorIn;
301 uniform float greenColorIn;
302 out vec4 my_FragColor;
303 void main()
304 {
305 my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
306 })";
307
308 bindProgramPipeline(vertString, fragString);
309
310 // Set the output color to red
311 GLint location = glGetUniformLocation(mFragProg, "redColorIn");
312 glActiveShaderProgram(mPipeline, mFragProg);
313 glUniform1f(location, 1.0);
314 location = glGetUniformLocation(mFragProg, "greenColorIn");
315 glActiveShaderProgram(mPipeline, mFragProg);
316 glUniform1f(location, 0.0);
317
318 // These following calls to glUseProgramStages should not cause a re-link.
319 glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertProg);
320 EXPECT_GL_NO_ERROR();
321 glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProg);
322 EXPECT_GL_NO_ERROR();
323
324 drawQuadWithPPO("a_position", 0.5f, 1.0f);
325 ASSERT_GL_NO_ERROR();
326 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
327
328 glDeleteProgram(mVertProg);
329 glDeleteProgram(mFragProg);
330 }
331
332 // Tests that an incorrect enum to GetInteger does not cause an application crash.
TEST_P(ContextNoErrorTest,InvalidGetIntegerDoesNotCrash)333 TEST_P(ContextNoErrorTest, InvalidGetIntegerDoesNotCrash)
334 {
335 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
336
337 GLint value = 1;
338 glGetIntegerv(GL_TEXTURE_2D, &value);
339 EXPECT_GL_NO_ERROR();
340 EXPECT_EQ(value, 1);
341 }
342
343 // Test that we ignore an invalid texture type when EGL_KHR_create_context_no_error is enabled.
TEST_P(ContextNoErrorTest,InvalidTextureType)344 TEST_P(ContextNoErrorTest, InvalidTextureType)
345 {
346 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
347
348 GLTexture texture;
349 constexpr GLenum kInvalidTextureType = 0;
350
351 glBindTexture(kInvalidTextureType, texture);
352 ASSERT_GL_NO_ERROR();
353
354 glTexParameteri(kInvalidTextureType, GL_TEXTURE_BASE_LEVEL, 0);
355 ASSERT_GL_NO_ERROR();
356 }
357
358 // Tests that we can draw with a program that is relinking when GL_KHR_no_error is enabled.
TEST_P(ContextNoErrorTestES3,DrawWithRelinkedProgram)359 TEST_P(ContextNoErrorTestES3, DrawWithRelinkedProgram)
360 {
361 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_no_error"));
362
363 int w = getWindowWidth();
364 int h = getWindowHeight();
365 glViewport(0, 0, w, h);
366
367 glClearColor(0, 0, 0, 1);
368 glClear(GL_COLOR_BUFFER_BIT);
369
370 constexpr char kVS[] = R"(#version 300 es
371 void main()
372 {
373 vec2 position = vec2(-1, -1);
374 if (gl_VertexID == 1)
375 position = vec2(3, -1);
376 else if (gl_VertexID == 2)
377 position = vec2(-1, 3);
378 gl_Position = vec4(position, 0, 1);
379 })";
380
381 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
382 GLuint red = CompileShader(GL_FRAGMENT_SHADER, essl3_shaders::fs::Red());
383 GLuint bad = CompileShader(GL_FRAGMENT_SHADER, essl1_shaders::fs::Blue());
384 GLuint green = CompileShader(GL_FRAGMENT_SHADER, essl3_shaders::fs::Green());
385
386 GLuint program = glCreateProgram();
387 glAttachShader(program, vs);
388 glAttachShader(program, red);
389 glLinkProgram(program);
390
391 // Use the program once; it's executable will be installed.
392 glUseProgram(program);
393 glEnable(GL_SCISSOR_TEST);
394 glScissor(0, 0, w / 4, h);
395 glDrawArrays(GL_TRIANGLES, 0, 3);
396
397 // Make it fail compilation, the draw should continue to use the old executable
398 glDetachShader(program, red);
399 glAttachShader(program, bad);
400 glLinkProgram(program);
401
402 glScissor(w / 4, 0, w / 2 - w / 4, h);
403 glDrawArrays(GL_TRIANGLES, 0, 3);
404
405 // Relink the program while it's bound. It should finish compiling before the following draw is
406 // attempted.
407 glDetachShader(program, bad);
408 glAttachShader(program, green);
409 glLinkProgram(program);
410
411 glScissor(w / 2, 0, w - w / 2, h);
412 glDrawArrays(GL_TRIANGLES, 0, 3);
413
414 EXPECT_PIXEL_RECT_EQ(0, 0, w / 2, h, GLColor::red);
415 EXPECT_PIXEL_RECT_EQ(w / 2, 0, w - w / 2, h, GLColor::green);
416 ASSERT_GL_NO_ERROR();
417 }
418
419 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ContextNoErrorTest);
420
421 ANGLE_INSTANTIATE_TEST_ES3(ContextNoErrorTestES3);
422
423 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContextNoErrorPPOTest31);
424 ANGLE_INSTANTIATE_TEST_ES31(ContextNoErrorPPOTest31);
425