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