// // Copyright 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. // // FramebufferAttachment.h: Defines the wrapper class gl::FramebufferAttachment, as well as the // objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. #ifndef LIBANGLE_FRAMEBUFFERATTACHMENT_H_ #define LIBANGLE_FRAMEBUFFERATTACHMENT_H_ #include "angle_gl.h" #include "common/angleutils.h" #include "libANGLE/Error.h" #include "libANGLE/ImageIndex.h" #include "libANGLE/Observer.h" #include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" namespace egl { class Surface; } namespace rx { // An implementation-specific object associated with an attachment. class FramebufferAttachmentRenderTarget : angle::NonCopyable { public: FramebufferAttachmentRenderTarget() {} virtual ~FramebufferAttachmentRenderTarget() {} }; class FramebufferAttachmentObjectImpl; } // namespace rx namespace gl { class FramebufferAttachmentObject; class Renderbuffer; class Texture; // FramebufferAttachment implements a GL framebuffer attachment. // Attachments are "light" containers, which store pointers to ref-counted GL objects. // We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments. // Note: Our old naming scheme used the term "Renderbuffer" for both GL renderbuffers and for // framebuffer attachments, which confused their usage. class FramebufferAttachment final { public: FramebufferAttachment(); FramebufferAttachment(const Context *context, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource, rx::Serial framebufferSerial); FramebufferAttachment(FramebufferAttachment &&other); FramebufferAttachment &operator=(FramebufferAttachment &&other); ~FramebufferAttachment(); void detach(const Context *context, rx::Serial framebufferSerial); void attach(const Context *context, GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource, GLsizei numViews, GLuint baseViewIndex, bool isMultiview, GLsizei samples, rx::Serial framebufferSerial); // Helper methods GLuint getRedSize() const; GLuint getGreenSize() const; GLuint getBlueSize() const; GLuint getAlphaSize() const; GLuint getDepthSize() const; GLuint getStencilSize() const; GLenum getComponentType() const; GLenum getColorEncoding() const; bool isTextureWithId(TextureID textureId) const { return mType == GL_TEXTURE && id() == textureId.value; } bool isExternalTexture() const { return mType == GL_TEXTURE && getTextureImageIndex().getType() == gl::TextureType::External; } bool isRenderbufferWithId(GLuint renderbufferId) const { return mType == GL_RENDERBUFFER && id() == renderbufferId; } GLenum getBinding() const { return mTarget.binding(); } GLuint id() const; // These methods are only legal to call on Texture attachments const ImageIndex &getTextureImageIndex() const; TextureTarget cubeMapFace() const; GLint mipLevel() const; GLint layer() const; bool isLayered() const; GLsizei getNumViews() const { return mNumViews; } bool isMultiview() const; GLint getBaseViewIndex() const; bool isRenderToTexture() const; GLsizei getRenderToTextureSamples() const; // The size of the underlying resource the attachment points to. The 'depth' value will // correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and // Renderbuffers, it will always be 1. Extents getSize() const; Format getFormat() const; GLsizei getSamples() const; // This will always return the actual sample count of the attachment even if // render_to_texture extension is active on this FBattachment object. GLsizei getResourceSamples() const; GLenum type() const { return mType; } bool isAttached() const { return mType != GL_NONE; } bool isRenderable(const Context *context) const; bool isYUV() const; bool isCreatedWithAHB() const; Renderbuffer *getRenderbuffer() const; Texture *getTexture() const; const egl::Surface *getSurface() const; FramebufferAttachmentObject *getResource() const; InitState initState() const; angle::Result initializeContents(const Context *context); void setInitState(InitState initState) const; // "T" must be static_castable from FramebufferAttachmentRenderTarget template angle::Result getRenderTarget(const Context *context, GLsizei samples, T **rtOut) const { static_assert(std::is_base_of(), "Invalid RenderTarget class."); return getRenderTargetImpl( context, samples, reinterpret_cast(rtOut)); } bool operator==(const FramebufferAttachment &other) const; bool operator!=(const FramebufferAttachment &other) const; static const GLsizei kDefaultNumViews; static const GLint kDefaultBaseViewIndex; static const GLint kDefaultRenderToTextureSamples; private: angle::Result getRenderTargetImpl(const Context *context, GLsizei samples, rx::FramebufferAttachmentRenderTarget **rtOut) const; // A framebuffer attachment points to one of three types of resources: Renderbuffers, // Textures and egl::Surface. The "Target" struct indicates which part of the // object an attachment references. For the three types: // - a Renderbuffer has a unique renderable target, and needs no target index // - a Texture has targets for every image and uses an ImageIndex // - a Surface has targets for Color and Depth/Stencil, and uses the attachment binding class Target { public: Target(); Target(GLenum binding, const ImageIndex &imageIndex); Target(const Target &other); Target &operator=(const Target &other); GLenum binding() const { return mBinding; } const ImageIndex &textureIndex() const { return mTextureIndex; } private: GLenum mBinding; ImageIndex mTextureIndex; }; GLenum mType; Target mTarget; FramebufferAttachmentObject *mResource; GLsizei mNumViews; bool mIsMultiview; GLint mBaseViewIndex; // A single-sampled texture can be attached to a framebuffer either as single-sampled or as // multisampled-render-to-texture. In the latter case, |mRenderToTextureSamples| will contain // the number of samples. For renderbuffers, the number of samples is inherited from the // renderbuffer itself. // // Note that textures cannot change storage between single and multisample once attached to a // framebuffer. Renderbuffers instead can, and caching the number of renderbuffer samples here // can lead to stale data. GLsizei mRenderToTextureSamples; }; // A base class for objects that FBO Attachments may point to. class FramebufferAttachmentObject : public angle::Subject, public angle::ObserverInterface { public: FramebufferAttachmentObject(); ~FramebufferAttachmentObject() override; virtual Extents getAttachmentSize(const ImageIndex &imageIndex) const = 0; virtual Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const = 0; virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const = 0; virtual bool isRenderable(const Context *context, GLenum binding, const ImageIndex &imageIndex) const = 0; virtual bool isYUV() const = 0; virtual bool isCreatedWithAHB() const = 0; virtual bool hasProtectedContent() const = 0; virtual void onAttach(const Context *context, rx::Serial framebufferSerial) = 0; virtual void onDetach(const Context *context, rx::Serial framebufferSerial) = 0; virtual GLuint getId() const = 0; // These are used for robust resource initialization. virtual InitState initState(GLenum binding, const ImageIndex &imageIndex) const = 0; virtual void setInitState(GLenum binding, const ImageIndex &imageIndex, InitState initState) = 0; angle::Result getAttachmentRenderTarget(const Context *context, GLenum binding, const ImageIndex &imageIndex, GLsizei samples, rx::FramebufferAttachmentRenderTarget **rtOut) const; angle::Result initializeContents(const Context *context, GLenum binding, const ImageIndex &imageIndex); protected: virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0; }; inline const ImageIndex &FramebufferAttachment::getTextureImageIndex() const { ASSERT(type() == GL_TEXTURE); return mTarget.textureIndex(); } inline Extents FramebufferAttachment::getSize() const { ASSERT(mResource); return mResource->getAttachmentSize(mTarget.textureIndex()); } inline Format FramebufferAttachment::getFormat() const { ASSERT(mResource); return mResource->getAttachmentFormat(mTarget.binding(), mTarget.textureIndex()); } inline GLsizei FramebufferAttachment::getSamples() const { return isRenderToTexture() ? getRenderToTextureSamples() : getResourceSamples(); } inline GLsizei FramebufferAttachment::getResourceSamples() const { ASSERT(mResource); return mResource->getAttachmentSamples(mTarget.textureIndex()); } inline angle::Result FramebufferAttachment::getRenderTargetImpl( const Context *context, GLsizei samples, rx::FramebufferAttachmentRenderTarget **rtOut) const { ASSERT(mResource); return mResource->getAttachmentRenderTarget(context, mTarget.binding(), mTarget.textureIndex(), samples, rtOut); } inline bool FramebufferAttachment::isRenderable(const Context *context) const { ASSERT(mResource); return mResource->isRenderable(context, mTarget.binding(), mTarget.textureIndex()); } inline bool FramebufferAttachment::isYUV() const { ASSERT(mResource); return mResource->isYUV(); } inline bool FramebufferAttachment::isCreatedWithAHB() const { ASSERT(mResource); return mResource->isCreatedWithAHB(); } } // namespace gl #endif // LIBANGLE_FRAMEBUFFERATTACHMENT_H_