xref: /aosp_15_r20/external/angle/src/tests/gl_tests/IncompleteTextureTest.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 
9 #include <vector>
10 #include "test_utils/gl_raii.h"
11 
12 using namespace angle;
13 
14 class IncompleteTextureTest : public ANGLETest<>
15 {
16   protected:
IncompleteTextureTest()17     IncompleteTextureTest()
18     {
19         setWindowWidth(128);
20         setWindowHeight(128);
21         setConfigRedBits(8);
22         setConfigGreenBits(8);
23         setConfigBlueBits(8);
24         setConfigAlphaBits(8);
25     }
26 
testSetUp()27     void testSetUp() override
28     {
29         constexpr char kVS[] = R"(precision highp float;
30 attribute vec4 position;
31 varying vec2 texcoord;
32 
33 void main()
34 {
35     gl_Position = position;
36     texcoord = (position.xy * 0.5) + 0.5;
37 })";
38 
39         constexpr char kFS[] = R"(precision highp float;
40 uniform sampler2D tex;
41 varying vec2 texcoord;
42 
43 void main()
44 {
45     gl_FragColor = texture2D(tex, texcoord);
46 })";
47 
48         mProgram = CompileProgram(kVS, kFS);
49         if (mProgram == 0)
50         {
51             FAIL() << "shader compilation failed.";
52         }
53 
54         mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
55     }
56 
testTearDown()57     void testTearDown() override { glDeleteProgram(mProgram); }
58 
59     GLuint mProgram;
60     GLint mTextureUniformLocation;
61 };
62 
63 class IncompleteTextureTestES3 : public ANGLETest<>
64 {
65   protected:
IncompleteTextureTestES3()66     IncompleteTextureTestES3()
67     {
68         setWindowWidth(128);
69         setWindowHeight(128);
70         setConfigRedBits(8);
71         setConfigGreenBits(8);
72         setConfigBlueBits(8);
73         setConfigAlphaBits(8);
74     }
75 
76   public:
setupFramebuffer(const GLenum sizedInternalFormat)77     void setupFramebuffer(const GLenum sizedInternalFormat)
78     {
79         glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
80         glRenderbufferStorage(GL_RENDERBUFFER, sizedInternalFormat, getWindowWidth(),
81                               getWindowHeight());
82         ASSERT_GL_NO_ERROR();
83 
84         glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
85         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
86                                   mRenderbuffer);
87         glViewport(0, 0, getWindowWidth(), getWindowHeight());
88         ASSERT_GL_NO_ERROR();
89     }
90 
91   private:
92     GLRenderbuffer mRenderbuffer;
93     GLFramebuffer mFramebuffer;
94 };
95 
96 class IncompleteTextureTestES31 : public ANGLETest<>
97 {
98   protected:
IncompleteTextureTestES31()99     IncompleteTextureTestES31()
100     {
101         setWindowWidth(128);
102         setWindowHeight(128);
103         setConfigRedBits(8);
104         setConfigGreenBits(8);
105         setConfigBlueBits(8);
106         setConfigAlphaBits(8);
107     }
108 };
109 
110 // Test rendering with an incomplete texture.
TEST_P(IncompleteTextureTest,IncompleteTexture2D)111 TEST_P(IncompleteTextureTest, IncompleteTexture2D)
112 {
113     GLTexture tex;
114     glActiveTexture(GL_TEXTURE0);
115     glBindTexture(GL_TEXTURE_2D, tex);
116 
117     glUseProgram(mProgram);
118     glUniform1i(mTextureUniformLocation, 0);
119 
120     constexpr GLsizei kTextureSize = 2;
121     std::vector<GLColor> textureData(kTextureSize * kTextureSize, GLColor::red);
122 
123     // Make a complete texture.
124     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA,
125                  GL_UNSIGNED_BYTE, textureData.data());
126     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
127 
128     // Should be complete - expect red.
129     drawQuad(mProgram, "position", 0.5f);
130     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "complete texture should be red";
131 
132     // Make texture incomplete.
133     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
134 
135     // Should be incomplete - expect black.
136     drawQuad(mProgram, "position", 0.5f);
137     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black) << "incomplete texture should be black";
138 
139     // Make texture complete by defining the second mip.
140     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, kTextureSize >> 1, kTextureSize >> 1, 0, GL_RGBA,
141                  GL_UNSIGNED_BYTE, textureData.data());
142 
143     // Should be complete - expect red.
144     drawQuad(mProgram, "position", 0.5f);
145     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "mip-complete texture should be red";
146 }
147 
148 // Tests redefining a texture with half the size works as expected.
TEST_P(IncompleteTextureTest,UpdateTexture)149 TEST_P(IncompleteTextureTest, UpdateTexture)
150 {
151     GLTexture tex;
152     glActiveTexture(GL_TEXTURE0);
153     glBindTexture(GL_TEXTURE_2D, tex);
154 
155     glUseProgram(mProgram);
156     glUniform1i(mTextureUniformLocation, 0);
157 
158     constexpr GLsizei redTextureSize = 64;
159     std::vector<GLColor> redTextureData(redTextureSize * redTextureSize, GLColor::red);
160     for (GLint mip = 0; mip < 7; ++mip)
161     {
162         const GLsizei mipSize = redTextureSize >> mip;
163 
164         glTexImage2D(GL_TEXTURE_2D, mip, GL_RGBA, mipSize, mipSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
165                      redTextureData.data());
166     }
167 
168     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
169     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
170 
171     drawQuad(mProgram, "position", 0.5f);
172     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
173 
174     constexpr GLsizei greenTextureSize = 32;
175     std::vector<GLColor> greenTextureData(greenTextureSize * greenTextureSize, GLColor::green);
176 
177     for (GLint mip = 0; mip < 6; ++mip)
178     {
179         const GLsizei mipSize = greenTextureSize >> mip;
180 
181         glTexSubImage2D(GL_TEXTURE_2D, mip, mipSize, mipSize, mipSize, mipSize, GL_RGBA,
182                         GL_UNSIGNED_BYTE, greenTextureData.data());
183     }
184 
185     drawQuad(mProgram, "position", 0.5f);
186     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - greenTextureSize, getWindowHeight() - greenTextureSize,
187                           GLColor::green);
188 }
189 
190 // Tests that incomplete textures don't get initialized with the unpack buffer contents.
TEST_P(IncompleteTextureTestES3,UnpackBufferBound)191 TEST_P(IncompleteTextureTestES3, UnpackBufferBound)
192 {
193     std::vector<GLColor> red(16, GLColor::red);
194 
195     GLBuffer unpackBuffer;
196     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
197     glBufferData(GL_PIXEL_UNPACK_BUFFER, red.size() * sizeof(GLColor), red.data(), GL_STATIC_DRAW);
198 
199     draw2DTexturedQuad(0.5f, 1.0f, true);
200     ASSERT_GL_NO_ERROR();
201 
202     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
203 }
204 
205 // Tests that the incomplete multisample texture has the correct alpha value.
TEST_P(IncompleteTextureTestES31,MultisampleTexture)206 TEST_P(IncompleteTextureTestES31, MultisampleTexture)
207 {
208     constexpr char kVS[] = R"(#version 310 es
209 in vec2 position;
210 out vec2 texCoord;
211 void main()
212 {
213     gl_Position = vec4(position, 0, 1);
214     texCoord = (position * 0.5) + 0.5;
215 })";
216 
217     constexpr char kFS[] = R"(#version 310 es
218 precision mediump float;
219 in vec2 texCoord;
220 out vec4 color;
221 uniform mediump sampler2DMS tex;
222 void main()
223 {
224     ivec2 texSize = textureSize(tex);
225     ivec2 texel = ivec2(vec2(texSize) * texCoord);
226     color = texelFetch(tex, texel, 0);
227 })";
228 
229     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
230     glClear(GL_COLOR_BUFFER_BIT);
231     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
232 
233     // The zero texture will be incomplete by default.
234     ANGLE_GL_PROGRAM(program, kVS, kFS);
235     drawQuad(program, "position", 0.5f);
236     ASSERT_GL_NO_ERROR();
237 
238     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
239 }
240 
241 // This mirrors a scenario seen in GFXBench Car Chase where a
242 // default CUBE_MAP_ARRAY texture is used without being setup.
243 // Its ends up sampling from an incomplete texture.
TEST_P(IncompleteTextureTestES31,IncompleteTextureCubeMapArray)244 TEST_P(IncompleteTextureTestES31, IncompleteTextureCubeMapArray)
245 {
246     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_cube_map_array"));
247 
248     constexpr char kVS[] =
249         R"(#version 310 es
250         precision mediump float;
251         in vec3 pos;
252         void main() {
253             gl_Position = vec4(pos, 1.0);
254         })";
255 
256     constexpr char kFS[] =
257         R"(#version 310 es
258         #extension GL_EXT_texture_cube_map_array : enable
259         precision mediump float;
260         out vec4 color;
261         uniform lowp samplerCubeArray uTex;
262         void main(){
263             vec4 outColor = vec4(0.0);
264 
265             // Pull a color from each cube face to ensure they are all initialized
266             outColor += texture(uTex, vec4(1.0, 0.0, 0.0, 0.0));
267             outColor += texture(uTex, vec4(-1.0, 0.0, 0.0, 0.0));
268             outColor += texture(uTex, vec4(0.0, 1.0, 0.0, 0.0));
269             outColor += texture(uTex, vec4(0.0, -1.0, 0.0, 0.0));
270             outColor += texture(uTex, vec4(0.0, 0.0, 1.0, 0.0));
271             outColor += texture(uTex, vec4(0.0, 0.0, -1.0, 0.0));
272 
273             color = outColor;
274         })";
275 
276     ANGLE_GL_PROGRAM(program, kVS, kFS);
277     glUseProgram(program);
278 
279     glUniform1i(glGetUniformLocation(program, "uTex"), 0);
280     glActiveTexture(GL_TEXTURE0);
281 
282     // Bind the default texture and don't set it up. This ends up being incomplete.
283     glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);
284 
285     drawQuad(program, "pos", 0.5f, 1.0f, true);
286     ASSERT_GL_NO_ERROR();
287 
288     EXPECT_PIXEL_COLOR_EQ(0, 0, angle::GLColor::black);
289 }
290 
291 // Verifies that an incomplete integer texture has a signed integer type default value.
TEST_P(IncompleteTextureTestES3,IntegerType)292 TEST_P(IncompleteTextureTestES3, IntegerType)
293 {
294     // GLES backend on Adreno has a problem to create a incomplete texture, although it doesn't go
295     // through the routine which creates a incomplete texture in the ANGLE driver.
296     ANGLE_SKIP_TEST_IF(IsAdreno() && IsAndroid() && IsOpenGLES());
297 
298     // http://crbug.com/1168370
299     ANGLE_SKIP_TEST_IF(IsMac() && IsARM64() && IsOpenGL());
300 
301     constexpr char kVS[] = R"(#version 300 es
302 in highp vec2 position;
303 out highp vec2 texCoord;
304 void main()
305 {
306     gl_Position = vec4(position, 0, 1);
307     texCoord = (position * 0.5) + 0.5;
308 })";
309 
310     constexpr char kFS[] = R"(#version 300 es
311 in highp vec2 texCoord;
312 out highp ivec4 color;
313 uniform highp isampler2D tex;
314 void main()
315 {
316     ivec2 texSize = textureSize(tex, 0);
317     ivec2 texel = ivec2(vec2(texSize) * texCoord);
318     color = texelFetch(tex, texel, 0);
319 })";
320 
321     constexpr GLint clearColori[4] = {-10, 20, -30, 40};
322     constexpr GLint blackColori[4] = {0, 0, 0, 127};
323 
324     setupFramebuffer(GL_RGBA8I);
325     glClearBufferiv(GL_COLOR, 0, clearColori);
326     ASSERT_GL_NO_ERROR();
327     EXPECT_PIXEL_8I(0, 0, clearColori[0], clearColori[1], clearColori[2], clearColori[3]);
328 
329     // Since no texture attachment has been specified, it is incomplete by definition
330     ANGLE_GL_PROGRAM(program, kVS, kFS);
331 
332     glUseProgram(program);
333 
334     drawQuad(program, "position", 0.5f);
335     ASSERT_GL_NO_ERROR();
336 
337     const int width  = getWindowWidth() - 1;
338     const int height = getWindowHeight() - 1;
339     EXPECT_PIXEL_8I(0, 0, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
340     EXPECT_PIXEL_8I(width, 0, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
341     EXPECT_PIXEL_8I(0, height, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
342     EXPECT_PIXEL_8I(width, height, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
343 }
344 
345 // Verifies that an incomplete unsigned integer texture has an unsigned integer type default value.
TEST_P(IncompleteTextureTestES3,UnsignedIntegerType)346 TEST_P(IncompleteTextureTestES3, UnsignedIntegerType)
347 {
348     // GLES backend on Adreno has a problem to create a incomplete texture, although it doesn't go
349     // through the routine which creates a incomplete texture in the ANGLE driver.
350     ANGLE_SKIP_TEST_IF(IsAdreno() && IsAndroid() && IsOpenGLES());
351 
352     // http://crbug.com/1168370
353     ANGLE_SKIP_TEST_IF(IsMac() && IsARM64() && IsOpenGL());
354 
355     constexpr char kVS[] = R"(#version 300 es
356 in highp vec2 position;
357 out highp vec2 texCoord;
358 void main()
359 {
360     gl_Position = vec4(position, 0, 1);
361     texCoord = (position * 0.5) + 0.5;
362 })";
363 
364     constexpr char kFS[] = R"(#version 300 es
365 in highp vec2 texCoord;
366 out highp uvec4 color;
367 uniform highp usampler2D tex;
368 void main()
369 {
370     ivec2 texSize = textureSize(tex, 0);
371     ivec2 texel = ivec2(vec2(texSize) * texCoord);
372     color = texelFetch(tex, texel, 0);
373 })";
374 
375     constexpr GLuint clearColorui[4] = {40, 30, 20, 10};
376     constexpr GLuint blackColorui[4] = {0, 0, 0, 255};
377 
378     setupFramebuffer(GL_RGBA8UI);
379     glClearBufferuiv(GL_COLOR, 0, clearColorui);
380     ASSERT_GL_NO_ERROR();
381     EXPECT_PIXEL_8UI(0, 0, clearColorui[0], clearColorui[1], clearColorui[2], clearColorui[3]);
382 
383     // Since no texture attachment has been specified, it is incomplete by definition
384     ANGLE_GL_PROGRAM(program, kVS, kFS);
385 
386     glUseProgram(program);
387 
388     drawQuad(program, "position", 0.5f);
389     ASSERT_GL_NO_ERROR();
390 
391     const int width  = getWindowWidth() - 1;
392     const int height = getWindowHeight() - 1;
393     EXPECT_PIXEL_8UI(0, 0, blackColorui[0], blackColorui[1], blackColorui[2], blackColorui[3]);
394     EXPECT_PIXEL_8UI(width, 0, blackColorui[0], blackColorui[1], blackColorui[2], blackColorui[3]);
395     EXPECT_PIXEL_8UI(0, height, blackColorui[0], blackColorui[1], blackColorui[2], blackColorui[3]);
396     EXPECT_PIXEL_8UI(width, height, blackColorui[0], blackColorui[1], blackColorui[2],
397                      blackColorui[3]);
398 }
399 
400 // Verifies that we are able to create an incomplete shadow texture.
TEST_P(IncompleteTextureTestES3,ShadowType)401 TEST_P(IncompleteTextureTestES3, ShadowType)
402 {
403     // GLES backend on Adreno has a problem to create a incomplete texture, although it doesn't go
404     // through the routine which creates a incomplete texture in the ANGLE driver.
405     ANGLE_SKIP_TEST_IF(IsAdreno() && IsAndroid() && IsOpenGLES());
406 
407     // http://anglebug.com/42264125
408     ANGLE_SKIP_TEST_IF(IsD3D11());
409 
410     constexpr char kVS[] = R"(#version 300 es
411 in highp vec2 position;
412 out highp vec3 texCoord;
413 void main()
414 {
415     gl_Position = vec4(position, 0, 1);
416     texCoord = vec3(((position * 0.5) + 0.5), 0.5);
417 })";
418 
419     constexpr char kFS[] = R"(#version 300 es
420 in highp vec3 texCoord;
421 out highp vec4 color;
422 uniform highp sampler2DShadow tex;
423 void main()
424 {
425     color = vec4(vec3(texture(tex, texCoord)), 1.0f);
426 })";
427 
428     constexpr GLColor clearColor = {10, 40, 20, 30};
429     constexpr GLColor blackColor = {0, 0, 0, 255};
430 
431     setupFramebuffer(GL_RGBA8);
432     glClearBufferfv(GL_COLOR, 0, clearColor.toNormalizedVector().data());
433     ASSERT_GL_NO_ERROR();
434     EXPECT_PIXEL_EQ(0, 0, clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
435 
436     // Since no texture attachment has been specified, it is incomplete by definition
437     ANGLE_GL_PROGRAM(program, kVS, kFS);
438 
439     glUseProgram(program);
440     glUniform1i(glGetUniformLocation(program, "tex"), 1);
441     ASSERT_GL_NO_ERROR();
442 
443     drawQuad(program, "position", 0.5f);
444     ASSERT_GL_NO_ERROR();
445 
446     const int width  = getWindowWidth() - 1;
447     const int height = getWindowHeight() - 1;
448     EXPECT_PIXEL_EQ(0, 0, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
449     EXPECT_PIXEL_EQ(width, 0, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
450     EXPECT_PIXEL_EQ(0, height, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
451     EXPECT_PIXEL_EQ(width, height, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
452 }
453 
454 ANGLE_INSTANTIATE_TEST_ES2(IncompleteTextureTest);
455 
456 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IncompleteTextureTestES3);
457 ANGLE_INSTANTIATE_TEST_ES3(IncompleteTextureTestES3);
458 
459 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IncompleteTextureTestES31);
460 ANGLE_INSTANTIATE_TEST_ES31(IncompleteTextureTestES31);
461