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