1//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// FramebufferAttachment.h: Defines the wrapper class gl::FramebufferAttachment, as well as the
8// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.
9
10#ifndef LIBANGLE_FRAMEBUFFERATTACHMENT_H_
11#define LIBANGLE_FRAMEBUFFERATTACHMENT_H_
12
13#include "angle_gl.h"
14#include "common/angleutils.h"
15#include "libANGLE/Error.h"
16#include "libANGLE/ImageIndex.h"
17#include "libANGLE/Observer.h"
18#include "libANGLE/angletypes.h"
19#include "libANGLE/formatutils.h"
20#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h"
21
22namespace egl
23{
24class Surface;
25}
26
27namespace rx
28{
29// An implementation-specific object associated with an attachment.
30
31class FramebufferAttachmentRenderTarget : angle::NonCopyable
32{
33  public:
34    FramebufferAttachmentRenderTarget() {}
35    virtual ~FramebufferAttachmentRenderTarget() {}
36};
37
38class FramebufferAttachmentObjectImpl;
39}  // namespace rx
40
41namespace gl
42{
43class FramebufferAttachmentObject;
44class Renderbuffer;
45class Texture;
46
47// FramebufferAttachment implements a GL framebuffer attachment.
48// Attachments are "light" containers, which store pointers to ref-counted GL objects.
49// We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments.
50// Note: Our old naming scheme used the term "Renderbuffer" for both GL renderbuffers and for
51// framebuffer attachments, which confused their usage.
52
53class FramebufferAttachment final
54{
55  public:
56    FramebufferAttachment();
57
58    FramebufferAttachment(const Context *context,
59                          GLenum type,
60                          GLenum binding,
61                          const ImageIndex &textureIndex,
62                          FramebufferAttachmentObject *resource,
63                          rx::Serial framebufferSerial);
64
65    FramebufferAttachment(FramebufferAttachment &&other);
66    FramebufferAttachment &operator=(FramebufferAttachment &&other);
67
68    ~FramebufferAttachment();
69
70    void detach(const Context *context, rx::Serial framebufferSerial);
71    void attach(const Context *context,
72                GLenum type,
73                GLenum binding,
74                const ImageIndex &textureIndex,
75                FramebufferAttachmentObject *resource,
76                GLsizei numViews,
77                GLuint baseViewIndex,
78                bool isMultiview,
79                GLsizei samples,
80                rx::Serial framebufferSerial);
81
82    // Helper methods
83    GLuint getRedSize() const;
84    GLuint getGreenSize() const;
85    GLuint getBlueSize() const;
86    GLuint getAlphaSize() const;
87    GLuint getDepthSize() const;
88    GLuint getStencilSize() const;
89    GLenum getComponentType() const;
90    GLenum getColorEncoding() const;
91
92    bool isTextureWithId(TextureID textureId) const
93    {
94        return mType == GL_TEXTURE && id() == textureId.value;
95    }
96    bool isExternalTexture() const
97    {
98        return mType == GL_TEXTURE && getTextureImageIndex().getType() == gl::TextureType::External;
99    }
100    bool isRenderbufferWithId(GLuint renderbufferId) const
101    {
102        return mType == GL_RENDERBUFFER && id() == renderbufferId;
103    }
104
105    GLenum getBinding() const { return mTarget.binding(); }
106    GLuint id() const;
107
108    // These methods are only legal to call on Texture attachments
109    const ImageIndex &getTextureImageIndex() const;
110    TextureTarget cubeMapFace() const;
111    GLint mipLevel() const;
112    GLint layer() const;
113    bool isLayered() const;
114
115    GLsizei getNumViews() const { return mNumViews; }
116
117    bool isMultiview() const;
118    GLint getBaseViewIndex() const;
119
120    bool isRenderToTexture() const;
121    GLsizei getRenderToTextureSamples() const;
122
123    // The size of the underlying resource the attachment points to. The 'depth' value will
124    // correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and
125    // Renderbuffers, it will always be 1.
126    Extents getSize() const;
127    Format getFormat() const;
128    GLsizei getSamples() const;
129    // This will always return the actual sample count of the attachment even if
130    // render_to_texture extension is active on this FBattachment object.
131    GLsizei getResourceSamples() const;
132    GLenum type() const { return mType; }
133    bool isAttached() const { return mType != GL_NONE; }
134    bool isRenderable(const Context *context) const;
135    bool isYUV() const;
136
137    Renderbuffer *getRenderbuffer() const;
138    Texture *getTexture() const;
139    const egl::Surface *getSurface() const;
140    FramebufferAttachmentObject *getResource() const;
141    InitState initState() const;
142    angle::Result initializeContents(const Context *context);
143    void setInitState(InitState initState) const;
144
145    // "T" must be static_castable from FramebufferAttachmentRenderTarget
146    template <typename T>
147    angle::Result getRenderTarget(const Context *context, GLsizei samples, T **rtOut) const
148    {
149        static_assert(std::is_base_of<rx::FramebufferAttachmentRenderTarget, T>(),
150                      "Invalid RenderTarget class.");
151        return getRenderTargetImpl(
152            context, samples, reinterpret_cast<rx::FramebufferAttachmentRenderTarget **>(rtOut));
153    }
154
155    bool operator==(const FramebufferAttachment &other) const;
156    bool operator!=(const FramebufferAttachment &other) const;
157
158    static const GLsizei kDefaultNumViews;
159    static const GLint kDefaultBaseViewIndex;
160    static const GLint kDefaultRenderToTextureSamples;
161
162  private:
163    angle::Result getRenderTargetImpl(const Context *context,
164                                      GLsizei samples,
165                                      rx::FramebufferAttachmentRenderTarget **rtOut) const;
166
167    // A framebuffer attachment points to one of three types of resources: Renderbuffers,
168    // Textures and egl::Surface. The "Target" struct indicates which part of the
169    // object an attachment references. For the three types:
170    //   - a Renderbuffer has a unique renderable target, and needs no target index
171    //   - a Texture has targets for every image and uses an ImageIndex
172    //   - a Surface has targets for Color and Depth/Stencil, and uses the attachment binding
173    class Target
174    {
175      public:
176        Target();
177        Target(GLenum binding, const ImageIndex &imageIndex);
178        Target(const Target &other);
179        Target &operator=(const Target &other);
180
181        GLenum binding() const { return mBinding; }
182        const ImageIndex &textureIndex() const { return mTextureIndex; }
183
184      private:
185        GLenum mBinding;
186        ImageIndex mTextureIndex;
187    };
188
189    GLenum mType;
190    Target mTarget;
191    FramebufferAttachmentObject *mResource;
192    GLsizei mNumViews;
193    bool mIsMultiview;
194    GLint mBaseViewIndex;
195    // A single-sampled texture can be attached to a framebuffer either as single-sampled or as
196    // multisampled-render-to-texture.  In the latter case, |mRenderToTextureSamples| will contain
197    // the number of samples.  For renderbuffers, the number of samples is inherited from the
198    // renderbuffer itself.
199    //
200    // Note that textures cannot change storage between single and multisample once attached to a
201    // framebuffer.  Renderbuffers instead can, and caching the number of renderbuffer samples here
202    // can lead to stale data.
203    GLsizei mRenderToTextureSamples;
204};
205
206// A base class for objects that FBO Attachments may point to.
207class FramebufferAttachmentObject : public angle::Subject, public angle::ObserverInterface
208{
209  public:
210    FramebufferAttachmentObject();
211    ~FramebufferAttachmentObject() override;
212
213    virtual Extents getAttachmentSize(const ImageIndex &imageIndex) const                  = 0;
214    virtual Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const = 0;
215    virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const               = 0;
216    virtual bool isRenderable(const Context *context,
217                              GLenum binding,
218                              const ImageIndex &imageIndex) const                          = 0;
219    virtual bool isYUV() const                                                             = 0;
220    virtual bool hasProtectedContent() const                                               = 0;
221
222    virtual void onAttach(const Context *context, rx::Serial framebufferSerial) = 0;
223    virtual void onDetach(const Context *context, rx::Serial framebufferSerial) = 0;
224    virtual GLuint getId() const                                                = 0;
225
226    // These are used for robust resource initialization.
227    virtual InitState initState(const ImageIndex &imageIndex) const              = 0;
228    virtual void setInitState(const ImageIndex &imageIndex, InitState initState) = 0;
229
230    angle::Result getAttachmentRenderTarget(const Context *context,
231                                            GLenum binding,
232                                            const ImageIndex &imageIndex,
233                                            GLsizei samples,
234                                            rx::FramebufferAttachmentRenderTarget **rtOut) const;
235
236    angle::Result initializeContents(const Context *context, const ImageIndex &imageIndex);
237
238  protected:
239    virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0;
240};
241
242inline const ImageIndex &FramebufferAttachment::getTextureImageIndex() const
243{
244    ASSERT(type() == GL_TEXTURE);
245    return mTarget.textureIndex();
246}
247
248inline Extents FramebufferAttachment::getSize() const
249{
250    ASSERT(mResource);
251    return mResource->getAttachmentSize(mTarget.textureIndex());
252}
253
254inline Format FramebufferAttachment::getFormat() const
255{
256    ASSERT(mResource);
257    return mResource->getAttachmentFormat(mTarget.binding(), mTarget.textureIndex());
258}
259
260inline GLsizei FramebufferAttachment::getSamples() const
261{
262    return isRenderToTexture() ? getRenderToTextureSamples() : getResourceSamples();
263}
264
265inline GLsizei FramebufferAttachment::getResourceSamples() const
266{
267    ASSERT(mResource);
268    return mResource->getAttachmentSamples(mTarget.textureIndex());
269}
270
271inline angle::Result FramebufferAttachment::getRenderTargetImpl(
272    const Context *context,
273    GLsizei samples,
274    rx::FramebufferAttachmentRenderTarget **rtOut) const
275{
276    ASSERT(mResource);
277    return mResource->getAttachmentRenderTarget(context, mTarget.binding(), mTarget.textureIndex(),
278                                                samples, rtOut);
279}
280
281inline bool FramebufferAttachment::isRenderable(const Context *context) const
282{
283    ASSERT(mResource);
284    return mResource->isRenderable(context, mTarget.binding(), mTarget.textureIndex());
285}
286
287inline bool FramebufferAttachment::isYUV() const
288{
289    ASSERT(mResource);
290    return mResource->isYUV();
291}
292
293}  // namespace gl
294
295#endif  // LIBANGLE_FRAMEBUFFERATTACHMENT_H_
296