1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "test_utils/ANGLETest.h"
8 
9 namespace angle
10 {
11 
12 class CopyTexImageTest : public ANGLETest
13 {
14   protected:
CopyTexImageTest()15     CopyTexImageTest()
16     {
17         setWindowWidth(16);
18         setWindowHeight(16);
19         setConfigRedBits(8);
20         setConfigGreenBits(8);
21         setConfigBlueBits(8);
22         setConfigAlphaBits(8);
23     }
24 
createFramebuffer(GLenum format,GLenum type,GLfloat color[4]) const25     GLuint createFramebuffer(GLenum format, GLenum type, GLfloat color[4]) const
26     {
27         GLuint fbo;
28         glGenFramebuffers(1, &fbo);
29         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
30 
31         GLuint texture = createTexture(format, type);
32         glBindTexture(GL_TEXTURE_2D, texture);
33         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
34 
35         glClearColor(color[0], color[1], color[2], color[3]);
36         glClear(GL_COLOR_BUFFER_BIT);
37 
38         return fbo;
39     }
40 
createTexture(GLenum format,GLenum type) const41     GLuint createTexture(GLenum format, GLenum type) const
42     {
43         GLuint tex;
44         glGenTextures(1, &tex);
45         glBindTexture(GL_TEXTURE_2D, tex);
46         glTexImage2D(GL_TEXTURE_2D, 0, format, 16, 16, 0, format, type, nullptr);
47 
48         // Disable mipmapping
49         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
50         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
51 
52         return tex;
53     }
54 
createTextureFromCopyTexImage(GLuint fbo,GLenum format) const55     GLuint createTextureFromCopyTexImage(GLuint fbo, GLenum format) const
56     {
57         GLuint tex;
58         glGenTextures(1, &tex);
59         glBindTexture(GL_TEXTURE_2D, tex);
60 
61         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
62         glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, 16, 16, 0);
63 
64         // Disable mipmapping
65         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
66         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
67 
68         return tex;
69     }
70 
copyTextureWithCopyTexSubImage(GLuint fbo,GLuint texture,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei w,GLsizei h) const71     void copyTextureWithCopyTexSubImage(GLuint fbo,
72                                         GLuint texture,
73                                         GLint xoffset,
74                                         GLint yoffset,
75                                         GLint x,
76                                         GLint y,
77                                         GLsizei w,
78                                         GLsizei h) const
79     {
80         glBindTexture(GL_TEXTURE_2D, texture);
81         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
82         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, w, h);
83     }
84 
SetUp()85     void SetUp() override
86     {
87         ANGLETest::SetUp();
88 
89         const std::string vsSource =
90             "precision highp float;\n"
91             "attribute vec4 position;\n"
92             "varying vec2 texcoord;\n"
93             "\n"
94             "void main()\n"
95             "{\n"
96             "    gl_Position = position;\n"
97             "    texcoord = (position.xy * 0.5) + 0.5;\n"
98             "    texcoord.y = 1.0 - texcoord.y;\n"
99             "}\n";
100 
101         const std::string textureFSSource =
102             "precision highp float;\n"
103             "uniform sampler2D tex;\n"
104             "varying vec2 texcoord;\n"
105             "\n"
106             "void main()\n"
107             "{\n"
108             "    gl_FragColor = texture2D(tex, texcoord);\n"
109             "}\n";
110 
111         mTextureProgram = CompileProgram(vsSource, textureFSSource);
112         if (mTextureProgram == 0)
113         {
114             FAIL() << "shader compilation failed.";
115         }
116 
117         mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
118 
119         ASSERT_GL_NO_ERROR();
120     }
121 
TearDown()122     void TearDown() override
123     {
124         glDeleteProgram(mTextureProgram);
125 
126         ANGLETest::TearDown();
127     }
128 
verifyResults(GLuint texture,GLubyte data[4],GLint x,GLint y)129     void verifyResults(GLuint texture, GLubyte data[4], GLint x, GLint y)
130     {
131         glViewport(0, 0, 16, 16);
132 
133         glBindFramebuffer(GL_FRAMEBUFFER, 0);
134 
135         // Draw a quad with the target texture
136         glUseProgram(mTextureProgram);
137         glBindTexture(GL_TEXTURE_2D, texture);
138         glUniform1i(mTextureUniformLocation, 0);
139 
140         drawQuad(mTextureProgram, "position", 0.5f);
141 
142         // Expect that the rendered quad has the same color as the source texture
143         EXPECT_PIXEL_NEAR(x, y, data[0], data[1], data[2], data[3], 1.0);
144     }
145 
146     GLuint mTextureProgram;
147     GLint mTextureUniformLocation;
148 };
149 
TEST_P(CopyTexImageTest,RGBAToL)150 TEST_P(CopyTexImageTest, RGBAToL)
151 {
152     GLfloat color[] = {
153         0.25f, 1.0f, 0.75f, 0.5f,
154     };
155 
156     GLuint fbo = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color);
157     GLuint tex = createTextureFromCopyTexImage(fbo, GL_LUMINANCE);
158 
159     GLubyte expected[] = {
160         64, 64, 64, 255,
161     };
162     verifyResults(tex, expected, 0, 0);
163 }
164 
TEST_P(CopyTexImageTest,RGBToL)165 TEST_P(CopyTexImageTest, RGBToL)
166 {
167     // TODO (geofflang): Figure out why CopyTex[Sub]Image doesn't work with
168     // RGB->L on older Intel chips
169     if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
170     {
171         std::cout << "Test skipped on Intel OpenGL." << std::endl;
172         return;
173     }
174 
175     GLfloat color[] = {
176         0.25f, 1.0f, 0.75f, 0.5f,
177     };
178 
179     GLuint fbo = createFramebuffer(GL_RGB, GL_UNSIGNED_BYTE, color);
180     GLuint tex = createTextureFromCopyTexImage(fbo, GL_LUMINANCE);
181 
182     GLubyte expected[] = {
183         64, 64, 64, 255,
184     };
185     verifyResults(tex, expected, 0, 0);
186 }
187 
TEST_P(CopyTexImageTest,RGBAToLA)188 TEST_P(CopyTexImageTest, RGBAToLA)
189 {
190     GLfloat color[] = {
191         0.25f, 1.0f, 0.75f, 0.5f,
192     };
193 
194     GLuint fbo = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color);
195     GLuint tex = createTextureFromCopyTexImage(fbo, GL_LUMINANCE_ALPHA);
196 
197     GLubyte expected[] = {
198         64, 64, 64, 127,
199     };
200     verifyResults(tex, expected, 0, 0);
201 }
202 
TEST_P(CopyTexImageTest,RGBAToA)203 TEST_P(CopyTexImageTest, RGBAToA)
204 {
205     GLfloat color[] = {
206         0.25f, 1.0f, 0.75f, 0.5f,
207     };
208 
209     GLuint fbo = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color);
210     GLuint tex = createTextureFromCopyTexImage(fbo, GL_ALPHA);
211 
212     GLubyte expected[] = {
213         0, 0, 0, 127,
214     };
215     verifyResults(tex, expected, 0, 0);
216 }
217 
TEST_P(CopyTexImageTest,SubImageRGBAToL)218 TEST_P(CopyTexImageTest, SubImageRGBAToL)
219 {
220     GLfloat color0[] = {
221         0.25f, 1.0f, 0.75f, 0.5f,
222     };
223     GLuint fbo0 = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color0);
224     GLuint tex  = createTextureFromCopyTexImage(fbo0, GL_LUMINANCE);
225 
226     GLfloat color1[] = {
227         0.5f, 0.25f, 1.0f, 0.75f,
228     };
229     GLuint fbo1 = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color1);
230     copyTextureWithCopyTexSubImage(fbo1, tex, 2, 4, 5, 6, 8, 8);
231 
232     GLubyte expected0[] = {
233         64, 64, 64, 255,
234     };
235     verifyResults(tex, expected0, 0, 0);
236 
237     GLubyte expected1[] = {
238         127, 127, 127, 255,
239     };
240     verifyResults(tex, expected1, 7, 7);
241 }
242 
TEST_P(CopyTexImageTest,SubImageRGBAToLA)243 TEST_P(CopyTexImageTest, SubImageRGBAToLA)
244 {
245     GLfloat color0[] = {
246         0.25f, 1.0f, 0.75f, 0.5f,
247     };
248     GLuint fbo0 = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color0);
249     GLuint tex  = createTextureFromCopyTexImage(fbo0, GL_LUMINANCE_ALPHA);
250 
251     GLfloat color1[] = {
252         0.5f, 0.25f, 1.0f, 0.75f,
253     };
254     GLuint fbo1 = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color1);
255     copyTextureWithCopyTexSubImage(fbo1, tex, 2, 4, 5, 6, 8, 8);
256 
257     GLubyte expected0[] = {
258         64, 64, 64, 127,
259     };
260     verifyResults(tex, expected0, 0, 0);
261 
262     GLubyte expected1[] = {
263         127, 127, 127, 192,
264     };
265     verifyResults(tex, expected1, 7, 7);
266 }
267 
TEST_P(CopyTexImageTest,SubImageRGBToL)268 TEST_P(CopyTexImageTest, SubImageRGBToL)
269 {
270     // TODO (geofflang): Figure out why CopyTex[Sub]Image doesn't work with
271     // RGB->L on older Intel chips
272     if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
273     {
274         std::cout << "Test skipped on Intel OpenGL." << std::endl;
275         return;
276     }
277 
278     GLfloat color0[] = {
279         0.25f, 1.0f, 0.75f, 0.5f,
280     };
281     GLuint fbo0 = createFramebuffer(GL_RGB, GL_UNSIGNED_BYTE, color0);
282     GLuint tex  = createTextureFromCopyTexImage(fbo0, GL_LUMINANCE);
283 
284     GLfloat color1[] = {
285         0.5f, 0.25f, 1.0f, 0.75f,
286     };
287     GLuint fbo1 = createFramebuffer(GL_RGB, GL_UNSIGNED_BYTE, color1);
288     copyTextureWithCopyTexSubImage(fbo1, tex, 2, 4, 5, 6, 8, 8);
289 
290     GLubyte expected0[] = {
291         64, 64, 64, 255,
292     };
293     verifyResults(tex, expected0, 0, 0);
294 
295     GLubyte expected1[] = {
296         127, 127, 127, 255,
297     };
298     verifyResults(tex, expected1, 7, 7);
299 }
300 
301 // specialization of CopyTexImageTest is added so that some tests can be explicitly run with an ES3
302 // context
303 class CopyTexImageTestES3 : public CopyTexImageTest
304 {
305 };
306 
307 //  The test verifies that glCopyTexSubImage2D generates a GL_INVALID_OPERATION error
308 //  when the read buffer is GL_NONE.
309 //  Reference: GLES 3.0.4, Section 3.8.5 Alternate Texture Image Specification Commands
TEST_P(CopyTexImageTestES3,ReadBufferIsNone)310 TEST_P(CopyTexImageTestES3, ReadBufferIsNone)
311 {
312     GLfloat color[] = {
313         0.25f, 1.0f, 0.75f, 0.5f,
314     };
315 
316     GLuint fbo = createFramebuffer(GL_RGBA, GL_UNSIGNED_BYTE, color);
317     GLuint tex = createTextureFromCopyTexImage(fbo, GL_RGBA);
318 
319     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
320     glBindTexture(GL_TEXTURE_2D, tex);
321 
322     glReadBuffer(GL_NONE);
323 
324     EXPECT_GL_NO_ERROR();
325     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 4, 4);
326     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
327 
328     glDeleteFramebuffers(1, &fbo);
329     glDeleteTextures(1, &tex);
330 }
331 
332 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
333 // tests should be run against.
334 ANGLE_INSTANTIATE_TEST(CopyTexImageTest,
335                        ES2_D3D9(),
336                        ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
337                        ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
338                        ES2_OPENGL(),
339                        ES2_OPENGL(3, 3),
340                        ES2_OPENGLES());
341 
342 ANGLE_INSTANTIATE_TEST(CopyTexImageTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
343 }
344