xref: /aosp_15_r20/external/angle/src/tests/gl_tests/SRGBFramebufferTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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 
7 // SRGBFramebufferTest.cpp: Tests of sRGB framebuffer functionality.
8 
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 
12 namespace
13 {
14 constexpr angle::GLColor linearColor(64, 127, 191, 255);
15 constexpr angle::GLColor srgbColor(13, 54, 133, 255);
16 }  // namespace
17 
18 namespace angle
19 {
20 
21 class SRGBFramebufferTest : public ANGLETest<>
22 {
23   protected:
SRGBFramebufferTest()24     SRGBFramebufferTest()
25     {
26         setWindowWidth(128);
27         setWindowHeight(128);
28         setConfigRedBits(8);
29         setConfigGreenBits(8);
30         setConfigBlueBits(8);
31         setConfigAlphaBits(8);
32     }
33 
testSetUp()34     void testSetUp() override
35     {
36         mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
37         ASSERT_NE(0u, mProgram);
38 
39         mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
40         ASSERT_NE(-1, mColorLocation);
41     }
42 
testTearDown()43     void testTearDown() override { glDeleteProgram(mProgram); }
44 
45     GLuint mProgram      = 0;
46     GLint mColorLocation = -1;
47 };
48 
49 class SRGBFramebufferTestES3 : public SRGBFramebufferTest
50 {};
51 
52 // Test basic validation of GL_EXT_sRGB_write_control
TEST_P(SRGBFramebufferTest,Validation)53 TEST_P(SRGBFramebufferTest, Validation)
54 {
55     GLenum expectedError =
56         IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ? GL_NO_ERROR : GL_INVALID_ENUM;
57 
58     GLboolean value = GL_FALSE;
59     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
60     EXPECT_GL_ERROR(expectedError);
61 
62     glGetBooleanv(GL_FRAMEBUFFER_SRGB_EXT, &value);
63     EXPECT_GL_ERROR(expectedError);
64     if (expectedError == GL_NO_ERROR)
65     {
66         EXPECT_GL_TRUE(value);
67     }
68 
69     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
70     EXPECT_GL_ERROR(expectedError);
71 
72     glGetBooleanv(GL_FRAMEBUFFER_SRGB_EXT, &value);
73     EXPECT_GL_ERROR(expectedError);
74     if (expectedError == GL_NO_ERROR)
75     {
76         EXPECT_GL_FALSE(value);
77     }
78 }
79 
80 // Test basic functionality of GL_EXT_sRGB_write_control
TEST_P(SRGBFramebufferTest,BasicUsage)81 TEST_P(SRGBFramebufferTest, BasicUsage)
82 {
83     if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
84         (!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
85     {
86         std::cout
87             << "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
88             << std::endl;
89         return;
90     }
91 
92     GLTexture texture;
93     glBindTexture(GL_TEXTURE_2D, texture);
94     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
95                  nullptr);
96 
97     GLFramebuffer framebuffer;
98     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
99     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
100 
101     glUseProgram(mProgram);
102     glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
103 
104     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
105     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
106     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
107 
108     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
109     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
110     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
111 }
112 
113 // Test that GL_EXT_sRGB_write_control state applies to all framebuffers if multiple are used
114 // 1. disable srgb
115 // 2. draw to both framebuffers
116 // 3. enable srgb
117 // 4. draw to both framebuffers
TEST_P(SRGBFramebufferTest,MultipleFramebuffers)118 TEST_P(SRGBFramebufferTest, MultipleFramebuffers)
119 {
120     if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
121         (!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
122     {
123         std::cout
124             << "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
125             << std::endl;
126         return;
127     }
128 
129     // NVIDIA failures on older drivers
130     // http://anglebug.com/42264177
131     ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGLES());
132 
133     GLTexture texture;
134     glBindTexture(GL_TEXTURE_2D, texture);
135     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
136                  nullptr);
137 
138     GLFramebuffer framebuffer1;
139     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
140     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
141 
142     glUseProgram(mProgram);
143     glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
144 
145     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
146     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
147     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
148 
149     GLFramebuffer framebuffer2;
150     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
151     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
152     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
153     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
154 
155     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
156     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
157     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
158     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
159 
160     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
161     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
162     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
163 }
164 
165 // Test that we behave correctly when we toggle FRAMEBUFFER_SRGB_EXT on a framebuffer that has an
166 // attachment in linear colorspace
TEST_P(SRGBFramebufferTest,NegativeAlreadyLinear)167 TEST_P(SRGBFramebufferTest, NegativeAlreadyLinear)
168 {
169     if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
170         (!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
171     {
172         std::cout
173             << "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
174             << std::endl;
175         return;
176     }
177 
178     GLTexture texture;
179     glBindTexture(GL_TEXTURE_2D, texture);
180     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
181 
182     GLFramebuffer framebuffer;
183     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
184     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
185 
186     glUseProgram(mProgram);
187     glUniform4fv(mColorLocation, 1, linearColor.toNormalizedVector().data());
188 
189     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
190     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
191     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
192 
193     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
194     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
195     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
196 }
197 
198 // Test that lifetimes of internal resources are tracked correctly by deleting a texture and then
199 // attempting to use it. This is expected to produce a non-fatal error.
TEST_P(SRGBFramebufferTest,NegativeLifetimeTracking)200 TEST_P(SRGBFramebufferTest, NegativeLifetimeTracking)
201 {
202     if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
203         (!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
204     {
205         std::cout
206             << "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
207             << std::endl;
208         return;
209     }
210 
211     // NVIDIA failures
212     // http://anglebug.com/42264177
213     ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGLES());
214 
215     GLTexture texture;
216     glBindTexture(GL_TEXTURE_2D, texture);
217     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
218                  nullptr);
219 
220     GLFramebuffer framebuffer;
221     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
222     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
223 
224     glUseProgram(mProgram);
225     glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
226 
227     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
228     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
229     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
230 
231     // Delete the texture
232     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
233     texture.reset();
234 
235     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
236     EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
237 
238     GLColor throwaway_color;
239     glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &throwaway_color);
240     EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
241 }
242 
243 // Test that glBlitFramebuffer correctly converts colorspaces
TEST_P(SRGBFramebufferTestES3,BlitFramebuffer)244 TEST_P(SRGBFramebufferTestES3, BlitFramebuffer)
245 {
246     // http://anglebug.com/42264326
247     ANGLE_SKIP_TEST_IF(!IsVulkan());
248 
249     if (!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
250         (!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3))
251     {
252         std::cout
253             << "Test skipped because GL_EXT_sRGB_write_control and GL_EXT_sRGB are not available."
254             << std::endl;
255         return;
256     }
257 
258     GLTexture dstTexture;
259     glBindTexture(GL_TEXTURE_2D, dstTexture);
260     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
261                  nullptr);
262     GLFramebuffer dstFramebuffer;
263     glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
264     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTexture, 0);
265 
266     GLTexture srcTexture;
267     glBindTexture(GL_TEXTURE_2D, srcTexture);
268     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
269                  nullptr);
270 
271     GLFramebuffer srcFramebuffer;
272     glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer);
273     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexture, 0);
274 
275     glUseProgram(mProgram);
276     glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
277 
278     // Draw onto the framebuffer normally
279     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
280     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
281     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
282 
283     // Blit the framebuffer normally
284     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
285     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
286     glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
287     glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
288 
289     glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
290     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
291 
292     // Blit the framebuffer with forced linear colorspace
293     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
294     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
295     glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
296     glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
297 
298     glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
299     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
300 }
301 
302 // This test reproduces an issue in the Vulkan backend found in the Chromium CI that
303 // was caused by enabling the VK_KHR_image_format_list extension on SwiftShader
304 // which exposed GL_EXT_sRGB_write_control.
TEST_P(SRGBFramebufferTest,DrawToSmallFBOClearLargeFBO)305 TEST_P(SRGBFramebufferTest, DrawToSmallFBOClearLargeFBO)
306 {
307     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
308                        (!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3));
309 
310     // Disabling GL_FRAMEBUFFER_SRGB_EXT caused the issue
311     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
312 
313     // The issue involved framebuffers of two different sizes.
314     // The smaller needed to be drawn to, while the larger one could be just cleared
315     // to reproduce the issue. These are the smallest tested sizes that generated
316     // the validation error.
317     constexpr GLsizei kDimensionsSmall[] = {1, 1};
318     constexpr GLsizei kDimensionsLarge[] = {2, 2};
319     {
320         GLTexture texture;
321         glBindTexture(GL_TEXTURE_2D, texture);
322         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kDimensionsSmall[0], kDimensionsSmall[1]);
323         glBindTexture(GL_TEXTURE_2D, 0);
324 
325         GLFramebuffer framebuffer;
326         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
327         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
328 
329         unsigned char vertexData[] = {0};
330         GLBuffer vertexBuffer;
331         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
332         glBufferData(GL_ARRAY_BUFFER, sizeof(char), vertexData, GL_STATIC_DRAW);
333 
334         unsigned int indexData[] = {0};
335         GLBuffer indexBuffer;
336         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
337         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int), indexData, GL_STATIC_DRAW);
338 
339         glUseProgram(mProgram);
340 
341         glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
342 
343         EXPECT_GL_NO_ERROR();
344     }
345     {
346         GLTexture texture;
347         glBindTexture(GL_TEXTURE_2D, texture);
348         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kDimensionsLarge[0], kDimensionsLarge[1]);
349         glBindTexture(GL_TEXTURE_2D, 0);
350 
351         GLFramebuffer framebuffer;
352         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
353         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
354 
355         // Vulkan validation happened to fail here with:
356         // "Cannot execute a render pass with renderArea not within the bound of the framebuffer"
357         glClear(GL_COLOR_BUFFER_BIT);
358 
359         EXPECT_GL_NO_ERROR();
360     }
361 }
362 
363 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
364 // tests should be run against.
365 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SRGBFramebufferTest);
366 ANGLE_INSTANTIATE_TEST_ES3(SRGBFramebufferTestES3);
367 
368 }  // namespace angle
369