Commit ce8602ab by Kenneth Russell Committed by Commit Bot

WebGL requires GL_FRAMEBUFFER_UNSUPPORTED for identical FBO attachments.

If the same level of a texture is attached to multiple color attachments of a framebuffer object, for example, the WebGL conformance tests require generating a GL_FRAMEBUFFER_UNSUPPORTED error. The Direct3D backend already had this restriction; apply it to all backends when the WebGL compatibility extension is enabled. Fixes the following WebGL conformance tests with the pass-through command decoder in Chrome: conformance/extensions/webgl-draw-buffers-framebuffer-unsupported conformance2/rendering/framebuffer-unsupported BUG=angleproject:2168 Change-Id: I340d06ca0ee969989c6c5725512b1b9542281477 Reviewed-on: https://chromium-review.googlesource.com/699856 Commit-Queue: Kenneth Russell <kbr@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent c1abf917
...@@ -1125,8 +1125,19 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -1125,8 +1125,19 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
} }
// The WebGL conformance tests implicitly define that all framebuffer
// attachments must be unique. For example, the same level of a texture can
// not be attached to two different color attachments.
if (state.getExtensions().webglCompatibility)
{
if (!mState.colorAttachmentsAreUniqueImages())
{
return GL_FRAMEBUFFER_UNSUPPORTED;
}
}
syncState(context); syncState(context);
if (!mImpl->checkStatus()) if (!mImpl->checkStatus(context))
{ {
return GL_FRAMEBUFFER_UNSUPPORTED; return GL_FRAMEBUFFER_UNSUPPORTED;
} }
......
...@@ -78,7 +78,7 @@ class FramebufferImpl : angle::NonCopyable ...@@ -78,7 +78,7 @@ class FramebufferImpl : angle::NonCopyable
GLbitfield mask, GLbitfield mask,
GLenum filter) = 0; GLenum filter) = 0;
virtual bool checkStatus() const = 0; virtual bool checkStatus(const gl::Context *context) const = 0;
virtual void syncState(const gl::Context *context, virtual void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) = 0; const gl::Framebuffer::DirtyBits &dirtyBits) = 0;
......
...@@ -48,7 +48,7 @@ class MockFramebufferImpl : public rx::FramebufferImpl ...@@ -48,7 +48,7 @@ class MockFramebufferImpl : public rx::FramebufferImpl
GLbitfield, GLbitfield,
GLenum)); GLenum));
MOCK_CONST_METHOD0(checkStatus, bool()); MOCK_CONST_METHOD1(checkStatus, bool(const gl::Context *));
MOCK_METHOD2(syncState, void(const gl::Context *, const gl::Framebuffer::DirtyBits &)); MOCK_METHOD2(syncState, void(const gl::Context *, const gl::Framebuffer::DirtyBits &));
...@@ -60,7 +60,7 @@ inline ::testing::NiceMock<MockFramebufferImpl> *MakeFramebufferMock() ...@@ -60,7 +60,7 @@ inline ::testing::NiceMock<MockFramebufferImpl> *MakeFramebufferMock()
::testing::NiceMock<MockFramebufferImpl> *framebufferImpl = ::testing::NiceMock<MockFramebufferImpl> *framebufferImpl =
new ::testing::NiceMock<MockFramebufferImpl>(); new ::testing::NiceMock<MockFramebufferImpl>();
// TODO(jmadill): add ON_CALLS for other returning methods // TODO(jmadill): add ON_CALLS for other returning methods
ON_CALL(*framebufferImpl, checkStatus()).WillByDefault(::testing::Return(true)); ON_CALL(*framebufferImpl, checkStatus(testing::_)).WillByDefault(::testing::Return(true));
// We must mock the destructor since NiceMock doesn't work for destructors. // We must mock the destructor since NiceMock doesn't work for destructors.
EXPECT_CALL(*framebufferImpl, destructor()).Times(1).RetiresOnSaturation(); EXPECT_CALL(*framebufferImpl, destructor()).Times(1).RetiresOnSaturation();
......
...@@ -285,7 +285,7 @@ gl::Error FramebufferD3D::blit(const gl::Context *context, ...@@ -285,7 +285,7 @@ gl::Error FramebufferD3D::blit(const gl::Context *context,
return gl::NoError(); return gl::NoError();
} }
bool FramebufferD3D::checkStatus() const bool FramebufferD3D::checkStatus(const gl::Context *context) const
{ {
// if we have both a depth and stencil buffer, they must refer to the same object // if we have both a depth and stencil buffer, they must refer to the same object
// since we only support packed_depth_stencil and not separate depth and stencil // since we only support packed_depth_stencil and not separate depth and stencil
...@@ -295,10 +295,15 @@ bool FramebufferD3D::checkStatus() const ...@@ -295,10 +295,15 @@ bool FramebufferD3D::checkStatus() const
return false; return false;
} }
// D3D11 does not allow for overlapping RenderTargetViews // D3D11 does not allow for overlapping RenderTargetViews.
if (!mState.colorAttachmentsAreUniqueImages()) // If WebGL compatibility is enabled, this has already been checked at a higher level.
ASSERT(!context->getExtensions().webglCompatibility || mState.colorAttachmentsAreUniqueImages());
if (!context->getExtensions().webglCompatibility)
{ {
return false; if (!mState.colorAttachmentsAreUniqueImages())
{
return false;
}
} }
// D3D requires all render targets to have the same dimensions. // D3D requires all render targets to have the same dimensions.
......
...@@ -92,7 +92,7 @@ class FramebufferD3D : public FramebufferImpl ...@@ -92,7 +92,7 @@ class FramebufferD3D : public FramebufferImpl
GLbitfield mask, GLbitfield mask,
GLenum filter) override; GLenum filter) override;
bool checkStatus() const override; bool checkStatus(const gl::Context *context) const override;
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) override; const gl::Framebuffer::DirtyBits &dirtyBits) override;
......
...@@ -594,7 +594,7 @@ gl::Error FramebufferGL::getSamplePosition(size_t index, GLfloat *xy) const ...@@ -594,7 +594,7 @@ gl::Error FramebufferGL::getSamplePosition(size_t index, GLfloat *xy) const
return gl::NoError(); return gl::NoError();
} }
bool FramebufferGL::checkStatus() const bool FramebufferGL::checkStatus(const gl::Context *context) const
{ {
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
GLenum status = mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER); GLenum status = mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER);
......
...@@ -87,7 +87,7 @@ class FramebufferGL : public FramebufferImpl ...@@ -87,7 +87,7 @@ class FramebufferGL : public FramebufferImpl
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override; gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
bool checkStatus() const override; bool checkStatus(const gl::Context *context) const override;
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) override; const gl::Framebuffer::DirtyBits &dirtyBits) override;
......
...@@ -179,7 +179,7 @@ gl::Error FramebufferNULL::blit(const gl::Context *context, ...@@ -179,7 +179,7 @@ gl::Error FramebufferNULL::blit(const gl::Context *context,
return gl::NoError(); return gl::NoError();
} }
bool FramebufferNULL::checkStatus() const bool FramebufferNULL::checkStatus(const gl::Context *context) const
{ {
return true; return true;
} }
......
...@@ -63,7 +63,7 @@ class FramebufferNULL : public FramebufferImpl ...@@ -63,7 +63,7 @@ class FramebufferNULL : public FramebufferImpl
GLbitfield mask, GLbitfield mask,
GLenum filter) override; GLenum filter) override;
bool checkStatus() const override; bool checkStatus(const gl::Context *context) const override;
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) override; const gl::Framebuffer::DirtyBits &dirtyBits) override;
......
...@@ -346,7 +346,7 @@ gl::Error FramebufferVk::blit(const gl::Context *context, ...@@ -346,7 +346,7 @@ gl::Error FramebufferVk::blit(const gl::Context *context,
return gl::InternalError(); return gl::InternalError();
} }
bool FramebufferVk::checkStatus() const bool FramebufferVk::checkStatus(const gl::Context *context) const
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
return bool(); return bool();
......
...@@ -76,7 +76,7 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk ...@@ -76,7 +76,7 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk
GLbitfield mask, GLbitfield mask,
GLenum filter) override; GLenum filter) override;
bool checkStatus() const override; bool checkStatus(const gl::Context *context) const override;
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) override; const gl::Framebuffer::DirtyBits &dirtyBits) override;
......
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