• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.get());
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.get());
99     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 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/5641
131     ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGLES());
132 
133     GLTexture texture;
134     glBindTexture(GL_TEXTURE_2D, texture.get());
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.get());
140     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 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.get());
151     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 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.get());
157     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
158     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
159 
160     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2.get());
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.get());
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.get());
184     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 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/5641
213     ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGLES());
214 
215     GLTexture texture;
216     glBindTexture(GL_TEXTURE_2D, texture.get());
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.get());
222     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 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/5790
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.get());
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.get());
264     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTexture.get(),
265                            0);
266 
267     GLTexture srcTexture;
268     glBindTexture(GL_TEXTURE_2D, srcTexture.get());
269     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
270                  nullptr);
271 
272     GLFramebuffer srcFramebuffer;
273     glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer.get());
274     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexture.get(),
275                            0);
276 
277     glUseProgram(mProgram);
278     glUniform4fv(mColorLocation, 1, srgbColor.toNormalizedVector().data());
279 
280     // Draw onto the framebuffer normally
281     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
282     drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
283     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
284 
285     // Blit the framebuffer normally
286     glEnable(GL_FRAMEBUFFER_SRGB_EXT);
287     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
288     glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
289     glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
290 
291     glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
292     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
293 
294     // Blit the framebuffer with forced linear colorspace
295     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
296     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
297     glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
298     glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
299 
300     glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
301     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
302 }
303 
304 // This test reproduces an issue in the Vulkan backend found in the Chromium CI that
305 // was caused by enabling the VK_KHR_image_format_list extension on SwiftShader
306 // which exposed GL_EXT_sRGB_write_control.
TEST_P(SRGBFramebufferTest,DrawToSmallFBOClearLargeFBO)307 TEST_P(SRGBFramebufferTest, DrawToSmallFBOClearLargeFBO)
308 {
309     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB_write_control") ||
310                        (!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3));
311 
312     // Disabling GL_FRAMEBUFFER_SRGB_EXT caused the issue
313     glDisable(GL_FRAMEBUFFER_SRGB_EXT);
314 
315     // The issue involved framebuffers of two different sizes.
316     // The smaller needed to be drawn to, while the larger one could be just cleared
317     // to reproduce the issue. These are the smallest tested sizes that generated
318     // the validation error.
319     constexpr GLsizei kDimensionsSmall[] = {1, 1};
320     constexpr GLsizei kDimensionsLarge[] = {2, 2};
321     {
322         GLTexture texture;
323         glBindTexture(GL_TEXTURE_2D, texture.get());
324         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kDimensionsSmall[0], kDimensionsSmall[1]);
325         glBindTexture(GL_TEXTURE_2D, 0);
326 
327         GLFramebuffer framebuffer;
328         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
329         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(),
330                                0);
331 
332         unsigned char vertexData[] = {0};
333         GLBuffer vertexBuffer;
334         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
335         glBufferData(GL_ARRAY_BUFFER, sizeof(char), vertexData, GL_STATIC_DRAW);
336 
337         unsigned int indexData[] = {0};
338         GLBuffer indexBuffer;
339         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
340         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int), indexData, GL_STATIC_DRAW);
341 
342         glUseProgram(mProgram);
343 
344         glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
345 
346         EXPECT_GL_NO_ERROR();
347     }
348     {
349         GLTexture texture;
350         glBindTexture(GL_TEXTURE_2D, texture.get());
351         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kDimensionsLarge[0], kDimensionsLarge[1]);
352         glBindTexture(GL_TEXTURE_2D, 0);
353 
354         GLFramebuffer framebuffer;
355         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
356         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(),
357                                0);
358 
359         // Vulkan validation happened to fail here with:
360         // "Cannot execute a render pass with renderArea not within the bound of the framebuffer"
361         glClear(GL_COLOR_BUFFER_BIT);
362 
363         EXPECT_GL_NO_ERROR();
364     }
365 }
366 
367 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
368 // tests should be run against.
369 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SRGBFramebufferTest);
370 ANGLE_INSTANTIATE_TEST_ES3(SRGBFramebufferTestES3);
371 
372 }  // namespace angle
373