Commit 60f6eb20 by Frank Henigman Committed by Commit Bot

Add WebGL test that draws to missing attachment.

In WebGL one can Clear, DrawArrays, and DrawElements to a framebuffer with a missing attachment with no error. BUG=angleproject:1822 Change-Id: I4dece2fa8fad31c812e24ae18bdc380c2857a1f8 Reviewed-on: https://chromium-review.googlesource.com/502967Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Frank Henigman <fjhenigman@chromium.org>
parent 4cdac9eb
......@@ -358,9 +358,9 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams,
gl::Extents framebufferSize;
if (depthStencilRenderTarget != nullptr)
if (depthStencilAttachment != nullptr)
{
framebufferSize = depthStencilRenderTarget->getExtents();
framebufferSize = depthStencilAttachment->getSize();
}
else
{
......
......@@ -43,6 +43,7 @@ class WebGLFramebufferTest : public ANGLETest
GLbitfield allowedStatuses);
void testRenderingAndReading(GLuint program);
void testUsingIncompleteFramebuffer(GLenum depthFormat, GLenum depthAttachment);
void testDrawingMissingAttachment();
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
};
......@@ -715,44 +716,49 @@ void testFramebufferIncompleteDimensions(GLenum depthFormat, GLenum depthAttachm
EXPECT_GL_NO_ERROR();
}
// Test drawing or reading from a missing framebuffer attachment.
void testReadingFromMissingAttachment()
class NoColorFB final : angle::NonCopyable
{
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
constexpr int size = 16;
// The only scenario we can verify is an attempt to read or copy
// from a missing color attachment while the framebuffer is still
// complete.
GLRenderbuffer depthBuffer;
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
public:
NoColorFB(int size)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
// After depth renderbuffer setup
EXPECT_GL_NO_ERROR();
// The only scenario we can verify is an attempt to read or copy
// from a missing color attachment while the framebuffer is still
// complete.
glBindRenderbuffer(GL_RENDERBUFFER, mDepthBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
mDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
// Unable to allocate a framebuffer with just a depth attachment; this is legal.
// Try just a depth/stencil renderbuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
GLRenderbuffer depthStencilBuffer;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, size, size);
// After depth+stencil renderbuffer setup
// After depth renderbuffer setup
EXPECT_GL_NO_ERROR();
// Unable to allocate a framebuffer with just a depth+stencil attachment; this is legal.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
return;
// Unable to allocate a framebuffer with just a depth attachment; this is legal.
// Try just a depth/stencil renderbuffer.
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
glBindRenderbuffer(GL_RENDERBUFFER, mDepthStencilBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mDepthStencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, size, size);
// After depth+stencil renderbuffer setup
EXPECT_GL_NO_ERROR();
}
}
private:
GLRenderbuffer mDepthBuffer;
GLRenderbuffer mDepthStencilBuffer;
GLFramebuffer mFBO;
};
// Test reading from a missing framebuffer attachment.
void TestReadingMissingAttachment(int size)
{
// The FBO has no color attachment. ReadPixels, CopyTexImage2D,
// and CopyTexSubImage2D should all generate INVALID_OPERATION.
......@@ -779,6 +785,26 @@ void testReadingFromMissingAttachment()
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Test drawing to a missing framebuffer attachment.
void WebGLFramebufferTest::testDrawingMissingAttachment()
{
// Simple draw program.
const std::string &vertexShader = "attribute vec4 pos; void main() { gl_Position = pos; }";
const std::string &fragmentShader = "void main() { gl_FragColor = vec4(1, 0, 0, 1); }";
ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
// try glDrawArrays
drawQuad(program, "pos", 0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
// try glDrawElements
drawIndexedQuad(program, "pos", 0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
}
// Determine if we can attach both color and depth or color and depth_stencil
TEST_P(WebGLFramebufferTest, CheckValidColorDepthCombination)
{
......@@ -791,7 +817,19 @@ TEST_P(WebGLFramebufferTest, CheckValidColorDepthCombination)
testFramebufferIncompleteAttachment(depthFormat);
testFramebufferIncompleteMissingAttachment();
testUsingIncompleteFramebuffer(depthFormat, depthAttachment);
testReadingFromMissingAttachment();
constexpr int size = 16;
NoColorFB fb(size);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
{
// The FBO has no color attachment. ReadPixels, CopyTexImage2D,
// and CopyTexSubImage2D should all generate INVALID_OPERATION.
TestReadingMissingAttachment(size);
// The FBO has no color attachment. Clear, DrawArrays,
// and DrawElements should not generate an error.
testDrawingMissingAttachment();
}
}
}
......
......@@ -89,6 +89,8 @@ std::array<angle::Vector3, 4> GetIndexedQuadVertices()
return vertices;
}
static constexpr GLushort IndexedQuadIndices[6] = {0, 1, 2, 0, 2, 3};
} // anonymous namespace
GLColorRGB::GLColorRGB() : R(0), G(0), B(0)
......@@ -204,6 +206,7 @@ ANGLETest::ANGLETest()
mHeight(16),
mIgnoreD3D11SDKLayersWarnings(false),
mQuadVertexBuffer(0),
mQuadIndexBuffer(0),
mDeferContextInit(false)
{
mEGLWindow =
......@@ -238,6 +241,10 @@ ANGLETest::~ANGLETest()
{
glDeleteBuffers(1, &mQuadVertexBuffer);
}
if (mQuadIndexBuffer)
{
glDeleteBuffers(1, &mQuadIndexBuffer);
}
SafeDelete(mEGLWindow);
}
......@@ -373,6 +380,18 @@ void ANGLETest::setupIndexedQuadVertexBuffer(GLfloat positionAttribZ, GLfloat po
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 4, quadVertices.data(), GL_STATIC_DRAW);
}
void ANGLETest::setupIndexedQuadIndexBuffer()
{
if (mQuadIndexBuffer == 0)
{
glGenBuffers(1, &mQuadIndexBuffer);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(angle::IndexedQuadIndices),
angle::IndexedQuadIndices, GL_STATIC_DRAW);
}
// static
void ANGLETest::drawQuad(GLuint program,
const std::string &positionAttribName,
......@@ -448,6 +467,15 @@ void ANGLETest::drawIndexedQuad(GLuint program,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale)
{
drawIndexedQuad(program, positionAttribName, positionAttribZ, positionAttribXYScale, false);
}
void ANGLETest::drawIndexedQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useIndexBuffer)
{
GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str());
GLint activeProgram = 0;
......@@ -457,21 +485,37 @@ void ANGLETest::drawIndexedQuad(GLuint program,
glUseProgram(program);
}
GLuint prevBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevBinding));
GLuint prevCoordBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevCoordBinding));
setupIndexedQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, prevBinding);
glBindBuffer(GL_ARRAY_BUFFER, prevCoordBinding);
const GLushort indices[] = {
0, 1, 2, 0, 2, 3,
};
GLuint prevIndexBinding = 0;
const GLvoid *indices;
if (useIndexBuffer)
{
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,
reinterpret_cast<GLint *>(&prevIndexBinding));
setupIndexedQuadIndexBuffer();
indices = 0;
}
else
{
indices = angle::IndexedQuadIndices;
}
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
if (useIndexBuffer)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevIndexBinding);
}
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
......
......@@ -231,6 +231,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
void setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale);
void setupIndexedQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale);
void setupIndexedQuadIndexBuffer();
void drawQuad(GLuint program, const std::string &positionAttribName, GLfloat positionAttribZ);
void drawQuad(GLuint program,
......@@ -250,6 +251,11 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale);
void drawIndexedQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useBufferObject);
static GLuint compileShader(GLenum type, const std::string &source);
static bool extensionEnabled(const std::string &extName);
......@@ -306,6 +312,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
// Used for indexed quad rendering
GLuint mQuadVertexBuffer;
GLuint mQuadIndexBuffer;
angle::PlatformMethods mPlatformMethods;
TestPlatformContext mPlatformContext;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment