Commit 9bc9a321 by Martin Radev Committed by Commit Bot

Integrate multiview state in FBO completeness check

The patch extends the FBO completeness validation to include the multiview state members according to the ANGLE_multiview specification. It also changes the numViews in FramebufferAttachment to be consistently of type GLsizei instead of GLint. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: Ibe550ba03204d808d96a4edf4807c68421aa1158 Reviewed-on: https://chromium-review.googlesource.com/581193 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 7c5f5268
...@@ -39,6 +39,32 @@ void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmen ...@@ -39,6 +39,32 @@ void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmen
binding->bind(resource ? resource->getDirtyChannel() : nullptr); binding->bind(resource ? resource->getDirtyChannel() : nullptr);
} }
bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
const FramebufferAttachment *secondAttachment)
{
ASSERT(firstAttachment && secondAttachment);
ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
{
return false;
}
if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
{
return false;
}
if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
{
return false;
}
if (firstAttachment->getMultiviewViewportOffsets() !=
secondAttachment->getMultiviewViewportOffsets())
{
return false;
}
return true;
}
bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment) bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
{ {
ASSERT(attachment.isAttached()); ASSERT(attachment.isAttached());
...@@ -797,6 +823,8 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -797,6 +823,8 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
Optional<GLboolean> fixedSampleLocations; Optional<GLboolean> fixedSampleLocations;
bool hasRenderbuffer = false; bool hasRenderbuffer = false;
const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments) for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
{ {
if (colorAttachment.isAttached()) if (colorAttachment.isAttached())
...@@ -835,6 +863,11 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -835,6 +863,11 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
} }
} }
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
}
hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER); hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
hasAttachments = true; hasAttachments = true;
} }
...@@ -860,6 +893,11 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -860,6 +893,11 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
} }
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
}
hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER); hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
hasAttachments = true; hasAttachments = true;
} }
...@@ -884,6 +922,11 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -884,6 +922,11 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
} }
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
}
hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER); hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
hasAttachments = true; hasAttachments = true;
} }
...@@ -910,6 +953,12 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -910,6 +953,12 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
{ {
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
} }
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
&mState.mWebGLDepthStencilAttachment))
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
}
} }
else if (mState.mStencilAttachment.isAttached() && else if (mState.mStencilAttachment.isAttached() &&
mState.mStencilAttachment.getDepthSize() > 0) mState.mStencilAttachment.getDepthSize() > 0)
......
...@@ -23,7 +23,7 @@ namespace gl ...@@ -23,7 +23,7 @@ namespace gl
////// FramebufferAttachment::Target Implementation ////// ////// FramebufferAttachment::Target Implementation //////
const GLint FramebufferAttachment::kDefaultNumViews = 1; const GLsizei FramebufferAttachment::kDefaultNumViews = 1;
const GLenum FramebufferAttachment::kDefaultMultiviewLayout = GL_NONE; const GLenum FramebufferAttachment::kDefaultMultiviewLayout = GL_NONE;
const GLint FramebufferAttachment::kDefaultBaseViewIndex = 0; const GLint FramebufferAttachment::kDefaultBaseViewIndex = 0;
const GLint FramebufferAttachment::kDefaultViewportOffsets[2] = {0}; const GLint FramebufferAttachment::kDefaultViewportOffsets[2] = {0};
...@@ -231,7 +231,7 @@ GLint FramebufferAttachment::layer() const ...@@ -231,7 +231,7 @@ GLint FramebufferAttachment::layer() const
return 0; return 0;
} }
GLint FramebufferAttachment::getNumViews() const GLsizei FramebufferAttachment::getNumViews() const
{ {
return mNumViews; return mNumViews;
} }
......
...@@ -97,7 +97,7 @@ class FramebufferAttachment final ...@@ -97,7 +97,7 @@ class FramebufferAttachment final
GLenum cubeMapFace() const; GLenum cubeMapFace() const;
GLint mipLevel() const; GLint mipLevel() const;
GLint layer() const; GLint layer() const;
GLint getNumViews() const; GLsizei getNumViews() const;
GLenum getMultiviewLayout() const; GLenum getMultiviewLayout() const;
GLint getBaseViewIndex() const; GLint getBaseViewIndex() const;
const std::vector<Offset> &getMultiviewViewportOffsets() const; const std::vector<Offset> &getMultiviewViewportOffsets() const;
...@@ -129,7 +129,7 @@ class FramebufferAttachment final ...@@ -129,7 +129,7 @@ class FramebufferAttachment final
bool operator==(const FramebufferAttachment &other) const; bool operator==(const FramebufferAttachment &other) const;
bool operator!=(const FramebufferAttachment &other) const; bool operator!=(const FramebufferAttachment &other) const;
static const GLint kDefaultNumViews; static const GLsizei kDefaultNumViews;
static const GLenum kDefaultMultiviewLayout; static const GLenum kDefaultMultiviewLayout;
static const GLint kDefaultBaseViewIndex; static const GLint kDefaultBaseViewIndex;
static const GLint kDefaultViewportOffsets[2]; static const GLint kDefaultViewportOffsets[2];
...@@ -163,7 +163,7 @@ class FramebufferAttachment final ...@@ -163,7 +163,7 @@ class FramebufferAttachment final
GLenum mType; GLenum mType;
Target mTarget; Target mTarget;
FramebufferAttachmentObject *mResource; FramebufferAttachmentObject *mResource;
GLint mNumViews; GLsizei mNumViews;
GLenum mMultiviewLayout; GLenum mMultiviewLayout;
GLint mBaseViewIndex; GLint mBaseViewIndex;
std::vector<Offset> mViewportOffsets; std::vector<Offset> mViewportOffsets;
......
...@@ -11,6 +11,20 @@ ...@@ -11,6 +11,20 @@
using namespace angle; using namespace angle;
namespace
{
GLuint CreateTexture2D(GLenum internalFormat, GLenum format, GLenum type)
{
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, nullptr);
return tex;
}
} // namespace
class FramebufferMultiviewTest : public ANGLETest class FramebufferMultiviewTest : public ANGLETest
{ {
protected: protected:
...@@ -55,14 +69,6 @@ class FramebufferMultiviewTest : public ANGLETest ...@@ -55,14 +69,6 @@ class FramebufferMultiviewTest : public ANGLETest
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
void createTexture2D()
{
glGenTextures(1, &mTexture2D);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA16F, 1, 1);
ASSERT_GL_NO_ERROR();
}
void createTexture2DArray() void createTexture2DArray()
{ {
glGenTextures(1, &mTexture2DArray); glGenTextures(1, &mTexture2DArray);
...@@ -102,7 +108,8 @@ TEST_P(FramebufferMultiviewTest, DefaultState) ...@@ -102,7 +108,8 @@ TEST_P(FramebufferMultiviewTest, DefaultState)
return; return;
} }
createTexture2D(); mTexture2D = CreateTexture2D(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture2D, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture2D, 0);
GLint numViews = -1; GLint numViews = -1;
...@@ -139,7 +146,8 @@ TEST_P(FramebufferMultiviewTest, DefaultState) ...@@ -139,7 +146,8 @@ TEST_P(FramebufferMultiviewTest, DefaultState)
// the ANGLE_multiview tokens results in an INVALID_ENUM error. // the ANGLE_multiview tokens results in an INVALID_ENUM error.
TEST_P(FramebufferMultiviewTest, NegativeFramebufferStateQueries) TEST_P(FramebufferMultiviewTest, NegativeFramebufferStateQueries)
{ {
createTexture2D(); mTexture2D = CreateTexture2D(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture2D, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture2D, 0);
GLint numViews = -1; GLint numViews = -1;
...@@ -176,7 +184,8 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewSideBySideArguments) ...@@ -176,7 +184,8 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewSideBySideArguments)
return; return;
} }
createTexture2D(); mTexture2D = CreateTexture2D(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
// Negative offsets. // Negative offsets.
int viewportOffsets[2] = {-1}; int viewportOffsets[2] = {-1};
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture2D, glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture2D,
...@@ -219,7 +228,8 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewLayeredArguments) ...@@ -219,7 +228,8 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewLayeredArguments)
// available. // available.
TEST_P(FramebufferMultiviewTest, ExtensionNotAvailableCheck) TEST_P(FramebufferMultiviewTest, ExtensionNotAvailableCheck)
{ {
createTexture2D(); mTexture2D = CreateTexture2D(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
int viewportOffsets[2] = {0}; int viewportOffsets[2] = {0};
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture2D, glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture2D,
0, 1, &viewportOffsets[0]); 0, 1, &viewportOffsets[0]);
...@@ -235,7 +245,8 @@ TEST_P(FramebufferMultiviewTest, ModifySideBySideState) ...@@ -235,7 +245,8 @@ TEST_P(FramebufferMultiviewTest, ModifySideBySideState)
} }
const GLint viewportOffsets[4] = {0, 0, 1, 2}; const GLint viewportOffsets[4] = {0, 0, 1, 2};
createTexture2D(); mTexture2D = CreateTexture2D(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture2D, glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture2D,
0, 2, &viewportOffsets[0]); 0, 2, &viewportOffsets[0]);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -272,4 +283,100 @@ TEST_P(FramebufferMultiviewTest, ModifySideBySideState) ...@@ -272,4 +283,100 @@ TEST_P(FramebufferMultiviewTest, ModifySideBySideState)
} }
} }
// Test framebuffer completeness status of a side-by-side framebuffer with color and depth
// attachments.
TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsSideBySide)
{
if (!requestMultiviewExtension())
{
return;
}
mTexture2D = CreateTexture2D(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
GLuint otherTexture = CreateTexture2D(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
ASSERT_GL_NO_ERROR();
GLuint depthTexture = CreateTexture2D(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT);
ASSERT_GL_NO_ERROR();
const GLint viewportOffsets[4] = {0, 0, 2, 0};
const GLint otherViewportOffsets[4] = {2, 0, 4, 0};
// Set the 0th attachment and keep it as it is till the end of the test. The 1st or depth
// attachment will me modified to change the framebuffer's status.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture2D,
0, 2, &viewportOffsets[0]);
ASSERT_GL_NO_ERROR();
// Color attachment 1.
{
// Test framebuffer completeness when the number of views differ.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
otherTexture, 0, 1, &viewportOffsets[0]);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Test framebuffer completeness when the viewport offsets differ.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
otherTexture, 0, 2, &otherViewportOffsets[0]);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Test framebuffer completeness when attachment layouts differ.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, otherTexture,
0);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Test that framebuffer is complete when the number of views, viewport offsets and layouts
// are the same.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
otherTexture, 0, 2, &viewportOffsets[0]);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Reset attachment 1
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0, 0, 1,
&viewportOffsets[0]);
}
// Depth attachment.
{
// Test framebuffer completeness when the number of views differ.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
depthTexture, 0, 1, &viewportOffsets[0]);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Test framebuffer completeness when the viewport offsets differ.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
depthTexture, 0, 2, &otherViewportOffsets[0]);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Test framebuffer completeness when attachment layouts differ.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Test that framebuffer is complete when the number of views, viewport offsets and layouts
// are the same.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
depthTexture, 0, 2, &viewportOffsets[0]);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
glDeleteTextures(1, &depthTexture);
glDeleteTextures(1, &otherTexture);
}
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL());
\ No newline at end of file
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