• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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