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 namespace angle
11 {
12
13 class CopyTexImageTest : public ANGLETest<>
14 {
15 protected:
CopyTexImageTest()16 CopyTexImageTest()
17 {
18 setWindowWidth(32);
19 setWindowHeight(32);
20 setConfigRedBits(8);
21 setConfigGreenBits(8);
22 setConfigBlueBits(8);
23 setConfigAlphaBits(8);
24 }
25
testSetUp()26 void testSetUp() override
27 {
28 mTextureProgram =
29 CompileProgram(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
30 if (mTextureProgram == 0)
31 {
32 FAIL() << "shader compilation failed.";
33 }
34
35 mTextureUniformLocation =
36 glGetUniformLocation(mTextureProgram, essl1_shaders::Texture2DUniform());
37
38 ASSERT_GL_NO_ERROR();
39 }
40
testTearDown()41 void testTearDown() override { glDeleteProgram(mTextureProgram); }
42
initializeResources(GLenum internalFormat,GLenum format,GLenum type)43 void initializeResources(GLenum internalFormat, GLenum format, GLenum type)
44 {
45 for (size_t i = 0; i < kFboCount; ++i)
46 {
47 glBindTexture(GL_TEXTURE_2D, mFboTextures[i]);
48 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, kFboSizes[i], kFboSizes[i], 0, format,
49 type, nullptr);
50
51 // Disable mipmapping
52 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
53 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
54
55 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[i]);
56 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
57 mFboTextures[i], 0);
58
59 glClearColor(kFboColors[i][0], kFboColors[i][1], kFboColors[i][2], kFboColors[i][3]);
60 glClear(GL_COLOR_BUFFER_BIT);
61 }
62
63 ASSERT_GL_NO_ERROR();
64 }
65
initializeResources(GLenum format,GLenum type)66 void initializeResources(GLenum format, GLenum type)
67 {
68 initializeResources(format, format, type);
69 }
70
verifyResults(GLuint texture,const GLubyte data[4],GLint fboSize,GLint xs,GLint ys,GLint xe,GLint ye)71 void verifyResults(GLuint texture,
72 const GLubyte data[4],
73 GLint fboSize,
74 GLint xs,
75 GLint ys,
76 GLint xe,
77 GLint ye)
78 {
79 glViewport(0, 0, fboSize, fboSize);
80
81 glBindFramebuffer(GL_FRAMEBUFFER, 0);
82
83 // Draw a quad with the target texture
84 glUseProgram(mTextureProgram);
85 glBindTexture(GL_TEXTURE_2D, texture);
86 glUniform1i(mTextureUniformLocation, 0);
87
88 drawQuad(mTextureProgram, essl1_shaders::PositionAttrib(), 0.5f);
89
90 // Expect that the rendered quad has the same color as the source texture
91 EXPECT_PIXEL_NEAR(xs, ys, data[0], data[1], data[2], data[3], 1.0);
92 EXPECT_PIXEL_NEAR(xs, ye - 1, data[0], data[1], data[2], data[3], 1.0);
93 EXPECT_PIXEL_NEAR(xe - 1, ys, data[0], data[1], data[2], data[3], 1.0);
94 EXPECT_PIXEL_NEAR(xe - 1, ye - 1, data[0], data[1], data[2], data[3], 1.0);
95 EXPECT_PIXEL_NEAR((xs + xe) / 2, (ys + ye) / 2, data[0], data[1], data[2], data[3], 1.0);
96 }
97
verifyCheckeredResults(GLuint texture,const GLubyte data0[4],const GLubyte data1[4],const GLubyte data2[4],const GLubyte data3[4],GLint fboWidth,GLint fboHeight)98 void verifyCheckeredResults(GLuint texture,
99 const GLubyte data0[4],
100 const GLubyte data1[4],
101 const GLubyte data2[4],
102 const GLubyte data3[4],
103 GLint fboWidth,
104 GLint fboHeight)
105 {
106 glViewport(0, 0, fboWidth, fboHeight);
107
108 glBindFramebuffer(GL_FRAMEBUFFER, 0);
109
110 // Draw a quad with the target texture
111 glUseProgram(mTextureProgram);
112 glBindTexture(GL_TEXTURE_2D, texture);
113 glUniform1i(mTextureUniformLocation, 0);
114
115 drawQuad(mTextureProgram, essl1_shaders::PositionAttrib(), 0.5f);
116
117 // Expect that the rendered quad has the same color as the source texture
118 EXPECT_PIXEL_EQ(fboWidth / 4, fboHeight / 4, data0[0], data0[1], data0[2], data0[3]);
119 EXPECT_PIXEL_EQ(fboWidth / 4, 3 * fboHeight / 4, data1[0], data1[1], data1[2], data1[3]);
120 EXPECT_PIXEL_EQ(3 * fboWidth / 4, fboHeight / 4, data2[0], data2[1], data2[2], data2[3]);
121 EXPECT_PIXEL_EQ(3 * fboWidth / 4, 3 * fboHeight / 4, data3[0], data3[1], data3[2],
122 data3[3]);
123 }
124
runCopyTexImageTest(GLenum format,GLubyte expected[3][4])125 void runCopyTexImageTest(GLenum format, GLubyte expected[3][4])
126 {
127 GLTexture tex;
128 glBindTexture(GL_TEXTURE_2D, tex);
129
130 // Disable mipmapping
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
133
134 // Perform the copy multiple times.
135 //
136 // - The first time, a new texture is created
137 // - The second time, as the fbo size is the same as previous, the texture storage is not
138 // recreated.
139 // - The third time, the fbo size is different, so a new texture is created.
140 for (size_t i = 0; i < kFboCount; ++i)
141 {
142 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[i]);
143
144 glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, kFboSizes[i], kFboSizes[i], 0);
145 ASSERT_GL_NO_ERROR();
146
147 verifyResults(tex, expected[i], kFboSizes[i], 0, 0, kFboSizes[i], kFboSizes[i]);
148 }
149 }
150
151 // x, y, width, height specify the portion of fbo to be copied into tex.
152 // flip_y specifies if the glCopyTextImage must be done from y-flipped fbo.
runCopyTexImageTestCheckered(GLenum format,const uint32_t x[3],const uint32_t y[3],const uint32_t width[3],const uint32_t height[3],const GLubyte expectedData0[4],const GLubyte expectedData1[4],const GLubyte expectedData2[4],const GLubyte expectedData3[4],bool mesaFlipY)153 void runCopyTexImageTestCheckered(GLenum format,
154 const uint32_t x[3],
155 const uint32_t y[3],
156 const uint32_t width[3],
157 const uint32_t height[3],
158 const GLubyte expectedData0[4],
159 const GLubyte expectedData1[4],
160 const GLubyte expectedData2[4],
161 const GLubyte expectedData3[4],
162 bool mesaFlipY)
163 {
164 GLTexture tex;
165 glBindTexture(GL_TEXTURE_2D, tex);
166
167 // Disable mipmapping
168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
170
171 // Perform the copy multiple times.
172 for (size_t i = 0; i < kFboCount; ++i)
173 {
174 glViewport(0, 0, kFboSizes[i], kFboSizes[i]);
175 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[i]);
176
177 ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(),
178 essl1_shaders::fs::Checkered());
179 drawQuad(checkerProgram, essl1_shaders::PositionAttrib(), 0.5f);
180 EXPECT_GL_NO_ERROR();
181
182 if (mesaFlipY)
183 glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
184 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x[i], y[i], width[i], height[i], 0);
185 ASSERT_GL_NO_ERROR();
186
187 verifyCheckeredResults(tex, expectedData0, expectedData1, expectedData2, expectedData3,
188 kFboSizes[i], kFboSizes[i]);
189 }
190 }
191
runCopyTexSubImageTest(GLenum format,GLubyte expected[3][4])192 void runCopyTexSubImageTest(GLenum format, GLubyte expected[3][4])
193 {
194 GLTexture tex;
195 glBindTexture(GL_TEXTURE_2D, tex);
196
197 // Disable mipmapping
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
200
201 // Create the texture with copy of the first fbo.
202 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
203 glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, kFboSizes[0], kFboSizes[0], 0);
204 ASSERT_GL_NO_ERROR();
205
206 verifyResults(tex, expected[0], kFboSizes[0], 0, 0, kFboSizes[0], kFboSizes[0]);
207
208 // Make sure out-of-bound writes to the texture return invalid value.
209 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[1]);
210
211 // xoffset < 0 and yoffset < 0
212 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, -1, -1, 0, 0, kFboSizes[0], kFboSizes[0]);
213 ASSERT_GL_ERROR(GL_INVALID_VALUE);
214
215 // xoffset + width > w and yoffset + height > h
216 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 0, 0, kFboSizes[0], kFboSizes[0]);
217 ASSERT_GL_ERROR(GL_INVALID_VALUE);
218
219 // xoffset + width > w and yoffset + height > h, out of bounds
220 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, -1, -1, 1 + kFboSizes[0], 1 + kFboSizes[0]);
221 ASSERT_GL_ERROR(GL_INVALID_VALUE);
222
223 // Copy the second fbo over a portion of the image.
224 GLint offset = kFboSizes[0] / 2;
225 GLint extent = kFboSizes[0] - offset;
226
227 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, offset, offset, kFboSizes[1] / 2, kFboSizes[1] / 2,
228 extent, extent);
229 ASSERT_GL_NO_ERROR();
230
231 verifyResults(tex, expected[1], kFboSizes[0], offset, offset, kFboSizes[0], kFboSizes[0]);
232
233 // The rest of the image should be untouched
234 verifyResults(tex, expected[0], kFboSizes[0], 0, 0, offset, offset);
235 verifyResults(tex, expected[0], kFboSizes[0], offset, 0, kFboSizes[0], offset);
236 verifyResults(tex, expected[0], kFboSizes[0], 0, offset, offset, kFboSizes[0]);
237
238 // Copy the third fbo over another portion of the image.
239 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[2]);
240
241 offset = kFboSizes[0] / 4;
242 extent = kFboSizes[0] - offset;
243
244 // While width and height are set as 3/4 of the size, the fbo offset is given such that
245 // after clipping, width and height are effectively 1/2 of the size.
246 GLint srcOffset = kFboSizes[2] - kFboSizes[0] / 2;
247 GLint effectiveExtent = kFboSizes[0] / 2;
248
249 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, offset, offset, srcOffset, srcOffset, extent, extent);
250 ASSERT_GL_NO_ERROR();
251
252 verifyResults(tex, expected[2], kFboSizes[0], offset, offset, effectiveExtent,
253 effectiveExtent);
254
255 // The rest of the image should be untouched
256 verifyResults(tex, expected[1], kFboSizes[0], offset + effectiveExtent, kFboSizes[0] / 2,
257 kFboSizes[0], kFboSizes[0]);
258 verifyResults(tex, expected[1], kFboSizes[0], kFboSizes[0] / 2, offset + effectiveExtent,
259 kFboSizes[0], kFboSizes[0]);
260
261 verifyResults(tex, expected[0], kFboSizes[0], 0, 0, kFboSizes[0], offset);
262 verifyResults(tex, expected[0], kFboSizes[0], 0, 0, offset, kFboSizes[0]);
263 verifyResults(tex, expected[0], kFboSizes[0], offset + effectiveExtent, 0, kFboSizes[0],
264 kFboSizes[0] / 2);
265 verifyResults(tex, expected[0], kFboSizes[0], 0, offset + effectiveExtent, kFboSizes[0] / 2,
266 kFboSizes[0]);
267 }
268
testBGRAToRGBAConversion()269 void testBGRAToRGBAConversion()
270 {
271 GLFramebuffer framebuffer;
272 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
273
274 GLColor bgraInputData(128, 64, 255, 255);
275 GLColor bgraExpectedData(255, 64, 128, 255);
276
277 GLTexture bgraTexture;
278 glBindTexture(GL_TEXTURE_2D, bgraTexture);
279 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, 1, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
280 &bgraInputData);
281
282 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, bgraTexture, 0);
283 EXPECT_PIXEL_COLOR_EQ(0, 0, bgraExpectedData);
284
285 // Copy BGRA framebuffer -> RGBA texture
286 GLTexture rgbaTexture;
287 glBindTexture(GL_TEXTURE_2D, rgbaTexture);
288 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
289 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
290
291 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgbaTexture, 0);
292 EXPECT_PIXEL_COLOR_EQ(0, 0, bgraExpectedData);
293 }
294
testRGBAToBGRAConversion()295 void testRGBAToBGRAConversion()
296 {
297 GLFramebuffer framebuffer;
298 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
299
300 GLColor rgbaData(255, 128, 64, 255);
301
302 GLTexture rgbaTexture;
303 glBindTexture(GL_TEXTURE_2D, rgbaTexture);
304 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rgbaData);
305
306 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgbaTexture, 0);
307 EXPECT_PIXEL_COLOR_EQ(0, 0, rgbaData);
308
309 // Copy RGBA framebuffer -> BGRA Texture
310 GLTexture bgraTexture;
311 glBindTexture(GL_TEXTURE_2D, bgraTexture);
312 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, 1, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
313 nullptr);
314
315 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
316
317 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, bgraTexture, 0);
318 EXPECT_PIXEL_COLOR_EQ(0, 0, rgbaData);
319 }
320
321 GLuint mTextureProgram;
322 GLint mTextureUniformLocation;
323
324 static constexpr uint32_t kFboCount = 3;
325 GLFramebuffer mFbos[kFboCount];
326 GLTexture mFboTextures[kFboCount];
327
328 static constexpr uint32_t kFboSizes[kFboCount] = {16, 16, 32};
329 static constexpr GLfloat kFboColors[kFboCount][4] = {{0.25f, 1.0f, 0.75f, 0.5f},
330 {1.0f, 0.75f, 0.5f, 0.25f},
331 {0.5f, 0.25f, 1.0f, 0.75f}};
332 };
333
TEST_P(CopyTexImageTest,RGBAToRGB)334 TEST_P(CopyTexImageTest, RGBAToRGB)
335 {
336 GLubyte expected[3][4] = {
337 {64, 255, 191, 255},
338 {255, 191, 127, 255},
339 {127, 64, 255, 255},
340 };
341
342 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
343 runCopyTexImageTest(GL_RGB, expected);
344 }
345
TEST_P(CopyTexImageTest,RGBAToL)346 TEST_P(CopyTexImageTest, RGBAToL)
347 {
348 GLubyte expected[3][4] = {
349 {64, 64, 64, 255},
350 {255, 255, 255, 255},
351 {127, 127, 127, 255},
352 };
353
354 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
355 runCopyTexImageTest(GL_LUMINANCE, expected);
356 }
357
TEST_P(CopyTexImageTest,RGBToL)358 TEST_P(CopyTexImageTest, RGBToL)
359 {
360 GLubyte expected[3][4] = {
361 {64, 64, 64, 255},
362 {255, 255, 255, 255},
363 {127, 127, 127, 255},
364 };
365
366 initializeResources(GL_RGB, GL_UNSIGNED_BYTE);
367 runCopyTexImageTest(GL_LUMINANCE, expected);
368 }
369
TEST_P(CopyTexImageTest,RGBAToLA)370 TEST_P(CopyTexImageTest, RGBAToLA)
371 {
372 GLubyte expected[3][4] = {
373 {64, 64, 64, 127},
374 {255, 255, 255, 64},
375 {127, 127, 127, 191},
376 };
377
378 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
379 runCopyTexImageTest(GL_LUMINANCE_ALPHA, expected);
380 }
381
TEST_P(CopyTexImageTest,RGBAToA)382 TEST_P(CopyTexImageTest, RGBAToA)
383 {
384 GLubyte expected[3][4] = {
385 {0, 0, 0, 127},
386 {0, 0, 0, 64},
387 {0, 0, 0, 191},
388 };
389
390 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
391 runCopyTexImageTest(GL_ALPHA, expected);
392 }
393
TEST_P(CopyTexImageTest,SubImageRGBAToRGB)394 TEST_P(CopyTexImageTest, SubImageRGBAToRGB)
395 {
396 GLubyte expected[3][4] = {
397 {64, 255, 191, 255},
398 {255, 191, 127, 255},
399 {127, 64, 255, 255},
400 };
401
402 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
403 runCopyTexSubImageTest(GL_RGB, expected);
404 }
405
TEST_P(CopyTexImageTest,SubImageRGBAToL)406 TEST_P(CopyTexImageTest, SubImageRGBAToL)
407 {
408 GLubyte expected[3][4] = {
409 {64, 64, 64, 255},
410 {255, 255, 255, 255},
411 {127, 127, 127, 255},
412 };
413
414 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
415 runCopyTexSubImageTest(GL_LUMINANCE, expected);
416 }
417
TEST_P(CopyTexImageTest,SubImageRGBAToLA)418 TEST_P(CopyTexImageTest, SubImageRGBAToLA)
419 {
420 GLubyte expected[3][4] = {
421 {64, 64, 64, 127},
422 {255, 255, 255, 64},
423 {127, 127, 127, 191},
424 };
425
426 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
427 runCopyTexSubImageTest(GL_LUMINANCE_ALPHA, expected);
428 }
429
TEST_P(CopyTexImageTest,SubImageRGBToL)430 TEST_P(CopyTexImageTest, SubImageRGBToL)
431 {
432 GLubyte expected[3][4] = {
433 {64, 64, 64, 255},
434 {255, 255, 255, 255},
435 {127, 127, 127, 255},
436 };
437
438 initializeResources(GL_RGB, GL_UNSIGNED_BYTE);
439 runCopyTexSubImageTest(GL_LUMINANCE, expected);
440 }
441
TEST_P(CopyTexImageTest,RGBXToL)442 TEST_P(CopyTexImageTest, RGBXToL)
443 {
444 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_rgbx_internal_format"));
445
446 GLubyte expected[3][4] = {
447 {64, 64, 64, 255},
448 {255, 255, 255, 255},
449 {127, 127, 127, 255},
450 };
451
452 initializeResources(GL_RGBX8_ANGLE, GL_RGB, GL_UNSIGNED_BYTE);
453 runCopyTexImageTest(GL_LUMINANCE, expected);
454 }
455
456 // Read default framebuffer with glCopyTexImage2D().
TEST_P(CopyTexImageTest,DefaultFramebuffer)457 TEST_P(CopyTexImageTest, DefaultFramebuffer)
458 {
459 // Seems to be a bug in Mesa with the GLX back end: cannot read framebuffer until we draw to it.
460 // glCopyTexImage2D() below will fail without this clear.
461 glClear(GL_COLOR_BUFFER_BIT);
462
463 const GLint w = getWindowWidth(), h = getWindowHeight();
464 GLTexture tex;
465 glBindTexture(GL_TEXTURE_2D, tex);
466 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
467 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, w, h, 0);
468 EXPECT_GL_NO_ERROR();
469 }
470
471 // Read default framebuffer with glCopyTexSubImage2D().
TEST_P(CopyTexImageTest,SubDefaultFramebuffer)472 TEST_P(CopyTexImageTest, SubDefaultFramebuffer)
473 {
474 // Seems to be a bug in Mesa with the GLX back end: cannot read framebuffer until we draw to it.
475 // glCopyTexSubImage2D() below will fail without this clear.
476 glClear(GL_COLOR_BUFFER_BIT);
477
478 const GLint w = getWindowWidth(), h = getWindowHeight();
479 GLTexture tex;
480 glBindTexture(GL_TEXTURE_2D, tex);
481 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
482 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
483 EXPECT_GL_NO_ERROR();
484 }
485
486 // Calling CopyTexSubImage from cubeMap texture.
TEST_P(CopyTexImageTest,CopyTexSubImageFromCubeMap)487 TEST_P(CopyTexImageTest, CopyTexSubImageFromCubeMap)
488 {
489 constexpr GLsizei kCubeMapFaceCount = 6;
490
491 // The framebuffer will be a face of a cube map with a different colors for each face. Each
492 // glCopyTexSubImage2D will take one face of this image to copy over a pixel in a 1x6
493 // framebuffer.
494 GLColor fboPixels[kCubeMapFaceCount] = {GLColor::red, GLColor::yellow, GLColor::green,
495 GLColor::cyan, GLColor::blue, GLColor::magenta};
496 GLColor whitePixels[kCubeMapFaceCount] = {GLColor::white, GLColor::white, GLColor::white,
497 GLColor::white, GLColor::white, GLColor::white};
498
499 GLTexture fboTex;
500 glBindTexture(GL_TEXTURE_CUBE_MAP, fboTex);
501 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
502 face++)
503 {
504 GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
505
506 glTexImage2D(face, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &fboPixels[faceIndex]);
507 }
508
509 GLTexture dstTex;
510 glBindTexture(GL_TEXTURE_2D, dstTex);
511 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeMapFaceCount, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
512 whitePixels);
513
514 GLFramebuffer fbo;
515 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
516
517 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
518 face++)
519 {
520 GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
521
522 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face, fboTex, 0);
523
524 ASSERT_GL_NO_ERROR();
525 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
526
527 // Copy the fbo (a cube map face) into a pixel of the destination texture.
528 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, faceIndex, 0, 0, 0, 1, 1);
529 }
530
531 // Make sure all the copies are done correctly.
532 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
533
534 ASSERT_GL_NO_ERROR();
535 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
536
537 for (GLsizei faceIndex = 0; faceIndex < kCubeMapFaceCount; ++faceIndex)
538 {
539 EXPECT_PIXEL_COLOR_EQ(faceIndex, 0, fboPixels[faceIndex]);
540 }
541 }
542
543 // Calling CopyTexSubImage to a non-cube-complete texture.
TEST_P(CopyTexImageTest,CopyTexSubImageToNonCubeCompleteDestination)544 TEST_P(CopyTexImageTest, CopyTexSubImageToNonCubeCompleteDestination)
545 {
546 constexpr GLsizei kCubeMapFaceCount = 6;
547
548 // The framebuffer will be a 1x6 image with 6 different colors. Each glCopyTexSubImage2D will
549 // take one pixel of this image to copy over each face of a cube map.
550 GLColor fboPixels[kCubeMapFaceCount] = {GLColor::red, GLColor::yellow, GLColor::green,
551 GLColor::cyan, GLColor::blue, GLColor::magenta};
552 GLColor whitePixel = GLColor::white;
553
554 GLTexture fboTex;
555 glBindTexture(GL_TEXTURE_2D, fboTex);
556 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeMapFaceCount, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
557 fboPixels);
558
559 GLFramebuffer fbo;
560 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
561 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
562
563 ASSERT_GL_NO_ERROR();
564 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
565
566 GLTexture cubeMap;
567 glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMap);
568
569 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
570 face++)
571 {
572 GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
573
574 // Initialize the face with a color not found in the fbo.
575 glTexImage2D(face, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &whitePixel);
576
577 // Copy one pixel from the fbo into this face. The first 5 copies are done on a
578 // non-cube-complete texture.
579 glCopyTexSubImage2D(face, 0, 0, 0, faceIndex, 0, 1, 1);
580 }
581
582 // Make sure all the copies are done correctly.
583 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
584 face++)
585 {
586 GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
587
588 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face, cubeMap, 0);
589
590 ASSERT_GL_NO_ERROR();
591 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
592
593 EXPECT_PIXEL_COLOR_EQ(0, 0, fboPixels[faceIndex]);
594 }
595 }
596
597 // Deleting textures after copying to them. http://anglebug.com/4267
TEST_P(CopyTexImageTest,DeleteAfterCopyingToTextures)598 TEST_P(CopyTexImageTest, DeleteAfterCopyingToTextures)
599 {
600 GLTexture texture;
601 glBindTexture(GL_TEXTURE_2D, texture);
602 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
603 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
604 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
605 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
606 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
607
608 GLTexture texture2;
609 glBindTexture(GL_TEXTURE_2D, texture2);
610 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
611 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
612 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
613 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
614 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
615
616 GLFramebuffer framebuffer;
617 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
618 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
619 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
620
621 // Perform CopyTexImage2D
622 glBindTexture(GL_TEXTURE_2D, texture);
623 glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
624 ASSERT_GL_NO_ERROR();
625 // Not necessary to do any CopyTexImage2D operations to texture2.
626
627 // Perform CopyTexSubImage2D
628 glBindTexture(GL_TEXTURE_2D, texture);
629 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
630 ASSERT_GL_NO_ERROR();
631 glBindTexture(GL_TEXTURE_2D, texture2);
632 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
633 ASSERT_GL_NO_ERROR();
634
635 // Clean up - provokes crash on buggy drivers.
636 texture.reset();
637 // Crashes on Intel GPUs on macOS.
638 texture2.reset();
639 }
640
641 // Test if glCopyTexImage2D() implementation performs conversions well from GL_TEXTURE_3D to
642 // GL_TEXTURE_2D.
643 // This is similar to CopyTexImageTestES3.CopyTexSubImageFromTexture3D but for GL_OES_texture_3D
644 // extension.
TEST_P(CopyTexImageTest,CopyTexSubImageFrom3DTexureOES)645 TEST_P(CopyTexImageTest, CopyTexSubImageFrom3DTexureOES)
646 {
647 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
648 // TODO(anglebug.com/3801)
649 // Seems to fail on D3D11 Windows.
650 ANGLE_SKIP_TEST_IF(IsD3D11() && IsWindows());
651
652 // http://anglebug.com/4927
653 ANGLE_SKIP_TEST_IF((IsPixel2() || IsNexus5X()) && IsOpenGLES());
654
655 constexpr GLsizei kDepth = 6;
656
657 // The framebuffer will be a slice of a 3d texture with a different colors for each slice. Each
658 // glCopyTexSubImage2D will take one face of this image to copy over a pixel in a 1x6
659 // framebuffer.
660 GLColor fboPixels[kDepth] = {GLColor::red, GLColor::yellow, GLColor::green,
661 GLColor::cyan, GLColor::blue, GLColor::magenta};
662 GLColor whitePixels[kDepth] = {GLColor::white, GLColor::white, GLColor::white,
663 GLColor::white, GLColor::white, GLColor::white};
664
665 GLTexture fboTex;
666 glBindTexture(GL_TEXTURE_3D, fboTex);
667 glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, kDepth, 0, GL_RGBA, GL_UNSIGNED_BYTE,
668 fboPixels);
669
670 GLTexture dstTex;
671 glBindTexture(GL_TEXTURE_2D, dstTex);
672 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kDepth, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, whitePixels);
673
674 GLFramebuffer fbo;
675 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
676
677 for (GLsizei slice = 0; slice < kDepth; ++slice)
678 {
679 glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, fboTex, 0,
680 slice);
681
682 ASSERT_GL_NO_ERROR();
683 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
684
685 // Copy the fbo (a 3d slice) into a pixel of the destination texture.
686 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, slice, 0, 0, 0, 1, 1);
687 }
688
689 // Make sure all the copies are done correctly.
690 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
691
692 ASSERT_GL_NO_ERROR();
693 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
694
695 for (GLsizei slice = 0; slice < kDepth; ++slice)
696 {
697 EXPECT_PIXEL_COLOR_EQ(slice, 0, fboPixels[slice]);
698 }
699 }
700
701 // Tests image copy from y-flipped fbo works.
TEST_P(CopyTexImageTest,CopyTexImageMesaYFlip)702 TEST_P(CopyTexImageTest, CopyTexImageMesaYFlip)
703 {
704 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
705
706 std::array<uint32_t, 3> copyOrigin{0};
707 std::array<uint32_t, 3> copySize;
708 for (size_t i = 0; i < kFboCount; i++)
709 copySize[i] = kFboSizes[i];
710
711 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
712 runCopyTexImageTestCheckered(GL_RGBA, copyOrigin.data(), copyOrigin.data(), copySize.data(),
713 copySize.data(), GLColor::green.data(), GLColor::red.data(),
714 GLColor::yellow.data(), GLColor::blue.data(),
715 true /* mesaFlipY */);
716 }
717
718 // Tests image partial copy from y-flipped fbo works.
TEST_P(CopyTexImageTest,CopyTexImageMesaYFlipPartial)719 TEST_P(CopyTexImageTest, CopyTexImageMesaYFlipPartial)
720 {
721 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
722
723 std::array<uint32_t, kFboCount> copyX;
724 std::array<uint32_t, kFboCount> copyY{0};
725 std::array<uint32_t, kFboCount> copyWidth;
726 std::array<uint32_t, kFboCount> copyHeight;
727
728 for (size_t i = 0; i < kFboCount; i++)
729 {
730 copyX[i] = kFboSizes[i] / 2;
731 copyHeight[i] = kFboSizes[i];
732 }
733 copyWidth = copyX;
734
735 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
736 runCopyTexImageTestCheckered(GL_RGBA, copyX.data(), copyY.data(), copyWidth.data(),
737 copyHeight.data(), GLColor::yellow.data(), GLColor::blue.data(),
738 GLColor::yellow.data(), GLColor::blue.data(),
739 true /* mesaFlipY */);
740 }
741
742 // Tests subimage copy from y-flipped fbo works.
TEST_P(CopyTexImageTest,CopyTexSubImageMesaYFlip)743 TEST_P(CopyTexImageTest, CopyTexSubImageMesaYFlip)
744 {
745 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
746
747 GLuint format = GL_RGBA;
748 initializeResources(format, GL_UNSIGNED_BYTE);
749
750 glViewport(0, 0, kFboSizes[0], kFboSizes[0]);
751 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
752
753 ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(),
754 essl1_shaders::fs::Checkered());
755 drawQuad(checkerProgram, essl1_shaders::PositionAttrib(), 0.5f);
756 EXPECT_GL_NO_ERROR();
757
758 GLTexture tex;
759 glBindTexture(GL_TEXTURE_2D, tex);
760
761 // Disable mipmapping
762 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
763 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
764
765 // Create the texture with copy of the first fbo.
766 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
767 glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
768 glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, kFboSizes[0], kFboSizes[0], 0);
769 ASSERT_GL_NO_ERROR();
770
771 // Make sure out-of-bound writes to the texture return invalid value.
772 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[1]);
773 drawQuad(checkerProgram, essl1_shaders::PositionAttrib(), 0.5f);
774 EXPECT_GL_NO_ERROR();
775
776 glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
777
778 // xoffset < 0 and yoffset < 0
779 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, -1, -1, 0, 0, kFboSizes[0], kFboSizes[0]);
780 ASSERT_GL_ERROR(GL_INVALID_VALUE);
781
782 // xoffset + width > w and yoffset + height > h
783 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 0, 0, kFboSizes[0], kFboSizes[0]);
784 ASSERT_GL_ERROR(GL_INVALID_VALUE);
785
786 // xoffset + width > w and yoffset + height > h, out of bounds
787 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, -1, -1, 1 + kFboSizes[0], 1 + kFboSizes[0]);
788 ASSERT_GL_ERROR(GL_INVALID_VALUE);
789
790 // Copy the second fbo over a portion of the image.
791 GLint offset = kFboSizes[0] / 2;
792 GLint extent = kFboSizes[0] - offset;
793 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, offset, offset, kFboSizes[1] / 2, kFboSizes[1] / 2,
794 extent, extent);
795 ASSERT_GL_NO_ERROR();
796
797 // Only part of the image is changed.
798 verifyCheckeredResults(tex, GLColor::green.data(), GLColor::red.data(), GLColor::yellow.data(),
799 GLColor::blue.data(), kFboSizes[0], kFboSizes[0]);
800 }
801
802 // Tests that set RobustResourceInit to true, so that code path with
803 // RobustResourceInit == true can be checked
804 class CopyTexImageTestRobustResourceInit : public CopyTexImageTest
805 {
806 protected:
CopyTexImageTestRobustResourceInit()807 CopyTexImageTestRobustResourceInit() : CopyTexImageTest() { setRobustResourceInit(true); }
808 };
809
810 // Adapted from the fuzz test with invalid input
TEST_P(CopyTexImageTestRobustResourceInit,InvalidInputParam)811 TEST_P(CopyTexImageTestRobustResourceInit, InvalidInputParam)
812 {
813 glClear(GL_COLOR_BUFFER_BIT);
814
815 const GLint w = getWindowWidth(), h = getWindowHeight();
816 GLTexture tex;
817 glBindTexture(GL_TEXTURE_2D, tex);
818 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
819
820 // pass y that is greater than max2DTextureSize
821 GLenum target = GL_TEXTURE_2D;
822 GLint level = 0;
823 GLenum internalFormat = GL_LUMINANCE_ALPHA;
824 GLint x = 0;
825 GLint y = 13434880;
826 GLsizei width = 0;
827 GLsizei height = 65830;
828 GLint border = 0;
829 glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
830 EXPECT_GL_ERROR(GL_INVALID_VALUE);
831
832 // pass x and width that will result in integer overflow when we apply x+width
833 target = GL_TEXTURE_2D;
834 level = 0;
835 internalFormat = GL_LUMINANCE_ALPHA;
836 x = std::numeric_limits<GLint>::max();
837 y = 0;
838 width = 253;
839 height = 1;
840 border = 0;
841 glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
842 EXPECT_GL_ERROR(GL_INVALID_VALUE);
843 }
844
845 // specialization of CopyTexImageTest is added so that some tests can be explicitly run with an ES3
846 // context
847 class CopyTexImageTestES3 : public CopyTexImageTest
848 {
849 protected:
850 void initialize3DTexture(GLTexture &texture,
851 const GLsizei imageWidth,
852 const GLsizei imageHeight,
853 const GLsizei imageDepth,
854 const GLColor *textureData);
855 void initialize2DTexture(GLTexture &texture,
856 const GLsizei imageWidth,
857 const GLsizei imageHeight,
858 const GLColor *textureData);
859 void initialize2DTextureUShort4444(GLTexture &texture,
860 const GLsizei imageWidth,
861 const GLsizei imageHeight,
862 const GLColor *textureData);
863 void fillTexture(std::vector<GLColor> &texture, const GLColor color);
864 void clearTexture(GLFramebuffer &fbo, GLTexture &texture, const GLColor color);
865 void copyTexSubImage3D(GLTexture &subTexture2D,
866 const GLint xOffset,
867 const GLint yOffset,
868 const GLsizei subImageWidth,
869 const GLsizei subImageHeight,
870 const GLsizei imageDepth);
871 void verifyCopyTexSubImage3D(GLTexture &texture3D,
872 const GLint xOffset,
873 const GLint yOffset,
874 const GLColor subImageColor);
875
876 // Constants
877 const GLColor kSubImageColor = GLColor::yellow;
878 // 3D image dimensions
879 const GLsizei kImageWidth = getWindowWidth();
880 const GLsizei kImageHeight = getWindowHeight();
881 const GLsizei kImageDepth = 4;
882 // 2D sub-image dimensions
883 const GLsizei kSubImageWidth = getWindowWidth() / 4;
884 const GLsizei kSubImageHeight = getWindowHeight() / 4;
885 // Sub-Image Offsets
886 const GLint kXOffset = getWindowWidth() - kSubImageWidth;
887 const GLint kYOffset = getWindowHeight() - kSubImageHeight;
888 };
889
890 // The test verifies that glCopyTexSubImage2D generates a GL_INVALID_OPERATION error
891 // when the read buffer is GL_NONE.
892 // Reference: GLES 3.0.4, Section 3.8.5 Alternate Texture Image Specification Commands
TEST_P(CopyTexImageTestES3,ReadBufferIsNone)893 TEST_P(CopyTexImageTestES3, ReadBufferIsNone)
894 {
895 initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
896
897 GLTexture tex;
898 glBindTexture(GL_TEXTURE_2D, tex);
899 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
900 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
901
902 glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
903 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kFboSizes[0], kFboSizes[0], 0);
904
905 glReadBuffer(GL_NONE);
906
907 EXPECT_GL_NO_ERROR();
908 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 4, 4);
909 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
910 }
911
912 // Test CopyTexImage3D with some simple parameters with a 2D array texture.
913 TEST_P(CopyTexImageTestES3, 2DArraySubImage)
914 {
915 // Seems to fail on AMD OpenGL Windows.
916 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && IsWindows());
917
918 GLTexture tex;
919 glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
920
921 constexpr GLsizei kTexSize = 4;
922 constexpr GLsizei kLayerOffset = 1;
923 constexpr GLsizei kLayers = 2;
924
925 // Clear screen to green.
926 glClearColor(0, 1, 0, 1);
927 glClear(GL_COLOR_BUFFER_BIT);
928
929 // Initialize a two-layer 2D array texture with red.
930 std::vector<GLColor> red(kTexSize * kTexSize * kLayers, GLColor::red);
931 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kTexSize, kTexSize, kLayers, 0, GL_RGBA,
932 GL_UNSIGNED_BYTE, red.data());
933 glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, kLayerOffset, 0, 0, kTexSize, kTexSize);
934 ASSERT_GL_NO_ERROR();
935
936 // Check level 0 (red from image data) and 1 (green from backbuffer clear).
937 GLFramebuffer fbo;
938 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
939 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0);
940 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
941 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 1);
942 for (int x = 0; x < kTexSize; x++)
943 {
944 for (int y = 0; y < kTexSize; y++)
945 {
946 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
947 }
948 }
949 ASSERT_GL_NO_ERROR();
950 }
951
952 // Test if glCopyTexImage2D() implementation performs conversions well from GL_TEXTURE_3D to
953 // GL_TEXTURE_2D.
TEST_P(CopyTexImageTestES3,CopyTexSubImageFromTexture3D)954 TEST_P(CopyTexImageTestES3, CopyTexSubImageFromTexture3D)
955 {
956 // TODO(anglebug.com/3801)
957 // Seems to fail on D3D11 Windows.
958 ANGLE_SKIP_TEST_IF(IsD3D11() && IsWindows());
959
960 constexpr GLsizei kTexSize = 4;
961 constexpr GLsizei kLayers = 2;
962 std::vector<GLColor> red(kTexSize * kTexSize * kLayers, GLColor::red);
963
964 GLFramebuffer fbo;
965 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
966 glBindTexture(GL_TEXTURE_2D, 0);
967
968 // We will be reading from zeroth color attachment.
969 glReadBuffer(GL_COLOR_ATTACHMENT0);
970
971 GLTexture src_object_id;
972 glBindTexture(GL_TEXTURE_3D, src_object_id);
973 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, kTexSize, kTexSize, kLayers, 0, GL_RGBA,
974 GL_UNSIGNED_BYTE, NULL);
975 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, kTexSize, kTexSize, 1, GL_RGBA, GL_UNSIGNED_BYTE,
976 red.data());
977 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, src_object_id, 0, 1);
978 ASSERT_GL_NO_ERROR();
979
980 GLTexture dst_object_id;
981 glBindTexture(GL_TEXTURE_2D, dst_object_id);
982 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, kTexSize, kTexSize, 0);
983 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_object_id,
984 0);
985 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
986 ASSERT_GL_NO_ERROR();
987 }
988
989 // Test that copying from a non-zero base texture works.
TEST_P(CopyTexImageTestES3,CopyTexSubImageFromNonZeroBase)990 TEST_P(CopyTexImageTestES3, CopyTexSubImageFromNonZeroBase)
991 {
992 // http://anglebug.com/5000
993 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
994
995 constexpr GLsizei kTexSize = 4;
996 std::vector<GLColor> red(kTexSize * kTexSize, GLColor::red);
997 std::vector<GLColor> green(kTexSize * kTexSize, GLColor::green);
998
999 // Create a framebuffer attached to a non-zero base texture
1000 GLTexture srcColor;
1001 glBindTexture(GL_TEXTURE_2D, srcColor);
1002 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1003 red.data());
1004 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1005 green.data());
1006 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
1007 ASSERT_GL_NO_ERROR();
1008
1009 GLFramebuffer fbo;
1010 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1011 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcColor, 1);
1012 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1013
1014 // Create a texture with an identical format
1015 GLTexture dstColor;
1016 glBindTexture(GL_TEXTURE_2D, dstColor);
1017 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1018 nullptr);
1019 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1020 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1021 ASSERT_GL_NO_ERROR();
1022
1023 // Copy into a part of this texture.
1024 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kTexSize / 2, kTexSize / 2);
1025 ASSERT_GL_NO_ERROR();
1026
1027 // Verify it.
1028 constexpr std::array<GLubyte, 4> kExpected = {0, 255, 0, 255};
1029 verifyResults(dstColor, kExpected.data(), kTexSize, 0, 0, kTexSize / 2, kTexSize / 2);
1030
1031 // Copy into another part of the texture. The previous verification ensures that the texture's
1032 // internal image is allocated, so this should be a direct copy.
1033 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1034 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kTexSize / 2, kTexSize / 2, 0, 0, kTexSize / 2,
1035 kTexSize / 2);
1036 ASSERT_GL_NO_ERROR();
1037
1038 // Verify it.
1039 verifyResults(dstColor, kExpected.data(), kTexSize, kTexSize / 2, kTexSize / 2, kTexSize,
1040 kTexSize);
1041 }
1042
1043 // Test that copying into a non-zero base texture works.
TEST_P(CopyTexImageTestES3,CopyTexSubImageToNonZeroBase)1044 TEST_P(CopyTexImageTestES3, CopyTexSubImageToNonZeroBase)
1045 {
1046 // http://anglebug.com/5000
1047 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
1048
1049 constexpr GLsizei kTexSize = 4;
1050 std::vector<GLColor> green(kTexSize * kTexSize, GLColor::green);
1051
1052 // Create a framebuffer attached to a non-zero base texture
1053 GLTexture srcColor;
1054 glBindTexture(GL_TEXTURE_2D, srcColor);
1055 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1056 green.data());
1057 ASSERT_GL_NO_ERROR();
1058
1059 GLFramebuffer fbo;
1060 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1061 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcColor, 0);
1062 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1063
1064 // Create a texture with an identical format
1065 GLTexture dstColor;
1066 glBindTexture(GL_TEXTURE_2D, dstColor);
1067 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1068 nullptr);
1069 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1070 nullptr);
1071 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
1072 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
1073 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1074 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1075 ASSERT_GL_NO_ERROR();
1076
1077 // Copy into a part of this texture.
1078 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kTexSize / 2, kTexSize / 2);
1079 ASSERT_GL_NO_ERROR();
1080
1081 // Verify it.
1082 constexpr std::array<GLubyte, 4> kExpected = {0, 255, 0, 255};
1083 verifyResults(dstColor, kExpected.data(), kTexSize, 0, 0, kTexSize / 2, kTexSize / 2);
1084
1085 // Copy into another part of the texture. The previous verification ensures that the texture's
1086 // internal image is allocated, so this should be a direct copy.
1087 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1088 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, kTexSize / 2, kTexSize / 2, 0, 0, kTexSize / 2,
1089 kTexSize / 2);
1090 ASSERT_GL_NO_ERROR();
1091
1092 // Verify it.
1093 verifyResults(dstColor, kExpected.data(), kTexSize, kTexSize / 2, kTexSize / 2, kTexSize,
1094 kTexSize);
1095 }
1096
1097 // Initialize the 3D texture we will copy the subImage data into
initialize3DTexture(GLTexture & texture,const GLsizei imageWidth,const GLsizei imageHeight,const GLsizei imageDepth,const GLColor * textureData)1098 void CopyTexImageTestES3::initialize3DTexture(GLTexture &texture,
1099 const GLsizei imageWidth,
1100 const GLsizei imageHeight,
1101 const GLsizei imageDepth,
1102 const GLColor *textureData)
1103 {
1104 glBindTexture(GL_TEXTURE_3D, texture);
1105 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, imageWidth, imageHeight, imageDepth, 0, GL_RGBA,
1106 GL_UNSIGNED_BYTE, textureData);
1107 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1108 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1109 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
1110 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1111 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1112 }
1113
initialize2DTexture(GLTexture & texture,const GLsizei imageWidth,const GLsizei imageHeight,const GLColor * textureData)1114 void CopyTexImageTestES3::initialize2DTexture(GLTexture &texture,
1115 const GLsizei imageWidth,
1116 const GLsizei imageHeight,
1117 const GLColor *textureData)
1118 {
1119 glBindTexture(GL_TEXTURE_2D, texture);
1120 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1121 textureData);
1122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1124 }
1125
initialize2DTextureUShort4444(GLTexture & texture,const GLsizei imageWidth,const GLsizei imageHeight,const GLColor * textureData)1126 void CopyTexImageTestES3::initialize2DTextureUShort4444(GLTexture &texture,
1127 const GLsizei imageWidth,
1128 const GLsizei imageHeight,
1129 const GLColor *textureData)
1130 {
1131 glBindTexture(GL_TEXTURE_2D, texture);
1132 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA,
1133 GL_UNSIGNED_SHORT_4_4_4_4, textureData);
1134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1136 }
1137
fillTexture(std::vector<GLColor> & texture,const GLColor color)1138 void CopyTexImageTestES3::fillTexture(std::vector<GLColor> &texture, const GLColor color)
1139 {
1140 for (auto &texel : texture)
1141 {
1142 texel = color;
1143 }
1144 }
1145
clearTexture(GLFramebuffer & fbo,GLTexture & texture,const GLColor color)1146 void CopyTexImageTestES3::clearTexture(GLFramebuffer &fbo, GLTexture &texture, const GLColor color)
1147 {
1148 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1149 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1150 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1151 glClearColor(color.R, color.G, color.B, color.A);
1152 glClear(GL_COLOR_BUFFER_BIT);
1153 EXPECT_PIXEL_COLOR_EQ(0, 0, color);
1154 }
1155
copyTexSubImage3D(GLTexture & subTexture2D,const GLint xOffset,const GLint yOffset,const GLsizei subImageWidth,const GLsizei subImageHeight,const GLsizei imageDepth)1156 void CopyTexImageTestES3::copyTexSubImage3D(GLTexture &subTexture2D,
1157 const GLint xOffset,
1158 const GLint yOffset,
1159 const GLsizei subImageWidth,
1160 const GLsizei subImageHeight,
1161 const GLsizei imageDepth)
1162 {
1163 // Copy the 2D sub-image into the 3D texture
1164 for (int currLayer = 0; currLayer < imageDepth; ++currLayer)
1165 {
1166 // Bind the 2D texture to GL_COLOR_ATTACHMENT0
1167 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1168 subTexture2D, 0);
1169 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1170 glCopyTexSubImage3D(GL_TEXTURE_3D, 0, xOffset, yOffset, currLayer, 0, 0, subImageWidth,
1171 subImageHeight);
1172 ASSERT_GL_NO_ERROR();
1173 }
1174 }
1175
verifyCopyTexSubImage3D(GLTexture & texture3D,const GLint xOffset,const GLint yOffset,const GLColor subImageColor)1176 void CopyTexImageTestES3::verifyCopyTexSubImage3D(GLTexture &texture3D,
1177 const GLint xOffset,
1178 const GLint yOffset,
1179 const GLColor subImageColor)
1180 {
1181 // Bind to an FBO to check the copy was successful
1182 for (int currLayer = 0; currLayer < kImageDepth; ++currLayer)
1183 {
1184 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0, currLayer);
1185 ASSERT_GL_NO_ERROR();
1186 EXPECT_PIXEL_COLOR_EQ(xOffset, yOffset, subImageColor);
1187 }
1188 }
1189
1190 // Test glCopyTexSubImage3D with initialized texture data
1191 TEST_P(CopyTexImageTestES3, 3DSubImageRawTextureData)
1192 {
1193 // Texture data
1194 std::vector<GLColor> textureData(kImageWidth * kImageHeight * kImageDepth);
1195
1196 // Fill the textures with color
1197 fillTexture(textureData, GLColor::red);
1198
1199 GLFramebuffer fbo;
1200 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1201
1202 GLTexture texture3D;
1203 initialize3DTexture(texture3D, kImageWidth, kImageHeight, kImageDepth, textureData.data());
1204
1205 // The 2D texture that will be the sub-image copied into the destination texture
1206 GLTexture subTexture2D;
1207 initialize2DTexture(subTexture2D, kSubImageWidth, kSubImageHeight, nullptr);
1208 clearTexture(fbo, subTexture2D, kSubImageColor);
1209
1210 // Copy the 2D subimage into the 3D texture
1211 copyTexSubImage3D(subTexture2D, kXOffset, kYOffset, kSubImageWidth, kSubImageHeight,
1212 kImageDepth);
1213
1214 // Verify the color wasn't overwritten
1215 verifyCopyTexSubImage3D(texture3D, 0, 0, GLColor::red);
1216 // Verify the copy succeeded
1217 verifyCopyTexSubImage3D(texture3D, kXOffset, kYOffset, kSubImageColor);
1218
1219 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1220 glBindTexture(GL_TEXTURE_2D, 0);
1221 glBindTexture(GL_TEXTURE_3D, 0);
1222 }
1223
1224 // Test glCopyTexSubImage3D with initialized texture data that was drawn to
1225 TEST_P(CopyTexImageTestES3, 3DSubImageDrawTextureData)
1226 {
1227 // TODO(anglebug.com/3801)
1228 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11());
1229
1230 GLFramebuffer fbo;
1231 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1232
1233 // The 3D texture we will copy the sub-image into
1234 GLTexture texture3D;
1235 initialize3DTexture(texture3D, kImageWidth, kImageHeight, kImageDepth, nullptr);
1236
1237 // Draw to each layer in the 3D texture
1238 for (int currLayer = 0; currLayer < kImageDepth; ++currLayer)
1239 {
1240 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1241 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0,
1242 currLayer);
1243 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0,
1244 currLayer);
1245 ASSERT_GL_NO_ERROR();
1246 glUseProgram(greenProgram);
1247 drawQuad(greenProgram, std::string(essl1_shaders::PositionAttrib()), 0.0f);
1248 ASSERT_GL_NO_ERROR();
1249 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1250 }
1251
1252 // The 2D texture that will be the sub-image copied into the destination texture
1253 GLTexture subTexture2D;
1254 initialize2DTexture(subTexture2D, kSubImageWidth, kSubImageHeight, nullptr);
1255 clearTexture(fbo, subTexture2D, kSubImageColor);
1256
1257 // Copy the 2D sub-image into the 3D texture
1258 copyTexSubImage3D(subTexture2D, kXOffset, kYOffset, kSubImageWidth, kSubImageHeight,
1259 kImageDepth);
1260
1261 // Verify the color wasn't overwritten
1262 verifyCopyTexSubImage3D(texture3D, 0, 0, GLColor::green);
1263 // Verify the copy succeeded
1264 verifyCopyTexSubImage3D(texture3D, kXOffset, kYOffset, kSubImageColor);
1265
1266 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1267 glBindTexture(GL_TEXTURE_2D, 0);
1268 glBindTexture(GL_TEXTURE_3D, 0);
1269 }
1270
1271 // Test glCopyTexSubImage3D with mismatched texture formats
1272 TEST_P(CopyTexImageTestES3, 3DSubImageDrawMismatchedTextureTypes)
1273 {
1274 // TODO(anglebug.com/3801)
1275 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11());
1276
1277 // TODO(anglebug.com/5491)
1278 ANGLE_SKIP_TEST_IF(IsIOS() && IsOpenGLES());
1279
1280 GLFramebuffer fbo;
1281 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1282
1283 // The 3D texture we will copy the sub-image into
1284 GLTexture texture3D;
1285 initialize3DTexture(texture3D, kImageWidth, kImageHeight, kImageDepth, nullptr);
1286
1287 // Draw to each layer in the 3D texture
1288 for (int currLayer = 0; currLayer < kImageDepth; ++currLayer)
1289 {
1290 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1291 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0, currLayer);
1292 ASSERT_GL_NO_ERROR();
1293 glUseProgram(greenProgram);
1294 drawQuad(greenProgram, std::string(essl1_shaders::PositionAttrib()), 0.0f);
1295 ASSERT_GL_NO_ERROR();
1296 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1297 }
1298
1299 // The 2D texture that will be the sub-image copied into the destination texture
1300 GLTexture subTexture2D;
1301 initialize2DTextureUShort4444(subTexture2D, kSubImageWidth, kSubImageHeight, nullptr);
1302 clearTexture(fbo, subTexture2D, kSubImageColor);
1303
1304 // Copy the 2D sub-image into the 3D texture
1305 copyTexSubImage3D(subTexture2D, kXOffset, kYOffset, kSubImageWidth, kSubImageHeight,
1306 kImageDepth);
1307
1308 // Verify the color wasn't overwritten
1309 verifyCopyTexSubImage3D(texture3D, 0, 0, GLColor::green);
1310 // Verify the copy succeeded
1311 verifyCopyTexSubImage3D(texture3D, kXOffset, kYOffset, kSubImageColor);
1312
1313 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1314 glBindTexture(GL_TEXTURE_2D, 0);
1315 glBindTexture(GL_TEXTURE_3D, 0);
1316 }
1317
1318 // Make sure a single-level texture can be redefined through glCopyTexImage2D from a framebuffer
1319 // bound to the same texture. Regression test for a bug in the Vulkan backend where the texture was
1320 // released before the copy.
TEST_P(CopyTexImageTestES3,RedefineSameLevel)1321 TEST_P(CopyTexImageTestES3, RedefineSameLevel)
1322 {
1323 constexpr GLsizei kSize = 32;
1324 constexpr GLsizei kHalfSize = kSize / 2;
1325
1326 // Create a single-level texture with four colors in different regions.
1327 std::vector<GLColor> initData(kSize * kSize);
1328 for (GLsizei y = 0; y < kSize; ++y)
1329 {
1330 const bool isTop = y < kHalfSize;
1331 for (GLsizei x = 0; x < kSize; ++x)
1332 {
1333 const bool isLeft = x < kHalfSize;
1334
1335 GLColor color = isLeft && isTop ? GLColor::red
1336 : isLeft && !isTop ? GLColor::green
1337 : !isLeft && isTop ? GLColor::blue
1338 : GLColor::yellow;
1339 color.A = 123;
1340 initData[y * kSize + x] = color;
1341 }
1342 }
1343
1344 GLTexture tex;
1345 glBindTexture(GL_TEXTURE_2D, tex);
1346 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1347 initData.data());
1348
1349 // Bind the framebuffer to the same texture
1350 GLFramebuffer framebuffer;
1351 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1352 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
1353
1354 // Redefine the texture
1355 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kHalfSize / 2, kHalfSize / 2, kHalfSize, kHalfSize,
1356 0);
1357
1358 // Verify copy is done correctly.
1359 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1360
1361 EXPECT_PIXEL_RECT_EQ(0, 0, kHalfSize / 2, kHalfSize / 2, GLColor::red);
1362 EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, 0, kHalfSize / 2, kHalfSize / 2, GLColor::blue);
1363 EXPECT_PIXEL_RECT_EQ(0, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, GLColor::green);
1364 EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2,
1365 GLColor::yellow);
1366 }
1367
1368 class CopyTexImagePreRotationTest : public ANGLETest<>
1369 {
1370 protected:
CopyTexImagePreRotationTest()1371 CopyTexImagePreRotationTest()
1372 {
1373 // Use a non-square window to catch width/height mismatch bugs
1374 setWindowWidth(54);
1375 setWindowHeight(32);
1376 setConfigRedBits(8);
1377 setConfigGreenBits(8);
1378 setConfigBlueBits(8);
1379 setConfigAlphaBits(8);
1380 }
1381 };
1382
1383 // Basic copy test in the presence of pre-rotation
TEST_P(CopyTexImagePreRotationTest,Basic)1384 TEST_P(CopyTexImagePreRotationTest, Basic)
1385 {
1386 glClearColor(1, 0, 1, 1);
1387 glClear(GL_COLOR_BUFFER_BIT);
1388
1389 const int w = getWindowWidth();
1390 const int h = getWindowHeight();
1391
1392 GLTexture texture;
1393 glBindTexture(GL_TEXTURE_2D, texture);
1394 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, w, h);
1395
1396 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
1397
1398 // Verify results
1399 GLFramebuffer fbo;
1400 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1401 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1402
1403 EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::magenta);
1404 ASSERT_GL_NO_ERROR();
1405 }
1406
1407 // Copy test in the presence of pre-rotation with non-zero offsets and non-square sizes
TEST_P(CopyTexImagePreRotationTest,NonZeroNonSquare)1408 TEST_P(CopyTexImagePreRotationTest, NonZeroNonSquare)
1409 {
1410 // Draw four colors in the framebuffer
1411 ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(),
1412 essl1_shaders::fs::Checkered());
1413 drawQuad(checkerProgram, essl1_shaders::PositionAttrib(), 0.5f);
1414
1415 const int w = getWindowWidth();
1416 const int h = getWindowHeight();
1417
1418 const int texWidth = (w + 6) * 2;
1419 const int texHeight = (h - 8) * 2;
1420
1421 GLTexture texture;
1422 glBindTexture(GL_TEXTURE_2D, texture);
1423 glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, texWidth * 2, texHeight * 2);
1424
1425 // Copy with non-zero non-symmetric offsets to mips 0 and 1.
1426 //
1427 // The framebuffer is:
1428 //
1429 // 54
1430 // ____________^____________
1431 // / \
1432 // +------------+------------+\
1433 // | | | |
1434 // | Red | Blue | |
1435 // | | | |
1436 // | | | |
1437 // +------------+------------+ > 32
1438 // | | | |
1439 // | Green | Yellow | |
1440 // | | | |
1441 // | | | |
1442 // +------------+------------+/
1443 //
1444 // The texture's mip 0 is 120x48 and mip 1 is 60x24.
1445 //
1446 struct Copy
1447 {
1448 int mip;
1449 int texX, texY;
1450 int x, y;
1451 int width, height;
1452 GLColor expect;
1453 };
1454
1455 // Make random copies with non-zero offsets, non-zero sizes and generally different numbers to
1456 // catch any mix up.
1457 const std::array<Copy, 4> kCopies = {{
1458 {1, 20, 13, 11, 2, 9, 13, GLColor::red},
1459 {1, 31, 17, 29, 27, 20, 5, GLColor::yellow},
1460 {0, 57, 1, 3, 22, 17, 9, GLColor::green},
1461 {0, 19, 38, 46, 4, 3, 11, GLColor::blue},
1462 }};
1463
1464 for (size_t i = 0; i < kCopies.size(); ++i)
1465 {
1466 glCopyTexSubImage2D(GL_TEXTURE_2D, kCopies[i].mip, kCopies[i].texX, kCopies[i].texY,
1467 kCopies[i].x, kCopies[i].y, kCopies[i].width, kCopies[i].height);
1468 }
1469
1470 // Verify results
1471 GLFramebuffer fbo;
1472 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1473
1474 for (int mip = 0; mip < 2; ++mip)
1475 {
1476 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, mip);
1477 for (size_t i = 0; i < kCopies.size(); ++i)
1478 {
1479 if (kCopies[i].mip == mip)
1480 {
1481 EXPECT_PIXEL_RECT_EQ(kCopies[i].texX, kCopies[i].texY, kCopies[i].width,
1482 kCopies[i].height, kCopies[i].expect);
1483 }
1484 }
1485 }
1486 ASSERT_GL_NO_ERROR();
1487 }
1488
1489 // ANGLE allows BGRA <-> RGBA copies. Test that these work and correctly swizzle the channels.
TEST_P(CopyTexImageTest,BGRAAndRGBAConversions)1490 TEST_P(CopyTexImageTest, BGRAAndRGBAConversions)
1491 {
1492 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_BGRA8888"));
1493 testBGRAToRGBAConversion();
1494 testRGBAToBGRAConversion();
1495 }
1496
1497 // ANGLE allows BGRA <-> RGBA copies. Test that these work and correctly swizzle the channels.
1498 // ES3 uses different validation code for glCopyTexImage.
TEST_P(CopyTexImageTestES3,BGRAAndRGBAConversions)1499 TEST_P(CopyTexImageTestES3, BGRAAndRGBAConversions)
1500 {
1501 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_BGRA8888"));
1502 testBGRAToRGBAConversion();
1503 testRGBAToBGRAConversion();
1504 }
1505
1506 ANGLE_INSTANTIATE_TEST_ES2_AND(
1507 CopyTexImageTest,
1508 ES2_D3D11_PRESENT_PATH_FAST(),
1509 ES3_VULKAN(),
1510 ES2_OPENGL().enable(Feature::EmulateCopyTexImage2D),
1511 ES2_OPENGLES().enable(Feature::EmulateCopyTexImage2D),
1512 ES2_OPENGL().enable(Feature::EmulateCopyTexImage2DFromRenderbuffers),
1513 ES2_OPENGLES().enable(Feature::EmulateCopyTexImage2DFromRenderbuffers));
1514
1515 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CopyTexImageTestES3);
1516 ANGLE_INSTANTIATE_TEST_ES3_AND(
1517 CopyTexImageTestES3,
1518 ES3_OPENGL().enable(Feature::EmulateCopyTexImage2D),
1519 ES3_OPENGLES().enable(Feature::EmulateCopyTexImage2D),
1520 ES3_OPENGL().enable(Feature::EmulateCopyTexImage2DFromRenderbuffers),
1521 ES3_OPENGLES().enable(Feature::EmulateCopyTexImage2DFromRenderbuffers));
1522
1523 ANGLE_INSTANTIATE_TEST_ES2_AND(
1524 CopyTexImageTestRobustResourceInit,
1525 ES2_D3D11_PRESENT_PATH_FAST(),
1526 ES3_VULKAN(),
1527 ES2_OPENGL().enable(Feature::EmulateCopyTexImage2D),
1528 ES2_OPENGLES().enable(Feature::EmulateCopyTexImage2D),
1529 ES2_OPENGL().enable(Feature::EmulateCopyTexImage2DFromRenderbuffers),
1530 ES2_OPENGLES().enable(Feature::EmulateCopyTexImage2DFromRenderbuffers));
1531
1532 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CopyTexImagePreRotationTest);
1533 ANGLE_INSTANTIATE_TEST_ES3_AND(CopyTexImagePreRotationTest,
1534 ES3_VULKAN().enable(Feature::EmulatedPrerotation90),
1535 ES3_VULKAN().enable(Feature::EmulatedPrerotation180),
1536 ES3_VULKAN().enable(Feature::EmulatedPrerotation270));
1537
1538 } // namespace angle
1539