Commit bccb0d56 by Geoff Lang Committed by Commit Bot

Add messages for framebuffer completeness errors.

This also creates a common code path for all framebuffer completeness errors (FramebufferStatus::Incomplete) which helps for adding a debug breakpoint. Bug: angleproject:5949 Change-Id: Ib102dbf86e020777e56c6dc6b78dda8ebdba2127 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2888110 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent e354ff1a
......@@ -6447,7 +6447,7 @@ GLenum Context::checkFramebufferStatus(GLenum target)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
return framebuffer->checkStatus(this);
return framebuffer->checkStatus(this).status;
}
void Context::compileShader(ShaderProgramID shader)
......
......@@ -143,6 +143,41 @@ MSG kFragDataBindingIndexOutOfRange = "Fragment output color index must be zero
MSG kFragmentInputTypeNotFloatingPoint = "Fragment input type is not a floating point scalar or vector.";
MSG kFramebufferIncomplete = "Framebuffer is incomplete.";
MSG kFramebufferIncompleteAttachment = "Attachment type must be compatible with attachment object.";
MSG kFramebufferIncompleteAttachmentDepthGreaterThanMaxLayers = "Framebuffer is incomplete: Attachment depth is greater than MAX_FRAMEBUFFER_LAYERS.";
MSG kFramebufferIncompleteAttachmentInconsistantBitPlanes = "Framebuffer is incomplete: Attachments have inconsistent bit plane counts.";
MSG kFramebufferIncompleteAttachmentLayerGreaterThanDepth = "Framebuffer is incomplete: Attachment layer is greater than texture layer count.";
MSG kFramebufferIncompleteAttachmentLevelNotBaseLevelForIncompleteMipTexture = "Framebuffer is incomplete: Attachment level not equal to the base level and the texture is not mipmap complete.";
MSG kFramebufferIncompleteAttachmentLevelOutOfBaseMaxLevelRange = "Framebuffer is incomplete: Attachment level is not in the [base level, max level] range.";
MSG kFramebufferIncompleteAttachmentNoDepthBitsInDepthBuffer = "Framebuffer is incomplete: Depth attachment has no depth bits.";
MSG kFramebufferIncompleteAttachmentNoStencilBitsInStencilBuffer = "Framebuffer is incomplete: Stencil attachment has no stencil bits.";
MSG kFramebufferIncompleteAttachmentNotCubeComplete = "Framebuffer is incomplete: Attachment is an incomplete cube map.";
MSG kFramebufferIncompleteAttachmentNotRenderable = "Framebuffer is incomplete: Attachment is not renderable.";
MSG kFramebufferIncompleteAttachmentSamplesGreaterThanMaxSupportedSamples = "Framebuffer is incomplete: Attachment samples are greater than the maximum supported samples for this format.";
MSG kFramebufferIncompleteAttachmentsNotUnique = "Framebuffer is incomplete: All attachments must be unique.";
MSG kFramebufferIncompleteAttachmentWebGLDepthBufferHasStencilBits = "Framebuffer is incomplete: Stencil attachment has depth bits.";
MSG kFramebufferIncompleteAttachmentWebGLDepthStencilNoDepthOrStencilBits = "Framebuffer is incomplete: Depth stencil attachment has no depth bits or no stencil bits.";
MSG kFramebufferIncompleteAttachmentWebGLStencilBufferHasDepthBits = "Framebuffer is incomplete: Stencil attachment has depth bits.";
MSG kFramebufferIncompleteAttachmentZeroSize = "Framebuffer is incomplete: Attachment has zero size.";
MSG kFramebufferIncompleteDefaultZeroSize = "Framebuffer is incomplete: No attachments and default size is zero.";
MSG kFramebufferIncompleteDepthAndStencilBuffersNotTheSame = "Framebuffer is incomplete: Depth and stencil attachments are not the same.";
MSG kFramebufferIncompleteDepthStencilInColorBuffer = "Framebuffer is incomplete: Depth stencil texture in color attachment.";
MSG kFramebufferIncompleteDriverUnsupported = "Framebuffer is incomplete: Driver does not support this framebuffer configuration.";
MSG kFramebufferIncompleteInconsistantAttachmentSizes = "Framebuffer is incomplete: Attachments are not all the same size.";
MSG kFramebufferIncompleteInternalError = "Framebuffer is incomplete: Internal error.";
MSG kFramebufferIncompleteMismatchedLayeredAttachments = "Framebuffer is incomplete: If one attachment is layered, all must be layered.";
MSG kFramebufferIncompleteMismatchedLayeredTexturetypes = "Framebuffer is incomplete: If an attachments are layered, they must all be the same texture type.";
MSG kFramebufferIncompleteMultisampleDepthStencilSampleCountDivisibleByColorSampleCount = "Framebuffer is incomplete: Depth stencil sample count must be divisible by the color sample count.";
MSG kFramebufferIncompleteMultisampleInconsistentFixedSampleLocations = "Framebuffer is incomplete: Attachments have inconsistent fixed sample locations.";
MSG kFramebufferIncompleteMultisampleInconsistentSampleCounts = "Framebuffer is incomplete: Attachments have different sample counts.";
MSG kFramebufferIncompleteMultisampleNonFixedSamplesWithRenderbuffers = "Framebuffer is incomplete: All textures must have fixed samples if paired with multisample renderbuffers.";
MSG kFramebufferIncompleteMultiviewBaseViewMismatch = "Framebuffer is incomplete: Attachments have inconsistent multiview base view.";
MSG kFramebufferIncompleteMultiviewMismatch = "Framebuffer is incomplete: Attachments have inconsistent multiview enabled state.";
MSG kFramebufferIncompleteMultiviewViewsMismatch = "Framebuffer is incomplete: Attachments have inconsistent multiview view counts.";
MSG kFramebufferIncompleteSurfaceless = "Framebuffer is incomplete: Framebuffer is surfaceless.";
MSG kFramebufferIncompleteUnsupportedMissmatchedDimensions = "Framebuffer is incomplete: Mismatched attachment sizes are unsupported.";
MSG kFramebufferIncompleteUnsupportedNonUniqueAttachments = "Framebuffer is incomplete: Non-unique attachments are unsupported.";
MSG kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers = "Framebuffer is incomplete: Separate depth and stencil buffers are unsupported.";
MSG kFramebufferIncompleteWebGLDepthStencilInconsistant = "Framebuffer is incomplete: WebGL depth stencil state is inconsistent.";
MSG kFramebufferTextureInvalidLayer = "Layer invalid for framebuffer texture attachment.";
MSG kFramebufferTextureInvalidMipLevel = "Mip level invalid for framebuffer texture attachment.";
MSG kFramebufferTextureLayerIncorrectTextureType = "Texture is not a three-dimensional or two-dimensionsal array texture.";
......
......@@ -50,6 +50,17 @@ class State;
class Texture;
class TextureCapsMap;
struct FramebufferStatus
{
bool isComplete() const;
static FramebufferStatus Complete();
static FramebufferStatus Incomplete(GLenum status, const char *reason);
GLenum status = GL_FRAMEBUFFER_COMPLETE;
const char *reason = nullptr;
};
class FramebufferState final : angle::NonCopyable
{
public:
......@@ -293,7 +304,7 @@ class Framebuffer final : public angle::ObserverInterface,
void invalidateCompletenessCache();
ANGLE_INLINE bool cachedStatusValid() { return mCachedStatus.valid(); }
ANGLE_INLINE GLenum checkStatus(const Context *context) const
ANGLE_INLINE const FramebufferStatus &checkStatus(const Context *context) const
{
// The default framebuffer is always complete except when it is surfaceless in which
// case it is always unsupported.
......@@ -309,7 +320,7 @@ class Framebuffer final : public angle::ObserverInterface,
// Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE.
ANGLE_INLINE bool isComplete(const Context *context) const
{
return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
return checkStatus(context).isComplete();
}
bool hasValidDepthStencil() const;
......@@ -429,8 +440,8 @@ class Framebuffer final : public angle::ObserverInterface,
FramebufferAttachment *attachment,
GLenum matchType,
GLuint matchId);
GLenum checkStatusWithGLFrontEnd(const Context *context) const;
GLenum checkStatusImpl(const Context *context) const;
FramebufferStatus checkStatusWithGLFrontEnd(const Context *context) const;
const FramebufferStatus &checkStatusImpl(const Context *context) const;
void setAttachment(const Context *context,
GLenum type,
GLenum binding,
......@@ -491,7 +502,7 @@ class Framebuffer final : public angle::ObserverInterface,
FramebufferState mState;
rx::FramebufferImpl *mImpl;
mutable Optional<GLenum> mCachedStatus;
mutable Optional<FramebufferStatus> mCachedStatus;
std::vector<angle::ObserverBinding> mDirtyColorAttachmentBindings;
angle::ObserverBinding mDirtyDepthAttachmentBinding;
angle::ObserverBinding mDirtyStencilAttachmentBinding;
......
......@@ -82,7 +82,7 @@ class FramebufferImpl : angle::NonCopyable
GLbitfield mask,
GLenum filter) = 0;
virtual bool checkStatus(const gl::Context *context) const = 0;
virtual gl::FramebufferStatus checkStatus(const gl::Context *context) const = 0;
virtual angle::Result syncState(const gl::Context *context,
GLenum binding,
......
......@@ -52,7 +52,7 @@ class MockFramebufferImpl : public rx::FramebufferImpl
GLbitfield,
GLenum));
MOCK_CONST_METHOD1(checkStatus, bool(const gl::Context *));
MOCK_CONST_METHOD1(checkStatus, gl::FramebufferStatus(const gl::Context *));
MOCK_METHOD4(syncState,
angle::Result(const gl::Context *,
......@@ -68,7 +68,8 @@ inline ::testing::NiceMock<MockFramebufferImpl> *MakeFramebufferMock()
::testing::NiceMock<MockFramebufferImpl> *framebufferImpl =
new ::testing::NiceMock<MockFramebufferImpl>();
// TODO(jmadill): add ON_CALLS for other returning methods
ON_CALL(*framebufferImpl, checkStatus(testing::_)).WillByDefault(::testing::Return(true));
ON_CALL(*framebufferImpl, checkStatus(testing::_))
.WillByDefault(::testing::Return(gl::FramebufferStatus::Complete()));
// We must mock the destructor since NiceMock doesn't work for destructors.
EXPECT_CALL(*framebufferImpl, destructor()).Times(1).RetiresOnSaturation();
......
......@@ -10,6 +10,7 @@
#include "common/bitset_utils.h"
#include "libANGLE/Context.h"
#include "libANGLE/ErrorStrings.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Surface.h"
......@@ -249,13 +250,15 @@ angle::Result FramebufferD3D::blit(const gl::Context *context,
return angle::Result::Continue;
}
bool FramebufferD3D::checkStatus(const gl::Context *context) const
gl::FramebufferStatus FramebufferD3D::checkStatus(const gl::Context *context) const
{
// 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
if (mState.hasSeparateDepthAndStencilAttachments())
{
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
}
// D3D11 does not allow for overlapping RenderTargetViews.
......@@ -266,17 +269,21 @@ bool FramebufferD3D::checkStatus(const gl::Context *context) const
{
if (!mState.colorAttachmentsAreUniqueImages())
{
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedNonUniqueAttachments);
}
}
// D3D requires all render targets to have the same dimensions.
if (!mState.attachmentsHaveSameDimensions())
{
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions);
}
return true;
return gl::FramebufferStatus::Complete();
}
angle::Result FramebufferD3D::syncState(const gl::Context *context,
......
......@@ -92,7 +92,7 @@ class FramebufferD3D : public FramebufferImpl
GLbitfield mask,
GLenum filter) override;
bool checkStatus(const gl::Context *context) const override;
gl::FramebufferStatus checkStatus(const gl::Context *context) const override;
angle::Result syncState(const gl::Context *context,
GLenum binding,
......
......@@ -10,6 +10,7 @@
#include "common/bitset_utils.h"
#include "common/debug.h"
#include "libANGLE/ErrorStrings.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/State.h"
#include "libANGLE/angletypes.h"
......@@ -1188,7 +1189,7 @@ bool FramebufferGL::shouldSyncStateBeforeCheckStatus() const
return true;
}
bool FramebufferGL::checkStatus(const gl::Context *context) const
gl::FramebufferStatus FramebufferGL::checkStatus(const gl::Context *context) const
{
const FunctionsGL *functions = GetFunctionsGL(context);
StateManagerGL *stateManager = GetStateManagerGL(context);
......@@ -1197,9 +1198,12 @@ bool FramebufferGL::checkStatus(const gl::Context *context) const
GLenum status = functions->checkFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
WARN() << "GL framebuffer returned incomplete.";
WARN() << "GL framebuffer returned incomplete: " << gl::FmtHex(status);
return gl::FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteDriverUnsupported);
}
return (status == GL_FRAMEBUFFER_COMPLETE);
return gl::FramebufferStatus::Complete();
}
angle::Result FramebufferGL::syncState(const gl::Context *context,
......
......@@ -79,7 +79,7 @@ class FramebufferGL : public FramebufferImpl
// The GL back-end requires a full sync state before we call checkStatus.
bool shouldSyncStateBeforeCheckStatus() const override;
bool checkStatus(const gl::Context *context) const override;
gl::FramebufferStatus checkStatus(const gl::Context *context) const override;
angle::Result syncState(const gl::Context *context,
GLenum binding,
......
......@@ -78,7 +78,7 @@ class FramebufferMtl : public FramebufferImpl
GLbitfield mask,
GLenum filter) override;
bool checkStatus(const gl::Context *context) const override;
gl::FramebufferStatus checkStatus(const gl::Context *context) const override;
angle::Result syncState(const gl::Context *context,
GLenum binding,
......@@ -120,7 +120,7 @@ class FramebufferMtl : public FramebufferImpl
private:
void reset();
bool checkPackedDepthStencilAttachment() const;
gl::FramebufferStatus checkPackedDepthStencilAttachment() const;
angle::Result invalidateImpl(ContextMtl *contextMtl, size_t count, const GLenum *attachments);
angle::Result blitWithDraw(const gl::Context *context,
FramebufferMtl *srcFrameBuffer,
......
......@@ -14,6 +14,7 @@
#include "common/MemoryBuffer.h"
#include "common/angleutils.h"
#include "common/debug.h"
#include "libANGLE/ErrorStrings.h"
#include "libANGLE/renderer/metal/BufferMtl.h"
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/FrameBufferMtl.h"
......@@ -468,18 +469,22 @@ angle::Result FramebufferMtl::blitWithDraw(const gl::Context *context,
return angle::Result::Continue;
}
bool FramebufferMtl::checkStatus(const gl::Context *context) const
gl::FramebufferStatus FramebufferMtl::checkStatus(const gl::Context *context) const
{
if (!mState.attachmentsHaveSameDimensions())
{
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions);
}
ContextMtl *contextMtl = mtl::GetImpl(context);
if (!contextMtl->getDisplay()->getFeatures().allowSeparatedDepthStencilBuffers.enabled &&
mState.hasSeparateDepthAndStencilAttachments())
{
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
}
if (mState.getDepthAttachment() && mState.getDepthAttachment()->getFormat().info->depthBits &&
......@@ -495,10 +500,10 @@ bool FramebufferMtl::checkStatus(const gl::Context *context) const
return checkPackedDepthStencilAttachment();
}
return true;
return gl::FramebufferStatus::Complete();
}
bool FramebufferMtl::checkPackedDepthStencilAttachment() const
gl::FramebufferStatus FramebufferMtl::checkPackedDepthStencilAttachment() const
{
if (ANGLE_APPLE_AVAILABLE_XCI(10.14, 13.0, 12.0))
{
......@@ -509,7 +514,9 @@ bool FramebufferMtl::checkPackedDepthStencilAttachment() const
{
WARN() << "Packed depth stencil texture/buffer must not be mixed with other "
"texture/buffer.";
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
}
}
else
......@@ -520,10 +527,12 @@ bool FramebufferMtl::checkPackedDepthStencilAttachment() const
{
WARN() << "Packed depth stencil texture/buffer must be bound to both depth & stencil "
"attachment point.";
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
}
}
return true;
return gl::FramebufferStatus::Complete();
}
angle::Result FramebufferMtl::syncState(const gl::Context *context,
......
......@@ -151,9 +151,9 @@ angle::Result FramebufferNULL::blit(const gl::Context *context,
return angle::Result::Continue;
}
bool FramebufferNULL::checkStatus(const gl::Context *context) const
gl::FramebufferStatus FramebufferNULL::checkStatus(const gl::Context *context) const
{
return true;
return gl::FramebufferStatus::Complete();
}
angle::Result FramebufferNULL::syncState(const gl::Context *context,
......
......@@ -65,7 +65,7 @@ class FramebufferNULL : public FramebufferImpl
GLbitfield mask,
GLenum filter) override;
bool checkStatus(const gl::Context *context) const override;
gl::FramebufferStatus checkStatus(const gl::Context *context) const override;
angle::Result syncState(const gl::Context *context,
GLenum binding,
......
......@@ -15,6 +15,7 @@
#include "common/vulkan/vk_headers.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/ErrorStrings.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
......@@ -1458,16 +1459,18 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
return angle::Result::Continue;
}
bool FramebufferVk::checkStatus(const gl::Context *context) const
gl::FramebufferStatus FramebufferVk::checkStatus(const gl::Context *context) const
{
// 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
if (mState.hasSeparateDepthAndStencilAttachments())
{
return false;
return gl::FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
}
return true;
return gl::FramebufferStatus::Complete();
}
angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
......
......@@ -107,7 +107,7 @@ class FramebufferVk : public FramebufferImpl
GLbitfield mask,
GLenum filter) override;
bool checkStatus(const gl::Context *context) const override;
gl::FramebufferStatus checkStatus(const gl::Context *context) const override;
angle::Result syncState(const gl::Context *context,
GLenum binding,
......
......@@ -763,9 +763,11 @@ template <GLenum ErrorCode = GL_INVALID_FRAMEBUFFER_OPERATION>
ANGLE_INLINE bool ValidateFramebufferComplete(const Context *context,
const Framebuffer *framebuffer)
{
if (!framebuffer->isComplete(context))
const FramebufferStatus &framebufferStatus = framebuffer->checkStatus(context);
if (!framebufferStatus.isComplete())
{
context->validationError(ErrorCode, err::kFramebufferIncomplete);
ASSERT(framebufferStatus.reason != nullptr);
context->validationError(ErrorCode, framebufferStatus.reason);
return false;
}
......
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