xref: /aosp_15_r20/external/angle/src/tests/gl_tests/MaxTextureSizeTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 <cmath>
8 
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 
12 using namespace angle;
13 
14 class MaxTextureSizeTest : public ANGLETest<>
15 {
16   protected:
MaxTextureSizeTest()17     MaxTextureSizeTest()
18     {
19         setWindowWidth(512);
20         setWindowHeight(512);
21         setConfigRedBits(8);
22         setConfigGreenBits(8);
23         setConfigBlueBits(8);
24         setConfigAlphaBits(8);
25     }
26 
testSetUp()27     void testSetUp() override
28     {
29         constexpr char kVS[] = R"(precision highp float;
30 attribute vec4 position;
31 varying vec2 texcoord;
32 
33 void main()
34 {
35     gl_Position = position;
36     texcoord = (position.xy * 0.5) + 0.5;
37 })";
38 
39         constexpr char kTextureFS[] = R"(precision highp float;
40 uniform sampler2D tex;
41 varying vec2 texcoord;
42 
43 void main()
44 {
45     gl_FragColor = texture2D(tex, texcoord);
46 })";
47 
48         constexpr char kBlueFS[] = R"(precision highp float;
49 void main()
50 {
51     gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
52 })";
53 
54         mTextureProgram = CompileProgram(kVS, kTextureFS);
55         mBlueProgram    = CompileProgram(kVS, kBlueFS);
56         if (mTextureProgram == 0 || mBlueProgram == 0)
57         {
58             FAIL() << "shader compilation failed.";
59         }
60 
61         mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
62 
63         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTexture2DSize);
64         glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxTextureCubeSize);
65         glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
66 
67         ASSERT_GL_NO_ERROR();
68     }
69 
testTearDown()70     void testTearDown() override
71     {
72         glDeleteProgram(mTextureProgram);
73         glDeleteProgram(mBlueProgram);
74     }
75 
76     GLuint mTextureProgram;
77     GLint mTextureUniformLocation;
78 
79     GLuint mBlueProgram;
80 
81     GLint mMaxTexture2DSize;
82     GLint mMaxTextureCubeSize;
83     GLint mMaxRenderbufferSize;
84 };
85 
TEST_P(MaxTextureSizeTest,SpecificationTexImage)86 TEST_P(MaxTextureSizeTest, SpecificationTexImage)
87 {
88     GLuint tex;
89     glGenTextures(1, &tex);
90     glBindTexture(GL_TEXTURE_2D, tex);
91 
92     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
93     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
94     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
95     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
96 
97     GLsizei textureWidth  = mMaxTexture2DSize;
98     GLsizei textureHeight = 64;
99 
100     std::vector<GLubyte> data(textureWidth * textureHeight * 4);
101     for (int y = 0; y < textureHeight; y++)
102     {
103         for (int x = 0; x < textureWidth; x++)
104         {
105             GLubyte *pixel = &data[0] + ((y * textureWidth + x) * 4);
106 
107             // Draw a gradient, red in direction, green in y direction
108             pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255);
109             pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255);
110             pixel[2] = 0;
111             pixel[3] = 255;
112         }
113     }
114 
115     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA,
116                  GL_UNSIGNED_BYTE, &data[0]);
117     EXPECT_GL_NO_ERROR();
118 
119     glUseProgram(mTextureProgram);
120     glUniform1i(mTextureUniformLocation, 0);
121 
122     drawQuad(mTextureProgram, "position", 0.5f);
123 
124     std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
125     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
126 
127     for (int y = 1; y < getWindowHeight(); y++)
128     {
129         for (int x = 1; x < getWindowWidth(); x++)
130         {
131             const GLubyte *prevPixel = &pixels[0] + (((y - 1) * getWindowWidth() + (x - 1)) * 4);
132             const GLubyte *curPixel  = &pixels[0] + ((y * getWindowWidth() + x) * 4);
133 
134             EXPECT_GE(curPixel[0], prevPixel[0]);
135             EXPECT_GE(curPixel[1], prevPixel[1]);
136             EXPECT_EQ(curPixel[2], prevPixel[2]);
137             EXPECT_EQ(curPixel[3], prevPixel[3]);
138         }
139     }
140 }
141 
TEST_P(MaxTextureSizeTest,SpecificationTexStorage)142 TEST_P(MaxTextureSizeTest, SpecificationTexStorage)
143 {
144     if (getClientMajorVersion() < 3 && (!IsGLExtensionEnabled("GL_EXT_texture_storage") ||
145                                         !IsGLExtensionEnabled("GL_OES_rgb8_rgba8")))
146     {
147         return;
148     }
149 
150     GLuint tex;
151     glGenTextures(1, &tex);
152     glBindTexture(GL_TEXTURE_2D, tex);
153 
154     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
155     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
156     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
157     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
158 
159     GLsizei textureWidth  = 64;
160     GLsizei textureHeight = mMaxTexture2DSize;
161 
162     std::vector<GLubyte> data(textureWidth * textureHeight * 4);
163     for (int y = 0; y < textureHeight; y++)
164     {
165         for (int x = 0; x < textureWidth; x++)
166         {
167             GLubyte *pixel = &data[0] + ((y * textureWidth + x) * 4);
168 
169             // Draw a gradient, red in direction, green in y direction
170             pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255);
171             pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255);
172             pixel[2] = 0;
173             pixel[3] = 255;
174         }
175     }
176 
177     if (getClientMajorVersion() < 3)
178     {
179         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight);
180     }
181     else
182     {
183         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight);
184     }
185     EXPECT_GL_NO_ERROR();
186 
187     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE,
188                     &data[0]);
189     EXPECT_GL_NO_ERROR();
190 
191     glUseProgram(mTextureProgram);
192     glUniform1i(mTextureUniformLocation, 0);
193 
194     drawQuad(mTextureProgram, "position", 0.5f);
195 
196     std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
197     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
198 
199     for (int y = 1; y < getWindowHeight(); y++)
200     {
201         for (int x = 1; x < getWindowWidth(); x++)
202         {
203             const GLubyte *prevPixel = &pixels[0] + (((y - 1) * getWindowWidth() + (x - 1)) * 4);
204             const GLubyte *curPixel  = &pixels[0] + ((y * getWindowWidth() + x) * 4);
205 
206             EXPECT_GE(curPixel[0], prevPixel[0]);
207             EXPECT_GE(curPixel[1], prevPixel[1]);
208             EXPECT_EQ(curPixel[2], prevPixel[2]);
209             EXPECT_EQ(curPixel[3], prevPixel[3]);
210         }
211     }
212 }
213 
TEST_P(MaxTextureSizeTest,RenderToTexture)214 TEST_P(MaxTextureSizeTest, RenderToTexture)
215 {
216     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
217                        (!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit")));
218 
219     GLuint fbo       = 0;
220     GLuint textureId = 0;
221     // create a 1-level texture at maximum size
222     glGenTextures(1, &textureId);
223     glBindTexture(GL_TEXTURE_2D, textureId);
224 
225     GLsizei textureWidth  = 64;
226     GLsizei textureHeight = mMaxTexture2DSize;
227 
228     // texture setup code
229     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
230     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
231     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
232     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
233     glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, textureWidth, textureHeight, 0, GL_BGRA_EXT,
234                  GL_UNSIGNED_BYTE, nullptr);
235     EXPECT_GL_NO_ERROR();
236 
237     // create an FBO and attach the texture
238     glGenFramebuffers(1, &fbo);
239     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
240     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
241 
242     EXPECT_GL_NO_ERROR();
243     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
244 
245     const int frameCount = 64;
246     for (int i = 0; i < frameCount; i++)
247     {
248         // clear the screen
249         glBindFramebuffer(GL_FRAMEBUFFER, 0);
250 
251         GLubyte clearRed   = static_cast<GLubyte>((float(i) / frameCount) * 255);
252         GLubyte clearGreen = 255 - clearRed;
253         GLubyte clearBlue  = 0;
254 
255         glClearColor(clearRed / 255.0f, clearGreen / 255.0f, clearBlue / 255.0f, 1.0f);
256         glClear(GL_COLOR_BUFFER_BIT);
257 
258         // render blue into the texture
259         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
260         drawQuad(mBlueProgram, "position", 0.5f);
261 
262         // copy corner of texture to LL corner of window
263         glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0);
264         glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
265         glBlitFramebufferANGLE(0, 0, textureWidth - 1, getWindowHeight() - 1, 0, 0,
266                                textureWidth - 1, getWindowHeight() - 1, GL_COLOR_BUFFER_BIT,
267                                GL_NEAREST);
268         glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, 0);
269         EXPECT_GL_NO_ERROR();
270 
271         EXPECT_PIXEL_EQ(textureWidth / 2, getWindowHeight() / 2, 0, 0, 255, 255);
272         EXPECT_PIXEL_EQ(textureWidth + 10, getWindowHeight() / 2, clearRed, clearGreen, clearBlue,
273                         255);
274 
275         swapBuffers();
276     }
277 
278     glBindFramebuffer(GL_FRAMEBUFFER, 0);
279     glBindTexture(GL_TEXTURE_2D, 0);
280 
281     glDeleteFramebuffers(1, &fbo);
282     glDeleteTextures(1, &textureId);
283 }
284 
TEST_P(MaxTextureSizeTest,Render1xTexture)285 TEST_P(MaxTextureSizeTest, Render1xTexture)
286 {
287     // This is not spec compliant but checking for now anyway. We can fix it
288     // if we find a driver for which this is not true.
289     float power = std::roundf(std::log(static_cast<float>(mMaxTexture2DSize)) / std::log(2.0f));
290     EXPECT_EQ(std::pow(2.0f, power), mMaxTexture2DSize);
291 
292     // Make a the largest possbile texture but not too big.
293     const GLint testSize = std::min(mMaxTexture2DSize, 128 * 1024);
294 
295     glUseProgram(mTextureProgram);
296     glUniform1i(mTextureUniformLocation, 0);
297 
298     constexpr GLColor testColor(0, 255, 128, 255);
299     std::vector<GLColor> data(testSize, testColor);
300 
301     // Test a wide texture.
302     {
303         GLTexture texture1Id;
304         glBindTexture(GL_TEXTURE_2D, texture1Id);
305         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mMaxTexture2DSize, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
306                      data.data());
307         glGenerateMipmap(GL_TEXTURE_2D);
308 
309         glClear(GL_COLOR_BUFFER_BIT);
310         drawQuad(mTextureProgram, "position", 0.5f);
311 
312         EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), testColor);
313     }
314 
315     // Test a tall texture.
316     {
317         GLTexture texture2Id;
318         glBindTexture(GL_TEXTURE_2D, texture2Id);
319         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, mMaxTexture2DSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
320                      data.data());
321         glGenerateMipmap(GL_TEXTURE_2D);
322 
323         glClear(GL_COLOR_BUFFER_BIT);
324         drawQuad(mTextureProgram, "position", 0.5f);
325     }
326 
327     EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), testColor);
328 
329     EXPECT_GL_NO_ERROR();
330 }
331 
332 // TODO(geofflang): Fix the dependence on glBlitFramebufferANGLE without checks and assuming the
333 // default framebuffer is BGRA to enable the GL and GLES backends. (http://anglebug.com/42260299)
334 
335 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
336 // tests should be run against.
337 ANGLE_INSTANTIATE_TEST(MaxTextureSizeTest, ES2_D3D9(), ES2_D3D11(), ES2_VULKAN(), ES2_METAL());
338 
339 // This test suite is not instantiated on some OSes.
340 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MaxTextureSizeTest);
341