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 // http://anglebug.com/4092
194 ANGLE_SKIP_TEST_IF(IsVulkan());
195 std::vector<GLColor> red(16, GLColor::red);
196
197 GLBuffer unpackBuffer;
198 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer);
199 glBufferData(GL_PIXEL_UNPACK_BUFFER, red.size() * sizeof(GLColor), red.data(), GL_STATIC_DRAW);
200
201 draw2DTexturedQuad(0.5f, 1.0f, true);
202 ASSERT_GL_NO_ERROR();
203
204 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
205 }
206
207 // Tests that the incomplete multisample texture has the correct alpha value.
TEST_P(IncompleteTextureTestES31,MultisampleTexture)208 TEST_P(IncompleteTextureTestES31, MultisampleTexture)
209 {
210 // http://anglebug.com/4092
211 ANGLE_SKIP_TEST_IF(IsVulkan());
212 constexpr char kVS[] = R"(#version 310 es
213 in vec2 position;
214 out vec2 texCoord;
215 void main()
216 {
217 gl_Position = vec4(position, 0, 1);
218 texCoord = (position * 0.5) + 0.5;
219 })";
220
221 constexpr char kFS[] = R"(#version 310 es
222 precision mediump float;
223 in vec2 texCoord;
224 out vec4 color;
225 uniform mediump sampler2DMS tex;
226 void main()
227 {
228 ivec2 texSize = textureSize(tex);
229 ivec2 texel = ivec2(vec2(texSize) * texCoord);
230 color = texelFetch(tex, texel, 0);
231 })";
232
233 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
234 glClear(GL_COLOR_BUFFER_BIT);
235 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
236
237 // The zero texture will be incomplete by default.
238 ANGLE_GL_PROGRAM(program, kVS, kFS);
239 drawQuad(program, "position", 0.5f);
240 ASSERT_GL_NO_ERROR();
241
242 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
243 }
244
245 // Verifies that an incomplete integer texture has a signed integer type default value.
TEST_P(IncompleteTextureTestES3,IntegerType)246 TEST_P(IncompleteTextureTestES3, IntegerType)
247 {
248 // GLES backend on Adreno has a problem to create a incomplete texture, although it doesn't go
249 // through the routine which creates a incomplete texture in the ANGLE driver.
250 ANGLE_SKIP_TEST_IF(IsAdreno() && IsAndroid() && IsOpenGLES());
251
252 // http://crbug.com/1168370
253 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsOpenGL());
254
255 constexpr char kVS[] = R"(#version 300 es
256 in highp vec2 position;
257 out highp vec2 texCoord;
258 void main()
259 {
260 gl_Position = vec4(position, 0, 1);
261 texCoord = (position * 0.5) + 0.5;
262 })";
263
264 constexpr char kFS[] = R"(#version 300 es
265 in highp vec2 texCoord;
266 out highp ivec4 color;
267 uniform highp isampler2D tex;
268 void main()
269 {
270 ivec2 texSize = textureSize(tex, 0);
271 ivec2 texel = ivec2(vec2(texSize) * texCoord);
272 color = texelFetch(tex, texel, 0);
273 })";
274
275 constexpr GLint clearColori[4] = {-10, 20, -30, 40};
276 constexpr GLint blackColori[4] = {0, 0, 0, 127};
277
278 setupFramebuffer(GL_RGBA8I);
279 glClearBufferiv(GL_COLOR, 0, clearColori);
280 ASSERT_GL_NO_ERROR();
281 EXPECT_PIXEL_8I(0, 0, clearColori[0], clearColori[1], clearColori[2], clearColori[3]);
282
283 // Since no texture attachment has been specified, it is incomplete by definition
284 ANGLE_GL_PROGRAM(program, kVS, kFS);
285
286 glUseProgram(program);
287
288 drawQuad(program, "position", 0.5f);
289 ASSERT_GL_NO_ERROR();
290
291 const int width = getWindowWidth() - 1;
292 const int height = getWindowHeight() - 1;
293 EXPECT_PIXEL_8I(0, 0, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
294 EXPECT_PIXEL_8I(width, 0, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
295 EXPECT_PIXEL_8I(0, height, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
296 EXPECT_PIXEL_8I(width, height, blackColori[0], blackColori[1], blackColori[2], blackColori[3]);
297 }
298
299 // Verifies that an incomplete unsigned integer texture has an unsigned integer type default value.
TEST_P(IncompleteTextureTestES3,UnsignedIntegerType)300 TEST_P(IncompleteTextureTestES3, UnsignedIntegerType)
301 {
302 // GLES backend on Adreno has a problem to create a incomplete texture, although it doesn't go
303 // through the routine which creates a incomplete texture in the ANGLE driver.
304 ANGLE_SKIP_TEST_IF(IsAdreno() && IsAndroid() && IsOpenGLES());
305
306 // http://crbug.com/1168370
307 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsOpenGL());
308
309 constexpr char kVS[] = R"(#version 300 es
310 in highp vec2 position;
311 out highp vec2 texCoord;
312 void main()
313 {
314 gl_Position = vec4(position, 0, 1);
315 texCoord = (position * 0.5) + 0.5;
316 })";
317
318 constexpr char kFS[] = R"(#version 300 es
319 in highp vec2 texCoord;
320 out highp uvec4 color;
321 uniform highp usampler2D tex;
322 void main()
323 {
324 ivec2 texSize = textureSize(tex, 0);
325 ivec2 texel = ivec2(vec2(texSize) * texCoord);
326 color = texelFetch(tex, texel, 0);
327 })";
328
329 constexpr GLuint clearColorui[4] = {40, 30, 20, 10};
330 constexpr GLuint blackColorui[4] = {0, 0, 0, 255};
331
332 setupFramebuffer(GL_RGBA8UI);
333 glClearBufferuiv(GL_COLOR, 0, clearColorui);
334 ASSERT_GL_NO_ERROR();
335 EXPECT_PIXEL_8UI(0, 0, clearColorui[0], clearColorui[1], clearColorui[2], clearColorui[3]);
336
337 // Since no texture attachment has been specified, it is incomplete by definition
338 ANGLE_GL_PROGRAM(program, kVS, kFS);
339
340 glUseProgram(program);
341
342 drawQuad(program, "position", 0.5f);
343 ASSERT_GL_NO_ERROR();
344
345 const int width = getWindowWidth() - 1;
346 const int height = getWindowHeight() - 1;
347 EXPECT_PIXEL_8UI(0, 0, blackColorui[0], blackColorui[1], blackColorui[2], blackColorui[3]);
348 EXPECT_PIXEL_8UI(width, 0, blackColorui[0], blackColorui[1], blackColorui[2], blackColorui[3]);
349 EXPECT_PIXEL_8UI(0, height, blackColorui[0], blackColorui[1], blackColorui[2], blackColorui[3]);
350 EXPECT_PIXEL_8UI(width, height, blackColorui[0], blackColorui[1], blackColorui[2],
351 blackColorui[3]);
352 }
353
354 // Verifies that we are able to create an incomplete shadow texture.
TEST_P(IncompleteTextureTestES3,ShadowType)355 TEST_P(IncompleteTextureTestES3, ShadowType)
356 {
357 // GLES backend on Adreno has a problem to create a incomplete texture, although it doesn't go
358 // through the routine which creates a incomplete texture in the ANGLE driver.
359 ANGLE_SKIP_TEST_IF(IsAdreno() && IsAndroid() && IsOpenGLES());
360
361 // http://crbug.com/1168370
362 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsOpenGL());
363
364 // http://anglebug.com/5594
365 ANGLE_SKIP_TEST_IF(IsD3D11() || IsOSX());
366
367 constexpr char kVS[] = R"(#version 300 es
368 in highp vec2 position;
369 out highp vec3 texCoord;
370 void main()
371 {
372 gl_Position = vec4(position, 0, 1);
373 texCoord = vec3(((position * 0.5) + 0.5), 0.5);
374 })";
375
376 constexpr char kFS[] = R"(#version 300 es
377 in highp vec3 texCoord;
378 out highp vec4 color;
379 uniform highp sampler2DShadow tex;
380 void main()
381 {
382 color = vec4(vec3(texture(tex, texCoord)), 1.0f);
383 })";
384
385 constexpr GLColor clearColor = {10, 40, 20, 30};
386 constexpr GLColor blackColor = {0, 0, 0, 255};
387
388 setupFramebuffer(GL_RGBA8);
389 glClearBufferfv(GL_COLOR, 0, clearColor.toNormalizedVector().data());
390 ASSERT_GL_NO_ERROR();
391 EXPECT_PIXEL_EQ(0, 0, clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
392
393 // Since no texture attachment has been specified, it is incomplete by definition
394 ANGLE_GL_PROGRAM(program, kVS, kFS);
395
396 glUseProgram(program);
397 glUniform1i(glGetUniformLocation(program, "tex"), 1);
398 ASSERT_GL_NO_ERROR();
399
400 drawQuad(program, "position", 0.5f);
401 ASSERT_GL_NO_ERROR();
402
403 const int width = getWindowWidth() - 1;
404 const int height = getWindowHeight() - 1;
405 EXPECT_PIXEL_EQ(0, 0, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
406 EXPECT_PIXEL_EQ(width, 0, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
407 EXPECT_PIXEL_EQ(0, height, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
408 EXPECT_PIXEL_EQ(width, height, blackColor[0], blackColor[1], blackColor[2], blackColor[3]);
409 }
410
411 ANGLE_INSTANTIATE_TEST_ES2(IncompleteTextureTest);
412
413 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IncompleteTextureTestES3);
414 ANGLE_INSTANTIATE_TEST_ES3(IncompleteTextureTestES3);
415
416 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IncompleteTextureTestES31);
417 ANGLE_INSTANTIATE_TEST_ES31(IncompleteTextureTestES31);
418