blob: 07c7ee154d50adbf635a88096bb95a5a61399d65 [file] [log] [blame]
//
// 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 <vector>
#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<GLColor> 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<GLColor> 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<GLColor> 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<GLColor> 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);