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     GLColor linearColor = kLinearColor;
253     GLColor srgbColor   = kNonlinearColor;
254 
255     GLTexture tex;
256     glBindTexture(GL_TEXTURE_2D, tex.get());
257     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
258                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
259     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
260     ASSERT_GL_NO_ERROR();
261 
262     glUseProgram(mProgram);
263     glUniform1i(mTextureLocation, 0);
264 
265     glDisable(GL_DEPTH_TEST);
266     drawQuad(mProgram, "position", 0.5f);
267 
268     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
269 
270     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
271     drawQuad(mProgram, "position", 0.5f);
272 
273     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
274 }
275 
276 // Test basic functionality of SRGB override using the texture parameter
TEST_P(SRGBTextureTest,SRGBOverrideTextureParameter)277 TEST_P(SRGBTextureTest, SRGBOverrideTextureParameter)
278 {
279     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
280 
281     GLColor linearColor = kLinearColor;
282     GLColor srgbColor   = kNonlinearColor;
283 
284     GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
285 
286     GLTexture tex;
287     glBindTexture(GL_TEXTURE_2D, tex.get());
288     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
289                  &linearColor);
290     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
291     ASSERT_GL_NO_ERROR();
292 
293     glUseProgram(mProgram);
294     glUniform1i(mTextureLocation, 0);
295 
296     glDisable(GL_DEPTH_TEST);
297     drawQuad(mProgram, "position", 0.5f);
298 
299     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
300 
301     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
302     drawQuad(mProgram, "position", 0.5f);
303 
304     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
305 }
306 
307 // Test that all supported formats can be overridden
TEST_P(SRGBTextureTestES3,SRGBOverrideFormats)308 TEST_P(SRGBTextureTestES3, SRGBOverrideFormats)
309 {
310     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
311 
312     constexpr GLenum possibleFormats[] = {GL_RGB8,
313                                           GL_RGBA8,
314                                           GL_COMPRESSED_RGB8_ETC2,
315                                           GL_COMPRESSED_RGBA8_ETC2_EAC,
316                                           GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
317                                           GL_COMPRESSED_RGBA_ASTC_4x4,
318                                           GL_COMPRESSED_RGBA_ASTC_5x4,
319                                           GL_COMPRESSED_RGBA_ASTC_5x5,
320                                           GL_COMPRESSED_RGBA_ASTC_6x5,
321                                           GL_COMPRESSED_RGBA_ASTC_6x6,
322                                           GL_COMPRESSED_RGBA_ASTC_8x5,
323                                           GL_COMPRESSED_RGBA_ASTC_8x6,
324                                           GL_COMPRESSED_RGBA_ASTC_8x8,
325                                           GL_COMPRESSED_RGBA_ASTC_10x5,
326                                           GL_COMPRESSED_RGBA_ASTC_10x6,
327                                           GL_COMPRESSED_RGBA_ASTC_10x8,
328                                           GL_COMPRESSED_RGBA_ASTC_10x10,
329                                           GL_COMPRESSED_RGBA_ASTC_12x10,
330                                           GL_COMPRESSED_RGBA_ASTC_12x12,
331                                           GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
332                                           GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
333                                           GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
334                                           GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
335                                           GL_R8,
336                                           GL_RG8,
337                                           GL_COMPRESSED_RGBA_BPTC_UNORM_EXT};
338 
339     for (GLenum format : possibleFormats)
340     {
341         GLTexture tex;
342         glBindTexture(GL_TEXTURE_2D, tex.get());
343         glTexStorage2D(GL_TEXTURE_2D, 1, format, 1, 1);
344         GLenum error = glGetError();
345         if (error == GL_INVALID_ENUM)
346         {
347             // Format is not supported, we don't require the sRGB counterpart to be supported either
348             continue;
349         }
350         else
351         {
352             ASSERT_EQ(static_cast<GLenum>(GL_NO_ERROR), error);
353         }
354 
355         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
356         ASSERT_GL_NO_ERROR();
357 
358         glUseProgram(mProgram);
359         glUniform1i(mTextureLocation, 0);
360 
361         glDisable(GL_DEPTH_TEST);
362         drawQuad(mProgram, "position", 0.5f);
363         ASSERT_GL_NO_ERROR();
364         // Discard result, we are only checking that we don't try to reinterpret to an unsupported
365         // format
366     }
367 }
368 
369 // Test interaction between sRGB_override and sampler objects
TEST_P(SRGBTextureTestES3,SRGBOverrideTextureParameterWithSampler)370 TEST_P(SRGBTextureTestES3, SRGBOverrideTextureParameterWithSampler)
371 {
372     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
373 
374     GLColor linearColor = kLinearColor;
375     GLColor srgbColor   = kNonlinearColor;
376 
377     GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
378 
379     GLTexture tex;
380     glBindTexture(GL_TEXTURE_2D, tex.get());
381     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
382                  &linearColor);
383     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
384     ASSERT_GL_NO_ERROR();
385 
386     GLSampler sampler;
387     glBindSampler(0, sampler.get());
388 
389     glUseProgram(mProgram);
390     glUniform1i(mTextureLocation, 0);
391 
392     glDisable(GL_DEPTH_TEST);
393     drawQuad(mProgram, "position", 0.5f);
394 
395     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
396 
397     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
398     drawQuad(mProgram, "position", 0.5f);
399 
400     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
401 
402     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
403     drawQuad(mProgram, "position", 0.5f);
404 
405     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
406 }
407 
408 // Test that SRGB override is a noop when used on a nonlinear texture format
409 // EXT_texture_format_sRGB_override spec says:
410 // "If the internal format is not one of the above formats, then
411 // the value of TEXTURE_FORMAT_SRGB_OVERRIDE_EXT is ignored."
TEST_P(SRGBTextureTestES3,SRGBOverrideTextureParameterNoop)412 TEST_P(SRGBTextureTestES3, SRGBOverrideTextureParameterNoop)
413 {
414     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
415     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB"));
416 
417     GLColor linearColor = kLinearColor;
418     GLColor srgbColor   = kNonlinearColor;
419 
420     GLTexture tex;
421     glBindTexture(GL_TEXTURE_2D, tex.get());
422     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
423                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
424     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
425     ASSERT_GL_NO_ERROR();
426 
427     glUseProgram(mProgram);
428     glUniform1i(mTextureLocation, 0);
429 
430     glDisable(GL_DEPTH_TEST);
431     drawQuad(mProgram, "position", 0.5f);
432 
433     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
434 
435     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
436     drawQuad(mProgram, "position", 0.5f);
437 
438     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
439 }
440 
441 // Test basic functionality of SRGB decode using the sampler parameter
TEST_P(SRGBTextureTestES3,SRGBDecodeSamplerParameter)442 TEST_P(SRGBTextureTestES3, SRGBDecodeSamplerParameter)
443 {
444     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
445 
446     GLColor linearColor = kLinearColor;
447     GLColor srgbColor   = kNonlinearColor;
448 
449     GLTexture tex;
450     glBindTexture(GL_TEXTURE_2D, tex.get());
451     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
452                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
453     ASSERT_GL_NO_ERROR();
454 
455     GLSampler sampler;
456     glBindSampler(0, sampler.get());
457     glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
458 
459     glUseProgram(mProgram);
460     glUniform1i(mTextureLocation, 0);
461 
462     glDisable(GL_DEPTH_TEST);
463     drawQuad(mProgram, "position", 0.5f);
464 
465     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
466 
467     glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
468     drawQuad(mProgram, "position", 0.5f);
469 
470     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
471 }
472 
473 // Toggle between GL_DECODE_EXT and GL_SKIP_DECODE_EXT of sampler parameter
474 // GL_TEXTURE_SRGB_DECODE_EXT
TEST_P(SRGBTextureTestES3,SRGBDecodeSamplerParameterToggle)475 TEST_P(SRGBTextureTestES3, SRGBDecodeSamplerParameterToggle)
476 {
477     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
478 
479     GLColor linearColor = kLinearColor;
480     GLColor srgbColor   = kNonlinearColor;
481 
482     GLTexture tex;
483     glBindTexture(GL_TEXTURE_2D, tex.get());
484     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
485                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
486     ASSERT_GL_NO_ERROR();
487 
488     GLSampler sampler;
489     glBindSampler(0, sampler.get());
490 
491     glUseProgram(mProgram);
492     glUniform1i(mTextureLocation, 0);
493     glDisable(GL_DEPTH_TEST);
494 
495     for (int i = 0; i < 4; i++)
496     {
497         // Toggle betwee decode and skip decode and verify pixel value
498         GLint decode                  = ((i & 1) == 0) ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT;
499         angle::GLColor &expectedColor = ((i & 1) == 0) ? srgbColor : linearColor;
500 
501         glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, decode);
502         drawQuad(mProgram, "position", 0.5f);
503         EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedColor, 1.0);
504     }
505 }
506 
507 // Test that sampler state overrides texture state for srgb decode
TEST_P(SRGBTextureTestES3,SRGBDecodeTextureAndSamplerParameter)508 TEST_P(SRGBTextureTestES3, SRGBDecodeTextureAndSamplerParameter)
509 {
510     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
511 
512     GLColor linearColor = kLinearColor;
513     GLColor srgbColor   = kNonlinearColor;
514 
515     GLTexture tex;
516     glBindTexture(GL_TEXTURE_2D, tex.get());
517     glTexImage2D(GL_TEXTURE_2D, 0, getSRGBA8TextureInternalFormat(), 1, 1, 0,
518                  getSRGBA8TextureFormat(), GL_UNSIGNED_BYTE, &linearColor);
519 
520     ASSERT_GL_NO_ERROR();
521 
522     GLSampler sampler;
523     glBindSampler(0, sampler.get());
524 
525     glUseProgram(mProgram);
526     glUniform1i(mTextureLocation, 0);
527 
528     glDisable(GL_DEPTH_TEST);
529 
530     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
531     glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
532     drawQuad(mProgram, "position", 0.5f);
533 
534     EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);
535 
536     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
537     glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
538     drawQuad(mProgram, "position", 0.5f);
539 
540     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
541 }
542 
543 // Test that srgb decode state takes priority over srgb override state
TEST_P(SRGBTextureTestES3,SRGBDecodeOverridePriority)544 TEST_P(SRGBTextureTestES3, SRGBDecodeOverridePriority)
545 {
546     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_sRGB_decode"));
547     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
548 
549     GLColor linearColor = kLinearColor;
550 
551     GLenum internalFormat = getClientMajorVersion() >= 3 ? GL_RGBA8 : GL_RGBA;
552 
553     GLTexture tex;
554     glBindTexture(GL_TEXTURE_2D, tex.get());
555     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
556                  &linearColor);
557     ASSERT_GL_NO_ERROR();
558 
559     glUseProgram(mProgram);
560     glUniform1i(mTextureLocation, 0);
561 
562     glDisable(GL_DEPTH_TEST);
563 
564     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
565     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
566     drawQuad(mProgram, "position", 0.5f);
567 
568     EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
569 }
570 
571 // Test that mipmaps are generated correctly for sRGB textures
TEST_P(SRGBTextureTestES3,GenerateMipmaps)572 TEST_P(SRGBTextureTestES3, GenerateMipmaps)
573 {
574     ANGLE_SKIP_TEST_IF(IsOpenGL() && ((IsIntel() && IsOSX()) || IsAMD()));
575 
576     // http://anglebug.com/5108
577     ANGLE_SKIP_TEST_IF(IsMetal());
578 
579     auto createAndReadBackTexture = [this](GLenum internalFormat, const GLColor &color) {
580         constexpr GLsizei width  = 128;
581         constexpr GLsizei height = 128;
582 
583         std::array<GLColor, width * height> buf;
584         std::fill(buf.begin(), buf.end(), color);
585 
586         // Set up-left region of the texture as red color.
587         // In order to make sure bi-linear interpolation operates on different colors, red region
588         // is 1 pixel smaller than a quarter of the full texture on each side.
589         constexpr GLsizei redWidth  = width / 2 - 1;
590         constexpr GLsizei redHeight = height / 2 - 1;
591         std::array<GLColor, redWidth * redHeight> redBuf;
592         std::fill(redBuf.begin(), redBuf.end(), GLColor::red);
593 
594         GLTexture tex;
595         glBindTexture(GL_TEXTURE_2D, tex.get());
596         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
597         glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
598                      buf.data());
599         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, redWidth, redHeight, GL_RGBA, GL_UNSIGNED_BYTE,
600                         redBuf.data());
601         glGenerateMipmap(GL_TEXTURE_2D);
602 
603         constexpr GLsizei drawWidth  = 32;
604         constexpr GLsizei drawHeight = 32;
605         glViewport(0, 0, drawWidth, drawHeight);
606 
607         drawQuad(mProgram, "position", 0.5f);
608 
609         std::array<GLColor, drawWidth * drawHeight> result;
610         glReadPixels(0, 0, drawWidth, drawHeight, GL_RGBA, GL_UNSIGNED_BYTE, result.data());
611 
612         EXPECT_GL_NO_ERROR();
613 
614         return result;
615     };
616 
617     GLColor srgbaColor(0, 63, 127, 255);
618     auto srgbaReadback = createAndReadBackTexture(GL_SRGB8_ALPHA8, srgbaColor);
619 
620     GLColor linearColor(0, 13, 54, 255);
621     auto rgbaReadback = createAndReadBackTexture(GL_RGBA8, linearColor);
622 
623     ASSERT_EQ(srgbaReadback.size(), rgbaReadback.size());
624     for (size_t i = 0; i < srgbaReadback.size(); i++)
625     {
626         constexpr double tolerence = 7.0;
627         EXPECT_COLOR_NEAR(srgbaReadback[i], rgbaReadback[i], tolerence);
628     }
629 }
630 
631 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SRGBTextureTest);
632 
633 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SRGBTextureTestES3);
634 ANGLE_INSTANTIATE_TEST_ES3(SRGBTextureTestES3);
635 
636 }  // namespace angle
637