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