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 // SixteenBppTextureTest:
7 // Basic tests using 16bpp texture formats (e.g. GL_RGB565).
8
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11
12 #include "image_util/imageformats.h"
13
14 using namespace angle;
15
16 namespace
17 {
18
Convert565(const R5G6B5 & rgb565)19 GLColor Convert565(const R5G6B5 &rgb565)
20 {
21 gl::ColorF colorf;
22 R5G6B5::readColor(&colorf, &rgb565);
23 Vector4 vecColor(colorf.red, colorf.green, colorf.blue, colorf.alpha);
24 return GLColor(vecColor);
25 }
26
Convert565(const GLColor & glColor)27 R5G6B5 Convert565(const GLColor &glColor)
28 {
29 const Vector4 &vecColor = glColor.toNormalizedVector();
30 gl::ColorF colorf(vecColor.x(), vecColor.y(), vecColor.z(), vecColor.w());
31 R5G6B5 rgb565;
32 R5G6B5::writeColor(&rgb565, &colorf);
33 return rgb565;
34 }
35
36 class SixteenBppTextureTest : public ANGLETest<>
37 {
38 protected:
SixteenBppTextureTest()39 SixteenBppTextureTest()
40 {
41 setWindowWidth(128);
42 setWindowHeight(128);
43 setConfigRedBits(8);
44 setConfigGreenBits(8);
45 setConfigBlueBits(8);
46 setConfigAlphaBits(8);
47 }
48
testSetUp()49 void testSetUp() override
50 {
51 constexpr char kVS[] = R"(precision highp float;
52 attribute vec4 position;
53 varying vec2 texcoord;
54
55 void main()
56 {
57 gl_Position = vec4(position.xy, 0.0, 1.0);
58 texcoord = (position.xy * 0.5) + 0.5;
59 })";
60
61 constexpr char kFS[] = R"(precision highp float;
62 uniform sampler2D tex;
63 varying vec2 texcoord;
64
65 void main()
66 {
67 gl_FragColor = texture2D(tex, texcoord);
68 })";
69
70 m2DProgram = CompileProgram(kVS, kFS);
71 mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex");
72 }
73
testTearDown()74 void testTearDown() override { glDeleteProgram(m2DProgram); }
75
simpleValidationBase(GLuint tex)76 void simpleValidationBase(GLuint tex)
77 {
78 // Draw a quad using the texture
79 glClear(GL_COLOR_BUFFER_BIT);
80 glUseProgram(m2DProgram);
81 glUniform1i(mTexture2DUniformLocation, 0);
82 drawQuad(m2DProgram, "position", 0.5f);
83 ASSERT_GL_NO_ERROR();
84
85 int w = getWindowWidth() - 1;
86 int h = getWindowHeight() - 1;
87
88 // Check that it drew as expected
89 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
90 EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
91 EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
92 EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
93
94 // Generate mipmaps
95 glGenerateMipmap(GL_TEXTURE_2D);
96
97 // Draw a quad using the texture
98 glClear(GL_COLOR_BUFFER_BIT);
99 glUseProgram(m2DProgram);
100 glUniform1i(mTexture2DUniformLocation, 0);
101 drawQuad(m2DProgram, "position", 0.5f);
102 ASSERT_GL_NO_ERROR();
103
104 // Check that it drew as expected
105 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
106 EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
107 EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
108 EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
109
110 // Bind the texture as a framebuffer, render to it, then check the results
111 GLFramebuffer fbo;
112 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
113 glBindTexture(GL_TEXTURE_2D, 0);
114 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
115
116 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_UNSUPPORTED)
117 {
118 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
119 glClear(GL_COLOR_BUFFER_BIT);
120 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
121 EXPECT_PIXEL_EQ(1, 0, 255, 0, 0, 255);
122 EXPECT_PIXEL_EQ(1, 1, 255, 0, 0, 255);
123 EXPECT_PIXEL_EQ(0, 1, 255, 0, 0, 255);
124 }
125 else
126 {
127 std::cout << "Skipping rendering to an unsupported framebuffer format" << std::endl;
128 }
129 }
130
131 GLuint m2DProgram;
132 GLint mTexture2DUniformLocation;
133 };
134
135 class SixteenBppTextureTestES3 : public SixteenBppTextureTest
136 {};
137
138 // Simple validation test for GL_RGB565 textures.
139 // Samples from the texture, renders to it, generates mipmaps etc.
TEST_P(SixteenBppTextureTest,RGB565Validation)140 TEST_P(SixteenBppTextureTest, RGB565Validation)
141 {
142 GLuint test;
143 memcpy(&test, &GLColor::black, 4);
144
145 R5G6B5 pixels[4] = {Convert565(GLColor::red), Convert565(GLColor::green),
146 Convert565(GLColor::blue), Convert565(GLColor::yellow)};
147
148 glClearColor(0, 0, 0, 0);
149
150 // Create a simple RGB565 texture
151 GLTexture tex;
152 glBindTexture(GL_TEXTURE_2D, tex);
153 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, nullptr);
154 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
155 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
156 EXPECT_GL_NO_ERROR();
157
158 // Supply the data to it
159 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
160 EXPECT_GL_NO_ERROR();
161
162 simpleValidationBase(tex);
163 }
164
165 // Simple validation test for GL_RGB5_A1 textures.
166 // Samples from the texture, renders to it, generates mipmaps etc.
TEST_P(SixteenBppTextureTest,RGBA5551Validation)167 TEST_P(SixteenBppTextureTest, RGBA5551Validation)
168 {
169 GLushort pixels[4] = {
170 0xF801, // Red
171 0x07C1, // Green
172 0x003F, // Blue
173 0xFFC1 // Red + Green
174 };
175
176 // Create a simple 5551 texture
177 GLTexture tex;
178 glBindTexture(GL_TEXTURE_2D, tex);
179 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, nullptr);
180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
181 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
182 EXPECT_GL_NO_ERROR();
183
184 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixels);
185 EXPECT_GL_NO_ERROR();
186
187 simpleValidationBase(tex);
188 }
189
190 // Test to ensure calling Clear() on an RGBA5551 texture does something reasonable
191 // Based on WebGL test conformance/textures/texture-attachment-formats.html
TEST_P(SixteenBppTextureTest,RGBA5551ClearAlpha)192 TEST_P(SixteenBppTextureTest, RGBA5551ClearAlpha)
193 {
194 GLTexture tex;
195 GLFramebuffer fbo;
196
197 // Create a simple 5551 texture
198 glBindTexture(GL_TEXTURE_2D, tex);
199 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, nullptr);
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
202 EXPECT_GL_NO_ERROR();
203
204 // Bind the texture as a framebuffer, clear it, then check the results
205 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
206 glBindTexture(GL_TEXTURE_2D, 0);
207 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
208
209 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_UNSUPPORTED)
210 {
211 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
212 glClear(GL_COLOR_BUFFER_BIT);
213 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
214
215 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
216 glClear(GL_COLOR_BUFFER_BIT);
217 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 255);
218 }
219 else
220 {
221 std::cout << "Skipping rendering to an unsupported framebuffer format" << std::endl;
222 }
223 }
224
225 // Simple validation test for GL_RGBA4 textures.
226 // Samples from the texture, renders to it, generates mipmaps etc.
TEST_P(SixteenBppTextureTest,RGBA4444Validation)227 TEST_P(SixteenBppTextureTest, RGBA4444Validation)
228 {
229 GLushort pixels[4] = {
230 0xF00F, // Red
231 0x0F0F, // Green
232 0x00FF, // Blue
233 0xFF0F // Red + Green
234 };
235
236 glClearColor(0, 0, 0, 0);
237
238 // Generate a RGBA4444 texture, no mipmaps
239 GLTexture tex;
240 glBindTexture(GL_TEXTURE_2D, tex);
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, nullptr);
242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
243 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
244 EXPECT_GL_NO_ERROR();
245
246 // Provide some data for the texture
247 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixels);
248 EXPECT_GL_NO_ERROR();
249
250 simpleValidationBase(tex);
251 }
252
253 // Test uploading RGBA8 data to RGBA4 textures.
TEST_P(SixteenBppTextureTestES3,RGBA4UploadRGBA8)254 TEST_P(SixteenBppTextureTestES3, RGBA4UploadRGBA8)
255 {
256 const std::array<GLColor, 4> kFourColors = {
257 {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
258
259 GLTexture tex;
260 glBindTexture(GL_TEXTURE_2D, tex);
261 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
262 kFourColors.data());
263 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
264 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
265 ASSERT_GL_NO_ERROR();
266 simpleValidationBase(tex);
267 }
268
269 // Test uploading RGB8 data to RGB565 textures.
TEST_P(SixteenBppTextureTestES3,RGB565UploadRGB8)270 TEST_P(SixteenBppTextureTestES3, RGB565UploadRGB8)
271 {
272 std::vector<GLColorRGB> fourColors;
273 fourColors.push_back(GLColorRGB::red);
274 fourColors.push_back(GLColorRGB::green);
275 fourColors.push_back(GLColorRGB::blue);
276 fourColors.push_back(GLColorRGB::yellow);
277
278 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
279
280 GLTexture tex;
281 glBindTexture(GL_TEXTURE_2D, tex);
282 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, fourColors.data());
283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
285 ASSERT_GL_NO_ERROR();
286
287 simpleValidationBase(tex);
288 }
289
290 // Test uploading RGBA8 data to RGB5A41 textures.
TEST_P(SixteenBppTextureTestES3,RGB5A1UploadRGBA8)291 TEST_P(SixteenBppTextureTestES3, RGB5A1UploadRGBA8)
292 {
293 std::vector<GLColor> fourColors;
294 fourColors.push_back(GLColor::red);
295 fourColors.push_back(GLColor::green);
296 fourColors.push_back(GLColor::blue);
297 fourColors.push_back(GLColor::yellow);
298
299 GLTexture tex;
300 glBindTexture(GL_TEXTURE_2D, tex);
301 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
302 fourColors.data());
303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
305 ASSERT_GL_NO_ERROR();
306 simpleValidationBase(tex);
307 }
308
309 // Test uploading RGB10A2 data to RGB5A1 textures.
TEST_P(SixteenBppTextureTestES3,RGB5A1UploadRGB10A2)310 TEST_P(SixteenBppTextureTestES3, RGB5A1UploadRGB10A2)
311 {
312 struct RGB10A2
313 {
314 RGB10A2(uint32_t r, uint32_t g, uint32_t b, uint32_t a) : R(r), G(g), B(b), A(a) {}
315
316 uint32_t R : 10;
317 uint32_t G : 10;
318 uint32_t B : 10;
319 uint32_t A : 2;
320 };
321
322 uint32_t one10 = (1u << 10u) - 1u;
323
324 RGB10A2 red(one10, 0u, 0u, 0x3u);
325 RGB10A2 green(0u, one10, 0u, 0x3u);
326 RGB10A2 blue(0u, 0u, one10, 0x3u);
327 RGB10A2 yellow(one10, one10, 0u, 0x3u);
328
329 std::vector<RGB10A2> fourColors;
330 fourColors.push_back(red);
331 fourColors.push_back(green);
332 fourColors.push_back(blue);
333 fourColors.push_back(yellow);
334
335 GLTexture tex;
336 glBindTexture(GL_TEXTURE_2D, tex);
337 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 2, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV,
338 fourColors.data());
339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
341 ASSERT_GL_NO_ERROR();
342 simpleValidationBase(tex);
343 }
344
345 // Test reading from RGBA4 textures attached to FBO.
TEST_P(SixteenBppTextureTestES3,RGBA4FramebufferReadback)346 TEST_P(SixteenBppTextureTestES3, RGBA4FramebufferReadback)
347 {
348 // TODO(jmadill): Fix bug with GLES
349 ANGLE_SKIP_TEST_IF(IsOpenGLES());
350
351 Vector4 rawColor(0.5f, 0.7f, 1.0f, 0.0f);
352 GLColor expectedColor(rawColor);
353
354 GLFramebuffer fbo;
355 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
356
357 GLTexture tex;
358 glBindTexture(GL_TEXTURE_2D, tex);
359 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
360 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
361
362 glClearColor(rawColor.x(), rawColor.y(), rawColor.z(), rawColor.w());
363 glClear(GL_COLOR_BUFFER_BIT);
364
365 ASSERT_GL_NO_ERROR();
366
367 GLenum colorReadFormat = GL_NONE;
368 GLenum colorReadType = GL_NONE;
369 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, reinterpret_cast<GLint *>(&colorReadFormat));
370 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, reinterpret_cast<GLint *>(&colorReadType));
371
372 if (colorReadFormat == GL_RGBA && colorReadType == GL_UNSIGNED_BYTE)
373 {
374 GLColor actualColor = GLColor::black;
375 glReadPixels(0, 0, 1, 1, colorReadFormat, colorReadType, &actualColor);
376 EXPECT_COLOR_NEAR(expectedColor, actualColor, 20);
377 }
378 else
379 {
380 ASSERT_GLENUM_EQ(GL_RGBA, colorReadFormat);
381 ASSERT_TRUE(colorReadType == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT ||
382 colorReadType == GL_UNSIGNED_SHORT_4_4_4_4);
383
384 uint16_t rgba = 0;
385 glReadPixels(0, 0, 1, 1, colorReadFormat, colorReadType, &rgba);
386
387 GLubyte r8 = static_cast<GLubyte>((rgba & 0xF000) >> 12);
388 GLubyte g8 = static_cast<GLubyte>((rgba & 0x0F00) >> 8);
389 GLubyte b8 = static_cast<GLubyte>((rgba & 0x00F0) >> 4);
390 GLubyte a8 = static_cast<GLubyte>((rgba & 0x000F));
391
392 GLColor actualColor(r8 << 4, g8 << 4, b8 << 4, a8 << 4);
393 EXPECT_COLOR_NEAR(expectedColor, actualColor, 20);
394 }
395
396 ASSERT_GL_NO_ERROR();
397 }
398
399 // Test reading from RGB565 textures attached to FBO.
TEST_P(SixteenBppTextureTestES3,RGB565FramebufferReadback)400 TEST_P(SixteenBppTextureTestES3, RGB565FramebufferReadback)
401 {
402 // TODO(jmadill): Fix bug with GLES
403 ANGLE_SKIP_TEST_IF(IsOpenGLES());
404
405 GLFramebuffer fbo;
406 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
407
408 std::vector<GLColor> fourColors;
409 fourColors.push_back(GLColor::red);
410 fourColors.push_back(GLColor::green);
411 fourColors.push_back(GLColor::blue);
412 fourColors.push_back(GLColor::white);
413
414 constexpr char kVS[] =
415 "#version 300 es\n"
416 "in vec4 color;\n"
417 "in vec2 position;\n"
418 "out vec4 fcolor;\n"
419 "void main() {\n"
420 " fcolor = color;\n"
421 " gl_Position = vec4(position, 0.5, 1.0);\n"
422 "}";
423 constexpr char kFS[] =
424 "#version 300 es\n"
425 "in mediump vec4 fcolor;\n"
426 "out mediump vec4 color;\n"
427 "void main() {\n"
428 " color = fcolor;\n"
429 "}";
430
431 GLuint program = CompileProgram(kVS, kFS);
432 glUseProgram(program);
433
434 GLint colorLocation = glGetAttribLocation(program, "color");
435 ASSERT_NE(-1, colorLocation);
436 glEnableVertexAttribArray(colorLocation);
437 glVertexAttribPointer(colorLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, fourColors.data());
438
439 int w = getWindowWidth();
440 int h = getWindowHeight();
441
442 glViewport(0, 0, w, h);
443
444 GLTexture tex;
445 glBindTexture(GL_TEXTURE_2D, tex);
446 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
447 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
448
449 drawIndexedQuad(program, "position", 0.5f);
450
451 ASSERT_GL_NO_ERROR();
452
453 int t = 12;
454 EXPECT_PIXEL_COLOR_NEAR(0, h - 1, GLColor::red, t);
455 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::green, t);
456 EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, GLColor::blue, t);
457 EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, GLColor::white, t);
458
459 GLenum colorReadFormat = GL_NONE;
460 GLenum colorReadType = GL_NONE;
461 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, reinterpret_cast<GLint *>(&colorReadFormat));
462 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, reinterpret_cast<GLint *>(&colorReadType));
463
464 if (colorReadFormat == GL_RGB && colorReadType == GL_UNSIGNED_SHORT_5_6_5)
465 {
466 std::vector<R5G6B5> readColors(w * h);
467 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, readColors.data());
468
469 int hoffset = (h - 1) * w;
470 EXPECT_COLOR_NEAR(GLColor::red, Convert565(readColors[hoffset]), t);
471 EXPECT_COLOR_NEAR(GLColor::green, Convert565(readColors[0]), t);
472 EXPECT_COLOR_NEAR(GLColor::blue, Convert565(readColors[w - 1]), t);
473 EXPECT_COLOR_NEAR(GLColor::white, Convert565(readColors[w - 1 + hoffset]), t);
474 }
475
476 glDeleteProgram(program);
477 }
478
479 class SixteenBppTextureDitheringTestES3 : public SixteenBppTextureTestES3
480 {
481 protected:
SixteenBppTextureDitheringTestES3()482 SixteenBppTextureDitheringTestES3()
483 {
484 setWindowWidth(512);
485 setWindowHeight(512);
486 setConfigRedBits(8);
487 setConfigGreenBits(8);
488 setConfigBlueBits(8);
489 setConfigAlphaBits(8);
490 }
491
492 enum class Gradient
493 {
494 RedGreen,
495 RedBlue,
496 GreenBlue,
497 };
498
makeVS(Gradient gradient)499 std::string makeVS(Gradient gradient)
500 {
501 std::ostringstream vs;
502 vs << R"(#version 300 es
503 out mediump vec4 color;
504 void main()
505 {
506 // gl_VertexID x y
507 // 0 -1 -1 Black
508 // 1 1 -1 Red
509 // 2 -1 1 Green
510 // 3 1 1 Yellow
511 int bit0 = gl_VertexID & 1;
512 int bit1 = gl_VertexID >> 1;
513 gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1);
514 color = )";
515 switch (gradient)
516 {
517 case Gradient::RedGreen:
518 vs << "vec4(bit0, bit1, 0, 1)";
519 break;
520 case Gradient::RedBlue:
521 vs << "vec4(bit1, 0, bit0, 1)";
522 break;
523 case Gradient::GreenBlue:
524 vs << "vec4(0, bit0, bit1, 1)";
525 break;
526 }
527 vs << R"(;
528 })";
529
530 return vs.str();
531 }
532
getFS()533 const char *getFS()
534 {
535 return R"(#version 300 es
536 precision mediump float;
537 in vec4 color;
538 out vec4 colorOut;
539 void main()
540 {
541 colorOut = color;
542 })";
543 }
544
getRightColor(Gradient gradient)545 GLColor getRightColor(Gradient gradient)
546 {
547 switch (gradient)
548 {
549 case Gradient::RedGreen:
550 return GLColor::red;
551 case Gradient::RedBlue:
552 return GLColor::blue;
553 case Gradient::GreenBlue:
554 return GLColor::green;
555 default:
556 UNREACHABLE();
557 return GLColor::red;
558 }
559 }
560
getTopColor(Gradient gradient)561 GLColor getTopColor(Gradient gradient)
562 {
563 switch (gradient)
564 {
565 case Gradient::RedGreen:
566 return GLColor::green;
567 case Gradient::RedBlue:
568 return GLColor::red;
569 case Gradient::GreenBlue:
570 return GLColor::blue;
571 default:
572 UNREACHABLE();
573 return GLColor::red;
574 }
575 }
576
577 void bandingTest(GLuint fbo, GLenum format, Gradient gradient, bool ditheringExpected);
578 void bandingTestWithSwitch(GLenum format, Gradient gradient);
579 };
580
bandingTest(GLuint fbo,GLenum format,Gradient gradient,bool ditheringExpected)581 void SixteenBppTextureDitheringTestES3::bandingTest(GLuint fbo,
582 GLenum format,
583 Gradient gradient,
584 bool ditheringExpected)
585 {
586 int w = getWindowWidth();
587 int h = getWindowHeight();
588
589 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
590
591 GLTexture tex;
592 glBindTexture(GL_TEXTURE_2D, tex);
593 glTexStorage2D(GL_TEXTURE_2D, 1, format, w, h);
594 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
595
596 ANGLE_GL_PROGRAM(program, makeVS(gradient).c_str(), getFS());
597 glUseProgram(program);
598
599 glViewport(0, 0, w, h);
600
601 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
602 ASSERT_GL_NO_ERROR();
603
604 glBindFramebuffer(GL_FRAMEBUFFER, 0);
605
606 // Draw a quad using the texture
607 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
608 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
609
610 glUseProgram(m2DProgram);
611 glUniform1i(mTexture2DUniformLocation, 0);
612 drawQuad(m2DProgram, "position", 0.5f);
613 ASSERT_GL_NO_ERROR();
614
615 // Verify results. Note that no dithering algorithm is specified by the spec, so the test
616 // cannot actually verify that the output is dithered in any way. These tests exist for visual
617 // verification and debugging only.
618 int maxError = 0;
619 switch (format)
620 {
621 case GL_RGBA4:
622 maxError = 256 / 16;
623 break;
624 case GL_RGB5_A1:
625 case GL_RGB565:
626 maxError = 256 / 32;
627 break;
628 default:
629 UNREACHABLE();
630 }
631
632 const GLColor rightColor = getRightColor(gradient);
633 const GLColor topColor = getTopColor(gradient);
634 const GLColor topRightColor = GLColor(rightColor.R + topColor.R, rightColor.G + topColor.G,
635 rightColor.B + topColor.B, 255);
636
637 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::black, maxError);
638 EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, rightColor, maxError);
639 EXPECT_PIXEL_COLOR_NEAR(0, h - 1, topColor, maxError);
640 EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, topRightColor, maxError);
641 ASSERT_GL_NO_ERROR();
642
643 // Stricter pixel check on Android where dithering is supported by the driver or emulated.
644 if (getEGLWindow()->isFeatureEnabled(Feature::EmulateDithering) ||
645 getEGLWindow()->isFeatureEnabled(Feature::SupportsLegacyDithering))
646 {
647 uint32_t pixelCount = w * h;
648 std::vector<uint32_t> pixelData(pixelCount);
649 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data());
650
651 int samePixelCount = 0;
652 for (EGLint y = 0; y < h; ++y)
653 {
654 for (EGLint x = 0; x < w; ++x)
655 {
656 EGLint srcPixel = x + y * w;
657 if (x < w - 1 && pixelData[srcPixel] == pixelData[srcPixel + 1])
658 {
659 samePixelCount++;
660 }
661 }
662 }
663
664 double samePixelCountRatio = (1.0 * samePixelCount) / (w * h);
665 // ~0.3 (dithering) vs 0.8+ (no dithering)
666 if (ditheringExpected)
667 {
668 EXPECT_LT(samePixelCountRatio, 0.7);
669 }
670 else
671 {
672 EXPECT_GT(samePixelCountRatio, 0.7);
673 }
674 }
675 }
676
bandingTestWithSwitch(GLenum format,Gradient gradient)677 void SixteenBppTextureDitheringTestES3::bandingTestWithSwitch(GLenum format, Gradient gradient)
678 {
679 GLFramebuffer fbo;
680 GLFramebuffer anotherFbo;
681
682 // GL_DITHER defaults to enabled
683 bandingTest(fbo, format, gradient, true);
684
685 glDisable(GL_DITHER);
686 bandingTest(fbo, format, gradient, false);
687
688 // Check that still disabled after switching to another framebuffer
689 bandingTest(anotherFbo, format, gradient, false);
690
691 glEnable(GL_DITHER);
692 bandingTest(fbo, format, gradient, true);
693
694 // Check that it is now enabled on another framebuffer
695 bandingTest(anotherFbo, format, gradient, true);
696 }
697
698 // Test dithering applied to RGBA4.
TEST_P(SixteenBppTextureDitheringTestES3,RGBA4)699 TEST_P(SixteenBppTextureDitheringTestES3, RGBA4)
700 {
701 bandingTestWithSwitch(GL_RGBA4, Gradient::RedGreen);
702 }
703
704 // Test dithering applied to RGBA5551.
TEST_P(SixteenBppTextureDitheringTestES3,RGBA5551)705 TEST_P(SixteenBppTextureDitheringTestES3, RGBA5551)
706 {
707 bandingTestWithSwitch(GL_RGB5_A1, Gradient::RedBlue);
708 }
709
710 // Test dithering applied to RGB565.
TEST_P(SixteenBppTextureDitheringTestES3,RGB565)711 TEST_P(SixteenBppTextureDitheringTestES3, RGB565)
712 {
713 bandingTestWithSwitch(GL_RGB565, Gradient::GreenBlue);
714 }
715
716 ANGLE_INSTANTIATE_TEST_ES2(SixteenBppTextureTest);
717
718 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SixteenBppTextureTestES3);
719 ANGLE_INSTANTIATE_TEST_ES3(SixteenBppTextureTestES3);
720
721 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SixteenBppTextureDitheringTestES3);
722 ANGLE_INSTANTIATE_TEST_ES3(SixteenBppTextureDitheringTestES3);
723
724 } // namespace
725