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, ...@@ -358,9 +358,9 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams,
gl::Extents framebufferSize; gl::Extents framebufferSize;
if (depthStencilRenderTarget != nullptr) if (depthStencilAttachment != nullptr)
{ {
framebufferSize = depthStencilRenderTarget->getExtents(); framebufferSize = depthStencilAttachment->getSize();
} }
else else
{ {
......
...@@ -43,6 +43,7 @@ class WebGLFramebufferTest : public ANGLETest ...@@ -43,6 +43,7 @@ class WebGLFramebufferTest : public ANGLETest
GLbitfield allowedStatuses); GLbitfield allowedStatuses);
void testRenderingAndReading(GLuint program); void testRenderingAndReading(GLuint program);
void testUsingIncompleteFramebuffer(GLenum depthFormat, GLenum depthAttachment); void testUsingIncompleteFramebuffer(GLenum depthFormat, GLenum depthAttachment);
void testDrawingMissingAttachment();
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr; PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
}; };
...@@ -715,44 +716,49 @@ void testFramebufferIncompleteDimensions(GLenum depthFormat, GLenum depthAttachm ...@@ -715,44 +716,49 @@ void testFramebufferIncompleteDimensions(GLenum depthFormat, GLenum depthAttachm
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Test drawing or reading from a missing framebuffer attachment. class NoColorFB final : angle::NonCopyable
void testReadingFromMissingAttachment()
{ {
GLFramebuffer fbo; public:
glBindFramebuffer(GL_FRAMEBUFFER, fbo); NoColorFB(int size)
{
constexpr int size = 16; glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
// 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);
// After depth renderbuffer setup // The only scenario we can verify is an attempt to read or copy
EXPECT_GL_NO_ERROR(); // 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) // After depth renderbuffer setup
{
// 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
EXPECT_GL_NO_ERROR(); 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) 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, // The FBO has no color attachment. ReadPixels, CopyTexImage2D,
// and CopyTexSubImage2D should all generate INVALID_OPERATION. // and CopyTexSubImage2D should all generate INVALID_OPERATION.
...@@ -779,6 +785,26 @@ void testReadingFromMissingAttachment() ...@@ -779,6 +785,26 @@ void testReadingFromMissingAttachment()
EXPECT_GL_ERROR(GL_INVALID_OPERATION); 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 // Determine if we can attach both color and depth or color and depth_stencil
TEST_P(WebGLFramebufferTest, CheckValidColorDepthCombination) TEST_P(WebGLFramebufferTest, CheckValidColorDepthCombination)
{ {
...@@ -791,7 +817,19 @@ TEST_P(WebGLFramebufferTest, CheckValidColorDepthCombination) ...@@ -791,7 +817,19 @@ TEST_P(WebGLFramebufferTest, CheckValidColorDepthCombination)
testFramebufferIncompleteAttachment(depthFormat); testFramebufferIncompleteAttachment(depthFormat);
testFramebufferIncompleteMissingAttachment(); testFramebufferIncompleteMissingAttachment();
testUsingIncompleteFramebuffer(depthFormat, depthAttachment); 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() ...@@ -89,6 +89,8 @@ std::array<angle::Vector3, 4> GetIndexedQuadVertices()
return vertices; return vertices;
} }
static constexpr GLushort IndexedQuadIndices[6] = {0, 1, 2, 0, 2, 3};
} // anonymous namespace } // anonymous namespace
GLColorRGB::GLColorRGB() : R(0), G(0), B(0) GLColorRGB::GLColorRGB() : R(0), G(0), B(0)
...@@ -204,6 +206,7 @@ ANGLETest::ANGLETest() ...@@ -204,6 +206,7 @@ ANGLETest::ANGLETest()
mHeight(16), mHeight(16),
mIgnoreD3D11SDKLayersWarnings(false), mIgnoreD3D11SDKLayersWarnings(false),
mQuadVertexBuffer(0), mQuadVertexBuffer(0),
mQuadIndexBuffer(0),
mDeferContextInit(false) mDeferContextInit(false)
{ {
mEGLWindow = mEGLWindow =
...@@ -238,6 +241,10 @@ ANGLETest::~ANGLETest() ...@@ -238,6 +241,10 @@ ANGLETest::~ANGLETest()
{ {
glDeleteBuffers(1, &mQuadVertexBuffer); glDeleteBuffers(1, &mQuadVertexBuffer);
} }
if (mQuadIndexBuffer)
{
glDeleteBuffers(1, &mQuadIndexBuffer);
}
SafeDelete(mEGLWindow); SafeDelete(mEGLWindow);
} }
...@@ -373,6 +380,18 @@ void ANGLETest::setupIndexedQuadVertexBuffer(GLfloat positionAttribZ, GLfloat po ...@@ -373,6 +380,18 @@ void ANGLETest::setupIndexedQuadVertexBuffer(GLfloat positionAttribZ, GLfloat po
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 4, quadVertices.data(), GL_STATIC_DRAW); 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 // static
void ANGLETest::drawQuad(GLuint program, void ANGLETest::drawQuad(GLuint program,
const std::string &positionAttribName, const std::string &positionAttribName,
...@@ -448,6 +467,15 @@ void ANGLETest::drawIndexedQuad(GLuint program, ...@@ -448,6 +467,15 @@ void ANGLETest::drawIndexedQuad(GLuint program,
GLfloat positionAttribZ, GLfloat positionAttribZ,
GLfloat positionAttribXYScale) 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 positionLocation = glGetAttribLocation(program, positionAttribName.c_str());
GLint activeProgram = 0; GLint activeProgram = 0;
...@@ -457,21 +485,37 @@ void ANGLETest::drawIndexedQuad(GLuint program, ...@@ -457,21 +485,37 @@ void ANGLETest::drawIndexedQuad(GLuint program,
glUseProgram(program); glUseProgram(program);
} }
GLuint prevBinding = 0; GLuint prevCoordBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevBinding)); glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevCoordBinding));
setupIndexedQuadVertexBuffer(positionAttribZ, positionAttribXYScale); setupIndexedQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation); glEnableVertexAttribArray(positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, prevBinding); glBindBuffer(GL_ARRAY_BUFFER, prevCoordBinding);
const GLushort indices[] = { GLuint prevIndexBinding = 0;
0, 1, 2, 0, 2, 3, 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); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
if (useIndexBuffer)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevIndexBinding);
}
glDisableVertexAttribArray(positionLocation); glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr); glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
......
...@@ -231,6 +231,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters> ...@@ -231,6 +231,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
void setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale); void setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale);
void setupIndexedQuadVertexBuffer(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, const std::string &positionAttribName, GLfloat positionAttribZ);
void drawQuad(GLuint program, void drawQuad(GLuint program,
...@@ -250,6 +251,11 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters> ...@@ -250,6 +251,11 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
const std::string &positionAttribName, const std::string &positionAttribName,
GLfloat positionAttribZ, GLfloat positionAttribZ,
GLfloat positionAttribXYScale); 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 GLuint compileShader(GLenum type, const std::string &source);
static bool extensionEnabled(const std::string &extName); static bool extensionEnabled(const std::string &extName);
...@@ -306,6 +312,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters> ...@@ -306,6 +312,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
// Used for indexed quad rendering // Used for indexed quad rendering
GLuint mQuadVertexBuffer; GLuint mQuadVertexBuffer;
GLuint mQuadIndexBuffer;
angle::PlatformMethods mPlatformMethods; angle::PlatformMethods mPlatformMethods;
TestPlatformContext mPlatformContext; 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