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