1#include "ANGLETest.h"
2
3class MaxTextureSizeTest : public ANGLETest
4{
5protected:
6    MaxTextureSizeTest()
7    {
8        setWindowWidth(512);
9        setWindowHeight(512);
10        setConfigRedBits(8);
11        setConfigGreenBits(8);
12        setConfigBlueBits(8);
13        setConfigAlphaBits(8);
14    }
15
16    virtual void SetUp()
17    {
18        ANGLETest::SetUp();
19
20        const std::string vsSource = SHADER_SOURCE
21        (
22            precision highp float;
23            attribute vec4 position;
24            varying vec2 texcoord;
25
26            void main()
27            {
28                gl_Position = position;
29                texcoord = (position.xy * 0.5) + 0.5;
30            }
31        );
32
33        const std::string textureFSSource = SHADER_SOURCE
34        (
35            precision highp float;
36            uniform sampler2D tex;
37            varying vec2 texcoord;
38
39            void main()
40            {
41                gl_FragColor = texture2D(tex, texcoord);
42            }
43        );
44
45        const std::string blueFSSource = SHADER_SOURCE
46        (
47            precision highp float;
48
49            void main()
50            {
51                gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
52            }
53        );
54
55        mTextureProgram = CompileProgram(vsSource, textureFSSource);
56        mBlueProgram = CompileProgram(vsSource, blueFSSource);
57        if (mTextureProgram == 0 || mBlueProgram == 0)
58        {
59            FAIL() << "shader compilation failed.";
60        }
61
62        mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
63
64        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTexture2DSize);
65        glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxTextureCubeSize);
66        glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
67
68        ASSERT_GL_NO_ERROR();
69    }
70
71    virtual void TearDown()
72    {
73        glDeleteProgram(mTextureProgram);
74        glDeleteProgram(mBlueProgram);
75
76        ANGLETest::TearDown();
77    }
78
79    GLuint mTextureProgram;
80    GLint mTextureUniformLocation;
81
82    GLuint mBlueProgram;
83
84    GLint mMaxTexture2DSize;
85    GLint mMaxTextureCubeSize;
86    GLint mMaxRenderbufferSize;
87};
88
89TEST_F(MaxTextureSizeTest, SpecificationTexImage)
90{
91    GLuint tex;
92    glGenTextures(1, &tex);
93    glBindTexture(GL_TEXTURE_2D, tex);
94
95    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
96    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
97    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
98    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
99
100    GLsizei textureWidth = mMaxTexture2DSize;
101    GLsizei textureHeight = 64;
102
103    std::vector<GLubyte> data(textureWidth * textureHeight * 4);
104    for (int y = 0; y < textureHeight; y++)
105    {
106        for (int x = 0; x < textureWidth; x++)
107        {
108            GLubyte* pixel = data.data() + ((y * textureWidth + x) * 4);
109
110            // Draw a gradient, red in direction, green in y direction
111            pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255);
112            pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255);
113            pixel[2] = 0;
114            pixel[3] = 255;
115        }
116    }
117
118    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
119    EXPECT_GL_NO_ERROR();
120
121    glUseProgram(mTextureProgram);
122    glUniform1i(mTextureUniformLocation, 0);
123
124    drawQuad(mTextureProgram, "position", 0.5f);
125
126    std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
127    glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
128
129    for (int y = 1; y < getWindowHeight(); y++)
130    {
131        for (int x = 1; x < getWindowWidth(); x++)
132        {
133            const GLubyte* prevPixel = pixels.data() + (((y - 1) * getWindowWidth() + (x - 1)) * 4);
134            const GLubyte* curPixel = pixels.data() + ((y * getWindowWidth() + x) * 4);
135
136            EXPECT_GE(curPixel[0], prevPixel[0]);
137            EXPECT_GE(curPixel[1], prevPixel[1]);
138            EXPECT_EQ(curPixel[2], prevPixel[2]);
139            EXPECT_EQ(curPixel[3], prevPixel[3]);
140        }
141    }
142}
143
144TEST_F(MaxTextureSizeTest, SpecificationTexStorage)
145{
146    if (getClientVersion() < 3 && (!extensionEnabled("GL_EXT_texture_storage") || !extensionEnabled("GL_OES_rgb8_rgba8")))
147    {
148        return;
149    }
150
151    GLuint tex;
152    glGenTextures(1, &tex);
153    glBindTexture(GL_TEXTURE_2D, tex);
154
155    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
156    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
157    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
158    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
159
160    GLsizei textureWidth = 64;
161    GLsizei textureHeight = mMaxTexture2DSize;
162
163    std::vector<GLubyte> data(textureWidth * textureHeight * 4);
164    for (int y = 0; y < textureHeight; y++)
165    {
166        for (int x = 0; x < textureWidth; x++)
167        {
168            GLubyte* pixel = data.data() + ((y * textureWidth + x) * 4);
169
170            // Draw a gradient, red in direction, green in y direction
171            pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255);
172            pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255);
173            pixel[2] = 0;
174            pixel[3] = 255;
175        }
176    }
177
178    if (getClientVersion() < 3)
179    {
180        glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight);
181    }
182    else
183    {
184        glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight);
185    }
186    EXPECT_GL_NO_ERROR();
187
188    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
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.data());
198
199    for (int y = 1; y < getWindowHeight(); y++)
200    {
201        for (int x = 1; x < getWindowWidth(); x++)
202        {
203            const GLubyte* prevPixel = pixels.data() + (((y - 1) * getWindowWidth() + (x - 1)) * 4);
204            const GLubyte* curPixel = pixels.data() + ((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
214TEST_F(MaxTextureSizeTest, RenderToTexture)
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, textureHeight, textureWidth, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
231    EXPECT_GL_NO_ERROR();
232
233    // create an FBO and attach the texture
234    glGenFramebuffers(1, &fbo);
235    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
236    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
237
238    EXPECT_GL_NO_ERROR();
239    EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
240
241    const int frameCount = 64;
242    for (int i = 0; i < frameCount; i++)
243    {
244        // clear the screen
245        glBindFramebuffer(GL_FRAMEBUFFER, 0);
246
247        GLubyte clearRed = static_cast<GLubyte>((float(i) / frameCount) * 255);
248        GLubyte clearGreen = 255 - clearRed;
249        GLubyte clearBlue = 0;
250
251        glClearColor(clearRed / 255.0f, clearGreen / 255.0f, clearBlue / 255.0f, 1.0f);
252        glClear(GL_COLOR_BUFFER_BIT);
253
254        // render blue into the texture
255        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
256        drawQuad(mBlueProgram, "position", 0.5f);
257
258        // copy corner of texture to LL corner of window
259        glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0);
260        glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
261        glBlitFramebufferANGLE(0, 0, textureWidth - 1, getWindowHeight() - 1,
262                               0, 0, textureWidth - 1, getWindowHeight() - 1,
263                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
264        glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, 0);
265        EXPECT_GL_NO_ERROR();
266
267        EXPECT_PIXEL_EQ(textureWidth / 2, getWindowHeight() / 2, 0, 0, 255, 255);
268        EXPECT_PIXEL_EQ(textureWidth + 10, getWindowHeight() / 2, clearRed, clearGreen, clearBlue, 255);
269
270        swapBuffers();
271    }
272
273    glBindFramebuffer(GL_FRAMEBUFFER, 0);
274    glBindTexture(GL_TEXTURE_2D, 0);
275
276    glDeleteFramebuffers(1, &fbo);
277    glDeleteTextures(1, &textureId);
278}
279