| // |
| // Copyright 2015 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| #include "test_utils/ANGLETest.h" |
| |
| using namespace angle; |
| |
| class MaxTextureSizeTest : public ANGLETest |
| { |
| protected: |
| MaxTextureSizeTest() |
| { |
| setWindowWidth(512); |
| setWindowHeight(512); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| |
| void SetUp() override |
| { |
| ANGLETest::SetUp(); |
| |
| const std::string vsSource = SHADER_SOURCE |
| ( |
| precision highp float; |
| attribute vec4 position; |
| varying vec2 texcoord; |
| |
| void main() |
| { |
| gl_Position = position; |
| texcoord = (position.xy * 0.5) + 0.5; |
| } |
| ); |
| |
| const std::string textureFSSource = SHADER_SOURCE |
| ( |
| precision highp float; |
| uniform sampler2D tex; |
| varying vec2 texcoord; |
| |
| void main() |
| { |
| gl_FragColor = texture2D(tex, texcoord); |
| } |
| ); |
| |
| const std::string blueFSSource = SHADER_SOURCE |
| ( |
| precision highp float; |
| |
| void main() |
| { |
| gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); |
| } |
| ); |
| |
| mTextureProgram = CompileProgram(vsSource, textureFSSource); |
| mBlueProgram = CompileProgram(vsSource, blueFSSource); |
| if (mTextureProgram == 0 || mBlueProgram == 0) |
| { |
| FAIL() << "shader compilation failed."; |
| } |
| |
| mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex"); |
| |
| glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTexture2DSize); |
| glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxTextureCubeSize); |
| glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void TearDown() override |
| { |
| glDeleteProgram(mTextureProgram); |
| glDeleteProgram(mBlueProgram); |
| |
| ANGLETest::TearDown(); |
| } |
| |
| GLuint mTextureProgram; |
| GLint mTextureUniformLocation; |
| |
| GLuint mBlueProgram; |
| |
| GLint mMaxTexture2DSize; |
| GLint mMaxTextureCubeSize; |
| GLint mMaxRenderbufferSize; |
| }; |
| |
| TEST_P(MaxTextureSizeTest, SpecificationTexImage) |
| { |
| GLuint tex; |
| glGenTextures(1, &tex); |
| glBindTexture(GL_TEXTURE_2D, tex); |
| |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| |
| GLsizei textureWidth = mMaxTexture2DSize; |
| GLsizei textureHeight = 64; |
| |
| std::vector<GLubyte> data(textureWidth * textureHeight * 4); |
| for (int y = 0; y < textureHeight; y++) |
| { |
| for (int x = 0; x < textureWidth; x++) |
| { |
| GLubyte* pixel = &data[0] + ((y * textureWidth + x) * 4); |
| |
| // Draw a gradient, red in direction, green in y direction |
| pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255); |
| pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255); |
| pixel[2] = 0; |
| pixel[3] = 255; |
| } |
| } |
| |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); |
| EXPECT_GL_NO_ERROR(); |
| |
| glUseProgram(mTextureProgram); |
| glUniform1i(mTextureUniformLocation, 0); |
| |
| drawQuad(mTextureProgram, "position", 0.5f); |
| |
| std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4); |
| glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); |
| |
| for (int y = 1; y < getWindowHeight(); y++) |
| { |
| for (int x = 1; x < getWindowWidth(); x++) |
| { |
| const GLubyte* prevPixel = &pixels[0] + (((y - 1) * getWindowWidth() + (x - 1)) * 4); |
| const GLubyte* curPixel = &pixels[0] + ((y * getWindowWidth() + x) * 4); |
| |
| EXPECT_GE(curPixel[0], prevPixel[0]); |
| EXPECT_GE(curPixel[1], prevPixel[1]); |
| EXPECT_EQ(curPixel[2], prevPixel[2]); |
| EXPECT_EQ(curPixel[3], prevPixel[3]); |
| } |
| } |
| } |
| |
| TEST_P(MaxTextureSizeTest, SpecificationTexStorage) |
| { |
| if (getClientMajorVersion() < 3 && |
| (!extensionEnabled("GL_EXT_texture_storage") || !extensionEnabled("GL_OES_rgb8_rgba8"))) |
| { |
| return; |
| } |
| |
| GLuint tex; |
| glGenTextures(1, &tex); |
| glBindTexture(GL_TEXTURE_2D, tex); |
| |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| |
| GLsizei textureWidth = 64; |
| GLsizei textureHeight = mMaxTexture2DSize; |
| |
| std::vector<GLubyte> data(textureWidth * textureHeight * 4); |
| for (int y = 0; y < textureHeight; y++) |
| { |
| for (int x = 0; x < textureWidth; x++) |
| { |
| GLubyte* pixel = &data[0] + ((y * textureWidth + x) * 4); |
| |
| // Draw a gradient, red in direction, green in y direction |
| pixel[0] = static_cast<GLubyte>((float(x) / textureWidth) * 255); |
| pixel[1] = static_cast<GLubyte>((float(y) / textureHeight) * 255); |
| pixel[2] = 0; |
| pixel[3] = 255; |
| } |
| } |
| |
| if (getClientMajorVersion() < 3) |
| { |
| glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight); |
| } |
| else |
| { |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8_OES, textureWidth, textureHeight); |
| } |
| EXPECT_GL_NO_ERROR(); |
| |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); |
| EXPECT_GL_NO_ERROR(); |
| |
| glUseProgram(mTextureProgram); |
| glUniform1i(mTextureUniformLocation, 0); |
| |
| drawQuad(mTextureProgram, "position", 0.5f); |
| |
| std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4); |
| glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); |
| |
| for (int y = 1; y < getWindowHeight(); y++) |
| { |
| for (int x = 1; x < getWindowWidth(); x++) |
| { |
| const GLubyte* prevPixel = &pixels[0] + (((y - 1) * getWindowWidth() + (x - 1)) * 4); |
| const GLubyte* curPixel = &pixels[0] + ((y * getWindowWidth() + x) * 4); |
| |
| EXPECT_GE(curPixel[0], prevPixel[0]); |
| EXPECT_GE(curPixel[1], prevPixel[1]); |
| EXPECT_EQ(curPixel[2], prevPixel[2]); |
| EXPECT_EQ(curPixel[3], prevPixel[3]); |
| } |
| } |
| } |
| |
| TEST_P(MaxTextureSizeTest, RenderToTexture) |
| { |
| if (getClientMajorVersion() < 3 && (!extensionEnabled("GL_ANGLE_framebuffer_blit"))) |
| { |
| std::cout << "Test skipped due to missing glBlitFramebuffer[ANGLE] support." << std::endl; |
| return; |
| } |
| |
| GLuint fbo = 0; |
| GLuint textureId = 0; |
| // create a 1-level texture at maximum size |
| glGenTextures(1, &textureId); |
| glBindTexture(GL_TEXTURE_2D, textureId); |
| |
| GLsizei textureWidth = 64; |
| GLsizei textureHeight = mMaxTexture2DSize; |
| |
| // texture setup code |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, textureWidth, textureHeight, 0, GL_BGRA_EXT, |
| GL_UNSIGNED_BYTE, nullptr); |
| EXPECT_GL_NO_ERROR(); |
| |
| // create an FBO and attach the texture |
| glGenFramebuffers(1, &fbo); |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); |
| |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| |
| const int frameCount = 64; |
| for (int i = 0; i < frameCount; i++) |
| { |
| // clear the screen |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| GLubyte clearRed = static_cast<GLubyte>((float(i) / frameCount) * 255); |
| GLubyte clearGreen = 255 - clearRed; |
| GLubyte clearBlue = 0; |
| |
| glClearColor(clearRed / 255.0f, clearGreen / 255.0f, clearBlue / 255.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // render blue into the texture |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| drawQuad(mBlueProgram, "position", 0.5f); |
| |
| // copy corner of texture to LL corner of window |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo); |
| glBlitFramebufferANGLE(0, 0, textureWidth - 1, getWindowHeight() - 1, |
| 0, 0, textureWidth - 1, getWindowHeight() - 1, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, 0); |
| EXPECT_GL_NO_ERROR(); |
| |
| EXPECT_PIXEL_EQ(textureWidth / 2, getWindowHeight() / 2, 0, 0, 255, 255); |
| EXPECT_PIXEL_EQ(textureWidth + 10, getWindowHeight() / 2, clearRed, clearGreen, clearBlue, 255); |
| |
| swapBuffers(); |
| } |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| |
| glDeleteFramebuffers(1, &fbo); |
| glDeleteTextures(1, &textureId); |
| } |
| |
| // TODO(geofflang): Fix the dependence on glBlitFramebufferANGLE without checks and assuming the |
| // default framebuffer is BGRA to enable the GL and GLES backends. (http://anglebug.com/1289) |
| |
| // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. |
| ANGLE_INSTANTIATE_TEST(MaxTextureSizeTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3()); |