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