// // Copyright 2002 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.h: Defines the gl::Framebuffer class. Implements GL framebuffer // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. #ifndef LIBANGLE_FRAMEBUFFER_H_ #define LIBANGLE_FRAMEBUFFER_H_ #include #include "common/FixedVector.h" #include "common/Optional.h" #include "common/angleutils.h" #include "libANGLE/Constants.h" #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Observer.h" #include "libANGLE/RefCountObject.h" #include "libANGLE/State.h" namespace rx { class GLImplFactory; class FramebufferImpl; class RenderbufferImpl; class SurfaceImpl; } // namespace rx namespace egl { class Display; class Surface; } // namespace egl namespace gl { struct Caps; class Context; struct Extensions; class Framebuffer; class ImageIndex; struct Rectangle; class Renderbuffer; 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: explicit FramebufferState(rx::Serial serial); FramebufferState(const Caps &caps, FramebufferID id, rx::Serial serial); ~FramebufferState(); const std::string &getLabel() const; uint32_t getReadIndex() const; const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const; const FramebufferAttachment *getReadAttachment() const; const FramebufferAttachment *getFirstNonNullAttachment() const; const FramebufferAttachment *getFirstColorAttachment() const; const FramebufferAttachment *getDepthOrStencilAttachment() const; const FramebufferAttachment *getStencilOrDepthStencilAttachment() const; const FramebufferAttachment *getColorAttachment(size_t colorAttachment) const; const FramebufferAttachment *getDepthAttachment() const; const FramebufferAttachment *getStencilAttachment() const; const FramebufferAttachment *getDepthStencilAttachment() const; const FramebufferAttachment *getReadPixelsAttachment(GLenum readFormat) const; const std::vector &getDrawBufferStates() const { return mDrawBufferStates; } DrawBufferMask getEnabledDrawBuffers() const { return mEnabledDrawBuffers; } GLenum getReadBufferState() const { return mReadBufferState; } const std::vector &getColorAttachments() const { return mColorAttachments; } const DrawBufferMask getColorAttachmentsMask() const { return mColorAttachmentsMask; } const Extents getAttachmentExtentsIntersection() const; bool attachmentsHaveSameDimensions() const; bool hasSeparateDepthAndStencilAttachments() const; bool colorAttachmentsAreUniqueImages() const; Box getDimensions() const; Extents getExtents() const; const FramebufferAttachment *getDrawBuffer(size_t drawBufferIdx) const; size_t getDrawBufferCount() const; GLint getDefaultWidth() const { return mDefaultWidth; } GLint getDefaultHeight() const { return mDefaultHeight; } GLint getDefaultSamples() const { return mDefaultSamples; } bool getDefaultFixedSampleLocations() const { return mDefaultFixedSampleLocations; } GLint getDefaultLayers() const { return mDefaultLayers; } bool hasDepth() const; bool hasStencil() const; bool hasExternalTextureAttachment() const; bool hasYUVAttachment() const; bool isMultiview() const; ANGLE_INLINE GLsizei getNumViews() const { const FramebufferAttachment *attachment = getFirstNonNullAttachment(); if (attachment == nullptr) { return FramebufferAttachment::kDefaultNumViews; } return attachment->getNumViews(); } GLint getBaseViewIndex() const; SrgbWriteControlMode getWriteControlMode() const { return mSrgbWriteControlMode; } FramebufferID id() const { return mId; } bool isDefault() const; const gl::Offset &getSurfaceTextureOffset() const { return mSurfaceTextureOffset; } rx::Serial getFramebufferSerial() const { return mFramebufferSerial; } private: const FramebufferAttachment *getWebGLDepthStencilAttachment() const; const FramebufferAttachment *getWebGLDepthAttachment() const; const FramebufferAttachment *getWebGLStencilAttachment() const; friend class Framebuffer; // The Framebuffer ID is unique to a Context. // The Framebuffer Serial is unique to a Share Group. FramebufferID mId; rx::Serial mFramebufferSerial; std::string mLabel; std::vector mColorAttachments; FramebufferAttachment mDepthAttachment; FramebufferAttachment mStencilAttachment; // Tracks all the color buffers attached to this FramebufferDesc gl::DrawBufferMask mColorAttachmentsMask; std::vector mDrawBufferStates; GLenum mReadBufferState; DrawBufferMask mEnabledDrawBuffers; ComponentTypeMask mDrawBufferTypeMask; GLint mDefaultWidth; GLint mDefaultHeight; GLint mDefaultSamples; bool mDefaultFixedSampleLocations; GLint mDefaultLayers; // It's necessary to store all this extra state so we can restore attachments // when DEPTH_STENCIL/DEPTH/STENCIL is unbound in WebGL 1. FramebufferAttachment mWebGLDepthStencilAttachment; FramebufferAttachment mWebGLDepthAttachment; FramebufferAttachment mWebGLStencilAttachment; bool mWebGLDepthStencilConsistent; // Tracks if we need to initialize the resources for each attachment. angle::BitSet mResourceNeedsInit; bool mDefaultFramebufferReadAttachmentInitialized; FramebufferAttachment mDefaultFramebufferReadAttachment; // EXT_sRGB_write_control SrgbWriteControlMode mSrgbWriteControlMode; gl::Offset mSurfaceTextureOffset; }; class Framebuffer final : public angle::ObserverInterface, public LabeledObject, public angle::Subject { public: // Constructor to build application-defined framebuffers Framebuffer(const Caps &caps, rx::GLImplFactory *factory, FramebufferID id, egl::ShareGroup *shareGroup); // Constructor to build default framebuffers for a surface and context pair Framebuffer(const Context *context, egl::Surface *surface, egl::Surface *readSurface); // Constructor to build a fake default framebuffer when surfaceless Framebuffer(const Context *context, rx::GLImplFactory *factory, egl::Surface *readSurface); ~Framebuffer() override; void onDestroy(const Context *context); void setReadSurface(const Context *context, egl::Surface *readSurface); void setLabel(const Context *context, const std::string &label) override; const std::string &getLabel() const override; rx::FramebufferImpl *getImplementation() const { return mImpl; } FramebufferID id() const { return mState.mId; } void setAttachment(const Context *context, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource); void setAttachmentMultisample(const Context *context, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource, GLsizei samples); void setAttachmentMultiview(const Context *context, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource, GLsizei numViews, GLint baseViewIndex); void resetAttachment(const Context *context, GLenum binding); bool detachTexture(const Context *context, TextureID texture); bool detachRenderbuffer(const Context *context, RenderbufferID renderbuffer); const FramebufferAttachment *getColorAttachment(size_t colorAttachment) const; const FramebufferAttachment *getDepthAttachment() const; const FramebufferAttachment *getStencilAttachment() const; const FramebufferAttachment *getDepthStencilAttachment() const; const FramebufferAttachment *getDepthOrStencilAttachment() const; const FramebufferAttachment *getStencilOrDepthStencilAttachment() const; const FramebufferAttachment *getReadColorAttachment() const; GLenum getReadColorAttachmentType() const; const FramebufferAttachment *getFirstColorAttachment() const; const FramebufferAttachment *getFirstNonNullAttachment() const; const std::vector &getColorAttachments() const { return mState.mColorAttachments; } const FramebufferState &getState() const { return mState; } const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const; bool isMultiview() const; bool readDisallowedByMultiview() const; GLsizei getNumViews() const; GLint getBaseViewIndex() const; Extents getExtents() const; size_t getDrawbufferStateCount() const; GLenum getDrawBufferState(size_t drawBuffer) const; const std::vector &getDrawBufferStates() const; void setDrawBuffers(size_t count, const GLenum *buffers); const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const; ComponentType getDrawbufferWriteType(size_t drawBuffer) const; ComponentTypeMask getDrawBufferTypeMask() const; DrawBufferMask getDrawBufferMask() const; bool hasEnabledDrawBuffer() const; GLenum getReadBufferState() const; void setReadBuffer(GLenum buffer); size_t getNumColorAttachments() const; bool hasDepth() const; bool hasStencil() const; bool hasExternalTextureAttachment() const; bool hasYUVAttachment() const; bool usingExtendedDrawBuffers() const; // This method calls checkStatus. int getSamples(const Context *context) const; int getReadBufferResourceSamples(const Context *context) const; angle::Result getSamplePosition(const Context *context, size_t index, GLfloat *xy) const; GLint getDefaultWidth() const; GLint getDefaultHeight() const; GLint getDefaultSamples() const; bool getDefaultFixedSampleLocations() const; GLint getDefaultLayers() const; void setDefaultWidth(const Context *context, GLint defaultWidth); void setDefaultHeight(const Context *context, GLint defaultHeight); void setDefaultSamples(const Context *context, GLint defaultSamples); void setDefaultFixedSampleLocations(const Context *context, bool defaultFixedSampleLocations); void setDefaultLayers(GLint defaultLayers); void invalidateCompletenessCache(); ANGLE_INLINE bool cachedStatusValid() { return mCachedStatus.valid(); } 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. ASSERT(!isDefault() || mCachedStatus.valid()); if (isDefault() || (!hasAnyDirtyBit() && mCachedStatus.valid())) { return mCachedStatus.value(); } return checkStatusImpl(context); } // Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE. ANGLE_INLINE bool isComplete(const Context *context) const { return checkStatus(context).isComplete(); } bool hasValidDepthStencil() const; // Returns the offset into the texture backing the default framebuffer's surface if any. Returns // zero offset otherwise. The renderer will apply the offset to scissor and viewport rects used // for draws, clears, and blits. const gl::Offset &getSurfaceTextureOffset() const; angle::Result discard(const Context *context, size_t count, const GLenum *attachments); angle::Result invalidate(const Context *context, size_t count, const GLenum *attachments); angle::Result invalidateSub(const Context *context, size_t count, const GLenum *attachments, const Rectangle &area); angle::Result clear(const Context *context, GLbitfield mask); angle::Result clearBufferfv(const Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values); angle::Result clearBufferuiv(const Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values); angle::Result clearBufferiv(const Context *context, GLenum buffer, GLint drawbuffer, const GLint *values); angle::Result clearBufferfi(const Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLenum getImplementationColorReadFormat(const Context *context); GLenum getImplementationColorReadType(const Context *context); angle::Result readPixels(const Context *context, const Rectangle &area, GLenum format, GLenum type, const PixelPackState &pack, Buffer *packBuffer, void *pixels); angle::Result blit(const Context *context, const Rectangle &sourceArea, const Rectangle &destArea, GLbitfield mask, GLenum filter); bool isDefault() const { return mState.isDefault(); } enum DirtyBitType : size_t { DIRTY_BIT_COLOR_ATTACHMENT_0, DIRTY_BIT_COLOR_ATTACHMENT_MAX = DIRTY_BIT_COLOR_ATTACHMENT_0 + IMPLEMENTATION_MAX_DRAW_BUFFERS, DIRTY_BIT_DEPTH_ATTACHMENT = DIRTY_BIT_COLOR_ATTACHMENT_MAX, DIRTY_BIT_STENCIL_ATTACHMENT, DIRTY_BIT_COLOR_BUFFER_CONTENTS_0, DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX = DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 + IMPLEMENTATION_MAX_DRAW_BUFFERS, DIRTY_BIT_DEPTH_BUFFER_CONTENTS = DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX, DIRTY_BIT_STENCIL_BUFFER_CONTENTS, DIRTY_BIT_DRAW_BUFFERS, DIRTY_BIT_READ_BUFFER, DIRTY_BIT_DEFAULT_WIDTH, DIRTY_BIT_DEFAULT_HEIGHT, DIRTY_BIT_DEFAULT_SAMPLES, DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS, DIRTY_BIT_DEFAULT_LAYERS, DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE, DIRTY_BIT_UNKNOWN, DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN }; using DirtyBits = angle::BitSet; bool hasAnyDirtyBit() const { return mDirtyBits.any(); } DrawBufferMask getActiveFloat32ColorAttachmentDrawBufferMask() const { return mFloat32ColorAttachmentBits & getDrawBufferMask(); } bool hasResourceThatNeedsInit() const { return mState.mResourceNeedsInit.any(); } angle::Result syncState(const Context *context, GLenum framebufferBinding, Command command) const; void setWriteControlMode(SrgbWriteControlMode srgbWriteControlMode); // Observer implementation void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override; bool formsRenderingFeedbackLoopWith(const Context *context) const; bool formsCopyingFeedbackLoopWith(TextureID copyTextureID, GLint copyTextureLevel, GLint copyTextureLayer) const; angle::Result ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask); angle::Result ensureClearBufferAttachmentsInitialized(const Context *context, GLenum buffer, GLint drawbuffer); angle::Result ensureDrawAttachmentsInitialized(const Context *context); // Conservatively initializes both read color and depth. Blit can access the depth buffer. angle::Result ensureReadAttachmentsInitialized(const Context *context); Box getDimensions() const; static const FramebufferID kDefaultDrawFramebufferHandle; private: bool detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId); bool detachMatchingAttachment(const Context *context, FramebufferAttachment *attachment, GLenum matchType, GLuint matchId); FramebufferStatus checkStatusWithGLFrontEnd(const Context *context) const; const FramebufferStatus &checkStatusImpl(const Context *context) const; void setAttachment(const Context *context, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource, GLsizei numViews, GLuint baseViewIndex, bool isMultiview, GLsizei samplesIn); void commitWebGL1DepthStencilIfConsistent(const Context *context, GLsizei numViews, GLuint baseViewIndex, bool isMultiview, GLsizei samples); void setAttachmentImpl(const Context *context, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource, GLsizei numViews, GLuint baseViewIndex, bool isMultiview, GLsizei samples); void updateAttachment(const Context *context, FramebufferAttachment *attachment, size_t dirtyBit, angle::ObserverBinding *onDirtyBinding, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource, GLsizei numViews, GLuint baseViewIndex, bool isMultiview, GLsizei samples); void markDrawAttachmentsInitialized(bool color, bool depth, bool stencil); void markBufferInitialized(GLenum bufferType, GLint bufferIndex); angle::Result ensureBufferInitialized(const Context *context, GLenum bufferType, GLint bufferIndex); // Checks that we have a partially masked clear: // * some color channels are masked out // * some stencil values are masked out // * scissor test partially overlaps the framebuffer bool partialClearNeedsInit(const Context *context, bool color, bool depth, bool stencil); bool partialBufferClearNeedsInit(const Context *context, GLenum bufferType); FramebufferAttachment *getAttachmentFromSubjectIndex(angle::SubjectIndex index); ANGLE_INLINE void updateFloat32ColorAttachmentBits(size_t index, const gl::InternalFormat *format) { mFloat32ColorAttachmentBits.set(index, format->type == GL_FLOAT); } FramebufferState mState; rx::FramebufferImpl *mImpl; mutable Optional mCachedStatus; std::vector mDirtyColorAttachmentBindings; angle::ObserverBinding mDirtyDepthAttachmentBinding; angle::ObserverBinding mDirtyStencilAttachmentBinding; mutable DirtyBits mDirtyBits; DrawBufferMask mFloat32ColorAttachmentBits; // The dirty bits guard is checked when we get a dependent state change message. We verify that // we don't set a dirty bit that isn't already set, when inside the dirty bits syncState. mutable Optional mDirtyBitsGuard; }; } // namespace gl #endif // LIBANGLE_FRAMEBUFFER_H_