зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
ee991799fc
Коммит
cfd6b2b6e9
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче