blob: e9a0daed48b65e8e4c08386ad038d5de0f4b1e4a [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 "test_utils/gl_raii.h"
#include "util/EGLWindow.h"
using namespace angle;
class PbufferTest : public ANGLETest
{
protected:
PbufferTest()
{
setWindowWidth(512);
setWindowHeight(512);
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;
texcoord.y = 1.0 - texcoord.y;
})";
constexpr char kFS[] =
R"(precision highp float;
uniform sampler2D tex;
varying vec2 texcoord;
void main()
{
gl_FragColor = texture2D(tex, texcoord);
})";
mTextureProgram = CompileProgram(kVS, kFS);
if (mTextureProgram == 0)
{
FAIL() << "shader compilation failed.";
}
mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
EGLWindow *window = getEGLWindow();
EGLint surfaceType = 0;
eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_SURFACE_TYPE,
&surfaceType);
mSupportsPbuffers = (surfaceType & EGL_PBUFFER_BIT) != 0;
EGLint bindToTextureRGBA = 0;
eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_BIND_TO_TEXTURE_RGBA,
&bindToTextureRGBA);
mSupportsBindTexImage = (bindToTextureRGBA == EGL_TRUE);
const EGLint pBufferAttributes[] = {
EGL_WIDTH, static_cast<EGLint>(mPbufferSize),
EGL_HEIGHT, static_cast<EGLint>(mPbufferSize),
EGL_TEXTURE_FORMAT, mSupportsBindTexImage ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
EGL_TEXTURE_TARGET, mSupportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
EGL_NONE, EGL_NONE,
};
mPbuffer =
eglCreatePbufferSurface(window->getDisplay(), window->getConfig(), pBufferAttributes);
if (mSupportsPbuffers)
{
ASSERT_NE(mPbuffer, EGL_NO_SURFACE);
ASSERT_EGL_SUCCESS();
}
else
{
ASSERT_EQ(mPbuffer, EGL_NO_SURFACE);
ASSERT_EGL_ERROR(EGL_BAD_MATCH);
}
ASSERT_GL_NO_ERROR();
}
void testTearDown() override
{
glDeleteProgram(mTextureProgram);
EGLWindow *window = getEGLWindow();
eglDestroySurface(window->getDisplay(), mPbuffer);
}
GLuint mTextureProgram;
GLint mTextureUniformLocation;
const size_t mPbufferSize = 32;
EGLSurface mPbuffer;
bool mSupportsPbuffers;
bool mSupportsBindTexImage;
};
// Test clearing a Pbuffer and checking the color is correct
TEST_P(PbufferTest, Clearing)
{
ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
EGLWindow *window = getEGLWindow();
// Clear the window surface to blue and verify
window->makeCurrent();
ASSERT_EGL_SUCCESS();
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
// Apply the Pbuffer and clear it to purple and verify
eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
ASSERT_EGL_SUCCESS();
glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
0, 255, 255);
// Rebind the window surface and verify that it is still blue
window->makeCurrent();
ASSERT_EGL_SUCCESS();
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
}
// Bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest, BindTexImage)
{
// Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
// textures.
ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
EGLWindow *window = getEGLWindow();
// Apply the Pbuffer and clear it to purple
eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
ASSERT_EGL_SUCCESS();
glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
0, 255, 255);
// Apply the window surface
window->makeCurrent();
// Create a texture and bind the Pbuffer to it
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
EXPECT_GL_NO_ERROR();
eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
glViewport(0, 0, getWindowWidth(), getWindowHeight());
ASSERT_EGL_SUCCESS();
// Draw a quad and verify that it is purple
glUseProgram(mTextureProgram);
glUniform1i(mTextureUniformLocation, 0);
drawQuad(mTextureProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
// Unbind the texture
eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
ASSERT_EGL_SUCCESS();
// Verify that purple was drawn
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
glDeleteTextures(1, &texture);
}
// Verify that when eglBind/ReleaseTexImage are called, the texture images are freed and their
// size information is correctly updated.
TEST_P(PbufferTest, TextureSizeReset)
{
ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
ANGLE_SKIP_TEST_IF(!mSupportsBindTexImage);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
EXPECT_GL_NO_ERROR();
glUseProgram(mTextureProgram);
glUniform1i(mTextureUniformLocation, 0);
// Fill the texture with white pixels
std::vector<GLColor> whitePixels(mPbufferSize * mPbufferSize, GLColor::white);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(mPbufferSize),
static_cast<GLsizei>(mPbufferSize), 0, GL_RGBA, GL_UNSIGNED_BYTE,
whitePixels.data());
EXPECT_GL_NO_ERROR();
// Draw the white texture and verify that the pixels are correct
drawQuad(mTextureProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
// Bind the EGL surface and draw with it, results are undefined since nothing has
// been written to it
EGLWindow *window = getEGLWindow();
eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
drawQuad(mTextureProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
// Clear the back buffer to a unique color (green)
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Unbind the EGL surface and try to draw with the texture again, the texture's size should
// now be zero and incomplete so the back buffer should be black
eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
drawQuad(mTextureProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
// Bind a Pbuffer, redefine the texture, and verify it renders correctly
TEST_P(PbufferTest, BindTexImageAndRedefineTexture)
{
// Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
// textures.
ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
EGLWindow *window = getEGLWindow();
// Apply the Pbuffer and clear it to purple
eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
ASSERT_EGL_SUCCESS();
glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2, 255,
0, 255, 255);
// Apply the window surface
window->makeCurrent();
// Create a texture and bind the Pbuffer to it
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
EXPECT_GL_NO_ERROR();
eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
glViewport(0, 0, getWindowWidth(), getWindowHeight());
ASSERT_EGL_SUCCESS();
// Redefine the texture
unsigned int pixelValue = 0xFFFF00FF;
std::vector<unsigned int> pixelData(getWindowWidth() * getWindowHeight(), pixelValue);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, &pixelData[0]);
// Draw a quad and verify that it is magenta
glUseProgram(mTextureProgram);
glUniform1i(mTextureUniformLocation, 0);
drawQuad(mTextureProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
// Verify that magenta was drawn
EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
glDeleteTextures(1, &texture);
}
ANGLE_INSTANTIATE_TEST_ES2(PbufferTest);