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 using namespace angle;
10 
11 class MaxTextureSizeTest : public ANGLETest
12 {
13   protected:
MaxTextureSizeTest()14     MaxTextureSizeTest()
15     {
16         setWindowWidth(512);
17         setWindowHeight(512);
18         setConfigRedBits(8);
19         setConfigGreenBits(8);
20         setConfigBlueBits(8);
21         setConfigAlphaBits(8);
22     }
23 
SetUp()24     void SetUp() override
25     {
26         ANGLETest::SetUp();
27 
28         const std::string vsSource = SHADER_SOURCE
29         (
30             precision highp float;
31             attribute vec4 position;
32             varying vec2 texcoord;
33 
34             void main()
35             {
36                 gl_Position = position;
37                 texcoord = (position.xy * 0.5) + 0.5;
38             }
39         );
40 
41         const std::string textureFSSource = SHADER_SOURCE
42         (
43             precision highp float;
44             uniform sampler2D tex;
45             varying vec2 texcoord;
46 
47             void main()
48             {
49                 gl_FragColor = texture2D(tex, texcoord);
50             }
51         );
52 
53         const std::string blueFSSource = SHADER_SOURCE
54         (
55             precision highp float;
56 
57             void main()
58             {
59                 gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
60             }
61         );
62 
63         mTextureProgram = CompileProgram(vsSource, textureFSSource);
64         mBlueProgram = CompileProgram(vsSource, blueFSSource);
65         if (mTextureProgram == 0 || mBlueProgram == 0)
66         {
67             FAIL() << "shader compilation failed.";
68         }
69 
70         mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
71 
72         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTexture2DSize);
73         glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxTextureCubeSize);
74         glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
75 
76         ASSERT_GL_NO_ERROR();
77     }
78 
TearDown()79     void TearDown() override
80     {
81         glDeleteProgram(mTextureProgram);
82         glDeleteProgram(mBlueProgram);
83 
84         ANGLETest::TearDown();
85     }
86 
87     GLuint mTextureProgram;
88     GLint mTextureUniformLocation;
89 
90     GLuint mBlueProgram;
91 
92     GLint mMaxTexture2DSize;
93     GLint mMaxTextureCubeSize;
94     GLint mMaxRenderbufferSize;
95 };
96 
TEST_P(MaxTextureSizeTest,SpecificationTexImage)97 TEST_P(MaxTextureSizeTest, SpecificationTexImage)
98 {
99     GLuint tex;
100     glGenTextures(1, &tex);
101     glBindTexture(GL_TEXTURE_2D, tex);
102 
103     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
104     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
105     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
106     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
107 
108     GLsizei textureWidth = mMaxTexture2DSize;
109     GLsizei textureHeight = 64;
110 
111     std::vector<GLubyte> data(textureWidth * textureHeight * 4);
112     for (int y = 0; y < textureHeight; y++)
113     {
114         for (int x = 0; x < textureWidth; x++)
115         {
116             GLubyte* pixel = &data[0] + ((y * textureWidth + x) * 4);
117 
118             // Draw a gradient, red in direction, green in y direction
119             pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255);
120             pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255);
121             pixel[2] = 0;
122             pixel[3] = 255;
123         }
124     }
125 
126     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
127     EXPECT_GL_NO_ERROR();
128 
129     glUseProgram(mTextureProgram);
130     glUniform1i(mTextureUniformLocation, 0);
131 
132     drawQuad(mTextureProgram, "position", 0.5f);
133 
134     std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
135     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
136 
137     for (int y = 1; y < getWindowHeight(); y++)
138     {
139         for (int x = 1; x < getWindowWidth(); x++)
140         {
141             const GLubyte* prevPixel = &pixels[0] + (((y - 1) * getWindowWidth() + (x - 1)) * 4);
142             const GLubyte* curPixel = &pixels[0] + ((y * getWindowWidth() + x) * 4);
143 
144             EXPECT_GE(curPixel[0], prevPixel[0]);
145             EXPECT_GE(curPixel[1], prevPixel[1]);
146             EXPECT_EQ(curPixel[2], prevPixel[2]);
147             EXPECT_EQ(curPixel[3], prevPixel[3]);
148         }
149     }
150 }
151 
TEST_P(MaxTextureSizeTest,SpecificationTexStorage)152 TEST_P(MaxTextureSizeTest, SpecificationTexStorage)
153 {
154     if (getClientMajorVersion() < 3 &&
155         (!extensionEnabled("GL_EXT_texture_storage") || !extensionEnabled("GL_OES_rgb8_rgba8")))
156     {
157         return;
158     }
159 
160     GLuint tex;
161     glGenTextures(1, &tex);
162     glBindTexture(GL_TEXTURE_2D, tex);
163 
164     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
165     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
166     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
167     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
168 
169     GLsizei textureWidth = 64;
170     GLsizei textureHeight = mMaxTexture2DSize;
171 
172     std::vector<GLubyte> data(textureWidth * textureHeight * 4);
173     for (int y = 0; y < textureHeight; y++)
174     {
175         for (int x = 0; x < textureWidth; x++)
176         {
177             GLubyte* pixel = &data[0] + ((y * textureWidth + x) * 4);
178 
179             // Draw a gradient, red in direction, green in y direction
180             pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255);
181             pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255);
182             pixel[2] = 0;
183             pixel[3] = 255;
184         }
185     }
186 
187     if (getClientMajorVersion() < 3)
188     {
189         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight);
190     }
191     else
192     {
193         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight);
194     }
195     EXPECT_GL_NO_ERROR();
196 
197     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
198     EXPECT_GL_NO_ERROR();
199 
200     glUseProgram(mTextureProgram);
201     glUniform1i(mTextureUniformLocation, 0);
202 
203     drawQuad(mTextureProgram, "position", 0.5f);
204 
205     std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
206     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
207 
208     for (int y = 1; y < getWindowHeight(); y++)
209     {
210         for (int x = 1; x < getWindowWidth(); x++)
211         {
212             const GLubyte* prevPixel = &pixels[0] + (((y - 1) * getWindowWidth() + (x - 1)) * 4);
213             const GLubyte* curPixel = &pixels[0] + ((y * getWindowWidth() + x) * 4);
214 
215             EXPECT_GE(curPixel[0], prevPixel[0]);
216             EXPECT_GE(curPixel[1], prevPixel[1]);
217             EXPECT_EQ(curPixel[2], prevPixel[2]);
218             EXPECT_EQ(curPixel[3], prevPixel[3]);
219         }
220     }
221 }
222 
TEST_P(MaxTextureSizeTest,RenderToTexture)223 TEST_P(MaxTextureSizeTest, RenderToTexture)
224 {
225     if (getClientMajorVersion() < 3 && (!extensionEnabled("GL_ANGLE_framebuffer_blit")))
226     {
227         std::cout << "Test skipped due to missing glBlitFramebuffer[ANGLE] support." << std::endl;
228         return;
229     }
230 
231     GLuint fbo = 0;
232     GLuint textureId = 0;
233     // create a 1-level texture at maximum size
234     glGenTextures(1, &textureId);
235     glBindTexture(GL_TEXTURE_2D, textureId);
236 
237     GLsizei textureWidth = 64;
238     GLsizei textureHeight = mMaxTexture2DSize;
239 
240     // texture setup code
241     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
242     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
243     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
244     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
245     glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, textureWidth, textureHeight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
246     EXPECT_GL_NO_ERROR();
247 
248     // create an FBO and attach the texture
249     glGenFramebuffers(1, &fbo);
250     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
251     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
252 
253     EXPECT_GL_NO_ERROR();
254     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
255 
256     const int frameCount = 64;
257     for (int i = 0; i < frameCount; i++)
258     {
259         // clear the screen
260         glBindFramebuffer(GL_FRAMEBUFFER, 0);
261 
262         GLubyte clearRed = static_cast<GLubyte>((float(i) / frameCount) * 255);
263         GLubyte clearGreen = 255 - clearRed;
264         GLubyte clearBlue = 0;
265 
266         glClearColor(clearRed / 255.0f, clearGreen / 255.0f, clearBlue / 255.0f, 1.0f);
267         glClear(GL_COLOR_BUFFER_BIT);
268 
269         // render blue into the texture
270         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
271         drawQuad(mBlueProgram, "position", 0.5f);
272 
273         // copy corner of texture to LL corner of window
274         glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0);
275         glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
276         glBlitFramebufferANGLE(0, 0, textureWidth - 1, getWindowHeight() - 1,
277                                0, 0, textureWidth - 1, getWindowHeight() - 1,
278                                GL_COLOR_BUFFER_BIT, GL_NEAREST);
279         glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, 0);
280         EXPECT_GL_NO_ERROR();
281 
282         EXPECT_PIXEL_EQ(textureWidth / 2, getWindowHeight() / 2, 0, 0, 255, 255);
283         EXPECT_PIXEL_EQ(textureWidth + 10, getWindowHeight() / 2, clearRed, clearGreen, clearBlue, 255);
284 
285         swapBuffers();
286     }
287 
288     glBindFramebuffer(GL_FRAMEBUFFER, 0);
289     glBindTexture(GL_TEXTURE_2D, 0);
290 
291     glDeleteFramebuffers(1, &fbo);
292     glDeleteTextures(1, &textureId);
293 }
294 
295 // TODO(geofflang): Fix the dependence on glBlitFramebufferANGLE without checks and assuming the
296 // default framebuffer is BGRA to enable the GL and GLES backends. (http://anglebug.com/1289)
297 
298 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
299 ANGLE_INSTANTIATE_TEST(MaxTextureSizeTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
300