D3D11: Add a test to cover a clear RTV driver bug.

See dEQP-GLES3.functional.fbo.color.repeated_clear.sample.tex2d.rgba8

This test uses ClearRenderTargetView to clear various FBO textures,
but it does not seem to work correctly on my Nvidia configuration.
It has been reported to Nvidia. It also seems to fail on Intel.

Current GPU: NVIDIA GeForce GTX 660
Current Driver: 10.18.13.5598 (9-13-2015)
Works on Desktop OpenGL back-end, also on AMD R5230

BUG=angleproject:1305

Change-Id: I4b53b7376faf71f234d05c90f4fb55462de23e36
Reviewed-on: https://chromium-review.googlesource.com/314304
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Jamie Madill 2016-02-08 12:50:38 -05:00 коммит произвёл Commit Bot
Родитель ee991799fc
Коммит cfd6b2b6e9
1 изменённых файлов: 184 добавлений и 26 удалений

Просмотреть файл

@ -6,12 +6,37 @@
#include "test_utils/ANGLETest.h"
#include "random_utils.h"
#include "Vector.h"
using namespace angle;
namespace
{
Vector4 RandomVec4(int seed, float minValue, float maxValue)
{
RNG rng(seed);
srand(seed);
return Vector4(
rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue),
rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue));
}
GLColor Vec4ToColor(const Vector4 &vec)
{
GLColor color;
color.R = static_cast<uint8_t>(vec.x * 255.0f);
color.G = static_cast<uint8_t>(vec.y * 255.0f);
color.B = static_cast<uint8_t>(vec.z * 255.0f);
color.A = static_cast<uint8_t>(vec.w * 255.0f);
return color;
};
class ClearTestBase : public ANGLETest
{
protected:
ClearTestBase()
ClearTestBase() : mProgram(0)
{
setWindowWidth(128);
setWindowHeight(128);
@ -22,10 +47,35 @@ class ClearTestBase : public ANGLETest
setConfigDepthBits(24);
}
virtual void SetUp()
void SetUp() override
{
ANGLETest::SetUp();
mFBOs.resize(2, 0);
glGenFramebuffers(2, mFBOs.data());
ASSERT_GL_NO_ERROR();
}
void TearDown() override
{
glDeleteProgram(mProgram);
if (!mFBOs.empty())
{
glDeleteFramebuffers(static_cast<GLsizei>(mFBOs.size()), mFBOs.data());
}
if (!mTextures.empty())
{
glDeleteTextures(static_cast<GLsizei>(mTextures.size()), mTextures.data());
}
ANGLETest::TearDown();
}
void setupDefaultProgram()
{
const std::string vertexShaderSource = SHADER_SOURCE
(
precision highp float;
@ -48,26 +98,12 @@ class ClearTestBase : public ANGLETest
);
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
if (mProgram == 0)
{
FAIL() << "shader compilation failed.";
}
glGenFramebuffers(1, &mFBO);
ASSERT_GL_NO_ERROR();
}
virtual void TearDown()
{
glDeleteProgram(mProgram);
glDeleteFramebuffers(1, &mFBO);
ANGLETest::TearDown();
ASSERT_NE(0u, mProgram);
}
GLuint mProgram;
GLuint mFBO;
std::vector<GLuint> mFBOs;
std::vector<GLuint> mTextures;
};
class ClearTest : public ClearTestBase {};
@ -84,7 +120,7 @@ TEST_P(ClearTest, DefaultFramebuffer)
// Test clearing a RGBA8 Framebuffer
TEST_P(ClearTest, RGBA8Framebuffer)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
GLuint texture;
glGenTextures(1, &texture);
@ -118,7 +154,7 @@ TEST_P(ClearTest, ClearIssue)
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
GLuint rbo;
glGenRenderbuffers(1, &rbo);
@ -140,6 +176,7 @@ TEST_P(ClearTest, ClearIssue)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
setupDefaultProgram();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
@ -152,7 +189,7 @@ TEST_P(ClearTestES3, MaskedClearBufferBug)
{
unsigned char pixelData[] = { 255, 255, 255, 255 };
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
GLuint textures[2];
glGenTextures(2, &textures[0]);
@ -188,7 +225,7 @@ TEST_P(ClearTestES3, MaskedClearBufferBug)
TEST_P(ClearTestES3, BadFBOSerialBug)
{
// First make a simple framebuffer, and clear it to green
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
GLuint textures[2];
glGenTextures(2, &textures[0]);
@ -220,13 +257,14 @@ TEST_P(ClearTestES3, BadFBOSerialBug)
glDrawBuffers(1, drawBuffers);
setupDefaultProgram();
drawQuad(mProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
// Check that the first framebuffer is still green.
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
glDeleteTextures(2, textures);
@ -244,7 +282,7 @@ TEST_P(ClearTestES3, SRGBClear)
}
// First make a simple framebuffer, and clear it
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
GLuint texture;
glGenTextures(1, &texture);
@ -279,7 +317,7 @@ TEST_P(ClearTestES3, MixedSRGBClear)
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
GLuint textures[2];
glGenTextures(2, &textures[0]);
@ -311,6 +349,124 @@ TEST_P(ClearTestES3, MixedSRGBClear)
EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0);
}
// This test covers a D3D11 bug where calling ClearRenderTargetView sometimes wouldn't sync
// before a draw call. The test draws small quads to a larger FBO (the default back buffer).
// Before each blit to the back buffer it clears the quad to a certain color using
// ClearBufferfv to give a solid color. The sync problem goes away if we insert a call to
// flush or finish after ClearBufferfv or each draw.
TEST_P(ClearTestES3, RepeatedClear)
{
if (isD3D11() && (isNVidia() || isIntel()))
{
std::cout << "Test skipped on Nvidia and Intel D3D11." << std::endl;
return;
}
const std::string &vertexSource =
"#version 300 es\n"
"in highp vec2 position;\n"
"out highp vec2 v_coord;\n"
"void main(void)\n"
"{\n"
" gl_Position = vec4(position, 0, 1);\n"
" vec2 texCoord = (position * 0.5) + 0.5;\n"
" v_coord = texCoord;\n"
"}\n";
const std::string &fragmentSource =
"#version 300 es\n"
"in highp vec2 v_coord;\n"
"out highp vec4 color;\n"
"uniform sampler2D tex;\n"
"void main()\n"
"{\n"
" color = texture(tex, v_coord);\n"
"}\n";
mProgram = CompileProgram(vertexSource, fragmentSource);
ASSERT_NE(0u, mProgram);
mTextures.resize(1, 0);
glGenTextures(1, mTextures.data());
GLenum format = GL_RGBA8;
const int numRowsCols = 3;
const int cellSize = 32;
const int fboSize = cellSize;
const int backFBOSize = cellSize * numRowsCols;
const float fmtValueMin = 0.0f;
const float fmtValueMax = 1.0f;
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, format, fboSize, fboSize);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// larger fbo bound -- clear to transparent black
glUseProgram(mProgram);
GLint uniLoc = glGetUniformLocation(mProgram, "tex");
ASSERT_NE(-1, uniLoc);
glUniform1i(uniLoc, 0);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
glUseProgram(mProgram);
for (int cellY = 0; cellY < numRowsCols; cellY++)
{
for (int cellX = 0; cellX < numRowsCols; cellX++)
{
int seed = cellX + cellY * numRowsCols;
const Vector4 color = RandomVec4(seed, fmtValueMin, fmtValueMax);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
glClearBufferfv(GL_COLOR, 0, color.data());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Method 1: Set viewport and draw full-viewport quad
glViewport(cellX * cellSize, cellY * cellSize, cellSize, cellSize);
drawQuad(mProgram, "position", 0.5f);
// Uncommenting the glFinish call seems to make the test pass.
// glFinish();
}
}
std::vector<GLColor> pixelData(backFBOSize * backFBOSize);
glReadPixels(0, 0, backFBOSize, backFBOSize, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data());
for (int cellY = 0; cellY < numRowsCols; cellY++)
{
for (int cellX = 0; cellX < numRowsCols; cellX++)
{
int seed = cellX + cellY * numRowsCols;
const Vector4 color = RandomVec4(seed, fmtValueMin, fmtValueMax);
GLColor expectedColor = Vec4ToColor(color);
int testN = cellX * cellSize + cellY * backFBOSize * cellSize + backFBOSize + 1;
GLColor actualColor = pixelData[testN];
EXPECT_NEAR(expectedColor.R, actualColor.R, 1);
EXPECT_NEAR(expectedColor.G, actualColor.G, 1);
EXPECT_NEAR(expectedColor.B, actualColor.B, 1);
EXPECT_NEAR(expectedColor.A, actualColor.A, 1);
}
}
ASSERT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(ClearTest,
ES2_D3D9(),
@ -321,3 +477,5 @@ ANGLE_INSTANTIATE_TEST(ClearTest,
ES2_OPENGLES(),
ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(ClearTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
} // anonymous namespace