summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/Framebuffer.cpp')
-rw-r--r--src/3rdparty/angle/src/libANGLE/Framebuffer.cpp2182
1 files changed, 0 insertions, 2182 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
deleted file mode 100644
index 48e71685b3..0000000000
--- a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
+++ /dev/null
@@ -1,2182 +0,0 @@
-//
-// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
-// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
-
-#include "libANGLE/Framebuffer.h"
-
-#include "common/Optional.h"
-#include "common/bitset_utils.h"
-#include "common/utilities.h"
-#include "libANGLE/Config.h"
-#include "libANGLE/Context.h"
-#include "libANGLE/Display.h"
-#include "libANGLE/FramebufferAttachment.h"
-#include "libANGLE/Renderbuffer.h"
-#include "libANGLE/Surface.h"
-#include "libANGLE/Texture.h"
-#include "libANGLE/formatutils.h"
-#include "libANGLE/renderer/ContextImpl.h"
-#include "libANGLE/renderer/FramebufferImpl.h"
-#include "libANGLE/renderer/GLImplFactory.h"
-#include "libANGLE/renderer/RenderbufferImpl.h"
-#include "libANGLE/renderer/SurfaceImpl.h"
-
-using namespace angle;
-
-namespace gl
-{
-
-namespace
-{
-
-void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmentObject *resource)
-{
- 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)
-{
- ASSERT(attachment.isAttached());
-
- const Extents &size = attachment.getSize();
- if (size.width == 0 || size.height == 0)
- {
- return false;
- }
-
- const InternalFormat &format = *attachment.getFormat().info;
- if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
- {
- return false;
- }
-
- if (attachment.type() == GL_TEXTURE)
- {
- if (attachment.layer() >= size.depth)
- {
- return false;
- }
-
- // ES3 specifies that cube map texture attachments must be cube complete.
- // This language is missing from the ES2 spec, but we enforce it here because some
- // desktop OpenGL drivers also enforce this validation.
- // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
- const Texture *texture = attachment.getTexture();
- ASSERT(texture);
- if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
- !texture->getTextureState().isCubeComplete())
- {
- return false;
- }
-
- if (!texture->getImmutableFormat())
- {
- GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
-
- // From the ES 3.0 spec, pg 213:
- // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
- // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
- // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
- // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
- // the effective maximum texture level defined in the Mipmapping discussion of
- // section 3.8.10.4.
- if (attachmentMipLevel < texture->getBaseLevel() ||
- attachmentMipLevel > texture->getMipmapMaxLevel())
- {
- return false;
- }
-
- // Form the ES 3.0 spec, pg 213/214:
- // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
- // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
- // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
- // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
- // a cubemap texture, the texture must also be cube complete.
- if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
- {
- return false;
- }
- }
- }
-
- return true;
-};
-
-bool CheckAttachmentSampleCompleteness(const Context *context,
- const FramebufferAttachment &attachment,
- bool colorAttachment,
- Optional<int> *samples,
- Optional<bool> *fixedSampleLocations)
-{
- ASSERT(attachment.isAttached());
-
- if (attachment.type() == GL_TEXTURE)
- {
- const Texture *texture = attachment.getTexture();
- ASSERT(texture);
-
- const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
-
- // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
- // the same for all attached textures.
- bool fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type,
- attachmentImageIndex.mipIndex);
- if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
- {
- return false;
- }
- else
- {
- *fixedSampleLocations = fixedSampleloc;
- }
- }
-
- if (samples->valid())
- {
- if (attachment.getSamples() != samples->value())
- {
- if (colorAttachment)
- {
- // 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;
- }
- else
- {
- // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
- // when its depth or stencil samples are a multiple of the number of color samples.
- if (!context->getExtensions().framebufferMixedSamples)
- {
- return false;
- }
-
- if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
- {
- return false;
- }
- }
- }
- }
- else
- {
- *samples = attachment.getSamples();
- }
-
- return true;
-}
-
-// Needed to index into the attachment arrays/bitsets.
-static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
- gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
- "Framebuffer Dirty bit mismatch");
-static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
- gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
- "Framebuffer Dirty bit mismatch");
-static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
- gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
- "Framebuffer Dirty bit mismatch");
-
-Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
-{
- ASSERT(attachment->isAttached());
- if (attachment->initState() == InitState::MayNeedInit)
- {
- ANGLE_TRY(attachment->initializeContents(context));
- }
- return NoError();
-}
-
-bool IsColorMaskedOut(const BlendState &blend)
-{
- return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
- !blend.colorMaskAlpha);
-}
-
-bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
-{
- return !depthStencil.depthMask;
-}
-
-bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
-{
- return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
-}
-
-bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
-{
- switch (buffer)
- {
- case GL_COLOR:
- return IsColorMaskedOut(context->getGLState().getBlendState());
- case GL_DEPTH:
- return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
- case GL_STENCIL:
- return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
- case GL_DEPTH_STENCIL:
- return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
- IsStencilMaskedOut(context->getGLState().getDepthStencilState());
- default:
- UNREACHABLE();
- return true;
- }
-}
-
-} // anonymous namespace
-
-// This constructor is only used for default framebuffers.
-FramebufferState::FramebufferState()
- : mLabel(),
- mColorAttachments(1),
- mDrawBufferStates(1, GL_BACK),
- mReadBufferState(GL_BACK),
- mDefaultWidth(0),
- mDefaultHeight(0),
- mDefaultSamples(0),
- mDefaultFixedSampleLocations(GL_FALSE),
- mWebGLDepthStencilConsistent(true)
-{
- ASSERT(mDrawBufferStates.size() > 0);
- mEnabledDrawBuffers.set(0);
-}
-
-FramebufferState::FramebufferState(const Caps &caps)
- : mLabel(),
- mColorAttachments(caps.maxColorAttachments),
- mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
- mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
- mDefaultWidth(0),
- mDefaultHeight(0),
- mDefaultSamples(0),
- mDefaultFixedSampleLocations(GL_FALSE),
- mWebGLDepthStencilConsistent(true)
-{
- ASSERT(mDrawBufferStates.size() > 0);
- mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
-}
-
-FramebufferState::~FramebufferState()
-{
-}
-
-const std::string &FramebufferState::getLabel()
-{
- return mLabel;
-}
-
-const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
-{
- if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
- {
- return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
- }
-
- switch (attachment)
- {
- case GL_COLOR:
- case GL_BACK:
- return getColorAttachment(0);
- case GL_DEPTH:
- case GL_DEPTH_ATTACHMENT:
- return getDepthAttachment();
- case GL_STENCIL:
- case GL_STENCIL_ATTACHMENT:
- return getStencilAttachment();
- case GL_DEPTH_STENCIL:
- case GL_DEPTH_STENCIL_ATTACHMENT:
- return getDepthStencilAttachment();
- default:
- UNREACHABLE();
- return nullptr;
- }
-}
-
-size_t FramebufferState::getReadIndex() const
-{
- ASSERT(mReadBufferState == GL_BACK ||
- (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
- size_t readIndex = (mReadBufferState == GL_BACK
- ? 0
- : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
- ASSERT(readIndex < mColorAttachments.size());
- return readIndex;
-}
-
-const FramebufferAttachment *FramebufferState::getReadAttachment() const
-{
- if (mReadBufferState == GL_NONE)
- {
- return nullptr;
- }
- size_t readIndex = getReadIndex();
- return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
-}
-
-const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
-{
- auto *colorAttachment = getFirstColorAttachment();
- if (colorAttachment)
- {
- return colorAttachment;
- }
- return getDepthOrStencilAttachment();
-}
-
-const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
-{
- for (const FramebufferAttachment &colorAttachment : mColorAttachments)
- {
- if (colorAttachment.isAttached())
- {
- return &colorAttachment;
- }
- }
-
- return nullptr;
-}
-
-const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
-{
- if (mDepthAttachment.isAttached())
- {
- return &mDepthAttachment;
- }
- if (mStencilAttachment.isAttached())
- {
- return &mStencilAttachment;
- }
- return nullptr;
-}
-
-const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
-{
- if (mStencilAttachment.isAttached())
- {
- return &mStencilAttachment;
- }
- return getDepthStencilAttachment();
-}
-
-const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
-{
- ASSERT(colorAttachment < mColorAttachments.size());
- return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
- : nullptr;
-}
-
-const FramebufferAttachment *FramebufferState::getDepthAttachment() const
-{
- return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
-}
-
-const FramebufferAttachment *FramebufferState::getStencilAttachment() const
-{
- return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
-}
-
-const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
-{
- // A valid depth-stencil attachment has the same resource bound to both the
- // depth and stencil attachment points.
- if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
- mDepthAttachment == mStencilAttachment)
- {
- return &mDepthAttachment;
- }
-
- return nullptr;
-}
-
-bool FramebufferState::attachmentsHaveSameDimensions() const
-{
- Optional<Extents> attachmentSize;
-
- auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
- if (!attachment.isAttached())
- {
- return false;
- }
-
- if (!attachmentSize.valid())
- {
- attachmentSize = attachment.getSize();
- return false;
- }
-
- const auto &prevSize = attachmentSize.value();
- const auto &curSize = attachment.getSize();
- return (curSize.width != prevSize.width || curSize.height != prevSize.height);
- };
-
- for (const auto &attachment : mColorAttachments)
- {
- if (hasMismatchedSize(attachment))
- {
- return false;
- }
- }
-
- if (hasMismatchedSize(mDepthAttachment))
- {
- return false;
- }
-
- return !hasMismatchedSize(mStencilAttachment);
-}
-
-const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
-{
- ASSERT(drawBufferIdx < mDrawBufferStates.size());
- if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
- {
- // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
- // must be COLOR_ATTACHMENTi or NONE"
- ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
- (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
- return getAttachment(mDrawBufferStates[drawBufferIdx]);
- }
- else
- {
- return nullptr;
- }
-}
-
-size_t FramebufferState::getDrawBufferCount() const
-{
- return mDrawBufferStates.size();
-}
-
-bool FramebufferState::colorAttachmentsAreUniqueImages() const
-{
- for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
- firstAttachmentIdx++)
- {
- const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
- if (!firstAttachment.isAttached())
- {
- continue;
- }
-
- for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
- secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
- {
- const gl::FramebufferAttachment &secondAttachment =
- mColorAttachments[secondAttachmentIdx];
- if (!secondAttachment.isAttached())
- {
- continue;
- }
-
- if (firstAttachment == secondAttachment)
- {
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool FramebufferState::hasDepth() const
-{
- return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
-}
-
-bool FramebufferState::hasStencil() const
-{
- return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
-}
-
-GLsizei FramebufferState::getNumViews() const
-{
- const FramebufferAttachment *attachment = getFirstNonNullAttachment();
- if (attachment == nullptr)
- {
- return FramebufferAttachment::kDefaultNumViews;
- }
- return attachment->getNumViews();
-}
-
-const std::vector<Offset> *FramebufferState::getViewportOffsets() const
-{
- const FramebufferAttachment *attachment = getFirstNonNullAttachment();
- if (attachment == nullptr)
- {
- return nullptr;
- }
- return &attachment->getMultiviewViewportOffsets();
-}
-
-GLenum FramebufferState::getMultiviewLayout() const
-{
- const FramebufferAttachment *attachment = getFirstNonNullAttachment();
- if (attachment == nullptr)
- {
- return GL_NONE;
- }
- return attachment->getMultiviewLayout();
-}
-
-int FramebufferState::getBaseViewIndex() const
-{
- const FramebufferAttachment *attachment = getFirstNonNullAttachment();
- if (attachment == nullptr)
- {
- return GL_NONE;
- }
- return attachment->getBaseViewIndex();
-}
-
-Box FramebufferState::getDimensions() const
-{
- ASSERT(attachmentsHaveSameDimensions());
- ASSERT(getFirstNonNullAttachment() != nullptr);
- Extents extents = getFirstNonNullAttachment()->getSize();
- return Box(0, 0, 0, extents.width, extents.height, extents.depth);
-}
-
-Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
- : mState(caps),
- mImpl(factory->createFramebuffer(mState)),
- mId(id),
- mCachedStatus(),
- mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
- mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
-{
- ASSERT(mId != 0);
- ASSERT(mImpl != nullptr);
- ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
-
- for (uint32_t colorIndex = 0;
- colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
- {
- mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
- }
-}
-
-Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
- : mState(),
- mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
- mId(0),
- mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
- mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
- mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
-{
- ASSERT(mImpl != nullptr);
- mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
-
- const Context *proxyContext = display->getProxyContext();
-
- setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(),
- surface, FramebufferAttachment::kDefaultNumViews,
- FramebufferAttachment::kDefaultBaseViewIndex,
- FramebufferAttachment::kDefaultMultiviewLayout,
- FramebufferAttachment::kDefaultViewportOffsets);
-
- if (surface->getConfig()->depthSize > 0)
- {
- setAttachmentImpl(
- proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface,
- FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex,
- FramebufferAttachment::kDefaultMultiviewLayout,
- FramebufferAttachment::kDefaultViewportOffsets);
- }
-
- if (surface->getConfig()->stencilSize > 0)
- {
- setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL,
- gl::ImageIndex::MakeInvalid(), surface,
- FramebufferAttachment::kDefaultNumViews,
- FramebufferAttachment::kDefaultBaseViewIndex,
- FramebufferAttachment::kDefaultMultiviewLayout,
- FramebufferAttachment::kDefaultViewportOffsets);
- }
-}
-
-Framebuffer::Framebuffer(rx::GLImplFactory *factory)
- : mState(),
- mImpl(factory->createFramebuffer(mState)),
- mId(0),
- mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
- mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
- mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
-{
- mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
-}
-
-Framebuffer::~Framebuffer()
-{
- SafeDelete(mImpl);
-}
-
-void Framebuffer::onDestroy(const Context *context)
-{
- for (auto &attachment : mState.mColorAttachments)
- {
- attachment.detach(context);
- }
- mState.mDepthAttachment.detach(context);
- mState.mStencilAttachment.detach(context);
- mState.mWebGLDepthAttachment.detach(context);
- mState.mWebGLStencilAttachment.detach(context);
- mState.mWebGLDepthStencilAttachment.detach(context);
-
- mImpl->destroy(context);
-}
-
-void Framebuffer::destroyDefault(const egl::Display *display)
-{
- mImpl->destroyDefault(display);
-}
-
-void Framebuffer::setLabel(const std::string &label)
-{
- mState.mLabel = label;
-}
-
-const std::string &Framebuffer::getLabel() const
-{
- return mState.mLabel;
-}
-
-bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
-{
- return detachResourceById(context, GL_TEXTURE, textureId);
-}
-
-bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
-{
- return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
-}
-
-bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
-{
- bool found = false;
-
- for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
- {
- if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
- resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
- {
- found = true;
- }
- }
-
- if (context->isWebGL1())
- {
- const std::array<FramebufferAttachment *, 3> attachments = {
- {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
- &mState.mWebGLStencilAttachment}};
- for (FramebufferAttachment *attachment : attachments)
- {
- if (attachment->isAttached() && attachment->type() == resourceType &&
- attachment->id() == resourceId)
- {
- resetAttachment(context, attachment->getBinding());
- found = true;
- }
- }
- }
- else
- {
- if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
- DIRTY_BIT_DEPTH_ATTACHMENT))
- {
- found = true;
- }
- if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
- DIRTY_BIT_STENCIL_ATTACHMENT))
- {
- found = true;
- }
- }
-
- return found;
-}
-
-bool Framebuffer::detachMatchingAttachment(const Context *context,
- FramebufferAttachment *attachment,
- GLenum matchType,
- GLuint matchId,
- size_t dirtyBit)
-{
- if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
- {
- attachment->detach(context);
- mDirtyBits.set(dirtyBit);
- mState.mResourceNeedsInit.set(dirtyBit, false);
- return true;
- }
-
- return false;
-}
-
-const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
-{
- return mState.getColorAttachment(colorAttachment);
-}
-
-const FramebufferAttachment *Framebuffer::getDepthbuffer() const
-{
- return mState.getDepthAttachment();
-}
-
-const FramebufferAttachment *Framebuffer::getStencilbuffer() const
-{
- return mState.getStencilAttachment();
-}
-
-const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
-{
- return mState.getDepthStencilAttachment();
-}
-
-const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
-{
- return mState.getDepthOrStencilAttachment();
-}
-
-const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
-{
- return mState.getStencilOrDepthStencilAttachment();
-}
-
-const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
-{
- return mState.getReadAttachment();
-}
-
-GLenum Framebuffer::getReadColorbufferType() const
-{
- const FramebufferAttachment *readAttachment = mState.getReadAttachment();
- return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
-}
-
-const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
-{
- return mState.getFirstColorAttachment();
-}
-
-const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
-{
- return mState.getFirstNonNullAttachment();
-}
-
-const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
-{
- return mState.getAttachment(attachment);
-}
-
-size_t Framebuffer::getDrawbufferStateCount() const
-{
- return mState.mDrawBufferStates.size();
-}
-
-GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
-{
- ASSERT(drawBuffer < mState.mDrawBufferStates.size());
- return mState.mDrawBufferStates[drawBuffer];
-}
-
-const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
-{
- return mState.getDrawBufferStates();
-}
-
-void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
-{
- auto &drawStates = mState.mDrawBufferStates;
-
- ASSERT(count <= drawStates.size());
- std::copy(buffers, buffers + count, drawStates.begin());
- std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
- mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
-
- mState.mEnabledDrawBuffers.reset();
- for (size_t index = 0; index < count; ++index)
- {
- if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
- {
- mState.mEnabledDrawBuffers.set(index);
- }
- }
-}
-
-const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
-{
- return mState.getDrawBuffer(drawBuffer);
-}
-
-GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
-{
- const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
- if (attachment == nullptr)
- {
- return GL_NONE;
- }
-
- GLenum componentType = attachment->getFormat().info->componentType;
- switch (componentType)
- {
- case GL_INT:
- case GL_UNSIGNED_INT:
- return componentType;
-
- default:
- return GL_FLOAT;
- }
-}
-
-bool Framebuffer::hasEnabledDrawBuffer() const
-{
- for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
- {
- if (getDrawBuffer(drawbufferIdx) != nullptr)
- {
- return true;
- }
- }
-
- return false;
-}
-
-GLenum Framebuffer::getReadBufferState() const
-{
- return mState.mReadBufferState;
-}
-
-void Framebuffer::setReadBuffer(GLenum buffer)
-{
- ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
- (buffer >= GL_COLOR_ATTACHMENT0 &&
- (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
- mState.mReadBufferState = buffer;
- mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
-}
-
-size_t Framebuffer::getNumColorBuffers() const
-{
- return mState.mColorAttachments.size();
-}
-
-bool Framebuffer::hasDepth() const
-{
- return mState.hasDepth();
-}
-
-bool Framebuffer::hasStencil() const
-{
- return mState.hasStencil();
-}
-
-bool Framebuffer::usingExtendedDrawBuffers() const
-{
- for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
- {
- if (getDrawBuffer(drawbufferIdx) != nullptr)
- {
- return true;
- }
- }
-
- return false;
-}
-
-void Framebuffer::invalidateCompletenessCache()
-{
- if (mId != 0)
- {
- mCachedStatus.reset();
- }
-}
-
-GLenum Framebuffer::checkStatus(const Context *context)
-{
- // The default framebuffer is always complete except when it is surfaceless in which
- // case it is always unsupported. We return early because the default framebuffer may
- // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
- if (mId == 0)
- {
- ASSERT(mCachedStatus.valid());
- ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
- mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
- return mCachedStatus.value();
- }
-
- if (hasAnyDirtyBit() || !mCachedStatus.valid())
- {
- mCachedStatus = checkStatusImpl(context);
- }
-
- return mCachedStatus.value();
-}
-
-GLenum Framebuffer::checkStatusImpl(const Context *context)
-{
- const ContextState &state = context->getContextState();
-
- ASSERT(mId != 0);
-
- bool hasAttachments = false;
- Optional<unsigned int> colorbufferSize;
- Optional<int> samples;
- Optional<bool> fixedSampleLocations;
- bool hasRenderbuffer = false;
-
- const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
-
- for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
- {
- if (colorAttachment.isAttached())
- {
- if (!CheckAttachmentCompleteness(context, colorAttachment))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
-
- const InternalFormat &format = *colorAttachment.getFormat().info;
- if (format.depthBits > 0 || format.stencilBits > 0)
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
-
- if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
- &fixedSampleLocations))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- }
-
- // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
- // in GLES 3.0, there is no such restriction
- if (state.getClientMajorVersion() < 3)
- {
- if (colorbufferSize.valid())
- {
- if (format.pixelBytes != colorbufferSize.value())
- {
- return GL_FRAMEBUFFER_UNSUPPORTED;
- }
- }
- else
- {
- colorbufferSize = format.pixelBytes;
- }
- }
-
- if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
- }
-
- hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
- hasAttachments = true;
- }
- }
-
- const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
- if (depthAttachment.isAttached())
- {
- if (!CheckAttachmentCompleteness(context, depthAttachment))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
-
- const InternalFormat &format = *depthAttachment.getFormat().info;
- if (format.depthBits == 0)
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
-
- if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
- &fixedSampleLocations))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- }
-
- if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
- }
-
- hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
- hasAttachments = true;
- }
-
- const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
- if (stencilAttachment.isAttached())
- {
- if (!CheckAttachmentCompleteness(context, stencilAttachment))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
-
- const InternalFormat &format = *stencilAttachment.getFormat().info;
- if (format.stencilBits == 0)
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
-
- if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
- &fixedSampleLocations))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- }
-
- if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
- }
-
- hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
- hasAttachments = true;
- }
-
- // Starting from ES 3.0 stencil and depth, if present, should be the same image
- if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
- stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
- {
- return GL_FRAMEBUFFER_UNSUPPORTED;
- }
-
- // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
- if (state.isWebGL1())
- {
- if (!mState.mWebGLDepthStencilConsistent)
- {
- return GL_FRAMEBUFFER_UNSUPPORTED;
- }
-
- if (mState.mWebGLDepthStencilAttachment.isAttached())
- {
- if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
- mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
-
- if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
- &mState.mWebGLDepthStencilAttachment))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
- }
- }
- else if (mState.mStencilAttachment.isAttached() &&
- mState.mStencilAttachment.getDepthSize() > 0)
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
- else if (mState.mDepthAttachment.isAttached() &&
- mState.mDepthAttachment.getStencilSize() > 0)
- {
- return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
- }
-
- // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
- // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
- // is zero, the framebuffer is considered incomplete.
- GLint defaultWidth = mState.getDefaultWidth();
- GLint defaultHeight = mState.getDefaultHeight();
- if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
- {
- return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
- }
-
- // In ES 2.0 and WebGL, all color attachments must have the same width and height.
- // In ES 3.0, there is no such restriction.
- if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
- !mState.attachmentsHaveSameDimensions())
- {
- return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
- }
-
- // 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;
- }
-
- // 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);
- if (!mImpl->checkStatus(context))
- {
- return GL_FRAMEBUFFER_UNSUPPORTED;
- }
-
- return GL_FRAMEBUFFER_COMPLETE;
-}
-
-Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
-{
- // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
- // can be no-ops, so we should probably do that to ensure consistency.
- // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
-
- return mImpl->discard(context, count, attachments);
-}
-
-Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
-{
- // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
- // can be no-ops, so we should probably do that to ensure consistency.
- // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
-
- return mImpl->invalidate(context, count, attachments);
-}
-
-bool Framebuffer::partialClearNeedsInit(const Context *context,
- bool color,
- bool depth,
- bool stencil)
-{
- const auto &glState = context->getGLState();
-
- if (!glState.isRobustResourceInitEnabled())
- {
- return false;
- }
-
- // Scissors can affect clearing.
- // TODO(jmadill): Check for complete scissor overlap.
- if (glState.isScissorTestEnabled())
- {
- return true;
- }
-
- // If colors masked, we must clear before we clear. Do a simple check.
- // TODO(jmadill): Filter out unused color channels from the test.
- if (color)
- {
- const auto &blend = glState.getBlendState();
- if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
- blend.colorMaskAlpha))
- {
- return true;
- }
- }
-
- const auto &depthStencil = glState.getDepthStencilState();
- ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
- if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
- {
- return true;
- }
-
- return false;
-}
-
-Error Framebuffer::invalidateSub(const Context *context,
- size_t count,
- const GLenum *attachments,
- const gl::Rectangle &area)
-{
- // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
- // can be no-ops, so we should probably do that to ensure consistency.
- // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
-
- return mImpl->invalidateSub(context, count, attachments, area);
-}
-
-Error Framebuffer::clear(const gl::Context *context, GLbitfield mask)
-{
- const auto &glState = context->getGLState();
- if (glState.isRasterizerDiscardEnabled())
- {
- return NoError();
- }
-
- const auto &blend = glState.getBlendState();
- const auto &depthStencil = glState.getDepthStencilState();
-
- bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
- bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
- bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
-
- if (partialClearNeedsInit(context, color, depth, stencil))
- {
- ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
- }
-
- ANGLE_TRY(mImpl->clear(context, mask));
-
- if (glState.isRobustResourceInitEnabled())
- {
- markDrawAttachmentsInitialized(color, depth, stencil);
- }
-
- return NoError();
-}
-
-Error Framebuffer::clearBufferfv(const gl::Context *context,
- GLenum buffer,
- GLint drawbuffer,
- const GLfloat *values)
-{
- if (context->getGLState().isRasterizerDiscardEnabled() ||
- IsClearBufferMaskedOut(context, buffer))
- {
- return NoError();
- }
-
- if (partialBufferClearNeedsInit(context, buffer))
- {
- ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
- }
-
- ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
-
- if (context->isRobustResourceInitEnabled())
- {
- markBufferInitialized(buffer, drawbuffer);
- }
- return NoError();
-}
-
-Error Framebuffer::clearBufferuiv(const gl::Context *context,
- GLenum buffer,
- GLint drawbuffer,
- const GLuint *values)
-{
- if (context->getGLState().isRasterizerDiscardEnabled() ||
- IsClearBufferMaskedOut(context, buffer))
- {
- return NoError();
- }
-
- if (partialBufferClearNeedsInit(context, buffer))
- {
- ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
- }
-
- ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
-
- if (context->isRobustResourceInitEnabled())
- {
- markBufferInitialized(buffer, drawbuffer);
- }
- return NoError();
-}
-
-Error Framebuffer::clearBufferiv(const gl::Context *context,
- GLenum buffer,
- GLint drawbuffer,
- const GLint *values)
-{
- if (context->getGLState().isRasterizerDiscardEnabled() ||
- IsClearBufferMaskedOut(context, buffer))
- {
- return NoError();
- }
-
- if (partialBufferClearNeedsInit(context, buffer))
- {
- ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
- }
-
- ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
-
- if (context->isRobustResourceInitEnabled())
- {
- markBufferInitialized(buffer, drawbuffer);
- }
- return NoError();
-}
-
-Error Framebuffer::clearBufferfi(const gl::Context *context,
- GLenum buffer,
- GLint drawbuffer,
- GLfloat depth,
- GLint stencil)
-{
- if (context->getGLState().isRasterizerDiscardEnabled() ||
- IsClearBufferMaskedOut(context, buffer))
- {
- return NoError();
- }
-
- if (partialBufferClearNeedsInit(context, buffer))
- {
- ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
- }
-
- ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
-
- if (context->isRobustResourceInitEnabled())
- {
- markBufferInitialized(buffer, drawbuffer);
- }
- return NoError();
-}
-
-GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
-{
- return mImpl->getImplementationColorReadFormat(context);
-}
-
-GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
-{
- return mImpl->getImplementationColorReadType(context);
-}
-
-Error Framebuffer::readPixels(const gl::Context *context,
- const Rectangle &area,
- GLenum format,
- GLenum type,
- void *pixels)
-{
- ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
- ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
-
- Buffer *unpackBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
- if (unpackBuffer)
- {
- unpackBuffer->onPixelUnpack();
- }
-
- return NoError();
-}
-
-Error Framebuffer::blit(const gl::Context *context,
- const Rectangle &sourceArea,
- const Rectangle &destArea,
- GLbitfield mask,
- GLenum filter)
-{
- GLbitfield blitMask = mask;
-
- // Note that blitting is called against draw framebuffer.
- // See the code in gl::Context::blitFramebuffer.
- if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
- {
- blitMask &= ~GL_COLOR_BUFFER_BIT;
- }
-
- if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
- {
- blitMask &= ~GL_STENCIL_BUFFER_BIT;
- }
-
- if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
- {
- blitMask &= ~GL_DEPTH_BUFFER_BIT;
- }
-
- if (!blitMask)
- {
- return NoError();
- }
-
- auto *sourceFBO = context->getGLState().getReadFramebuffer();
- ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
-
- // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
- ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
-
- return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
-}
-
-int Framebuffer::getSamples(const Context *context)
-{
- if (complete(context))
- {
- return getCachedSamples(context);
- }
-
- return 0;
-}
-
-int Framebuffer::getCachedSamples(const Context *context)
-{
- // For a complete framebuffer, all attachments must have the same sample count.
- // In this case return the first nonzero sample size.
- const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
- if (firstNonNullAttachment)
- {
- ASSERT(firstNonNullAttachment->isAttached());
- return firstNonNullAttachment->getSamples();
- }
-
- // No attachments found.
- return 0;
-}
-
-Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
-{
- ANGLE_TRY(mImpl->getSamplePosition(index, xy));
- return NoError();
-}
-
-bool Framebuffer::hasValidDepthStencil() const
-{
- return mState.getDepthStencilAttachment() != nullptr;
-}
-
-void Framebuffer::setAttachment(const Context *context,
- GLenum type,
- GLenum binding,
- const ImageIndex &textureIndex,
- FramebufferAttachmentObject *resource)
-{
- setAttachment(context, type, binding, textureIndex, resource,
- FramebufferAttachment::kDefaultNumViews,
- FramebufferAttachment::kDefaultBaseViewIndex,
- FramebufferAttachment::kDefaultMultiviewLayout,
- FramebufferAttachment::kDefaultViewportOffsets);
-}
-
-void Framebuffer::setAttachment(const Context *context,
- GLenum type,
- GLenum binding,
- const ImageIndex &textureIndex,
- FramebufferAttachmentObject *resource,
- GLsizei numViews,
- GLuint baseViewIndex,
- GLenum multiviewLayout,
- const GLint *viewportOffsets)
-{
- // Context may be null in unit tests.
- if (!context || !context->isWebGL1())
- {
- setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
- multiviewLayout, viewportOffsets);
- return;
- }
-
- switch (binding)
- {
- case GL_DEPTH_STENCIL:
- case GL_DEPTH_STENCIL_ATTACHMENT:
- mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
- resource, numViews, baseViewIndex,
- multiviewLayout, viewportOffsets);
- break;
- case GL_DEPTH:
- case GL_DEPTH_ATTACHMENT:
- mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
- numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
- break;
- case GL_STENCIL:
- case GL_STENCIL_ATTACHMENT:
- mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
- numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
- break;
- default:
- setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
- baseViewIndex, multiviewLayout, viewportOffsets);
- return;
- }
-
- commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
-}
-
-void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
- GLenum type,
- GLenum binding,
- const ImageIndex &textureIndex,
- FramebufferAttachmentObject *resource,
- GLsizei numViews,
- GLint baseViewIndex)
-{
- setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
- GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
- FramebufferAttachment::kDefaultViewportOffsets);
-}
-
-void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
- GLenum type,
- GLenum binding,
- const ImageIndex &textureIndex,
- FramebufferAttachmentObject *resource,
- GLsizei numViews,
- const GLint *viewportOffsets)
-{
- setAttachment(context, type, binding, textureIndex, resource, numViews,
- FramebufferAttachment::kDefaultBaseViewIndex,
- GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
-}
-
-void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
- GLsizei numViews,
- GLuint baseViewIndex,
- GLenum multiviewLayout,
- const GLint *viewportOffsets)
-{
- int count = 0;
-
- std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
- &mState.mWebGLDepthAttachment,
- &mState.mWebGLStencilAttachment}};
- for (FramebufferAttachment *attachment : attachments)
- {
- if (attachment->isAttached())
- {
- count++;
- }
- }
-
- mState.mWebGLDepthStencilConsistent = (count <= 1);
- if (!mState.mWebGLDepthStencilConsistent)
- {
- // Inconsistent.
- return;
- }
-
- auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
- if (attachment.type() == GL_TEXTURE)
- {
- return attachment.getTextureImageIndex();
- }
- else
- {
- return ImageIndex::MakeInvalid();
- }
- };
-
- if (mState.mWebGLDepthAttachment.isAttached())
- {
- const auto &depth = mState.mWebGLDepthAttachment;
- setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
- getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
- baseViewIndex, multiviewLayout, viewportOffsets);
- setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
- nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
- }
- else if (mState.mWebGLStencilAttachment.isAttached())
- {
- const auto &stencil = mState.mWebGLStencilAttachment;
- setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
- numViews, baseViewIndex, multiviewLayout, viewportOffsets);
- setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
- getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
- numViews, baseViewIndex, multiviewLayout, viewportOffsets);
- }
- else if (mState.mWebGLDepthStencilAttachment.isAttached())
- {
- const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
- setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
- getImageIndexIfTextureAttachment(depthStencil),
- depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
- setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
- getImageIndexIfTextureAttachment(depthStencil),
- depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
- }
- else
- {
- setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
- numViews, baseViewIndex, multiviewLayout, viewportOffsets);
- setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
- nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
- }
-}
-
-void Framebuffer::setAttachmentImpl(const Context *context,
- GLenum type,
- GLenum binding,
- const ImageIndex &textureIndex,
- FramebufferAttachmentObject *resource,
- GLsizei numViews,
- GLuint baseViewIndex,
- GLenum multiviewLayout,
- const GLint *viewportOffsets)
-{
- switch (binding)
- {
- case GL_DEPTH_STENCIL:
- case GL_DEPTH_STENCIL_ATTACHMENT:
- {
- // ensure this is a legitimate depth+stencil format
- FramebufferAttachmentObject *attachmentObj = resource;
- if (resource)
- {
- const Format &format = resource->getAttachmentFormat(binding, textureIndex);
- if (format.info->depthBits == 0 || format.info->stencilBits == 0)
- {
- // Attaching nullptr detaches the current attachment.
- attachmentObj = nullptr;
- }
- }
-
- updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
- &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
- attachmentObj, numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
- updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
- &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
- attachmentObj, numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
- break;
- }
-
- case GL_DEPTH:
- case GL_DEPTH_ATTACHMENT:
- updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
- &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
- numViews, baseViewIndex, multiviewLayout, viewportOffsets);
- break;
-
- case GL_STENCIL:
- case GL_STENCIL_ATTACHMENT:
- updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
- &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
- numViews, baseViewIndex, multiviewLayout, viewportOffsets);
- break;
-
- case GL_BACK:
- mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource,
- numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
- mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
- // No need for a resource binding for the default FBO, it's always complete.
- break;
-
- default:
- {
- size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
- ASSERT(colorIndex < mState.mColorAttachments.size());
- size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
- updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
- &mDirtyColorAttachmentBindings[colorIndex], type, binding,
- textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
- viewportOffsets);
-
- // TODO(jmadill): ASSERT instead of checking the attachment exists in
- // formsRenderingFeedbackLoopWith
- bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
- mState.mEnabledDrawBuffers.set(colorIndex, enabled);
- }
- break;
- }
-
- mAttachedTextures.reset();
-}
-
-void Framebuffer::updateAttachment(const Context *context,
- FramebufferAttachment *attachment,
- size_t dirtyBit,
- OnAttachmentDirtyBinding *onDirtyBinding,
- GLenum type,
- GLenum binding,
- const ImageIndex &textureIndex,
- FramebufferAttachmentObject *resource,
- GLsizei numViews,
- GLuint baseViewIndex,
- GLenum multiviewLayout,
- const GLint *viewportOffsets)
-{
- attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
- multiviewLayout, viewportOffsets);
- mDirtyBits.set(dirtyBit);
- mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
- BindResourceChannel(onDirtyBinding, resource);
-}
-
-void Framebuffer::resetAttachment(const Context *context, GLenum binding)
-{
- setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
-}
-
-void Framebuffer::syncState(const Context *context)
-{
- if (mDirtyBits.any())
- {
- mImpl->syncState(context, mDirtyBits);
- mDirtyBits.reset();
- if (mId != 0)
- {
- mCachedStatus.reset();
- }
- }
-}
-
-void Framebuffer::signal(size_t dirtyBit, InitState state)
-{
- // TOOD(jmadill): Make this only update individual attachments to do less work.
- mCachedStatus.reset();
-
- // Mark the appropriate init flag.
- mState.mResourceNeedsInit.set(dirtyBit, state == InitState::MayNeedInit);
-}
-
-bool Framebuffer::complete(const Context *context)
-{
- return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
-}
-
-bool Framebuffer::cachedComplete() const
-{
- return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
-}
-
-bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
-{
- const Program *program = state.getProgram();
-
- // TODO(jmadill): Default framebuffer feedback loops.
- if (mId == 0)
- {
- return false;
- }
-
- // The bitset will skip inactive draw buffers.
- for (size_t drawIndex : mState.mEnabledDrawBuffers)
- {
- const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
- ASSERT(attachment.isAttached());
- if (attachment.type() == GL_TEXTURE)
- {
- // Validate the feedback loop.
- if (program->samplesFromTexture(state, attachment.id()))
- {
- return true;
- }
- }
- }
-
- // Validate depth-stencil feedback loop.
- const auto &dsState = state.getDepthStencilState();
-
- // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
- const FramebufferAttachment *depth = getDepthbuffer();
- if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
- {
- if (program->samplesFromTexture(state, depth->id()))
- {
- return true;
- }
- }
-
- // Note: we assume the front and back masks are the same for WebGL.
- const FramebufferAttachment *stencil = getStencilbuffer();
- ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
- if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
- dsState.stencilWritemask != 0)
- {
- // Skip the feedback loop check if depth/stencil point to the same resource.
- if (!depth || *stencil != *depth)
- {
- if (program->samplesFromTexture(state, stencil->id()))
- {
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
- GLint copyTextureLevel,
- GLint copyTextureLayer) const
-{
- if (mId == 0)
- {
- // It seems impossible to form a texture copying feedback loop with the default FBO.
- return false;
- }
-
- const FramebufferAttachment *readAttachment = getReadColorbuffer();
- ASSERT(readAttachment);
-
- if (readAttachment->isTextureWithId(copyTextureID))
- {
- const auto &imageIndex = readAttachment->getTextureImageIndex();
- if (imageIndex.mipIndex == copyTextureLevel)
- {
- // Check 3D/Array texture layers.
- return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
- copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
- imageIndex.layerIndex == copyTextureLayer;
- }
- }
- return false;
-}
-
-GLint Framebuffer::getDefaultWidth() const
-{
- return mState.getDefaultWidth();
-}
-
-GLint Framebuffer::getDefaultHeight() const
-{
- return mState.getDefaultHeight();
-}
-
-GLint Framebuffer::getDefaultSamples() const
-{
- return mState.getDefaultSamples();
-}
-
-bool Framebuffer::getDefaultFixedSampleLocations() const
-{
- return mState.getDefaultFixedSampleLocations();
-}
-
-void Framebuffer::setDefaultWidth(GLint defaultWidth)
-{
- mState.mDefaultWidth = defaultWidth;
- mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
-}
-
-void Framebuffer::setDefaultHeight(GLint defaultHeight)
-{
- mState.mDefaultHeight = defaultHeight;
- mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
-}
-
-void Framebuffer::setDefaultSamples(GLint defaultSamples)
-{
- mState.mDefaultSamples = defaultSamples;
- mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
-}
-
-void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)
-{
- mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
- mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
-}
-
-// TODO(jmadill): Remove this kludge.
-GLenum Framebuffer::checkStatus(const ValidationContext *context)
-{
- return checkStatus(static_cast<const Context *>(context));
-}
-
-int Framebuffer::getSamples(const ValidationContext *context)
-{
- return getSamples(static_cast<const Context *>(context));
-}
-
-GLsizei Framebuffer::getNumViews() const
-{
- return mState.getNumViews();
-}
-
-GLint Framebuffer::getBaseViewIndex() const
-{
- return mState.getBaseViewIndex();
-}
-
-const std::vector<Offset> *Framebuffer::getViewportOffsets() const
-{
- return mState.getViewportOffsets();
-}
-
-GLenum Framebuffer::getMultiviewLayout() const
-{
- return mState.getMultiviewLayout();
-}
-
-Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
-{
- if (!context->isRobustResourceInitEnabled())
- {
- return NoError();
- }
-
- // Note: we don't actually filter by the draw attachment enum. Just init everything.
- for (size_t bit : mState.mResourceNeedsInit)
- {
- switch (bit)
- {
- case DIRTY_BIT_DEPTH_ATTACHMENT:
- ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
- break;
- case DIRTY_BIT_STENCIL_ATTACHMENT:
- ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
- break;
- default:
- ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
- break;
- }
- }
-
- mState.mResourceNeedsInit.reset();
- return NoError();
-}
-
-Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
-{
- if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
- {
- return NoError();
- }
-
- if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
- {
- size_t readIndex = mState.getReadIndex();
- if (mState.mResourceNeedsInit[readIndex])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
- mState.mResourceNeedsInit.reset(readIndex);
- }
- }
-
- if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
- {
- if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
- mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
- }
- }
-
- if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
- {
- if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
- mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
- }
- }
-
- return NoError();
-}
-
-void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
-{
- // Mark attachments as initialized.
- if (color)
- {
- for (auto colorIndex : mState.mEnabledDrawBuffers)
- {
- auto &colorAttachment = mState.mColorAttachments[colorIndex];
- ASSERT(colorAttachment.isAttached());
- colorAttachment.setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(colorIndex);
- }
- }
-
- if (depth && mState.mDepthAttachment.isAttached())
- {
- mState.mDepthAttachment.setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
- }
-
- if (stencil && mState.mStencilAttachment.isAttached())
- {
- mState.mStencilAttachment.setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
- }
-}
-
-void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
-{
- switch (bufferType)
- {
- case GL_COLOR:
- {
- ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
- if (mState.mColorAttachments[bufferIndex].isAttached())
- {
- mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(bufferIndex);
- }
- break;
- }
- case GL_DEPTH:
- {
- if (mState.mDepthAttachment.isAttached())
- {
- mState.mDepthAttachment.setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
- }
- break;
- }
- case GL_STENCIL:
- {
- if (mState.mStencilAttachment.isAttached())
- {
- mState.mStencilAttachment.setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
- }
- break;
- }
- case GL_DEPTH_STENCIL:
- {
- if (mState.mDepthAttachment.isAttached())
- {
- mState.mDepthAttachment.setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
- }
- if (mState.mStencilAttachment.isAttached())
- {
- mState.mStencilAttachment.setInitState(InitState::Initialized);
- mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
- }
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
-}
-
-Box Framebuffer::getDimensions() const
-{
- return mState.getDimensions();
-}
-
-Error Framebuffer::ensureBufferInitialized(const Context *context,
- GLenum bufferType,
- GLint bufferIndex)
-{
- ASSERT(context->isRobustResourceInitEnabled());
-
- if (mState.mResourceNeedsInit.none())
- {
- return NoError();
- }
-
- switch (bufferType)
- {
- case GL_COLOR:
- {
- ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
- if (mState.mResourceNeedsInit[bufferIndex])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
- mState.mResourceNeedsInit.reset(bufferIndex);
- }
- break;
- }
- case GL_DEPTH:
- {
- if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
- mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
- }
- break;
- }
- case GL_STENCIL:
- {
- if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
- mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
- }
- break;
- }
- case GL_DEPTH_STENCIL:
- {
- if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
- mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
- }
- if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
- {
- ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
- mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
- }
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
-
- return NoError();
-}
-
-bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
-{
- if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
- {
- return false;
- }
-
- switch (bufferType)
- {
- case GL_COLOR:
- return partialClearNeedsInit(context, true, false, false);
- case GL_DEPTH:
- return partialClearNeedsInit(context, false, true, false);
- case GL_STENCIL:
- return partialClearNeedsInit(context, false, false, true);
- case GL_DEPTH_STENCIL:
- return partialClearNeedsInit(context, false, true, true);
- default:
- UNREACHABLE();
- return false;
- }
-}
-
-bool Framebuffer::hasTextureAttachment(const Texture *texture) const
-{
- if (!mAttachedTextures.valid())
- {
- std::set<const FramebufferAttachmentObject *> attachedTextures;
-
- for (const auto &colorAttachment : mState.mColorAttachments)
- {
- if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
- {
- attachedTextures.insert(colorAttachment.getResource());
- }
- }
-
- if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
- {
- attachedTextures.insert(mState.mDepthAttachment.getResource());
- }
-
- if (mState.mStencilAttachment.isAttached() &&
- mState.mStencilAttachment.type() == GL_TEXTURE)
- {
- attachedTextures.insert(mState.mStencilAttachment.getResource());
- }
-
- mAttachedTextures = std::move(attachedTextures);
- }
-
- return (mAttachedTextures.value().count(texture) > 0);
-}
-
-} // namespace gl