// // 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" #include #include "test_utils/gl_raii.h" using namespace angle; class IncompleteTextureTest : public ANGLETest { protected: IncompleteTextureTest() { setWindowWidth(128); setWindowHeight(128); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } void testSetUp() override { constexpr char kVS[] = R"(precision highp float; attribute vec4 position; varying vec2 texcoord; void main() { gl_Position = position; texcoord = (position.xy * 0.5) + 0.5; })"; constexpr char kFS[] = R"(precision highp float; uniform sampler2D tex; varying vec2 texcoord; void main() { gl_FragColor = texture2D(tex, texcoord); })"; mProgram = CompileProgram(kVS, kFS); if (mProgram == 0) { FAIL() << "shader compilation failed."; } mTextureUniformLocation = glGetUniformLocation(mProgram, "tex"); } void testTearDown() override { glDeleteProgram(mProgram); } GLuint mProgram; GLint mTextureUniformLocation; }; class IncompleteTextureTestES3 : public ANGLETest { protected: IncompleteTextureTestES3() { setWindowWidth(128); setWindowHeight(128); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; class IncompleteTextureTestES31 : public ANGLETest { protected: IncompleteTextureTestES31() { setWindowWidth(128); setWindowHeight(128); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } }; // Test rendering with an incomplete texture. TEST_P(IncompleteTextureTest, IncompleteTexture2D) { GLTexture tex; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glUseProgram(mProgram); glUniform1i(mTextureUniformLocation, 0); constexpr GLsizei kTextureSize = 2; std::vector textureData(kTextureSize * kTextureSize, GLColor::red); // Make a complete texture. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData.data()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Should be complete - expect red. drawQuad(mProgram, "position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "complete texture should be red"; // Make texture incomplete. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Should be incomplete - expect black. drawQuad(mProgram, "position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black) << "incomplete texture should be black"; // Make texture complete by defining the second mip. glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, kTextureSize >> 1, kTextureSize >> 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData.data()); // Should be complete - expect red. drawQuad(mProgram, "position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "mip-complete texture should be red"; } // Tests redefining a texture with half the size works as expected. TEST_P(IncompleteTextureTest, UpdateTexture) { GLTexture tex; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glUseProgram(mProgram); glUniform1i(mTextureUniformLocation, 0); constexpr GLsizei redTextureSize = 64; std::vector redTextureData(redTextureSize * redTextureSize, GLColor::red); for (GLint mip = 0; mip < 7; ++mip) { const GLsizei mipSize = redTextureSize >> mip; glTexImage2D(GL_TEXTURE_2D, mip, GL_RGBA, mipSize, mipSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, redTextureData.data()); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); drawQuad(mProgram, "position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); constexpr GLsizei greenTextureSize = 32; std::vector greenTextureData(greenTextureSize * greenTextureSize, GLColor::green); for (GLint mip = 0; mip < 6; ++mip) { const GLsizei mipSize = greenTextureSize >> mip; glTexSubImage2D(GL_TEXTURE_2D, mip, mipSize, mipSize, mipSize, mipSize, GL_RGBA, GL_UNSIGNED_BYTE, greenTextureData.data()); } drawQuad(mProgram, "position", 0.5f); EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - greenTextureSize, getWindowHeight() - greenTextureSize, GLColor::green); } // Tests that incomplete textures don't get initialized with the unpack buffer contents. TEST_P(IncompleteTextureTestES3, UnpackBufferBound) { // http://anglebug.com/4092 ANGLE_SKIP_TEST_IF(IsVulkan()); std::vector red(16, GLColor::red); GLBuffer unpackBuffer; glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBuffer); glBufferData(GL_PIXEL_UNPACK_BUFFER, red.size() * sizeof(GLColor), red.data(), GL_STATIC_DRAW); draw2DTexturedQuad(0.5f, 1.0f, true); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); } // Tests that the incomplete multisample texture has the correct alpha value. TEST_P(IncompleteTextureTestES31, MultisampleTexture) { // http://anglebug.com/4092 ANGLE_SKIP_TEST_IF(IsVulkan()); constexpr char kVS[] = R"(#version 310 es in vec2 position; out vec2 texCoord; void main() { gl_Position = vec4(position, 0, 1); texCoord = (position * 0.5) + 0.5; })"; constexpr char kFS[] = R"(#version 310 es precision mediump float; in vec2 texCoord; out vec4 color; uniform mediump sampler2DMS tex; void main() { ivec2 texSize = textureSize(tex); ivec2 texel = ivec2(vec2(texSize) * texCoord); color = texelFetch(tex, texel, 0); })"; glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); // The zero texture will be incomplete by default. ANGLE_GL_PROGRAM(program, kVS, kFS); drawQuad(program, "position", 0.5f); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); } // Use this to select which configurations (e.g. which renderer, which GLES major version) these // tests should be run against. ANGLE_INSTANTIATE_TEST_ES2(IncompleteTextureTest); ANGLE_INSTANTIATE_TEST_ES3(IncompleteTextureTestES3); ANGLE_INSTANTIATE_TEST_ES31(IncompleteTextureTestES31);