xref: /aosp_15_r20/external/angle/src/tests/gl_tests/CubeMapTextureTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 using namespace angle;
11 
12 class CubeMapTextureTest : public ANGLETest<>
13 {
14   protected:
CubeMapTextureTest()15     CubeMapTextureTest()
16     {
17         setWindowWidth(256);
18         setWindowHeight(256);
19         setConfigRedBits(8);
20         setConfigGreenBits(8);
21         setConfigBlueBits(8);
22         setConfigAlphaBits(8);
23     }
24 
testSetUp()25     void testSetUp() override
26     {
27         mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
28         if (mProgram == 0)
29         {
30             FAIL() << "shader compilation failed.";
31         }
32 
33         mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
34 
35         glUseProgram(mProgram);
36 
37         glClearColor(0, 0, 0, 0);
38         glClearDepthf(0.0);
39         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
40 
41         glEnable(GL_BLEND);
42         glDisable(GL_DEPTH_TEST);
43 
44         ASSERT_GL_NO_ERROR();
45     }
46 
testTearDown()47     void testTearDown() override { glDeleteProgram(mProgram); }
48 
49     void runSampleCoordinateTransformTest(const char *shader, const bool useES3);
50 
51     GLuint mProgram;
52     GLint mColorLocation;
53 };
54 
55 // Verify that rendering to the faces of a cube map consecutively will correctly render to each
56 // face.
TEST_P(CubeMapTextureTest,RenderToFacesConsecutively)57 TEST_P(CubeMapTextureTest, RenderToFacesConsecutively)
58 {
59     // TODO: Diagnose and fix. http://anglebug.com/42261648
60     ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsWindows());
61 
62     // http://anglebug.com/42261821
63     ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsFuchsia());
64 
65     const GLfloat faceColors[] = {
66         1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
67         1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
68     };
69 
70     GLuint tex = 0;
71     glGenTextures(1, &tex);
72     glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
73     for (GLenum face = 0; face < 6; face++)
74     {
75         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
76                      GL_UNSIGNED_BYTE, nullptr);
77     }
78     EXPECT_GL_NO_ERROR();
79 
80     GLuint fbo = 0;
81     glGenFramebuffers(1, &fbo);
82     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
83     EXPECT_GL_NO_ERROR();
84 
85     for (GLenum face = 0; face < 6; face++)
86     {
87         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
88                                GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, tex, 0);
89         EXPECT_GL_NO_ERROR();
90 
91         glUseProgram(mProgram);
92 
93         const GLfloat *faceColor = faceColors + (face * 4);
94         glUniform4f(mColorLocation, faceColor[0], faceColor[1], faceColor[2], faceColor[3]);
95 
96         drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
97         EXPECT_GL_NO_ERROR();
98     }
99 
100     for (GLenum face = 0; face < 6; face++)
101     {
102         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
103                                GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, tex, 0);
104         EXPECT_GL_NO_ERROR();
105 
106         const GLfloat *faceColor = faceColors + (face * 4);
107         EXPECT_PIXEL_EQ(0, 0, faceColor[0] * 255, faceColor[1] * 255, faceColor[2] * 255,
108                         faceColor[3] * 255);
109         EXPECT_GL_NO_ERROR();
110     }
111 
112     glDeleteFramebuffers(1, &fbo);
113     glDeleteTextures(1, &tex);
114 
115     EXPECT_GL_NO_ERROR();
116 }
117 
runSampleCoordinateTransformTest(const char * shader,const bool useES3)118 void CubeMapTextureTest::runSampleCoordinateTransformTest(const char *shader, const bool useES3)
119 {
120     // Fails to compile the shader.  anglebug.com/42262420
121     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
122 
123     constexpr GLsizei kCubeFaceCount            = 6;
124     constexpr GLsizei kCubeFaceSectionCount     = 4;
125     constexpr GLsizei kCubeFaceSectionCountSqrt = 2;
126 
127     constexpr GLColor faceColors[kCubeFaceCount][kCubeFaceSectionCount] = {
128         {GLColor(255, 0, 0, 255), GLColor(191, 0, 0, 255), GLColor(127, 0, 0, 255),
129          GLColor(63, 0, 0, 255)},
130         {GLColor(0, 255, 0, 255), GLColor(0, 191, 0, 255), GLColor(0, 127, 0, 255),
131          GLColor(0, 63, 0, 255)},
132         {GLColor(0, 0, 255, 255), GLColor(0, 0, 191, 255), GLColor(0, 0, 127, 255),
133          GLColor(0, 0, 63, 255)},
134         {GLColor(255, 63, 0, 255), GLColor(191, 127, 0, 255), GLColor(127, 191, 0, 255),
135          GLColor(63, 255, 0, 255)},
136         {GLColor(0, 255, 63, 255), GLColor(0, 191, 127, 255), GLColor(0, 127, 191, 255),
137          GLColor(0, 63, 255, 255)},
138         {GLColor(63, 0, 255, 255), GLColor(127, 0, 191, 255), GLColor(191, 0, 127, 255),
139          GLColor(255, 0, 63, 255)},
140     };
141 
142     constexpr GLsizei kTextureSize = 32;
143 
144     GLTexture tex;
145     glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
146     for (GLenum face = 0; face < kCubeFaceCount; face++)
147     {
148         std::vector<GLColor> faceData(kTextureSize * kTextureSize);
149 
150         // Create the face with four sections, each with a solid color from |faceColors|.
151         for (size_t row = 0; row < kTextureSize / kCubeFaceSectionCountSqrt; ++row)
152         {
153             for (size_t col = 0; col < kTextureSize / kCubeFaceSectionCountSqrt; ++col)
154             {
155                 for (size_t srow = 0; srow < kCubeFaceSectionCountSqrt; ++srow)
156                 {
157                     for (size_t scol = 0; scol < kCubeFaceSectionCountSqrt; ++scol)
158                     {
159                         size_t r = row + srow * kTextureSize / kCubeFaceSectionCountSqrt;
160                         size_t c = col + scol * kTextureSize / kCubeFaceSectionCountSqrt;
161                         size_t s = srow * kCubeFaceSectionCountSqrt + scol;
162                         faceData[r * kTextureSize + c] = faceColors[face][s];
163                     }
164                 }
165             }
166         }
167 
168         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA, kTextureSize, kTextureSize,
169                      0, GL_RGBA, GL_UNSIGNED_BYTE, faceData.data());
170     }
171     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
172     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
173     EXPECT_GL_NO_ERROR();
174 
175     GLTexture fboTex;
176     glBindTexture(GL_TEXTURE_2D, fboTex);
177     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeFaceCount, kCubeFaceSectionCount, 0, GL_RGBA,
178                  GL_UNSIGNED_BYTE, nullptr);
179 
180     GLFramebuffer fbo;
181     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
182     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
183     EXPECT_GL_NO_ERROR();
184 
185     ANGLE_GL_PROGRAM(program, useES3 ? essl3_shaders::vs::Simple() : essl1_shaders::vs::Simple(),
186                      shader);
187     glUseProgram(program);
188 
189     GLint texCubeLocation = glGetUniformLocation(program, "texCube");
190     ASSERT_NE(-1, texCubeLocation);
191     glUniform1i(texCubeLocation, 0);
192 
193     drawQuad(program, useES3 ? essl3_shaders::PositionAttrib() : essl1_shaders::PositionAttrib(),
194              0.5f);
195     EXPECT_GL_NO_ERROR();
196 
197     for (GLenum face = 0; face < kCubeFaceCount; face++)
198     {
199         // The following table defines the translation from textureCube coordinates to coordinates
200         // in each face.  The framebuffer has width 6 and height 4.  Every column corresponding to
201         // an x value represents one cube face.  The values in rows are samples from the four
202         // sections of the face.
203         //
204         // Major    Axis Direction Target    sc  tc  ma
205         //  +rx  TEXTURE_CUBE_MAP_POSITIVE_X −rz −ry rx
206         //  −rx  TEXTURE_CUBE_MAP_NEGATIVE_X  rz −ry rx
207         //  +ry  TEXTURE_CUBE_MAP_POSITIVE_Y  rx  rz ry
208         //  −ry  TEXTURE_CUBE_MAP_NEGATIVE_Y  rx −rz ry
209         //  +rz  TEXTURE_CUBE_MAP_POSITIVE_Z  rx −ry rz
210         //  −rz  TEXTURE_CUBE_MAP_NEGATIVE_Z −rx −ry rz
211         //
212         // This table is used only to determine the direction of growth for s and t.  The shader
213         // always generates (row,col) coordinates (0, 0), (0, 1), (1, 0), (1, 1) which is the order
214         // the data is uploaded to the faces, but based on the table above, the sample order would
215         // be different.
216         constexpr size_t faceSampledSections[kCubeFaceCount][kCubeFaceSectionCount] = {
217             {3, 2, 1, 0}, {2, 3, 0, 1}, {0, 1, 2, 3}, {2, 3, 0, 1}, {2, 3, 0, 1}, {3, 2, 1, 0},
218         };
219 
220         for (size_t section = 0; section < kCubeFaceSectionCount; ++section)
221         {
222             const GLColor sectionColor = faceColors[face][faceSampledSections[face][section]];
223 
224             EXPECT_PIXEL_COLOR_EQ(face, section, sectionColor)
225                 << "face " << face << ", section " << section;
226         }
227     }
228     EXPECT_GL_NO_ERROR();
229 }
230 
231 // Verify that cube map sampling follows the rules that map cubemap coordinates to coordinates
232 // within each face.  See section 3.7.5 of GLES2.0 (Cube Map Texture Selection).
TEST_P(CubeMapTextureTest,SampleCoordinateTransform)233 TEST_P(CubeMapTextureTest, SampleCoordinateTransform)
234 {
235     // http://anglebug.com/40096654
236     ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D9());
237     // Create a program that samples from 6x4 directions of the cubemap, draw and verify that the
238     // colors match the right color from |faceColors|.
239     constexpr char kFS[] = R"(precision mediump float;
240 
241 uniform samplerCube texCube;
242 
243 const mat4 coordInSection = mat4(
244     vec4(-0.5, -0.5, 0, 0),
245     vec4( 0.5, -0.5, 0, 0),
246     vec4(-0.5,  0.5, 0, 0),
247     vec4( 0.5,  0.5, 0, 0)
248 );
249 
250 void main()
251 {
252     vec3 coord;
253     if (gl_FragCoord.x < 2.0)
254     {
255         coord.x = gl_FragCoord.x < 1.0 ? 1.0 : -1.0;
256         coord.zy = coordInSection[int(gl_FragCoord.y)].xy;
257     }
258     else if (gl_FragCoord.x < 4.0)
259     {
260         coord.y = gl_FragCoord.x < 3.0 ? 1.0 : -1.0;
261         coord.xz = coordInSection[int(gl_FragCoord.y)].xy;
262     }
263     else
264     {
265         coord.z = gl_FragCoord.x < 5.0 ? 1.0 : -1.0;
266         coord.xy = coordInSection[int(gl_FragCoord.y)].xy;
267     }
268 
269     gl_FragColor = textureCube(texCube, coord);
270 })";
271 
272     runSampleCoordinateTransformTest(kFS, false);
273 }
274 
275 // On Android Vulkan, unequal x and y derivatives cause this test to fail.
TEST_P(CubeMapTextureTest,SampleCoordinateTransformGrad)276 TEST_P(CubeMapTextureTest, SampleCoordinateTransformGrad)
277 {
278     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_texture_lod"));
279 
280     constexpr char kFS[] = R"(#extension GL_EXT_shader_texture_lod : require
281 precision mediump float;
282 
283 uniform samplerCube texCube;
284 
285 const mat4 coordInSection = mat4(
286     vec4(-0.5, -0.5, 0, 0),
287     vec4( 0.5, -0.5, 0, 0),
288     vec4(-0.5,  0.5, 0, 0),
289     vec4( 0.5,  0.5, 0, 0)
290 );
291 
292 void main()
293 {
294     vec3 coord;
295     if (gl_FragCoord.x < 2.0)
296     {
297         coord.x = gl_FragCoord.x < 1.0 ? 1.0 : -1.0;
298         coord.zy = coordInSection[int(gl_FragCoord.y)].xy;
299     }
300     else if (gl_FragCoord.x < 4.0)
301     {
302         coord.y = gl_FragCoord.x < 3.0 ? 1.0 : -1.0;
303         coord.xz = coordInSection[int(gl_FragCoord.y)].xy;
304     }
305     else
306     {
307         coord.z = gl_FragCoord.x < 5.0 ? 1.0 : -1.0;
308         coord.xy = coordInSection[int(gl_FragCoord.y)].xy;
309     }
310 
311     gl_FragColor = textureCubeGradEXT(texCube, coord,
312                                       vec3(10.0, 10.0, 0.0), vec3(0.0, 10.0, 10.0));
313 })";
314 
315     runSampleCoordinateTransformTest(kFS, false);
316 }
317 
318 // Same as the previous but uses the ES 3.0 explicit gradient function.
TEST_P(CubeMapTextureTest,SampleCoordinateTransformGrad_ES3)319 TEST_P(CubeMapTextureTest, SampleCoordinateTransformGrad_ES3)
320 {
321     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
322 
323     constexpr char kFS[] = R"(#version 300 es
324 precision mediump float;
325 
326 uniform samplerCube texCube;
327 out vec4 my_FragColor;
328 
329 const mat4 coordInSection = mat4(
330     vec4(-0.5, -0.5, 0, 0),
331     vec4( 0.5, -0.5, 0, 0),
332     vec4(-0.5,  0.5, 0, 0),
333     vec4( 0.5,  0.5, 0, 0)
334 );
335 
336 void main()
337 {
338     vec3 coord;
339     if (gl_FragCoord.x < 2.0)
340     {
341         coord.x = gl_FragCoord.x < 1.0 ? 1.0 : -1.0;
342         coord.zy = coordInSection[int(gl_FragCoord.y)].xy;
343     }
344     else if (gl_FragCoord.x < 4.0)
345     {
346         coord.y = gl_FragCoord.x < 3.0 ? 1.0 : -1.0;
347         coord.xz = coordInSection[int(gl_FragCoord.y)].xy;
348     }
349     else
350     {
351         coord.z = gl_FragCoord.x < 5.0 ? 1.0 : -1.0;
352         coord.xy = coordInSection[int(gl_FragCoord.y)].xy;
353     }
354 
355     my_FragColor = textureGrad(texCube, coord,
356                                vec3(10.0, 10.0, 0.0), vec3(0.0, 10.0, 10.0));
357 })";
358 
359     runSampleCoordinateTransformTest(kFS, true);
360 }
361 
362 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
363 // tests should be run against.
364 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(CubeMapTextureTest);
365