• 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         constexpr char kVS[] =
29             "precision highp float;\n"
30             "attribute vec4 position;\n"
31             "varying vec2 texcoord;\n"
32             "\n"
33             "void main()\n"
34             "{\n"
35             "    gl_Position = position;\n"
36             "    texcoord = (position.xy * 0.5) + 0.5;\n"
37             "}\n";
38 
39         constexpr char kFS[] =
40             "precision highp float;\n"
41             "uniform sampler2D tex;\n"
42             "varying vec2 texcoord;\n"
43             "\n"
44             "void main()\n"
45             "{\n"
46             "    gl_FragColor = texture2D(tex, texcoord);\n"
47             "}\n";
48 
49         mTextureProgram = CompileProgram(kVS, kFS);
50         if (mTextureProgram == 0)
51         {
52             FAIL() << "shader compilation failed.";
53         }
54 
55         mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
56 
57         ASSERT_GL_NO_ERROR();
58     }
59 
testTearDown()60     void testTearDown() override { glDeleteProgram(mTextureProgram); }
61 
initializeResources(GLenum format,GLenum type)62     void initializeResources(GLenum format, GLenum type)
63     {
64         for (size_t i = 0; i < kFboCount; ++i)
65         {
66             glBindTexture(GL_TEXTURE_2D, mFboTextures[i]);
67             glTexImage2D(GL_TEXTURE_2D, 0, format, kFboSizes[i], kFboSizes[i], 0, format, type,
68                          nullptr);
69 
70             // Disable mipmapping
71             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
72             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
73 
74             glBindFramebuffer(GL_FRAMEBUFFER, mFbos[i]);
75             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
76                                    mFboTextures[i], 0);
77 
78             glClearColor(kFboColors[i][0], kFboColors[i][1], kFboColors[i][2], kFboColors[i][3]);
79             glClear(GL_COLOR_BUFFER_BIT);
80         }
81 
82         ASSERT_GL_NO_ERROR();
83     }
84 
verifyResults(GLuint texture,GLubyte data[4],GLint fboSize,GLint xs,GLint ys,GLint xe,GLint ye)85     void verifyResults(GLuint texture,
86                        GLubyte data[4],
87                        GLint fboSize,
88                        GLint xs,
89                        GLint ys,
90                        GLint xe,
91                        GLint ye)
92     {
93         glViewport(0, 0, fboSize, fboSize);
94 
95         glBindFramebuffer(GL_FRAMEBUFFER, 0);
96 
97         // Draw a quad with the target texture
98         glUseProgram(mTextureProgram);
99         glBindTexture(GL_TEXTURE_2D, texture);
100         glUniform1i(mTextureUniformLocation, 0);
101 
102         drawQuad(mTextureProgram, "position", 0.5f);
103 
104         // Expect that the rendered quad has the same color as the source texture
105         EXPECT_PIXEL_NEAR(xs, ys, data[0], data[1], data[2], data[3], 1.0);
106         EXPECT_PIXEL_NEAR(xs, ye - 1, data[0], data[1], data[2], data[3], 1.0);
107         EXPECT_PIXEL_NEAR(xe - 1, ys, data[0], data[1], data[2], data[3], 1.0);
108         EXPECT_PIXEL_NEAR(xe - 1, ye - 1, data[0], data[1], data[2], data[3], 1.0);
109         EXPECT_PIXEL_NEAR((xs + xe) / 2, (ys + ye) / 2, data[0], data[1], data[2], data[3], 1.0);
110     }
111 
runCopyTexImageTest(GLenum format,GLubyte expected[3][4])112     void runCopyTexImageTest(GLenum format, GLubyte expected[3][4])
113     {
114         GLTexture tex;
115         glBindTexture(GL_TEXTURE_2D, tex);
116 
117         // Disable mipmapping
118         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
119         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
120 
121         // Perform the copy multiple times.
122         //
123         // - The first time, a new texture is created
124         // - The second time, as the fbo size is the same as previous, the texture storage is not
125         //   recreated.
126         // - The third time, the fbo size is different, so a new texture is created.
127         for (size_t i = 0; i < kFboCount; ++i)
128         {
129             glBindFramebuffer(GL_FRAMEBUFFER, mFbos[i]);
130 
131             glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, kFboSizes[i], kFboSizes[i], 0);
132             ASSERT_GL_NO_ERROR();
133 
134             verifyResults(tex, expected[i], kFboSizes[i], 0, 0, kFboSizes[i], kFboSizes[i]);
135         }
136     }
137 
runCopyTexSubImageTest(GLenum format,GLubyte expected[3][4])138     void runCopyTexSubImageTest(GLenum format, GLubyte expected[3][4])
139     {
140         GLTexture tex;
141         glBindTexture(GL_TEXTURE_2D, tex);
142 
143         // Disable mipmapping
144         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
145         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
146 
147         // Create the texture with copy of the first fbo.
148         glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
149         glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, kFboSizes[0], kFboSizes[0], 0);
150         ASSERT_GL_NO_ERROR();
151 
152         verifyResults(tex, expected[0], kFboSizes[0], 0, 0, kFboSizes[0], kFboSizes[0]);
153 
154         // Make sure out-of-bound writes to the texture return invalid value.
155         glBindFramebuffer(GL_FRAMEBUFFER, mFbos[1]);
156 
157         // xoffset < 0 and yoffset < 0
158         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, -1, -1, 0, 0, kFboSizes[0], kFboSizes[0]);
159         ASSERT_GL_ERROR(GL_INVALID_VALUE);
160 
161         // xoffset + width > w and yoffset + height > h
162         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 0, 0, kFboSizes[0], kFboSizes[0]);
163         ASSERT_GL_ERROR(GL_INVALID_VALUE);
164 
165         // xoffset + width > w and yoffset + height > h, out of bounds
166         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, -1, -1, 1 + kFboSizes[0], 1 + kFboSizes[0]);
167         ASSERT_GL_ERROR(GL_INVALID_VALUE);
168 
169         // Copy the second fbo over a portion of the image.
170         GLint offset = kFboSizes[0] / 2;
171         GLint extent = kFboSizes[0] - offset;
172 
173         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, offset, offset, kFboSizes[1] / 2, kFboSizes[1] / 2,
174                             extent, extent);
175         ASSERT_GL_NO_ERROR();
176 
177         verifyResults(tex, expected[1], kFboSizes[0], offset, offset, kFboSizes[0], kFboSizes[0]);
178 
179         // The rest of the image should be untouched
180         verifyResults(tex, expected[0], kFboSizes[0], 0, 0, offset, offset);
181         verifyResults(tex, expected[0], kFboSizes[0], offset, 0, kFboSizes[0], offset);
182         verifyResults(tex, expected[0], kFboSizes[0], 0, offset, offset, kFboSizes[0]);
183 
184         // Copy the third fbo over another portion of the image.
185         glBindFramebuffer(GL_FRAMEBUFFER, mFbos[2]);
186 
187         offset = kFboSizes[0] / 4;
188         extent = kFboSizes[0] - offset;
189 
190         // While width and height are set as 3/4 of the size, the fbo offset is given such that
191         // after clipping, width and height are effectively 1/2 of the size.
192         GLint srcOffset       = kFboSizes[2] - kFboSizes[0] / 2;
193         GLint effectiveExtent = kFboSizes[0] / 2;
194 
195         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, offset, offset, srcOffset, srcOffset, extent, extent);
196         ASSERT_GL_NO_ERROR();
197 
198         verifyResults(tex, expected[2], kFboSizes[0], offset, offset, effectiveExtent,
199                       effectiveExtent);
200 
201         // The rest of the image should be untouched
202         verifyResults(tex, expected[1], kFboSizes[0], offset + effectiveExtent, kFboSizes[0] / 2,
203                       kFboSizes[0], kFboSizes[0]);
204         verifyResults(tex, expected[1], kFboSizes[0], kFboSizes[0] / 2, offset + effectiveExtent,
205                       kFboSizes[0], kFboSizes[0]);
206 
207         verifyResults(tex, expected[0], kFboSizes[0], 0, 0, kFboSizes[0], offset);
208         verifyResults(tex, expected[0], kFboSizes[0], 0, 0, offset, kFboSizes[0]);
209         verifyResults(tex, expected[0], kFboSizes[0], offset + effectiveExtent, 0, kFboSizes[0],
210                       kFboSizes[0] / 2);
211         verifyResults(tex, expected[0], kFboSizes[0], 0, offset + effectiveExtent, kFboSizes[0] / 2,
212                       kFboSizes[0]);
213     }
214 
215     GLuint mTextureProgram;
216     GLint mTextureUniformLocation;
217 
218     static constexpr uint32_t kFboCount = 3;
219     GLFramebuffer mFbos[kFboCount];
220     GLTexture mFboTextures[kFboCount];
221 
222     static constexpr uint32_t kFboSizes[kFboCount]    = {16, 16, 32};
223     static constexpr GLfloat kFboColors[kFboCount][4] = {{0.25f, 1.0f, 0.75f, 0.5f},
224                                                          {1.0f, 0.75f, 0.5f, 0.25f},
225                                                          {0.5f, 0.25f, 1.0f, 0.75f}};
226 };
227 
228 // Until C++17, need to redundantly declare the constexpr members outside the class (only the
229 // arrays, because the others are already const-propagated and not needed by the linker).
230 constexpr uint32_t CopyTexImageTest::kFboSizes[];
231 constexpr GLfloat CopyTexImageTest::kFboColors[][4];
232 
TEST_P(CopyTexImageTest,RGBAToRGB)233 TEST_P(CopyTexImageTest, RGBAToRGB)
234 {
235     GLubyte expected[3][4] = {
236         {64, 255, 191, 255},
237         {255, 191, 127, 255},
238         {127, 64, 255, 255},
239     };
240 
241     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
242     runCopyTexImageTest(GL_RGB, expected);
243 }
244 
TEST_P(CopyTexImageTest,RGBAToL)245 TEST_P(CopyTexImageTest, RGBAToL)
246 {
247     GLubyte expected[3][4] = {
248         {64, 64, 64, 255},
249         {255, 255, 255, 255},
250         {127, 127, 127, 255},
251     };
252 
253     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
254     runCopyTexImageTest(GL_LUMINANCE, expected);
255 }
256 
TEST_P(CopyTexImageTest,RGBToL)257 TEST_P(CopyTexImageTest, RGBToL)
258 {
259     GLubyte expected[3][4] = {
260         {64, 64, 64, 255},
261         {255, 255, 255, 255},
262         {127, 127, 127, 255},
263     };
264 
265     initializeResources(GL_RGB, GL_UNSIGNED_BYTE);
266     runCopyTexImageTest(GL_LUMINANCE, expected);
267 }
268 
TEST_P(CopyTexImageTest,RGBAToLA)269 TEST_P(CopyTexImageTest, RGBAToLA)
270 {
271     GLubyte expected[3][4] = {
272         {64, 64, 64, 127},
273         {255, 255, 255, 64},
274         {127, 127, 127, 191},
275     };
276 
277     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
278     runCopyTexImageTest(GL_LUMINANCE_ALPHA, expected);
279 }
280 
TEST_P(CopyTexImageTest,RGBAToA)281 TEST_P(CopyTexImageTest, RGBAToA)
282 {
283     GLubyte expected[3][4] = {
284         {0, 0, 0, 127},
285         {0, 0, 0, 64},
286         {0, 0, 0, 191},
287     };
288 
289     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
290     runCopyTexImageTest(GL_ALPHA, expected);
291 }
292 
TEST_P(CopyTexImageTest,SubImageRGBAToRGB)293 TEST_P(CopyTexImageTest, SubImageRGBAToRGB)
294 {
295     GLubyte expected[3][4] = {
296         {64, 255, 191, 255},
297         {255, 191, 127, 255},
298         {127, 64, 255, 255},
299     };
300 
301     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
302     runCopyTexSubImageTest(GL_RGB, expected);
303 }
304 
TEST_P(CopyTexImageTest,SubImageRGBAToL)305 TEST_P(CopyTexImageTest, SubImageRGBAToL)
306 {
307     GLubyte expected[3][4] = {
308         {64, 64, 64, 255},
309         {255, 255, 255, 255},
310         {127, 127, 127, 255},
311     };
312 
313     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
314     runCopyTexSubImageTest(GL_LUMINANCE, expected);
315 }
316 
TEST_P(CopyTexImageTest,SubImageRGBAToLA)317 TEST_P(CopyTexImageTest, SubImageRGBAToLA)
318 {
319     GLubyte expected[3][4] = {
320         {64, 64, 64, 127},
321         {255, 255, 255, 64},
322         {127, 127, 127, 191},
323     };
324 
325     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
326     runCopyTexSubImageTest(GL_LUMINANCE_ALPHA, expected);
327 }
328 
TEST_P(CopyTexImageTest,SubImageRGBToL)329 TEST_P(CopyTexImageTest, SubImageRGBToL)
330 {
331     GLubyte expected[3][4] = {
332         {64, 64, 64, 255},
333         {255, 255, 255, 255},
334         {127, 127, 127, 255},
335     };
336 
337     initializeResources(GL_RGB, GL_UNSIGNED_BYTE);
338     runCopyTexSubImageTest(GL_LUMINANCE, expected);
339 }
340 
341 // Read default framebuffer with glCopyTexImage2D().
TEST_P(CopyTexImageTest,DefaultFramebuffer)342 TEST_P(CopyTexImageTest, DefaultFramebuffer)
343 {
344     // Seems to be a bug in Mesa with the GLX back end: cannot read framebuffer until we draw to it.
345     // glCopyTexImage2D() below will fail without this clear.
346     glClear(GL_COLOR_BUFFER_BIT);
347 
348     const GLint w = getWindowWidth(), h = getWindowHeight();
349     GLTexture tex;
350     glBindTexture(GL_TEXTURE_2D, tex);
351     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
352     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, w, h, 0);
353     EXPECT_GL_NO_ERROR();
354 }
355 
356 // Read default framebuffer with glCopyTexSubImage2D().
TEST_P(CopyTexImageTest,SubDefaultFramebuffer)357 TEST_P(CopyTexImageTest, SubDefaultFramebuffer)
358 {
359     // Seems to be a bug in Mesa with the GLX back end: cannot read framebuffer until we draw to it.
360     // glCopyTexSubImage2D() below will fail without this clear.
361     glClear(GL_COLOR_BUFFER_BIT);
362 
363     const GLint w = getWindowWidth(), h = getWindowHeight();
364     GLTexture tex;
365     glBindTexture(GL_TEXTURE_2D, tex);
366     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
367     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
368     EXPECT_GL_NO_ERROR();
369 }
370 
371 // Calling CopyTexSubImage from cubeMap texture.
TEST_P(CopyTexImageTest,CopyTexSubImageFromCubeMap)372 TEST_P(CopyTexImageTest, CopyTexSubImageFromCubeMap)
373 {
374     constexpr GLsizei kCubeMapFaceCount = 6;
375 
376     // The framebuffer will be a face of a cube map with a different colors for each face.  Each
377     // glCopyTexSubImage2D will take one face of this image to copy over a pixel in a 1x6
378     // framebuffer.
379     GLColor fboPixels[kCubeMapFaceCount]   = {GLColor::red,  GLColor::yellow, GLColor::green,
380                                             GLColor::cyan, GLColor::blue,   GLColor::magenta};
381     GLColor whitePixels[kCubeMapFaceCount] = {GLColor::white, GLColor::white, GLColor::white,
382                                               GLColor::white, GLColor::white, GLColor::white};
383 
384     GLTexture fboTex;
385     glBindTexture(GL_TEXTURE_CUBE_MAP, fboTex);
386     for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
387          face++)
388     {
389         GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
390 
391         glTexImage2D(face, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &fboPixels[faceIndex]);
392     }
393 
394     GLTexture dstTex;
395     glBindTexture(GL_TEXTURE_2D, dstTex);
396     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeMapFaceCount, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
397                  whitePixels);
398 
399     GLFramebuffer fbo;
400     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
401 
402     for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
403          face++)
404     {
405         GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
406 
407         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face, fboTex, 0);
408 
409         ASSERT_GL_NO_ERROR();
410         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
411 
412         // Copy the fbo (a cube map face) into a pixel of the destination texture.
413         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, faceIndex, 0, 0, 0, 1, 1);
414     }
415 
416     // Make sure all the copies are done correctly.
417     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
418 
419     ASSERT_GL_NO_ERROR();
420     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
421 
422     for (GLsizei faceIndex = 0; faceIndex < kCubeMapFaceCount; ++faceIndex)
423     {
424         EXPECT_PIXEL_COLOR_EQ(faceIndex, 0, fboPixels[faceIndex]);
425     }
426 }
427 
428 // Calling CopyTexSubImage to a non-cube-complete texture.
TEST_P(CopyTexImageTest,CopyTexSubImageToNonCubeCompleteDestination)429 TEST_P(CopyTexImageTest, CopyTexSubImageToNonCubeCompleteDestination)
430 {
431     // TODO(hqle): Find what wrong with NVIDIA GPU. http://anglebug.com/4137
432     ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsMetal());
433 
434     constexpr GLsizei kCubeMapFaceCount = 6;
435 
436     // The framebuffer will be a 1x6 image with 6 different colors.  Each glCopyTexSubImage2D will
437     // take one pixel of this image to copy over each face of a cube map.
438     GLColor fboPixels[kCubeMapFaceCount] = {GLColor::red,  GLColor::yellow, GLColor::green,
439                                             GLColor::cyan, GLColor::blue,   GLColor::magenta};
440     GLColor whitePixel                   = GLColor::white;
441 
442     GLTexture fboTex;
443     glBindTexture(GL_TEXTURE_2D, fboTex);
444     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeMapFaceCount, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
445                  fboPixels);
446 
447     GLFramebuffer fbo;
448     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
449     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
450 
451     ASSERT_GL_NO_ERROR();
452     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
453 
454     GLTexture cubeMap;
455     glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMap);
456 
457     for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
458          face++)
459     {
460         GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
461 
462         // Initialize the face with a color not found in the fbo.
463         glTexImage2D(face, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &whitePixel);
464 
465         // Copy one pixel from the fbo into this face.  The first 5 copies are done on a
466         // non-cube-complete texture.
467         glCopyTexSubImage2D(face, 0, 0, 0, faceIndex, 0, 1, 1);
468     }
469 
470     // Make sure all the copies are done correctly.
471     for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
472          face++)
473     {
474         GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
475 
476         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face, cubeMap, 0);
477 
478         ASSERT_GL_NO_ERROR();
479         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
480 
481         EXPECT_PIXEL_COLOR_EQ(0, 0, fboPixels[faceIndex]);
482     }
483 }
484 
485 // Deleting textures after copying to them. http://anglebug.com/4267
TEST_P(CopyTexImageTest,DeleteAfterCopyingToTextures)486 TEST_P(CopyTexImageTest, DeleteAfterCopyingToTextures)
487 {
488     // Asserts on Vulkan backend. http://anglebug.com/4274
489     ANGLE_SKIP_TEST_IF(IsVulkan());
490 
491     GLTexture texture;
492     glBindTexture(GL_TEXTURE_2D, texture);
493     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
494     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
495     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
496     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
497     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
498 
499     GLTexture texture2;
500     glBindTexture(GL_TEXTURE_2D, texture2);
501     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
502     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
503     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
504     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
505     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
506 
507     GLFramebuffer framebuffer;
508     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
509     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
510     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
511 
512     // Perform CopyTexImage2D
513     glBindTexture(GL_TEXTURE_2D, texture);
514     glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
515     ASSERT_GL_NO_ERROR();
516     // Not necessary to do any CopyTexImage2D operations to texture2.
517 
518     // Perform CopyTexSubImage2D
519     glBindTexture(GL_TEXTURE_2D, texture);
520     glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
521     ASSERT_GL_NO_ERROR();
522     glBindTexture(GL_TEXTURE_2D, texture2);
523     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
524     ASSERT_GL_NO_ERROR();
525 
526     // Clean up - provokes crash on buggy drivers.
527     texture.reset();
528     // Crashes on Intel GPUs on macOS.
529     texture2.reset();
530 }
531 
532 // specialization of CopyTexImageTest is added so that some tests can be explicitly run with an ES3
533 // context
534 class CopyTexImageTestES3 : public CopyTexImageTest
535 {
536   protected:
537     void initialize3DTexture(GLTexture &texture,
538                              const GLsizei imageWidth,
539                              const GLsizei imageHeight,
540                              const GLsizei imageDepth,
541                              const GLColor *textureData);
542     void initialize2DTexture(GLTexture &texture,
543                              const GLsizei imageWidth,
544                              const GLsizei imageHeight,
545                              const GLColor *textureData);
546     void initialize2DTextureUShort4444(GLTexture &texture,
547                                        const GLsizei imageWidth,
548                                        const GLsizei imageHeight,
549                                        const GLColor *textureData);
550     void fillTexture(std::vector<GLColor> &texture, const GLColor color);
551     void clearTexture(GLFramebuffer &fbo, GLTexture &texture, const GLColor color);
552     void copyTexSubImage3D(GLTexture &subTexture2D,
553                            const GLint xOffset,
554                            const GLint yOffset,
555                            const GLsizei subImageWidth,
556                            const GLsizei subImageHeight,
557                            const GLsizei imageDepth);
558     void verifyCopyTexSubImage3D(GLTexture &texture3D,
559                                  const GLint xOffset,
560                                  const GLint yOffset,
561                                  const GLColor subImageColor);
562 
563     // Constants
564     const GLColor kSubImageColor = GLColor::yellow;
565     // 3D image dimensions
566     const GLsizei kImageWidth  = getWindowWidth();
567     const GLsizei kImageHeight = getWindowHeight();
568     const GLsizei kImageDepth  = 4;
569     // 2D sub-image dimensions
570     const GLsizei kSubImageWidth  = getWindowWidth() / 4;
571     const GLsizei kSubImageHeight = getWindowHeight() / 4;
572     // Sub-Image Offsets
573     const GLint kXOffset = getWindowWidth() - kSubImageWidth;
574     const GLint kYOffset = getWindowHeight() - kSubImageHeight;
575 };
576 
577 //  The test verifies that glCopyTexSubImage2D generates a GL_INVALID_OPERATION error
578 //  when the read buffer is GL_NONE.
579 //  Reference: GLES 3.0.4, Section 3.8.5 Alternate Texture Image Specification Commands
TEST_P(CopyTexImageTestES3,ReadBufferIsNone)580 TEST_P(CopyTexImageTestES3, ReadBufferIsNone)
581 {
582     initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
583 
584     GLTexture tex;
585     glBindTexture(GL_TEXTURE_2D, tex);
586     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
587     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
588 
589     glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
590     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kFboSizes[0], kFboSizes[0], 0);
591 
592     glReadBuffer(GL_NONE);
593 
594     EXPECT_GL_NO_ERROR();
595     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 4, 4);
596     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
597 }
598 
599 // Test CopyTexImage3D with some simple parameters with a 2D array texture.
600 TEST_P(CopyTexImageTestES3, 2DArraySubImage)
601 {
602     // Seems to fail on AMD OpenGL Windows.
603     ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() & IsWindows());
604 
605     GLTexture tex;
606     glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
607 
608     constexpr GLsizei kTexSize     = 4;
609     constexpr GLsizei kLayerOffset = 1;
610     constexpr GLsizei kLayers      = 2;
611 
612     // Clear screen to green.
613     glClearColor(0, 1, 0, 1);
614     glClear(GL_COLOR_BUFFER_BIT);
615 
616     // Initialize a two-layer 2D array texture with red.
617     std::vector<GLColor> red(kTexSize * kTexSize * kLayers, GLColor::red);
618     glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kTexSize, kTexSize, kLayers, 0, GL_RGBA,
619                  GL_UNSIGNED_BYTE, red.data());
620     glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, kLayerOffset, 0, 0, kTexSize, kTexSize);
621     ASSERT_GL_NO_ERROR();
622 
623     // Check level 0 (red from image data) and 1 (green from backbuffer clear).
624     GLFramebuffer fbo;
625     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
626     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0);
627     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
628     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 1);
629     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
630     ASSERT_GL_NO_ERROR();
631 }
632 
633 // 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)634 void CopyTexImageTestES3::initialize3DTexture(GLTexture &texture,
635                                               const GLsizei imageWidth,
636                                               const GLsizei imageHeight,
637                                               const GLsizei imageDepth,
638                                               const GLColor *textureData)
639 {
640     glBindTexture(GL_TEXTURE_3D, texture);
641     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, imageWidth, imageHeight, imageDepth, 0, GL_RGBA,
642                  GL_UNSIGNED_BYTE, textureData);
643     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
644     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
645     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
646     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
647     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
648 }
649 
initialize2DTexture(GLTexture & texture,const GLsizei imageWidth,const GLsizei imageHeight,const GLColor * textureData)650 void CopyTexImageTestES3::initialize2DTexture(GLTexture &texture,
651                                               const GLsizei imageWidth,
652                                               const GLsizei imageHeight,
653                                               const GLColor *textureData)
654 {
655     glBindTexture(GL_TEXTURE_2D, texture);
656     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
657                  textureData);
658     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
659     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
660 }
661 
initialize2DTextureUShort4444(GLTexture & texture,const GLsizei imageWidth,const GLsizei imageHeight,const GLColor * textureData)662 void CopyTexImageTestES3::initialize2DTextureUShort4444(GLTexture &texture,
663                                                         const GLsizei imageWidth,
664                                                         const GLsizei imageHeight,
665                                                         const GLColor *textureData)
666 {
667     glBindTexture(GL_TEXTURE_2D, texture);
668     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA,
669                  GL_UNSIGNED_SHORT_4_4_4_4, textureData);
670     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
671     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
672 }
673 
fillTexture(std::vector<GLColor> & texture,const GLColor color)674 void CopyTexImageTestES3::fillTexture(std::vector<GLColor> &texture, const GLColor color)
675 {
676     for (auto &texel : texture)
677     {
678         texel = color;
679     }
680 }
681 
clearTexture(GLFramebuffer & fbo,GLTexture & texture,const GLColor color)682 void CopyTexImageTestES3::clearTexture(GLFramebuffer &fbo, GLTexture &texture, const GLColor color)
683 {
684     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
685     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
686     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
687     glClearColor(color.R, color.G, color.B, color.A);
688     glClear(GL_COLOR_BUFFER_BIT);
689     EXPECT_PIXEL_COLOR_EQ(0, 0, color);
690 }
691 
copyTexSubImage3D(GLTexture & subTexture2D,const GLint xOffset,const GLint yOffset,const GLsizei subImageWidth,const GLsizei subImageHeight,const GLsizei imageDepth)692 void CopyTexImageTestES3::copyTexSubImage3D(GLTexture &subTexture2D,
693                                             const GLint xOffset,
694                                             const GLint yOffset,
695                                             const GLsizei subImageWidth,
696                                             const GLsizei subImageHeight,
697                                             const GLsizei imageDepth)
698 {
699     // Copy the 2D sub-image into the 3D texture
700     for (int currLayer = 0; currLayer < imageDepth; ++currLayer)
701     {
702         // Bind the 2D texture to GL_COLOR_ATTACHMENT0
703         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
704                                subTexture2D, 0);
705         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
706         glCopyTexSubImage3D(GL_TEXTURE_3D, 0, xOffset, yOffset, currLayer, 0, 0, subImageWidth,
707                             subImageHeight);
708         ASSERT_GL_NO_ERROR();
709     }
710 }
711 
verifyCopyTexSubImage3D(GLTexture & texture3D,const GLint xOffset,const GLint yOffset,const GLColor subImageColor)712 void CopyTexImageTestES3::verifyCopyTexSubImage3D(GLTexture &texture3D,
713                                                   const GLint xOffset,
714                                                   const GLint yOffset,
715                                                   const GLColor subImageColor)
716 {
717     // Bind to an FBO to check the copy was successful
718     for (int currLayer = 0; currLayer < kImageDepth; ++currLayer)
719     {
720         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0, currLayer);
721         ASSERT_GL_NO_ERROR();
722         EXPECT_PIXEL_COLOR_EQ(xOffset, yOffset, subImageColor);
723     }
724 }
725 
726 // Test glCopyTexSubImage3D with initialized texture data
727 TEST_P(CopyTexImageTestES3, 3DSubImageRawTextureData)
728 {
729     // Texture data
730     std::vector<GLColor> textureData(kImageWidth * kImageHeight * kImageDepth);
731 
732     // Fill the textures with color
733     fillTexture(textureData, GLColor::red);
734 
735     GLFramebuffer fbo;
736     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
737 
738     GLTexture texture3D;
739     initialize3DTexture(texture3D, kImageWidth, kImageHeight, kImageDepth, textureData.data());
740 
741     // The 2D texture that will be the sub-image copied into the destination texture
742     GLTexture subTexture2D;
743     initialize2DTexture(subTexture2D, kSubImageWidth, kSubImageHeight, nullptr);
744     clearTexture(fbo, subTexture2D, kSubImageColor);
745 
746     // Copy the 2D subimage into the 3D texture
747     copyTexSubImage3D(subTexture2D, kXOffset, kYOffset, kSubImageWidth, kSubImageHeight,
748                       kImageDepth);
749 
750     // Verify the color wasn't overwritten
751     verifyCopyTexSubImage3D(texture3D, 0, 0, GLColor::red);
752     // Verify the copy succeeded
753     verifyCopyTexSubImage3D(texture3D, kXOffset, kYOffset, kSubImageColor);
754 
755     glBindFramebuffer(GL_FRAMEBUFFER, 0);
756     glBindTexture(GL_TEXTURE_2D, 0);
757     glBindTexture(GL_TEXTURE_3D, 0);
758 }
759 
760 // Test glCopyTexSubImage3D with initialized texture data that was drawn to
761 TEST_P(CopyTexImageTestES3, 3DSubImageDrawTextureData)
762 {
763     // TODO(anglebug.com/3801)
764     ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11());
765 
766     GLFramebuffer fbo;
767     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
768 
769     // The 3D texture we will copy the sub-image into
770     GLTexture texture3D;
771     initialize3DTexture(texture3D, kImageWidth, kImageHeight, kImageDepth, nullptr);
772 
773     // Draw to each layer in the 3D texture
774     for (int currLayer = 0; currLayer < kImageDepth; ++currLayer)
775     {
776         ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
777         glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0,
778                                   currLayer);
779         glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0,
780                                   currLayer);
781         ASSERT_GL_NO_ERROR();
782         glUseProgram(greenProgram);
783         drawQuad(greenProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
784         ASSERT_GL_NO_ERROR();
785         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
786     }
787 
788     // The 2D texture that will be the sub-image copied into the destination texture
789     GLTexture subTexture2D;
790     initialize2DTexture(subTexture2D, kSubImageWidth, kSubImageHeight, nullptr);
791     clearTexture(fbo, subTexture2D, kSubImageColor);
792 
793     // Copy the 2D sub-image into the 3D texture
794     copyTexSubImage3D(subTexture2D, kXOffset, kYOffset, kSubImageWidth, kSubImageHeight,
795                       kImageDepth);
796 
797     // Verify the color wasn't overwritten
798     verifyCopyTexSubImage3D(texture3D, 0, 0, GLColor::green);
799     // Verify the copy succeeded
800     verifyCopyTexSubImage3D(texture3D, kXOffset, kYOffset, kSubImageColor);
801 
802     glBindFramebuffer(GL_FRAMEBUFFER, 0);
803     glBindTexture(GL_TEXTURE_2D, 0);
804     glBindTexture(GL_TEXTURE_3D, 0);
805 }
806 
807 // Test glCopyTexSubImage3D with mismatched texture formats
808 TEST_P(CopyTexImageTestES3, 3DSubImageDrawMismatchedTextureTypes)
809 {
810     // TODO(anglebug.com/3801)
811     ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11());
812 
813     GLFramebuffer fbo;
814     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
815 
816     // The 3D texture we will copy the sub-image into
817     GLTexture texture3D;
818     initialize3DTexture(texture3D, kImageWidth, kImageHeight, kImageDepth, nullptr);
819 
820     // Draw to each layer in the 3D texture
821     for (int currLayer = 0; currLayer < kImageDepth; ++currLayer)
822     {
823         ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
824         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture3D, 0, currLayer);
825         ASSERT_GL_NO_ERROR();
826         glUseProgram(greenProgram);
827         drawQuad(greenProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
828         ASSERT_GL_NO_ERROR();
829         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
830     }
831 
832     // The 2D texture that will be the sub-image copied into the destination texture
833     GLTexture subTexture2D;
834     initialize2DTextureUShort4444(subTexture2D, kSubImageWidth, kSubImageHeight, nullptr);
835     clearTexture(fbo, subTexture2D, kSubImageColor);
836 
837     // Copy the 2D sub-image into the 3D texture
838     copyTexSubImage3D(subTexture2D, kXOffset, kYOffset, kSubImageWidth, kSubImageHeight,
839                       kImageDepth);
840 
841     // Verify the color wasn't overwritten
842     verifyCopyTexSubImage3D(texture3D, 0, 0, GLColor::green);
843     // Verify the copy succeeded
844     verifyCopyTexSubImage3D(texture3D, kXOffset, kYOffset, kSubImageColor);
845 
846     glBindFramebuffer(GL_FRAMEBUFFER, 0);
847     glBindTexture(GL_TEXTURE_2D, 0);
848     glBindTexture(GL_TEXTURE_3D, 0);
849 }
850 
851 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
852 // tests should be run against.
853 ANGLE_INSTANTIATE_TEST(CopyTexImageTest,
854                        ES2_D3D9(),
855                        ES2_D3D11(),
856                        ES2_D3D11_PRESENT_PATH_FAST(),
857                        ES2_METAL(),
858                        ES2_OPENGL(),
859                        ES2_OPENGLES(),
860                        ES2_VULKAN(),
861                        ES3_VULKAN());
862 
863 ANGLE_INSTANTIATE_TEST_ES3(CopyTexImageTestES3);
864 }  // namespace angle
865