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
9 #include <vector>
10
11 using namespace angle;
12
13 namespace
14 {
15
16 class SwizzleTest : public ANGLETest<>
17 {
18 protected:
SwizzleTest()19 SwizzleTest()
20 {
21 setWindowWidth(128);
22 setWindowHeight(128);
23 setConfigRedBits(8);
24 setConfigGreenBits(8);
25 setConfigBlueBits(8);
26 setConfigAlphaBits(8);
27
28 constexpr GLenum swizzles[] = {
29 GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_ZERO, GL_ONE,
30 };
31
32 // Only use every 13th swizzle permutation, use a prime number to make sure the permuations
33 // are somewhat evenly distributed. Reduces the permuations from 1296 to 100.
34 constexpr size_t swizzleReductionFactor = 13;
35
36 size_t swizzleCount = 0;
37 for (GLenum r : swizzles)
38 {
39 for (GLenum g : swizzles)
40 {
41 for (GLenum b : swizzles)
42 {
43 for (GLenum a : swizzles)
44 {
45 swizzleCount++;
46 if (swizzleCount % swizzleReductionFactor != 0)
47 {
48 continue;
49 }
50
51 swizzlePermutation permutation;
52 permutation.swizzleRed = r;
53 permutation.swizzleGreen = g;
54 permutation.swizzleBlue = b;
55 permutation.swizzleAlpha = a;
56 mPermutations.push_back(permutation);
57 }
58 }
59 }
60 }
61 }
62
testSetUp()63 void testSetUp() override
64 {
65 constexpr char kVS[] = R"(precision highp float;
66 attribute vec4 position;
67 varying vec2 texcoord;
68
69 void main()
70 {
71 gl_Position = position;
72 texcoord = (position.xy * 0.5) + 0.5;
73 })";
74
75 constexpr char kFS[] = R"(precision highp float;
76 uniform sampler2D tex;
77 varying vec2 texcoord;
78
79 void main()
80 {
81 gl_FragColor = texture2D(tex, texcoord);
82 })";
83
84 mProgram = CompileProgram(kVS, kFS);
85 ASSERT_NE(0u, mProgram);
86
87 mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
88 ASSERT_NE(-1, mTextureUniformLocation);
89
90 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
91 ASSERT_GL_NO_ERROR();
92 }
93
testTearDown()94 void testTearDown() override
95 {
96 glDeleteProgram(mProgram);
97 glDeleteTextures(1, &mTexture);
98 }
99
isTextureSwizzleAvailable() const100 bool isTextureSwizzleAvailable() const
101 {
102 // On Metal back-end, texture swizzle is not always supported.
103 return !IsMetal() || IsMetalTextureSwizzleAvailable();
104 }
105
106 template <typename T>
init2DTexture(GLenum internalFormat,GLenum dataFormat,GLenum dataType,const T * data)107 void init2DTexture(GLenum internalFormat, GLenum dataFormat, GLenum dataType, const T *data)
108 {
109 glGenTextures(1, &mTexture);
110 glBindTexture(GL_TEXTURE_2D, mTexture);
111 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, dataFormat, dataType, data);
112
113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
115 }
116
init2DCompressedTexture(GLenum internalFormat,GLsizei width,GLsizei height,GLsizei dataSize,const GLubyte * data)117 void init2DCompressedTexture(GLenum internalFormat,
118 GLsizei width,
119 GLsizei height,
120 GLsizei dataSize,
121 const GLubyte *data)
122 {
123 glGenTextures(1, &mTexture);
124 glBindTexture(GL_TEXTURE_2D, mTexture);
125 glCompressedTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, dataSize, data);
126
127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
129 }
130
getExpectedValue(GLenum swizzle,GLubyte unswizzled[4])131 GLubyte getExpectedValue(GLenum swizzle, GLubyte unswizzled[4])
132 {
133 switch (swizzle)
134 {
135 case GL_RED:
136 return unswizzled[0];
137 case GL_GREEN:
138 return unswizzled[1];
139 case GL_BLUE:
140 return unswizzled[2];
141 case GL_ALPHA:
142 return unswizzled[3];
143 case GL_ZERO:
144 return 0;
145 case GL_ONE:
146 return 255;
147 default:
148 return 0;
149 }
150 }
151
runTest2D()152 void runTest2D()
153 {
154 glUseProgram(mProgram);
155 glBindTexture(GL_TEXTURE_2D, mTexture);
156 glUniform1i(mTextureUniformLocation, 0);
157
158 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
159 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
160 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
161 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
162
163 glClear(GL_COLOR_BUFFER_BIT);
164 drawQuad(mProgram, "position", 0.5f);
165
166 GLubyte unswizzled[4];
167 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &unswizzled);
168
169 ASSERT_GL_NO_ERROR();
170
171 for (const auto &permutation : mPermutations)
172 {
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, permutation.swizzleRed);
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, permutation.swizzleGreen);
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, permutation.swizzleBlue);
176 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, permutation.swizzleAlpha);
177
178 glClear(GL_COLOR_BUFFER_BIT);
179 drawQuad(mProgram, "position", 0.5f);
180
181 EXPECT_PIXEL_EQ(0, 0, getExpectedValue(permutation.swizzleRed, unswizzled),
182 getExpectedValue(permutation.swizzleGreen, unswizzled),
183 getExpectedValue(permutation.swizzleBlue, unswizzled),
184 getExpectedValue(permutation.swizzleAlpha, unswizzled));
185
186 ASSERT_GL_NO_ERROR();
187 }
188 }
189
190 GLuint mProgram = 0;
191 GLint mTextureUniformLocation = 0;
192
193 GLuint mTexture = 0;
194
195 struct swizzlePermutation
196 {
197 GLenum swizzleRed;
198 GLenum swizzleGreen;
199 GLenum swizzleBlue;
200 GLenum swizzleAlpha;
201 };
202 std::vector<swizzlePermutation> mPermutations;
203 };
204
205 class SwizzleIntegerTest : public SwizzleTest
206 {
207 protected:
testSetUp()208 void testSetUp() override
209 {
210 constexpr char kVS[] =
211 "#version 300 es\n"
212 "precision highp float;\n"
213 "in vec4 position;\n"
214 "out vec2 texcoord;\n"
215 "\n"
216 "void main()\n"
217 "{\n"
218 " gl_Position = position;\n"
219 " texcoord = (position.xy * 0.5) + 0.5;\n"
220 "}\n";
221
222 constexpr char kFS[] =
223 "#version 300 es\n"
224 "precision highp float;\n"
225 "precision highp usampler2D;\n"
226 "uniform usampler2D tex;\n"
227 "in vec2 texcoord;\n"
228 "out vec4 my_FragColor;\n"
229 "\n"
230 "void main()\n"
231 "{\n"
232 " uvec4 s = texture(tex, texcoord);\n"
233 " if (s[0] == 1u) s[0] = 255u;\n"
234 " if (s[1] == 1u) s[1] = 255u;\n"
235 " if (s[2] == 1u) s[2] = 255u;\n"
236 " if (s[3] == 1u) s[3] = 255u;\n"
237 " my_FragColor = vec4(s) / 255.0;\n"
238 "}\n";
239
240 mProgram = CompileProgram(kVS, kFS);
241 ASSERT_NE(0u, mProgram);
242
243 mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
244 ASSERT_NE(-1, mTextureUniformLocation);
245
246 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
247 ASSERT_GL_NO_ERROR();
248 }
249 };
250
TEST_P(SwizzleTest,RGBA8_2D)251 TEST_P(SwizzleTest, RGBA8_2D)
252 {
253 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
254
255 GLubyte data[] = {1, 64, 128, 200};
256 init2DTexture(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, data);
257 runTest2D();
258 }
259
TEST_P(SwizzleTest,RGB8_2D)260 TEST_P(SwizzleTest, RGB8_2D)
261 {
262 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
263
264 GLubyte data[] = {77, 66, 55};
265 init2DTexture(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, data);
266 runTest2D();
267 }
268
TEST_P(SwizzleTest,RG8_2D)269 TEST_P(SwizzleTest, RG8_2D)
270 {
271 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
272
273 GLubyte data[] = {11, 99};
274 init2DTexture(GL_RG8, GL_RG, GL_UNSIGNED_BYTE, data);
275 runTest2D();
276 }
277
TEST_P(SwizzleTest,R8_2D)278 TEST_P(SwizzleTest, R8_2D)
279 {
280 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
281
282 GLubyte data[] = {2};
283 init2DTexture(GL_R8, GL_RED, GL_UNSIGNED_BYTE, data);
284 runTest2D();
285 }
286
TEST_P(SwizzleTest,RGB10_A2_2D)287 TEST_P(SwizzleTest, RGB10_A2_2D)
288 {
289 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
290
291 GLuint data[] = {20u | (40u << 10) | (60u << 20) | (2u << 30)};
292 init2DTexture(GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, data);
293 runTest2D();
294 }
295
TEST_P(SwizzleTest,RGB10_2D)296 TEST_P(SwizzleTest, RGB10_2D)
297 {
298 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
299 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_texture_type_2_10_10_10_REV"));
300
301 GLuint data[] = {20u | (40u << 10) | (60u << 20) | (2u << 30)};
302 init2DTexture(GL_RGB, GL_RGB, GL_UNSIGNED_INT_2_10_10_10_REV, data);
303 runTest2D();
304 }
305
TEST_P(SwizzleTest,RGBA32F_2D)306 TEST_P(SwizzleTest, RGBA32F_2D)
307 {
308 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
309
310 GLfloat data[] = {0.25f, 0.5f, 0.75f, 0.8f};
311 init2DTexture(GL_RGBA32F, GL_RGBA, GL_FLOAT, data);
312 runTest2D();
313 }
314
TEST_P(SwizzleTest,RGB32F_2D)315 TEST_P(SwizzleTest, RGB32F_2D)
316 {
317 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
318
319 GLfloat data[] = {0.1f, 0.2f, 0.3f};
320 init2DTexture(GL_RGB32F, GL_RGB, GL_FLOAT, data);
321 runTest2D();
322 }
323
TEST_P(SwizzleTest,RG32F_2D)324 TEST_P(SwizzleTest, RG32F_2D)
325 {
326 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
327
328 GLfloat data[] = {0.9f, 0.1f};
329 init2DTexture(GL_RG32F, GL_RG, GL_FLOAT, data);
330 runTest2D();
331 }
332
TEST_P(SwizzleTest,R32F_2D)333 TEST_P(SwizzleTest, R32F_2D)
334 {
335 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
336
337 GLfloat data[] = {0.5f};
338 init2DTexture(GL_R32F, GL_RED, GL_FLOAT, data);
339 runTest2D();
340 }
341
TEST_P(SwizzleTest,D32F_2D)342 TEST_P(SwizzleTest, D32F_2D)
343 {
344 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
345
346 GLfloat data[] = {0.5f};
347 init2DTexture(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, data);
348 runTest2D();
349 }
350
TEST_P(SwizzleTest,D16_2D)351 TEST_P(SwizzleTest, D16_2D)
352 {
353 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
354
355 GLushort data[] = {0xFF};
356 init2DTexture(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, data);
357 runTest2D();
358 }
359
TEST_P(SwizzleTest,D24_2D)360 TEST_P(SwizzleTest, D24_2D)
361 {
362 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
363
364 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAMD() && IsWindows()); // anglebug.com/42262208
365 GLuint data[] = {0xFFFF};
366 init2DTexture(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, data);
367 runTest2D();
368 }
369
TEST_P(SwizzleTest,L8_2D)370 TEST_P(SwizzleTest, L8_2D)
371 {
372 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
373
374 GLubyte data[] = {0x77};
375 init2DTexture(GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
376 runTest2D();
377 }
378
TEST_P(SwizzleTest,A8_2D)379 TEST_P(SwizzleTest, A8_2D)
380 {
381 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
382
383 GLubyte data[] = {0x55};
384 init2DTexture(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, data);
385 runTest2D();
386 }
387
TEST_P(SwizzleTest,LA8_2D)388 TEST_P(SwizzleTest, LA8_2D)
389 {
390 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
391
392 GLubyte data[] = {0x77, 0x66};
393 init2DTexture(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
394 runTest2D();
395 }
396
TEST_P(SwizzleTest,L32F_2D)397 TEST_P(SwizzleTest, L32F_2D)
398 {
399 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
400
401 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
402
403 GLfloat data[] = {0.7f};
404 init2DTexture(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, data);
405 runTest2D();
406 }
407
TEST_P(SwizzleTest,A32F_2D)408 TEST_P(SwizzleTest, A32F_2D)
409 {
410 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
411
412 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
413
414 GLfloat data[] = {
415 0.4f,
416 };
417 init2DTexture(GL_ALPHA, GL_ALPHA, GL_FLOAT, data);
418 runTest2D();
419 }
420
TEST_P(SwizzleTest,LA32F_2D)421 TEST_P(SwizzleTest, LA32F_2D)
422 {
423 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
424
425 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
426
427 GLfloat data[] = {
428 0.5f,
429 0.6f,
430 };
431 init2DTexture(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, data);
432 runTest2D();
433 }
434
435 #include "media/pixel.inc"
436
TEST_P(SwizzleTest,CompressedDXT_2D)437 TEST_P(SwizzleTest, CompressedDXT_2D)
438 {
439 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
440
441 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
442
443 init2DCompressedTexture(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, pixel_0_width, pixel_0_height,
444 pixel_0_size, pixel_0_data);
445 runTest2D();
446 }
447
TEST_P(SwizzleTest,CompressedDXT1_RGB_2D)448 TEST_P(SwizzleTest, CompressedDXT1_RGB_2D)
449 {
450 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
451
452 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
453
454 init2DCompressedTexture(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, pixel_0_width, pixel_0_height,
455 pixel_0_size, pixel_0_data);
456 runTest2D();
457 }
458
TEST_P(SwizzleIntegerTest,RGB8UI_2D)459 TEST_P(SwizzleIntegerTest, RGB8UI_2D)
460 {
461 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
462
463 ANGLE_SKIP_TEST_IF(IsVulkan()); // anglebug.com/42261870 - integer textures
464 GLubyte data[] = {77, 66, 55};
465 init2DTexture(GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, data);
466 runTest2D();
467 }
468
469 // Test that updating the texture data still generates the correct swizzles
TEST_P(SwizzleTest,SubUpdate)470 TEST_P(SwizzleTest, SubUpdate)
471 {
472 ANGLE_SKIP_TEST_IF(!isTextureSwizzleAvailable());
473
474 GLColor data(1, 64, 128, 200);
475 init2DTexture(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &data);
476
477 glUseProgram(mProgram);
478 glBindTexture(GL_TEXTURE_2D, mTexture);
479 glUniform1i(mTextureUniformLocation, 0);
480
481 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
482 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
484 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
485
486 glClear(GL_COLOR_BUFFER_BIT);
487 drawQuad(mProgram, "position", 0.5f);
488
489 GLColor expectedData(data.R, data.R, data.R, data.R);
490 EXPECT_PIXEL_COLOR_EQ(0, 0, expectedData);
491
492 GLColor updateData(32, 234, 28, 232);
493 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &updateData);
494
495 glClear(GL_COLOR_BUFFER_BIT);
496 drawQuad(mProgram, "position", 0.5f);
497
498 GLColor expectedUpdateData(updateData.R, updateData.R, updateData.R, updateData.R);
499 EXPECT_PIXEL_COLOR_EQ(0, 0, expectedUpdateData);
500 }
501
502 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SwizzleTest);
503 ANGLE_INSTANTIATE_TEST_ES3_AND(SwizzleTest);
504
505 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SwizzleIntegerTest);
506 ANGLE_INSTANTIATE_TEST_ES3_AND(SwizzleIntegerTest);
507
508 } // namespace
509