xref: /aosp_15_r20/external/angle/src/tests/gl_tests/ContextNoErrorTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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