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.";
......
......@@ -15,6 +15,7 @@
#include "libANGLE/Config.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/ErrorStrings.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/Surface.h"
......@@ -35,40 +36,48 @@ namespace gl
namespace
{
bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
const FramebufferAttachment *secondAttachment)
FramebufferStatus CheckMultiviewStateMatchesForCompleteness(
const FramebufferAttachment *firstAttachment,
const FramebufferAttachment *secondAttachment)
{
ASSERT(firstAttachment && secondAttachment);
ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
{
return false;
return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
err::kFramebufferIncompleteMultiviewViewsMismatch);
}
if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
{
return false;
return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
err::kFramebufferIncompleteMultiviewBaseViewMismatch);
}
if (firstAttachment->isMultiview() != secondAttachment->isMultiview())
{
return false;
return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
err::kFramebufferIncompleteMultiviewMismatch);
}
return true;
return FramebufferStatus::Complete();
}
bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
FramebufferStatus CheckAttachmentCompleteness(const Context *context,
const FramebufferAttachment &attachment)
{
ASSERT(attachment.isAttached());
const Extents &size = attachment.getSize();
if (size.width == 0 || size.height == 0)
{
return false;
return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentZeroSize);
}
if (!attachment.isRenderable(context))
{
return false;
return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentNotRenderable);
}
if (attachment.type() == GL_TEXTURE)
......@@ -81,7 +90,9 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
{
if (attachment.layer() >= size.depth)
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentLayerGreaterThanDepth);
}
}
// If <image> is a three-dimensional texture or a two-dimensional array texture and the
......@@ -91,7 +102,9 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
{
if (size.depth >= context->getCaps().maxFramebufferLayers)
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentDepthGreaterThanMaxLayers);
}
}
......@@ -104,7 +117,9 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
if (texture->getType() == TextureType::CubeMap &&
!texture->getTextureState().isCubeComplete())
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentNotCubeComplete);
}
if (!texture->getImmutableFormat())
......@@ -121,7 +136,9 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
if (attachmentMipLevel < texture->getBaseLevel() ||
attachmentMipLevel > texture->getMipmapMaxLevel())
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentLevelOutOfBaseMaxLevelRange);
}
// Form the ES 3.0 spec, pg 213/214:
......@@ -132,18 +149,20 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
// a cubemap texture, the texture must also be cube complete.
if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentLevelNotBaseLevelForIncompleteMipTexture);
}
}
}
return true;
return FramebufferStatus::Complete();
}
bool CheckAttachmentSampleCounts(const Context *context,
GLsizei currAttachmentSamples,
GLsizei samples,
bool colorAttachment)
FramebufferStatus CheckAttachmentSampleCounts(const Context *context,
GLsizei currAttachmentSamples,
GLsizei samples,
bool colorAttachment)
{
if (currAttachmentSamples != samples)
{
......@@ -151,7 +170,9 @@ bool CheckAttachmentSampleCounts(const Context *context,
{
// APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
// all color attachments have the same number of samples for the FBO to be complete.
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
err::kFramebufferIncompleteMultisampleInconsistentSampleCounts);
}
else
{
......@@ -159,24 +180,30 @@ bool CheckAttachmentSampleCounts(const Context *context,
// when its depth or stencil samples are a multiple of the number of color samples.
if (!context->getExtensions().framebufferMixedSamples)
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
err::kFramebufferIncompleteMultisampleInconsistentSampleCounts);
}
if ((currAttachmentSamples % std::max(samples, 1)) != 0)
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
err::
kFramebufferIncompleteMultisampleDepthStencilSampleCountDivisibleByColorSampleCount);
}
}
}
return true;
return FramebufferStatus::Complete();
}
bool CheckAttachmentSampleCompleteness(const Context *context,
const FramebufferAttachment &attachment,
bool colorAttachment,
Optional<int> *samples,
Optional<bool> *fixedSampleLocations,
Optional<int> *renderToTextureSamples)
FramebufferStatus CheckAttachmentSampleCompleteness(const Context *context,
const FramebufferAttachment &attachment,
bool colorAttachment,
Optional<int> *samples,
Optional<bool> *fixedSampleLocations,
Optional<int> *renderToTextureSamples)
{
ASSERT(attachment.isAttached());
......@@ -188,14 +215,18 @@ bool CheckAttachmentSampleCompleteness(const Context *context,
const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
if (static_cast<GLuint>(attachment.getSamples()) > formatCaps.getMaxSamples())
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
err::kFramebufferIncompleteAttachmentSamplesGreaterThanMaxSupportedSamples);
}
const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
bool fixedSampleloc = texture->getAttachmentFixedSampleLocations(attachmentImageIndex);
if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
{
return false;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
err::kFramebufferIncompleteMultisampleInconsistentFixedSampleLocations);
}
else
{
......@@ -209,10 +240,12 @@ bool CheckAttachmentSampleCompleteness(const Context *context,
if (renderToTextureSamples->value() !=
FramebufferAttachment::kDefaultRenderToTextureSamples)
{
if (!CheckAttachmentSampleCounts(context, attachment.getRenderToTextureSamples(),
renderToTextureSamples->value(), colorAttachment))
FramebufferStatus sampleCountStatus =
CheckAttachmentSampleCounts(context, attachment.getRenderToTextureSamples(),
renderToTextureSamples->value(), colorAttachment);
if (!sampleCountStatus.isComplete())
{
return false;
return sampleCountStatus;
}
}
}
......@@ -227,10 +260,12 @@ bool CheckAttachmentSampleCompleteness(const Context *context,
if (renderToTextureSamples->value() ==
FramebufferAttachment::kDefaultRenderToTextureSamples)
{
if (!CheckAttachmentSampleCounts(context, attachment.getSamples(), samples->value(),
colorAttachment))
FramebufferStatus sampleCountStatus = CheckAttachmentSampleCounts(
context, attachment.getSamples(), samples->value(), colorAttachment);
if (!sampleCountStatus.isComplete())
{
return false;
return sampleCountStatus;
}
}
}
......@@ -239,7 +274,7 @@ bool CheckAttachmentSampleCompleteness(const Context *context,
*samples = attachment.getSamples();
}
return true;
return FramebufferStatus::Complete();
}
// Needed to index into the attachment arrays/bitsets.
......@@ -284,8 +319,32 @@ bool AttachmentOverlapsWithTexture(const FramebufferAttachment &attachment,
return attachmentLevel >= textureEffectiveBaseLevel && attachmentLevel <= textureMaxLevel;
}
} // anonymous namespace
bool FramebufferStatus::isComplete() const
{
return status == GL_FRAMEBUFFER_COMPLETE;
}
FramebufferStatus FramebufferStatus::Complete()
{
FramebufferStatus result;
result.status = GL_FRAMEBUFFER_COMPLETE;
result.reason = nullptr;
return result;
}
FramebufferStatus FramebufferStatus::Incomplete(GLenum status, const char *reason)
{
ASSERT(status != GL_FRAMEBUFFER_COMPLETE);
FramebufferStatus result;
result.status = status;
result.reason = reason;
return result;
}
// This constructor is only used for default framebuffers.
FramebufferState::FramebufferState(rx::Serial serial)
: mId(Framebuffer::kDefaultDrawFramebufferHandle),
......@@ -745,7 +804,7 @@ Framebuffer::Framebuffer(const Caps &caps,
Framebuffer::Framebuffer(const Context *context, egl::Surface *surface, egl::Surface *readSurface)
: mState(context->getShareGroup()->generateFramebufferSerial()),
mImpl(surface->getImplementation()->createDefaultFramebuffer(context, mState)),
mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
mCachedStatus(FramebufferStatus::Complete()),
mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
{
......@@ -787,7 +846,8 @@ Framebuffer::Framebuffer(const Context *context,
egl::Surface *readSurface)
: mState(context->getShareGroup()->generateFramebufferSerial()),
mImpl(factory->createFramebuffer(mState)),
mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
mCachedStatus(FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNDEFINED_OES,
err::kFramebufferIncompleteSurfaceless)),
mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
{
......@@ -1116,14 +1176,14 @@ void Framebuffer::invalidateCompletenessCache()
onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
}
GLenum Framebuffer::checkStatusImpl(const Context *context) const
const FramebufferStatus &Framebuffer::checkStatusImpl(const Context *context) const
{
ASSERT(!isDefault());
ASSERT(hasAnyDirtyBit() || !mCachedStatus.valid());
mCachedStatus = checkStatusWithGLFrontEnd(context);
if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
if (mCachedStatus.value().isComplete())
{
// We can skip syncState on several back-ends.
if (mImpl->shouldSyncStateBeforeCheckStatus())
......@@ -1133,20 +1193,19 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) const
angle::Result err = syncState(context, GL_FRAMEBUFFER, Command::Other);
if (err != angle::Result::Continue)
{
return 0;
mCachedStatus =
FramebufferStatus::Incomplete(0, err::kFramebufferIncompleteInternalError);
return mCachedStatus.value();
}
}
if (!mImpl->checkStatus(context))
{
mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
}
mCachedStatus = mImpl->checkStatus(context);
}
return mCachedStatus.value();
}
GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
FramebufferStatus Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
{
const State &state = context->getState();
......@@ -1168,21 +1227,27 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
{
if (colorAttachment.isAttached())
{
if (!CheckAttachmentCompleteness(context, colorAttachment))
FramebufferStatus attachmentCompleteness =
CheckAttachmentCompleteness(context, colorAttachment);
if (!attachmentCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return attachmentCompleteness;
}
const InternalFormat &format = *colorAttachment.getFormat().info;
if (format.depthBits > 0 || format.stencilBits > 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteDepthStencilInColorBuffer);
}
if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
&fixedSampleLocations, &renderToTextureSamples))
FramebufferStatus attachmentSampleCompleteness =
CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
&fixedSampleLocations, &renderToTextureSamples);
if (!attachmentSampleCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
return attachmentSampleCompleteness;
}
// in GLES 2.0, all color attachments attachments must have the same number of bitplanes
......@@ -1193,7 +1258,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
{
if (format.pixelBytes != colorbufferSize.value())
{
return GL_FRAMEBUFFER_UNSUPPORTED;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
err::kFramebufferIncompleteAttachmentInconsistantBitPlanes);
}
}
else
......@@ -1202,9 +1269,11 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
}
}
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
FramebufferStatus attachmentMultiviewCompleteness =
CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment);
if (!attachmentMultiviewCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
return attachmentMultiviewCompleteness;
}
hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
......@@ -1227,7 +1296,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
ASSERT(isLayered.valid());
if (isLayered.value() != colorAttachment.isLayered())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
err::kFramebufferIncompleteMismatchedLayeredAttachments);
}
else if (isLayered.value())
{
......@@ -1235,7 +1306,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
if (colorAttachmentsTextureType.value() !=
colorAttachment.getTextureImageIndex().getType())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
err::kFramebufferIncompleteMismatchedLayeredTexturetypes);
}
}
}
......@@ -1245,26 +1318,34 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
if (depthAttachment.isAttached())
{
if (!CheckAttachmentCompleteness(context, depthAttachment))
FramebufferStatus attachmentCompleteness =
CheckAttachmentCompleteness(context, depthAttachment);
if (!attachmentCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return attachmentCompleteness;
}
const InternalFormat &format = *depthAttachment.getFormat().info;
if (format.depthBits == 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentNoDepthBitsInDepthBuffer);
}
if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
&fixedSampleLocations, &renderToTextureSamples))
FramebufferStatus attachmentSampleCompleteness =
CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
&fixedSampleLocations, &renderToTextureSamples);
if (!attachmentSampleCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
return attachmentSampleCompleteness;
}
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
FramebufferStatus attachmentMultiviewCompleteness =
CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment);
if (!attachmentMultiviewCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
return attachmentMultiviewCompleteness;
}
hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
......@@ -1282,7 +1363,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
ASSERT(isLayered.valid());
if (isLayered.value() != depthAttachment.isLayered())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
err::kFramebufferIncompleteMismatchedLayeredAttachments);
}
}
}
......@@ -1290,26 +1373,34 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
if (stencilAttachment.isAttached())
{
if (!CheckAttachmentCompleteness(context, stencilAttachment))
FramebufferStatus attachmentCompleteness =
CheckAttachmentCompleteness(context, stencilAttachment);
if (!attachmentCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return attachmentCompleteness;
}
const InternalFormat &format = *stencilAttachment.getFormat().info;
if (format.stencilBits == 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentNoStencilBitsInStencilBuffer);
}
if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
&fixedSampleLocations, &renderToTextureSamples))
FramebufferStatus attachmentSampleCompleteness =
CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
&fixedSampleLocations, &renderToTextureSamples);
if (!attachmentSampleCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
return attachmentSampleCompleteness;
}
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
FramebufferStatus attachmentMultiviewCompleteness =
CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment);
if (!attachmentMultiviewCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
return attachmentMultiviewCompleteness;
}
hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
......@@ -1327,7 +1418,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
ASSERT(isLayered.valid());
if (isLayered.value() != stencilAttachment.isLayered())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
err::kFramebufferIncompleteMismatchedLayeredAttachments);
}
}
}
......@@ -1336,7 +1429,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
{
return GL_FRAMEBUFFER_UNSUPPORTED;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
err::kFramebufferIncompleteDepthAndStencilBuffersNotTheSame);
}
// Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
......@@ -1344,7 +1439,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
{
if (!mState.mWebGLDepthStencilConsistent)
{
return GL_FRAMEBUFFER_UNSUPPORTED;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_UNSUPPORTED,
err::kFramebufferIncompleteWebGLDepthStencilInconsistant);
}
if (mState.mWebGLDepthStencilAttachment.isAttached())
......@@ -1352,24 +1449,32 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentWebGLDepthStencilNoDepthOrStencilBits);
}
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
&mState.mWebGLDepthStencilAttachment))
FramebufferStatus attachmentMultiviewCompleteness =
CheckMultiviewStateMatchesForCompleteness(firstAttachment,
&mState.mWebGLDepthStencilAttachment);
if (!attachmentMultiviewCompleteness.isComplete())
{
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
return attachmentMultiviewCompleteness;
}
}
else if (mState.mStencilAttachment.isAttached() &&
mState.mStencilAttachment.getDepthSize() > 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentWebGLStencilBufferHasDepthBits);
}
else if (mState.mDepthAttachment.isAttached() &&
mState.mDepthAttachment.getStencilSize() > 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
err::kFramebufferIncompleteAttachmentWebGLDepthBufferHasStencilBits);
}
}
......@@ -1380,7 +1485,8 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
GLint defaultHeight = mState.getDefaultHeight();
if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
{
return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
err::kFramebufferIncompleteDefaultZeroSize);
}
// In ES 2.0 and WebGL, all color attachments must have the same width and height.
......@@ -1388,14 +1494,18 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
!mState.attachmentsHaveSameDimensions())
{
return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
err::kFramebufferIncompleteInconsistantAttachmentSizes);
}
// ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
// textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
return FramebufferStatus::Incomplete(
GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
err::kFramebufferIncompleteMultisampleNonFixedSamplesWithRenderbuffers);
}
// The WebGL conformance tests implicitly define that all framebuffer
......@@ -1405,11 +1515,12 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
{
if (!mState.colorAttachmentsAreUniqueImages())
{
return GL_FRAMEBUFFER_UNSUPPORTED;
return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNSUPPORTED,
err::kFramebufferIncompleteAttachmentsNotUnique);
}
}
return GL_FRAMEBUFFER_COMPLETE;
return FramebufferStatus::Complete();
}
angle::Result Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
......@@ -1607,7 +1718,7 @@ int Framebuffer::getSamples(const Context *context) const
return 0;
}
ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
ASSERT(mCachedStatus.valid() && mCachedStatus.value().isComplete());
// For a complete framebuffer, all attachments must have the same sample count.
// In this case return the first nonzero sample size.
......@@ -1624,7 +1735,7 @@ int Framebuffer::getReadBufferResourceSamples(const Context *context) const
return 0;
}
ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
ASSERT(mCachedStatus.valid() && mCachedStatus.value().isComplete());
const FramebufferAttachment *readAttachment = mState.getReadAttachment();
ASSERT(readAttachment == nullptr || readAttachment->isAttached());
......
......@@ -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