xref: /aosp_15_r20/external/angle/src/tests/gl_tests/SRGBTextureTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
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 
7 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9 
10 namespace angle
11 {
12 
13 // These two colors are equivelent in different colorspaces
14 constexpr GLColor kLinearColor(64, 127, 191, 255);
15 constexpr GLColor kNonlinearColor(13, 54, 133, 255);
16 
17 class SRGBTextureTest : public ANGLETest<>
18 {
19   protected:
SRGBTextureTest()20     SRGBTextureTest()
21     {
22         setWindowWidth(128);
23         setWindowHeight(128);
24         setConfigRedBits(8);
25         setConfigGreenBits(8);
26         setConfigBlueBits(8);
27         setConfigAlphaBits(8);
28     }
29 
testSetUp()30     void testSetUp() override
31     {
32         constexpr char kVS[] =
33             "precision highp float;\n"
34             "attribute vec4 position;\n"
35             "varying vec2 texcoord;\n"
36             "\n"
37             "void main()\n"
38             "{\n"
39             "   gl_Position = vec4(position.xy, 0.0, 1.0);\n"
40             "   texcoord = (position.xy * 0.5) + 0.5;\n"
41             "}\n";
42 
43         constexpr char kFS[] =
44             "precision highp float;\n"
45             "uniform sampler2D tex;\n"
46             "varying vec2 texcoord;\n"
47             "\n"
48             "void main()\n"
49             "{\n"
50             "   gl_FragColor = texture2D(tex, texcoord);\n"
51             "}\n";
52 
53         mProgram = CompileProgram(kVS, kFS);
54         ASSERT_NE(0u, mProgram);
55 
56         mTextureLocation = glGetUniformLocation(mProgram, "tex");
57         ASSERT_NE(-1, mTextureLocation);
58     }
59 
testTearDown()60     void testTearDown() override { glDeleteProgram(mProgram); }
61 
getSRGBA8TextureInternalFormat() const62     GLenum getSRGBA8TextureInternalFormat() const
63     {
64         return getClientMajorVersion() >= 3 ? GL_SRGB8_ALPHA8 : GL_SRGB_ALPHA_EXT;
65     }
66 
getSRGBA8TextureFormat() const67     GLenum getSRGBA8TextureFormat() const
68     {
69         return getClientMajorVersion() >= 3 ? GL_RGBA : GL_SRGB_ALPHA_EXT;
70     }
71 
getSRGB8TextureInternalFormat() const72     GLenum getSRGB8TextureInternalFormat() const
73     {
74         return getClientMajorVersion() >= 3 ? GL_SRGB8 : GL_SRGB_EXT;
75     }
76 
getSRGB8TextureFormat() const77     GLenum getSRGB8TextureFormat() const
78     {
79         return getClientMajorVersion() >= 3 ? GL_RGB : GL_SRGB_EXT;
80     }
81 
82     GLuint mProgram        = 0;
83     GLint mTextureLocation = -1;
84 };
85 
86 class SRGBTextureTestES3 : public SRGBTextureTest
87 {};
88 
89 // GenerateMipmaps should generate INVALID_OPERATION in ES 2.0 / WebGL 1.0 with EXT_sRGB.
90 // https://bugs.chromium.org/p/chromium/issues/detail?id=769989
TEST_P(SRGBTextureTest,SRGBValidation)91 TEST_P(SRGBTextureTest, SRGBValidation)
92 {
93     // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
94     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel() && IsOpenGLES());
95 
96     bool supported = IsGLExtensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;
97 
98     GLuint tex = 0;
99     glGenTextures(1, &tex);
100     glBindTexture(GL_TEXTURE_2D, tex);
101 
102     GLubyte pixel[3] = {0};
103     glTexImage2D(GL_TEXTURE_2D, 0, getSRGB8TextureInternalFormat(), 1, 1, 0,
104                  getSRGB8TextureFormat(), GL_UNSIGNED_BYTE, pixel);
105     if (supported)
106     {
107         EXPECT_GL_NO_ERROR();
108 
109         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSRGB8TextureFormat(), GL_UNSIGNED_BYTE,
110                         pixel);
111         EXPECT_GL_NO_ERROR();
112 
113         // Mipmap generation always generates errors for SRGB unsized in ES2 or SRGB8 sized in ES3.
114         glGenerateMipmap(GL_TEXTURE_2D);
115         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
116     }
117     else
118     {
119         EXPECT_GL_ERROR(GL_INVALID_ENUM);
120     }
121 
122     glDeleteTextures(1, &tex);
123 }
124 
TEST_P(SRGBTextureTest,SRGBAValidation)125 TEST_P(SRGBTextureTest, SRGBAValidation)
126 {
127     // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
128     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel() && IsOpenGLES());
129 
130     bool supported = IsGLExtensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;
131 
132     GLuint tex = 0;
133     glGenTextures(1, &tex);
134     glBindTexture(GL_TEXTURE_2D, tex);
135 
136     GLubyte pixel[4] = {0};
137     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
138                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, pixel);
139     if (supported)
140     {
141         EXPECT_GL_NO_ERROR();
142 
143         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE,
144                         pixel);
145         EXPECT_GL_NO_ERROR();
146 
147         glGenerateMipmap(GL_TEXTURE_2D);
148         if (getClientMajorVersion() < 3)
149         {
150             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
151         }
152         else
153         {
154             EXPECT_GL_NO_ERROR();
155         }
156     }
157     else
158     {
159         EXPECT_GL_ERROR(GL_INVALID_ENUM);
160     }
161 
162     glDeleteTextures(1, &tex);
163 }
164 
165 // Test that sized SRGBA formats allow generating mipmaps
TEST_P(SRGBTextureTestES3,SRGBASizedValidation)166 TEST_P(SRGBTextureTestES3, SRGBASizedValidation)
167 {
168     // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
169     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel() && IsOpenGLES());
170 
171     GLTexture tex;
172     glBindTexture(GL_TEXTURE_2D, tex);
173 
174     GLubyte pixel[4] = {0};
175     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
176                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, pixel);
177 
178     EXPECT_GL_NO_ERROR();
179 
180     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
181     EXPECT_GL_NO_ERROR();
182 
183     glGenerateMipmap(GL_TEXTURE_2D);
184     EXPECT_GL_NO_ERROR();
185 }
186 
TEST_P(SRGBTextureTest,SRGBARenderbuffer)187 TEST_P(SRGBTextureTest, SRGBARenderbuffer)
188 {
189     bool supported = IsGLExtensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;
190 
191     GLuint rbo = 0;
192     glGenRenderbuffers(1, &rbo);
193     glBindRenderbuffer(GL_RENDERBUFFER, rbo);
194 
195     glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8_ALPHA8_EXT, 1, 1);
196     if (supported)
197     {
198         EXPECT_GL_NO_ERROR();
199     }
200     else
201     {
202         EXPECT_GL_ERROR(GL_INVALID_ENUM);
203 
204         // Make sure the rbo has a size for future tests
205         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
206         EXPECT_GL_NO_ERROR();
207     }
208 
209     GLuint fbo = 0;
210     glGenFramebuffers(1, &fbo);
211     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
212     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
213     EXPECT_GL_NO_ERROR();
214 
215     GLint colorEncoding = 0;
216     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
217                                           GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT,
218                                           &colorEncoding);
219     if (supported)
220     {
221         EXPECT_GL_NO_ERROR();
222         EXPECT_EQ(GL_SRGB_EXT, colorEncoding);
223     }
224     else
225     {
226         EXPECT_GL_ERROR(GL_INVALID_ENUM);
227     }
228 
229     glDeleteFramebuffers(1, &fbo);
230     glDeleteRenderbuffers(1, &rbo);
231 }
232 
233 // Verify that if the srgb decode extension is available, srgb textures are too
TEST_P(SRGBTextureTest,SRGBDecodeExtensionAvailability)234 TEST_P(SRGBTextureTest, SRGBDecodeExtensionAvailability)
235 {
236     bool hasSRGBDecode = IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode");
237     if (hasSRGBDecode)
238     {
239         bool hasSRGBTextures = IsGLExtensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() >= 3;
240         EXPECT_TRUE(hasSRGBTextures);
241     }
242 }
243 
244 // Test basic functionality of SRGB decode using the texture parameter
TEST_P(SRGBTextureTest,SRGBDecodeTextureParameter)245 TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter)
246 {
247     // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
248     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel() && IsOpenGLES());
249 
250     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
251 
252     constexpr angle::GLColor srgbColor(64, 127, 191, 255);
253     constexpr angle::GLColor decodedToLinearColor(13, 54, 133, 255);
254 
255     GLTexture tex;
256     glBindTexture(GL_TEXTURE_2D, tex);
257     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
258                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, srgbColor.data());
259     ASSERT_GL_NO_ERROR();
260 
261     glUseProgram(mProgram);
262     glUniform1i(mTextureLocation, 0);
263     glDisable(GL_DEPTH_TEST);
264 
265     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
266     drawQuad(mProgram, "position", 0.5f);
267     EXPECT_PIXEL_COLOR_NEAR(0, 0, decodedToLinearColor, 1.0);
268 
269     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
270     drawQuad(mProgram, "position", 0.5f);
271     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
272 
273     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
274     drawQuad(mProgram, "position", 0.5f);
275     EXPECT_PIXEL_COLOR_NEAR(0, 0, decodedToLinearColor, 1.0);
276 }
277 
278 // Test interaction between SRGB decode and texelFetch
TEST_P(SRGBTextureTestES3,SRGBDecodeTexelFetch)279 TEST_P(SRGBTextureTestES3, SRGBDecodeTexelFetch)
280 {
281     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
282 
283     constexpr angle::GLColor srgbColor(64, 127, 191, 255);
284     constexpr angle::GLColor decodedToLinearColor(13, 54, 133, 255);
285 
286     constexpr char kTexelFetchFS[] = R"(#version 300 es
287 precision highp float;
288 precision highp int;
289 
290 uniform highp sampler2D tex;
291 
292 in vec4 v_position;
293 out vec4 my_FragColor;
294 
295 void main() {
296     ivec2 sampleCoords = ivec2(v_position.xy * 0.5 + 0.5);
297     my_FragColor = texelFetch(tex, sampleCoords, 0);
298 }
299 )";
300 
301     GLTexture tex;
302     glBindTexture(GL_TEXTURE_2D, tex);
303     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
304                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, srgbColor.data());
305     ASSERT_GL_NO_ERROR();
306 
307     glUseProgram(mProgram);
308     glUniform1i(mTextureLocation, 0);
309 
310     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
311     drawQuad(mProgram, "position", 0.5f);
312     EXPECT_PIXEL_COLOR_NEAR(0, 0, decodedToLinearColor, 1.0);
313 
314     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
315     drawQuad(mProgram, "position", 0.5f);
316     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
317 
318     ANGLE_GL_PROGRAM(texelFetchProgram, essl3_shaders::vs::Passthrough(), kTexelFetchFS);
319     glUseProgram(texelFetchProgram);
320     GLint texLocation = glGetUniformLocation(texelFetchProgram, "tex");
321     ASSERT_GE(texLocation, 0);
322     glUniform1i(texLocation, 0);
323 
324     drawQuad(texelFetchProgram, "a_position", 0.5f);
325     EXPECT_PIXEL_COLOR_NEAR(0, 0, decodedToLinearColor, 1.0);
326 }
327 
328 // Test basic functionality of SRGB override using the texture parameter
TEST_P(SRGBTextureTest,SRGBOverrideTextureParameter)329 TEST_P(SRGBTextureTest, SRGBOverrideTextureParameter)
330 {
331     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
332 
333     GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
334 
335     GLTexture tex;
336     glBindTexture(GL_TEXTURE_2D, tex);
337     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
338                  kLinearColor.data());
339     ASSERT_GL_NO_ERROR();
340 
341     glUseProgram(mProgram);
342     glUniform1i(mTextureLocation, 0);
343     glDisable(GL_DEPTH_TEST);
344 
345     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
346     drawQuad(mProgram, "position", 0.5f);
347     EXPECT_PIXEL_COLOR_NEAR(0, 0, kLinearColor, 1.0);
348 
349     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
350     drawQuad(mProgram, "position", 0.5f);
351     EXPECT_PIXEL_COLOR_NEAR(0, 0, kNonlinearColor, 1.0);
352 
353     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
354     drawQuad(mProgram, "position", 0.5f);
355     EXPECT_PIXEL_COLOR_NEAR(0, 0, kLinearColor, 1.0);
356 }
357 
358 // Test that all supported formats can be overridden
TEST_P(SRGBTextureTestES3,SRGBOverrideFormats)359 TEST_P(SRGBTextureTestES3, SRGBOverrideFormats)
360 {
361     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
362 
363     constexpr GLenum possibleFormats[] = {GL_RGB8,
364                                           GL_RGBA8,
365                                           GL_COMPRESSED_RGB8_ETC2,
366                                           GL_COMPRESSED_RGBA8_ETC2_EAC,
367                                           GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
368                                           GL_COMPRESSED_RGBA_ASTC_4x4,
369                                           GL_COMPRESSED_RGBA_ASTC_5x4,
370                                           GL_COMPRESSED_RGBA_ASTC_5x5,
371                                           GL_COMPRESSED_RGBA_ASTC_6x5,
372                                           GL_COMPRESSED_RGBA_ASTC_6x6,
373                                           GL_COMPRESSED_RGBA_ASTC_8x5,
374                                           GL_COMPRESSED_RGBA_ASTC_8x6,
375                                           GL_COMPRESSED_RGBA_ASTC_8x8,
376                                           GL_COMPRESSED_RGBA_ASTC_10x5,
377                                           GL_COMPRESSED_RGBA_ASTC_10x6,
378                                           GL_COMPRESSED_RGBA_ASTC_10x8,
379                                           GL_COMPRESSED_RGBA_ASTC_10x10,
380                                           GL_COMPRESSED_RGBA_ASTC_12x10,
381                                           GL_COMPRESSED_RGBA_ASTC_12x12,
382                                           GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
383                                           GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
384                                           GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
385                                           GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
386                                           GL_R8,
387                                           GL_RG8,
388                                           GL_COMPRESSED_RGBA_BPTC_UNORM_EXT};
389 
390     for (GLenum format : possibleFormats)
391     {
392         GLTexture tex;
393         glBindTexture(GL_TEXTURE_2D, tex);
394         glTexStorage2D(GL_TEXTURE_2D, 1, format, 4, 4);
395         GLenum error = glGetError();
396         if (error == GL_INVALID_ENUM)
397         {
398             // Format is not supported, we don't require the sRGB counterpart to be supported either
399             continue;
400         }
401         else
402         {
403             ASSERT_EQ(static_cast<GLenum>(GL_NO_ERROR), error);
404         }
405 
406         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
407         ASSERT_GL_NO_ERROR();
408 
409         glUseProgram(mProgram);
410         glUniform1i(mTextureLocation, 0);
411 
412         glDisable(GL_DEPTH_TEST);
413         drawQuad(mProgram, "position", 0.5f);
414         ASSERT_GL_NO_ERROR();
415         // Discard result, we are only checking that we don't try to reinterpret to an unsupported
416         // format
417     }
418 }
419 
420 // Test interaction between sRGB_override and sampler objects
TEST_P(SRGBTextureTestES3,SRGBOverrideTextureParameterWithSampler)421 TEST_P(SRGBTextureTestES3, SRGBOverrideTextureParameterWithSampler)
422 {
423     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
424 
425     GLColor linearColor = kLinearColor;
426     GLColor srgbColor   = kNonlinearColor;
427 
428     GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
429 
430     GLTexture tex;
431     glBindTexture(GL_TEXTURE_2D, tex);
432     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
433                  &linearColor);
434     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
435     ASSERT_GL_NO_ERROR();
436 
437     GLSampler sampler;
438     glBindSampler(0, sampler);
439 
440     glUseProgram(mProgram);
441     glUniform1i(mTextureLocation, 0);
442 
443     glDisable(GL_DEPTH_TEST);
444     drawQuad(mProgram, "position", 0.5f);
445 
446     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
447 
448     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
449     drawQuad(mProgram, "position", 0.5f);
450 
451     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
452 
453     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
454     drawQuad(mProgram, "position", 0.5f);
455 
456     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
457 }
458 
459 // Test that SRGB override is a noop when used on a nonlinear texture format
460 // EXT_texture_format_sRGB_override spec says:
461 // "If the internal format is not one of the above formats, then
462 // the value of TEXTURE_FORMAT_SRGB_OVERRIDE_EXT is ignored."
TEST_P(SRGBTextureTestES3,SRGBOverrideTextureParameterNoop)463 TEST_P(SRGBTextureTestES3, SRGBOverrideTextureParameterNoop)
464 {
465     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
466     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB"));
467 
468     GLColor linearColor = kLinearColor;
469     GLColor srgbColor   = kNonlinearColor;
470 
471     GLTexture tex;
472     glBindTexture(GL_TEXTURE_2D, tex);
473     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
474                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
475     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
476     ASSERT_GL_NO_ERROR();
477 
478     glUseProgram(mProgram);
479     glUniform1i(mTextureLocation, 0);
480 
481     glDisable(GL_DEPTH_TEST);
482     drawQuad(mProgram, "position", 0.5f);
483 
484     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
485 
486     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
487     drawQuad(mProgram, "position", 0.5f);
488 
489     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
490 }
491 
492 // Test basic functionality of SRGB decode using the sampler parameter
TEST_P(SRGBTextureTestES3,SRGBDecodeSamplerParameter)493 TEST_P(SRGBTextureTestES3, SRGBDecodeSamplerParameter)
494 {
495     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
496 
497     GLColor linearColor = kLinearColor;
498     GLColor srgbColor   = kNonlinearColor;
499 
500     GLTexture tex;
501     glBindTexture(GL_TEXTURE_2D, tex);
502     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
503                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
504     ASSERT_GL_NO_ERROR();
505 
506     GLSampler sampler;
507     glBindSampler(0, sampler);
508     glSamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
509 
510     glUseProgram(mProgram);
511     glUniform1i(mTextureLocation, 0);
512 
513     glDisable(GL_DEPTH_TEST);
514     drawQuad(mProgram, "position", 0.5f);
515 
516     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
517 
518     glSamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
519     drawQuad(mProgram, "position", 0.5f);
520 
521     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
522 }
523 
524 // Toggle between GL_DECODE_EXT and GL_SKIP_DECODE_EXT of sampler parameter
525 // GL_TEXTURE_SRGB_DECODE_EXT
TEST_P(SRGBTextureTestES3,SRGBDecodeSamplerParameterToggle)526 TEST_P(SRGBTextureTestES3, SRGBDecodeSamplerParameterToggle)
527 {
528     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
529 
530     GLColor linearColor = kLinearColor;
531     GLColor srgbColor   = kNonlinearColor;
532 
533     GLTexture tex;
534     glBindTexture(GL_TEXTURE_2D, tex);
535     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
536                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
537     ASSERT_GL_NO_ERROR();
538 
539     GLSampler sampler;
540     glBindSampler(0, sampler);
541 
542     glUseProgram(mProgram);
543     glUniform1i(mTextureLocation, 0);
544     glDisable(GL_DEPTH_TEST);
545 
546     for (int i = 0; i < 4; i++)
547     {
548         // Toggle betwee decode and skip decode and verify pixel value
549         GLint decode                  = ((i & 1) == 0) ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT;
550         angle::GLColor &expectedColor = ((i & 1) == 0) ? srgbColor : linearColor;
551 
552         glSamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, decode);
553         drawQuad(mProgram, "position", 0.5f);
554         EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedColor, 1.0);
555     }
556 }
557 
558 // Test that sampler state overrides texture state for srgb decode
TEST_P(SRGBTextureTestES3,SRGBDecodeTextureAndSamplerParameter)559 TEST_P(SRGBTextureTestES3, SRGBDecodeTextureAndSamplerParameter)
560 {
561     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
562 
563     GLColor linearColor = kLinearColor;
564     GLColor srgbColor   = kNonlinearColor;
565 
566     GLTexture tex;
567     glBindTexture(GL_TEXTURE_2D, tex);
568     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
569                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
570 
571     ASSERT_GL_NO_ERROR();
572 
573     GLSampler sampler;
574     glBindSampler(0, sampler);
575 
576     glUseProgram(mProgram);
577     glUniform1i(mTextureLocation, 0);
578 
579     glDisable(GL_DEPTH_TEST);
580 
581     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
582     glSamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
583     drawQuad(mProgram, "position", 0.5f);
584 
585     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
586 
587     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
588     glSamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
589     drawQuad(mProgram, "position", 0.5f);
590 
591     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
592 }
593 
594 // Test that srgb decode state takes priority over srgb override state
TEST_P(SRGBTextureTestES3,SRGBDecodeOverridePriority)595 TEST_P(SRGBTextureTestES3, SRGBDecodeOverridePriority)
596 {
597     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
598     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
599 
600     GLColor linearColor = kLinearColor;
601 
602     GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
603 
604     GLTexture tex;
605     glBindTexture(GL_TEXTURE_2D, tex);
606     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
607                  &linearColor);
608     ASSERT_GL_NO_ERROR();
609 
610     glUseProgram(mProgram);
611     glUniform1i(mTextureLocation, 0);
612 
613     glDisable(GL_DEPTH_TEST);
614 
615     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
616     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
617     drawQuad(mProgram, "position", 0.5f);
618 
619     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
620 }
621 
622 // Test that mipmaps are generated correctly for sRGB textures
TEST_P(SRGBTextureTestES3,GenerateMipmaps)623 TEST_P(SRGBTextureTestES3, GenerateMipmaps)
624 {
625     ANGLE_SKIP_TEST_IF(IsOpenGL() && ((IsIntel() && IsMac()) || IsAMD()));
626 
627     auto createAndReadBackTexture = [this](GLenum internalFormat, const GLColor &color) {
628         constexpr GLsizei width  = 128;
629         constexpr GLsizei height = 128;
630 
631         std::array<GLColor, width * height> buf;
632         std::fill(buf.begin(), buf.end(), color);
633 
634         // Set up-left region of the texture as red color.
635         // In order to make sure bi-linear interpolation operates on different colors, red region
636         // is 1 pixel smaller than a quarter of the full texture on each side.
637         constexpr GLsizei redWidth  = width / 2 - 1;
638         constexpr GLsizei redHeight = height / 2 - 1;
639         std::array<GLColor, redWidth * redHeight> redBuf;
640         std::fill(redBuf.begin(), redBuf.end(), GLColor::red);
641 
642         GLTexture tex;
643         glBindTexture(GL_TEXTURE_2D, tex);
644         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
645         glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
646                      buf.data());
647         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, redWidth, redHeight, GL_RGBA, GL_UNSIGNED_BYTE,
648                         redBuf.data());
649         glGenerateMipmap(GL_TEXTURE_2D);
650 
651         constexpr GLsizei drawWidth  = 32;
652         constexpr GLsizei drawHeight = 32;
653         glViewport(0, 0, drawWidth, drawHeight);
654 
655         drawQuad(mProgram, "position", 0.5f);
656 
657         std::array<GLColor, drawWidth * drawHeight> result;
658         glReadPixels(0, 0, drawWidth, drawHeight, GL_RGBA, GL_UNSIGNED_BYTE, result.data());
659 
660         EXPECT_GL_NO_ERROR();
661 
662         return result;
663     };
664 
665     GLColor srgbaColor(0, 63, 127, 255);
666     auto srgbaReadback = createAndReadBackTexture(GL_SRGB8_ALPHA8, srgbaColor);
667 
668     GLColor linearColor(0, 13, 54, 255);
669     auto rgbaReadback = createAndReadBackTexture(GL_RGBA8, linearColor);
670 
671     ASSERT_EQ(srgbaReadback.size(), rgbaReadback.size());
672     for (size_t i = 0; i < srgbaReadback.size(); i++)
673     {
674         constexpr double tolerence = 7.0;
675         EXPECT_COLOR_NEAR(srgbaReadback[i], rgbaReadback[i], tolerence);
676     }
677 }
678 
679 // Test that generated mip levels are correct for solid color textures
TEST_P(SRGBTextureTestES3,GenerateMipmapsSolid)680 TEST_P(SRGBTextureTestES3, GenerateMipmapsSolid)
681 {
682     GLColor color(7, 7, 7, 7);
683 
684     std::array<GLColor, 4 * 4> buf;
685     std::fill(buf.begin(), buf.end(), color);
686 
687     GLTexture tex;
688     glBindTexture(GL_TEXTURE_2D, tex);
689     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
690     glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf.data());
691     glGenerateMipmap(GL_TEXTURE_2D);
692     ASSERT_GL_NO_ERROR();
693 
694     GLFramebuffer fb;
695     glBindFramebuffer(GL_READ_FRAMEBUFFER, fb);
696     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 1);
697     ASSERT_GL_NO_ERROR();
698 
699     EXPECT_PIXEL_COLOR_NEAR(0, 0, color, 1);
700 }
701 
702 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SRGBTextureTest);
703 
704 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SRGBTextureTestES3);
705 ANGLE_INSTANTIATE_TEST_ES3(SRGBTextureTestES3);
706 
707 }  // namespace angle
708