• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 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 // Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9 
10 #include "libANGLE/Framebuffer.h"
11 
12 #include "common/Optional.h"
13 #include "common/bitset_utils.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Config.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Display.h"
18 #include "libANGLE/FramebufferAttachment.h"
19 #include "libANGLE/Renderbuffer.h"
20 #include "libANGLE/Surface.h"
21 #include "libANGLE/Texture.h"
22 #include "libANGLE/angletypes.h"
23 #include "libANGLE/formatutils.h"
24 #include "libANGLE/renderer/ContextImpl.h"
25 #include "libANGLE/renderer/FramebufferImpl.h"
26 #include "libANGLE/renderer/GLImplFactory.h"
27 #include "libANGLE/renderer/RenderbufferImpl.h"
28 #include "libANGLE/renderer/SurfaceImpl.h"
29 
30 using namespace angle;
31 
32 namespace gl
33 {
34 
35 namespace
36 {
37 
CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment * firstAttachment,const FramebufferAttachment * secondAttachment)38 bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
39                                                const FramebufferAttachment *secondAttachment)
40 {
41     ASSERT(firstAttachment && secondAttachment);
42     ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
43 
44     if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
45     {
46         return false;
47     }
48     if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
49     {
50         return false;
51     }
52     if (firstAttachment->isMultiview() != secondAttachment->isMultiview())
53     {
54         return false;
55     }
56     return true;
57 }
58 
CheckAttachmentCompleteness(const Context * context,const FramebufferAttachment & attachment)59 bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
60 {
61     ASSERT(attachment.isAttached());
62 
63     const Extents &size = attachment.getSize();
64     if (size.width == 0 || size.height == 0)
65     {
66         return false;
67     }
68 
69     if (!attachment.isRenderable(context))
70     {
71         return false;
72     }
73 
74     if (attachment.type() == GL_TEXTURE)
75     {
76         // [EXT_geometry_shader] Section 9.4.1, "Framebuffer Completeness"
77         // If <image> is a three-dimensional texture or a two-dimensional array texture and the
78         // attachment is not layered, the selected layer is less than the depth or layer count,
79         // respectively, of the texture.
80         if (!attachment.isLayered())
81         {
82             if (attachment.layer() >= size.depth)
83             {
84                 return false;
85             }
86         }
87         // If <image> is a three-dimensional texture or a two-dimensional array texture and the
88         // attachment is layered, the depth or layer count, respectively, of the texture is less
89         // than or equal to the value of MAX_FRAMEBUFFER_LAYERS_EXT.
90         else
91         {
92             if (static_cast<GLuint>(size.depth) >= context->getCaps().maxFramebufferLayers)
93             {
94                 return false;
95             }
96         }
97 
98         // ES3 specifies that cube map texture attachments must be cube complete.
99         // This language is missing from the ES2 spec, but we enforce it here because some
100         // desktop OpenGL drivers also enforce this validation.
101         // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
102         const Texture *texture = attachment.getTexture();
103         ASSERT(texture);
104         if (texture->getType() == TextureType::CubeMap &&
105             !texture->getTextureState().isCubeComplete())
106         {
107             return false;
108         }
109 
110         if (!texture->getImmutableFormat())
111         {
112             GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
113 
114             // From the ES 3.0 spec, pg 213:
115             // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
116             // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
117             // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
118             // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
119             // the effective maximum texture level defined in the Mipmapping discussion of
120             // section 3.8.10.4.
121             if (attachmentMipLevel < texture->getBaseLevel() ||
122                 attachmentMipLevel > texture->getMipmapMaxLevel())
123             {
124                 return false;
125             }
126 
127             // Form the ES 3.0 spec, pg 213/214:
128             // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
129             // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
130             // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
131             // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
132             // a cubemap texture, the texture must also be cube complete.
133             if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
134             {
135                 return false;
136             }
137         }
138     }
139 
140     return true;
141 }
142 
CheckAttachmentSampleCompleteness(const Context * context,const FramebufferAttachment & attachment,bool colorAttachment,Optional<int> * samples,Optional<bool> * fixedSampleLocations)143 bool CheckAttachmentSampleCompleteness(const Context *context,
144                                        const FramebufferAttachment &attachment,
145                                        bool colorAttachment,
146                                        Optional<int> *samples,
147                                        Optional<bool> *fixedSampleLocations)
148 {
149     ASSERT(attachment.isAttached());
150 
151     if (attachment.type() == GL_TEXTURE)
152     {
153         const Texture *texture = attachment.getTexture();
154         ASSERT(texture);
155 
156         const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
157         bool fixedSampleloc = texture->getAttachmentFixedSampleLocations(attachmentImageIndex);
158         if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
159         {
160             return false;
161         }
162         else
163         {
164             *fixedSampleLocations = fixedSampleloc;
165         }
166     }
167 
168     if (samples->valid())
169     {
170         if (attachment.getSamples() != samples->value())
171         {
172             if (colorAttachment)
173             {
174                 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
175                 // all color attachments have the same number of samples for the FBO to be complete.
176                 return false;
177             }
178             else
179             {
180                 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
181                 // when its depth or stencil samples are a multiple of the number of color samples.
182                 if (!context->getExtensions().framebufferMixedSamples)
183                 {
184                     return false;
185                 }
186 
187                 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
188                 {
189                     return false;
190                 }
191             }
192         }
193     }
194     else
195     {
196         *samples = attachment.getSamples();
197     }
198 
199     return true;
200 }
201 
202 // Needed to index into the attachment arrays/bitsets.
203 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
204                   Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
205               "Framebuffer Dirty bit mismatch");
206 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
207                   Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
208               "Framebuffer Dirty bit mismatch");
209 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
210                   Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
211               "Framebuffer Dirty bit mismatch");
212 
InitAttachment(const Context * context,FramebufferAttachment * attachment)213 angle::Result InitAttachment(const Context *context, FramebufferAttachment *attachment)
214 {
215     ASSERT(attachment->isAttached());
216     if (attachment->initState() == InitState::MayNeedInit)
217     {
218         ANGLE_TRY(attachment->initializeContents(context));
219     }
220     return angle::Result::Continue;
221 }
222 
IsColorMaskedOut(const BlendState & blend)223 bool IsColorMaskedOut(const BlendState &blend)
224 {
225     return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
226             !blend.colorMaskAlpha);
227 }
228 
IsDepthMaskedOut(const DepthStencilState & depthStencil)229 bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
230 {
231     return !depthStencil.depthMask;
232 }
233 
IsStencilMaskedOut(const DepthStencilState & depthStencil)234 bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
235 {
236     return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
237 }
238 
IsClearBufferMaskedOut(const Context * context,GLenum buffer)239 bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
240 {
241     switch (buffer)
242     {
243         case GL_COLOR:
244             return IsColorMaskedOut(context->getState().getBlendState());
245         case GL_DEPTH:
246             return IsDepthMaskedOut(context->getState().getDepthStencilState());
247         case GL_STENCIL:
248             return IsStencilMaskedOut(context->getState().getDepthStencilState());
249         case GL_DEPTH_STENCIL:
250             return IsDepthMaskedOut(context->getState().getDepthStencilState()) &&
251                    IsStencilMaskedOut(context->getState().getDepthStencilState());
252         default:
253             UNREACHABLE();
254             return true;
255     }
256 }
257 
258 }  // anonymous namespace
259 
260 // This constructor is only used for default framebuffers.
FramebufferState()261 FramebufferState::FramebufferState()
262     : mId(0),
263       mLabel(),
264       mColorAttachments(1),
265       mDrawBufferStates(1, GL_BACK),
266       mReadBufferState(GL_BACK),
267       mDrawBufferTypeMask(),
268       mDefaultWidth(0),
269       mDefaultHeight(0),
270       mDefaultSamples(0),
271       mDefaultFixedSampleLocations(GL_FALSE),
272       mDefaultLayers(0),
273       mWebGLDepthStencilConsistent(true)
274 {
275     ASSERT(mDrawBufferStates.size() > 0);
276     mEnabledDrawBuffers.set(0);
277 }
278 
FramebufferState(const Caps & caps,GLuint id)279 FramebufferState::FramebufferState(const Caps &caps, GLuint id)
280     : mId(id),
281       mLabel(),
282       mColorAttachments(caps.maxColorAttachments),
283       mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
284       mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
285       mDrawBufferTypeMask(),
286       mDefaultWidth(0),
287       mDefaultHeight(0),
288       mDefaultSamples(0),
289       mDefaultFixedSampleLocations(GL_FALSE),
290       mDefaultLayers(0),
291       mWebGLDepthStencilConsistent(true)
292 {
293     ASSERT(mId != 0);
294     ASSERT(mDrawBufferStates.size() > 0);
295     mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
296 }
297 
~FramebufferState()298 FramebufferState::~FramebufferState() {}
299 
getLabel()300 const std::string &FramebufferState::getLabel()
301 {
302     return mLabel;
303 }
304 
getAttachment(const Context * context,GLenum attachment) const305 const FramebufferAttachment *FramebufferState::getAttachment(const Context *context,
306                                                              GLenum attachment) const
307 {
308     if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
309     {
310         return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
311     }
312 
313     // WebGL1 allows a developer to query for attachment parameters even when "inconsistant" (i.e.
314     // multiple conflicting attachment points) and requires us to return the framebuffer attachment
315     // associated with WebGL.
316     switch (attachment)
317     {
318         case GL_COLOR:
319         case GL_BACK:
320             return getColorAttachment(0);
321         case GL_DEPTH:
322         case GL_DEPTH_ATTACHMENT:
323             if (context->isWebGL1())
324             {
325                 return getWebGLDepthAttachment();
326             }
327             else
328             {
329                 return getDepthAttachment();
330             }
331         case GL_STENCIL:
332         case GL_STENCIL_ATTACHMENT:
333             if (context->isWebGL1())
334             {
335                 return getWebGLStencilAttachment();
336             }
337             else
338             {
339                 return getStencilAttachment();
340             }
341         case GL_DEPTH_STENCIL:
342         case GL_DEPTH_STENCIL_ATTACHMENT:
343             if (context->isWebGL1())
344             {
345                 return getWebGLDepthStencilAttachment();
346             }
347             else
348             {
349                 return getDepthStencilAttachment();
350             }
351         default:
352             UNREACHABLE();
353             return nullptr;
354     }
355 }
356 
getReadIndex() const357 size_t FramebufferState::getReadIndex() const
358 {
359     ASSERT(mReadBufferState == GL_BACK ||
360            (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
361     size_t readIndex = (mReadBufferState == GL_BACK
362                             ? 0
363                             : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
364     ASSERT(readIndex < mColorAttachments.size());
365     return readIndex;
366 }
367 
getReadAttachment() const368 const FramebufferAttachment *FramebufferState::getReadAttachment() const
369 {
370     if (mReadBufferState == GL_NONE)
371     {
372         return nullptr;
373     }
374     size_t readIndex = getReadIndex();
375     return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
376 }
377 
getFirstNonNullAttachment() const378 const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
379 {
380     auto *colorAttachment = getFirstColorAttachment();
381     if (colorAttachment)
382     {
383         return colorAttachment;
384     }
385     return getDepthOrStencilAttachment();
386 }
387 
getFirstColorAttachment() const388 const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
389 {
390     for (const FramebufferAttachment &colorAttachment : mColorAttachments)
391     {
392         if (colorAttachment.isAttached())
393         {
394             return &colorAttachment;
395         }
396     }
397 
398     return nullptr;
399 }
400 
getDepthOrStencilAttachment() const401 const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
402 {
403     if (mDepthAttachment.isAttached())
404     {
405         return &mDepthAttachment;
406     }
407     if (mStencilAttachment.isAttached())
408     {
409         return &mStencilAttachment;
410     }
411     return nullptr;
412 }
413 
getStencilOrDepthStencilAttachment() const414 const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
415 {
416     if (mStencilAttachment.isAttached())
417     {
418         return &mStencilAttachment;
419     }
420     return getDepthStencilAttachment();
421 }
422 
getColorAttachment(size_t colorAttachment) const423 const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
424 {
425     ASSERT(colorAttachment < mColorAttachments.size());
426     return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
427                                                            : nullptr;
428 }
429 
getDepthAttachment() const430 const FramebufferAttachment *FramebufferState::getDepthAttachment() const
431 {
432     return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
433 }
434 
getWebGLDepthAttachment() const435 const FramebufferAttachment *FramebufferState::getWebGLDepthAttachment() const
436 {
437     return mWebGLDepthAttachment.isAttached() ? &mWebGLDepthAttachment : nullptr;
438 }
439 
getWebGLDepthStencilAttachment() const440 const FramebufferAttachment *FramebufferState::getWebGLDepthStencilAttachment() const
441 {
442     return mWebGLDepthStencilAttachment.isAttached() ? &mWebGLDepthStencilAttachment : nullptr;
443 }
444 
getStencilAttachment() const445 const FramebufferAttachment *FramebufferState::getStencilAttachment() const
446 {
447     return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
448 }
449 
getWebGLStencilAttachment() const450 const FramebufferAttachment *FramebufferState::getWebGLStencilAttachment() const
451 {
452     return mWebGLStencilAttachment.isAttached() ? &mWebGLStencilAttachment : nullptr;
453 }
454 
getDepthStencilAttachment() const455 const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
456 {
457     // A valid depth-stencil attachment has the same resource bound to both the
458     // depth and stencil attachment points.
459     if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
460         mDepthAttachment == mStencilAttachment)
461     {
462         return &mDepthAttachment;
463     }
464 
465     return nullptr;
466 }
467 
attachmentsHaveSameDimensions() const468 bool FramebufferState::attachmentsHaveSameDimensions() const
469 {
470     Optional<Extents> attachmentSize;
471 
472     auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
473         if (!attachment.isAttached())
474         {
475             return false;
476         }
477 
478         if (!attachmentSize.valid())
479         {
480             attachmentSize = attachment.getSize();
481             return false;
482         }
483 
484         const auto &prevSize = attachmentSize.value();
485         const auto &curSize  = attachment.getSize();
486         return (curSize.width != prevSize.width || curSize.height != prevSize.height);
487     };
488 
489     for (const auto &attachment : mColorAttachments)
490     {
491         if (hasMismatchedSize(attachment))
492         {
493             return false;
494         }
495     }
496 
497     if (hasMismatchedSize(mDepthAttachment))
498     {
499         return false;
500     }
501 
502     return !hasMismatchedSize(mStencilAttachment);
503 }
504 
hasSeparateDepthAndStencilAttachments() const505 bool FramebufferState::hasSeparateDepthAndStencilAttachments() const
506 {
507     // if we have both a depth and stencil buffer, they must refer to the same object
508     // since we only support packed_depth_stencil and not separate depth and stencil
509     return (getDepthAttachment() != nullptr && getStencilAttachment() != nullptr &&
510             getDepthStencilAttachment() == nullptr);
511 }
512 
getDrawBuffer(size_t drawBufferIdx) const513 const FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
514 {
515     ASSERT(drawBufferIdx < mDrawBufferStates.size());
516     if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
517     {
518         // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
519         // must be COLOR_ATTACHMENTi or NONE"
520         ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
521                (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
522 
523         if (mDrawBufferStates[drawBufferIdx] == GL_BACK)
524         {
525             return getColorAttachment(0);
526         }
527         else
528         {
529             return getColorAttachment(mDrawBufferStates[drawBufferIdx] - GL_COLOR_ATTACHMENT0);
530         }
531     }
532     else
533     {
534         return nullptr;
535     }
536 }
537 
getDrawBufferCount() const538 size_t FramebufferState::getDrawBufferCount() const
539 {
540     return mDrawBufferStates.size();
541 }
542 
colorAttachmentsAreUniqueImages() const543 bool FramebufferState::colorAttachmentsAreUniqueImages() const
544 {
545     for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
546          firstAttachmentIdx++)
547     {
548         const FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
549         if (!firstAttachment.isAttached())
550         {
551             continue;
552         }
553 
554         for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
555              secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
556         {
557             const FramebufferAttachment &secondAttachment = mColorAttachments[secondAttachmentIdx];
558             if (!secondAttachment.isAttached())
559             {
560                 continue;
561             }
562 
563             if (firstAttachment == secondAttachment)
564             {
565                 return false;
566             }
567         }
568     }
569 
570     return true;
571 }
572 
hasDepth() const573 bool FramebufferState::hasDepth() const
574 {
575     return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
576 }
577 
hasStencil() const578 bool FramebufferState::hasStencil() const
579 {
580     return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
581 }
582 
isMultiview() const583 bool FramebufferState::isMultiview() const
584 {
585     const FramebufferAttachment *attachment = getFirstNonNullAttachment();
586     if (attachment == nullptr)
587     {
588         return false;
589     }
590     return attachment->isMultiview();
591 }
592 
getBaseViewIndex() const593 int FramebufferState::getBaseViewIndex() const
594 {
595     const FramebufferAttachment *attachment = getFirstNonNullAttachment();
596     if (attachment == nullptr)
597     {
598         return GL_NONE;
599     }
600     return attachment->getBaseViewIndex();
601 }
602 
getDimensions() const603 Box FramebufferState::getDimensions() const
604 {
605     Extents extents = getExtents();
606     return Box(0, 0, 0, extents.width, extents.height, extents.depth);
607 }
608 
getExtents() const609 Extents FramebufferState::getExtents() const
610 {
611     ASSERT(attachmentsHaveSameDimensions());
612     const FramebufferAttachment *first = getFirstNonNullAttachment();
613     if (first)
614     {
615         return first->getSize();
616     }
617     return Extents(getDefaultWidth(), getDefaultHeight(), 0);
618 }
619 
Framebuffer(const Caps & caps,rx::GLImplFactory * factory,GLuint id)620 Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
621     : mState(caps, id),
622       mImpl(factory->createFramebuffer(mState)),
623       mCachedStatus(),
624       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
625       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
626 {
627     ASSERT(mImpl != nullptr);
628     ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
629 
630     for (uint32_t colorIndex = 0;
631          colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
632     {
633         mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
634     }
635 }
636 
Framebuffer(const Context * context,egl::Surface * surface)637 Framebuffer::Framebuffer(const Context *context, egl::Surface *surface)
638     : mState(),
639       mImpl(surface->getImplementation()->createDefaultFramebuffer(context, mState)),
640       mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
641       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
642       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
643 {
644     ASSERT(mImpl != nullptr);
645     mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
646 
647     setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
648                       FramebufferAttachment::kDefaultNumViews,
649                       FramebufferAttachment::kDefaultBaseViewIndex, false);
650 
651     if (surface->getConfig()->depthSize > 0)
652     {
653         setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
654                           FramebufferAttachment::kDefaultNumViews,
655                           FramebufferAttachment::kDefaultBaseViewIndex, false);
656     }
657 
658     if (surface->getConfig()->stencilSize > 0)
659     {
660         setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
661                           FramebufferAttachment::kDefaultNumViews,
662                           FramebufferAttachment::kDefaultBaseViewIndex, false);
663     }
664     SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
665 
666     // Ensure the backend has a chance to synchronize its content for a new backbuffer.
667     mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
668 }
669 
Framebuffer(rx::GLImplFactory * factory)670 Framebuffer::Framebuffer(rx::GLImplFactory *factory)
671     : mState(),
672       mImpl(factory->createFramebuffer(mState)),
673       mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
674       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
675       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
676 {
677     mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
678     SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
679 }
680 
~Framebuffer()681 Framebuffer::~Framebuffer()
682 {
683     SafeDelete(mImpl);
684 }
685 
onDestroy(const Context * context)686 void Framebuffer::onDestroy(const Context *context)
687 {
688     for (auto &attachment : mState.mColorAttachments)
689     {
690         attachment.detach(context);
691     }
692     mState.mDepthAttachment.detach(context);
693     mState.mStencilAttachment.detach(context);
694     mState.mWebGLDepthAttachment.detach(context);
695     mState.mWebGLStencilAttachment.detach(context);
696     mState.mWebGLDepthStencilAttachment.detach(context);
697 
698     mImpl->destroy(context);
699 }
700 
setLabel(const Context * context,const std::string & label)701 void Framebuffer::setLabel(const Context *context, const std::string &label)
702 {
703     mState.mLabel = label;
704 }
705 
getLabel() const706 const std::string &Framebuffer::getLabel() const
707 {
708     return mState.mLabel;
709 }
710 
detachTexture(const Context * context,TextureID textureId)711 bool Framebuffer::detachTexture(const Context *context, TextureID textureId)
712 {
713     return detachResourceById(context, GL_TEXTURE, textureId.value);
714 }
715 
detachRenderbuffer(const Context * context,RenderbufferID renderbufferId)716 bool Framebuffer::detachRenderbuffer(const Context *context, RenderbufferID renderbufferId)
717 {
718     return detachResourceById(context, GL_RENDERBUFFER, renderbufferId.value);
719 }
720 
detachResourceById(const Context * context,GLenum resourceType,GLuint resourceId)721 bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
722 {
723     bool found = false;
724 
725     for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
726     {
727         if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
728                                      resourceId))
729         {
730             found = true;
731         }
732     }
733 
734     if (context->isWebGL1())
735     {
736         const std::array<FramebufferAttachment *, 3> attachments = {
737             {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
738              &mState.mWebGLStencilAttachment}};
739         for (FramebufferAttachment *attachment : attachments)
740         {
741             if (detachMatchingAttachment(context, attachment, resourceType, resourceId))
742             {
743                 found = true;
744             }
745         }
746     }
747     else
748     {
749         if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId))
750         {
751             found = true;
752         }
753         if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId))
754         {
755             found = true;
756         }
757     }
758 
759     return found;
760 }
761 
detachMatchingAttachment(const Context * context,FramebufferAttachment * attachment,GLenum matchType,GLuint matchId)762 bool Framebuffer::detachMatchingAttachment(const Context *context,
763                                            FramebufferAttachment *attachment,
764                                            GLenum matchType,
765                                            GLuint matchId)
766 {
767     if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
768     {
769         // We go through resetAttachment to make sure that all the required bookkeeping will be done
770         // such as updating enabled draw buffer state.
771         resetAttachment(context, attachment->getBinding());
772         return true;
773     }
774 
775     return false;
776 }
777 
getColorAttachment(size_t colorAttachment) const778 const FramebufferAttachment *Framebuffer::getColorAttachment(size_t colorAttachment) const
779 {
780     return mState.getColorAttachment(colorAttachment);
781 }
782 
getDepthAttachment() const783 const FramebufferAttachment *Framebuffer::getDepthAttachment() const
784 {
785     return mState.getDepthAttachment();
786 }
787 
getStencilAttachment() const788 const FramebufferAttachment *Framebuffer::getStencilAttachment() const
789 {
790     return mState.getStencilAttachment();
791 }
792 
getDepthStencilAttachment() const793 const FramebufferAttachment *Framebuffer::getDepthStencilAttachment() const
794 {
795     return mState.getDepthStencilAttachment();
796 }
797 
getDepthOrStencilAttachment() const798 const FramebufferAttachment *Framebuffer::getDepthOrStencilAttachment() const
799 {
800     return mState.getDepthOrStencilAttachment();
801 }
802 
getStencilOrDepthStencilAttachment() const803 const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
804 {
805     return mState.getStencilOrDepthStencilAttachment();
806 }
807 
getReadColorAttachment() const808 const FramebufferAttachment *Framebuffer::getReadColorAttachment() const
809 {
810     return mState.getReadAttachment();
811 }
812 
getReadColorAttachmentType() const813 GLenum Framebuffer::getReadColorAttachmentType() const
814 {
815     const FramebufferAttachment *readAttachment = mState.getReadAttachment();
816     return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
817 }
818 
getFirstColorAttachment() const819 const FramebufferAttachment *Framebuffer::getFirstColorAttachment() const
820 {
821     return mState.getFirstColorAttachment();
822 }
823 
getFirstNonNullAttachment() const824 const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
825 {
826     return mState.getFirstNonNullAttachment();
827 }
828 
getAttachment(const Context * context,GLenum attachment) const829 const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
830                                                         GLenum attachment) const
831 {
832     return mState.getAttachment(context, attachment);
833 }
834 
getDrawbufferStateCount() const835 size_t Framebuffer::getDrawbufferStateCount() const
836 {
837     return mState.mDrawBufferStates.size();
838 }
839 
getDrawBufferState(size_t drawBuffer) const840 GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
841 {
842     ASSERT(drawBuffer < mState.mDrawBufferStates.size());
843     return mState.mDrawBufferStates[drawBuffer];
844 }
845 
getDrawBufferStates() const846 const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
847 {
848     return mState.getDrawBufferStates();
849 }
850 
setDrawBuffers(size_t count,const GLenum * buffers)851 void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
852 {
853     auto &drawStates = mState.mDrawBufferStates;
854 
855     ASSERT(count <= drawStates.size());
856     std::copy(buffers, buffers + count, drawStates.begin());
857     std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
858     mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
859 
860     mState.mEnabledDrawBuffers.reset();
861     mState.mDrawBufferTypeMask.reset();
862 
863     for (size_t index = 0; index < count; ++index)
864     {
865         SetComponentTypeMask(getDrawbufferWriteType(index), index, &mState.mDrawBufferTypeMask);
866 
867         if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
868         {
869             mState.mEnabledDrawBuffers.set(index);
870         }
871     }
872 }
873 
getDrawBuffer(size_t drawBuffer) const874 const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
875 {
876     return mState.getDrawBuffer(drawBuffer);
877 }
878 
getDrawbufferWriteType(size_t drawBuffer) const879 ComponentType Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
880 {
881     const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
882     if (attachment == nullptr)
883     {
884         return ComponentType::NoType;
885     }
886 
887     GLenum componentType = attachment->getFormat().info->componentType;
888     switch (componentType)
889     {
890         case GL_INT:
891             return ComponentType::Int;
892         case GL_UNSIGNED_INT:
893             return ComponentType::UnsignedInt;
894 
895         default:
896             return ComponentType::Float;
897     }
898 }
899 
getDrawBufferTypeMask() const900 ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
901 {
902     return mState.mDrawBufferTypeMask;
903 }
904 
getDrawBufferMask() const905 DrawBufferMask Framebuffer::getDrawBufferMask() const
906 {
907     return mState.mEnabledDrawBuffers;
908 }
909 
hasEnabledDrawBuffer() const910 bool Framebuffer::hasEnabledDrawBuffer() const
911 {
912     for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
913     {
914         if (getDrawBuffer(drawbufferIdx) != nullptr)
915         {
916             return true;
917         }
918     }
919 
920     return false;
921 }
922 
getReadBufferState() const923 GLenum Framebuffer::getReadBufferState() const
924 {
925     return mState.mReadBufferState;
926 }
927 
setReadBuffer(GLenum buffer)928 void Framebuffer::setReadBuffer(GLenum buffer)
929 {
930     ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
931            (buffer >= GL_COLOR_ATTACHMENT0 &&
932             (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
933     mState.mReadBufferState = buffer;
934     mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
935 }
936 
getNumColorAttachments() const937 size_t Framebuffer::getNumColorAttachments() const
938 {
939     return mState.mColorAttachments.size();
940 }
941 
hasDepth() const942 bool Framebuffer::hasDepth() const
943 {
944     return mState.hasDepth();
945 }
946 
hasStencil() const947 bool Framebuffer::hasStencil() const
948 {
949     return mState.hasStencil();
950 }
951 
usingExtendedDrawBuffers() const952 bool Framebuffer::usingExtendedDrawBuffers() const
953 {
954     for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
955     {
956         if (getDrawBuffer(drawbufferIdx) != nullptr)
957         {
958             return true;
959         }
960     }
961 
962     return false;
963 }
964 
invalidateCompletenessCache()965 void Framebuffer::invalidateCompletenessCache()
966 {
967     if (mState.mId != 0)
968     {
969         mCachedStatus.reset();
970     }
971     onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
972 }
973 
checkStatusImpl(const Context * context)974 GLenum Framebuffer::checkStatusImpl(const Context *context)
975 {
976     ASSERT(!isDefault());
977     ASSERT(hasAnyDirtyBit() || !mCachedStatus.valid());
978 
979     mCachedStatus = checkStatusWithGLFrontEnd(context);
980 
981     if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
982     {
983         // We can skip syncState on several back-ends.
984         if (mImpl->shouldSyncStateBeforeCheckStatus())
985         {
986             angle::Result err = syncState(context);
987             if (err != angle::Result::Continue)
988             {
989                 return 0;
990             }
991         }
992 
993         if (!mImpl->checkStatus(context))
994         {
995             mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
996         }
997     }
998 
999     return mCachedStatus.value();
1000 }
1001 
checkStatusWithGLFrontEnd(const Context * context)1002 GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
1003 {
1004     const State &state = context->getState();
1005 
1006     ASSERT(mState.mId != 0);
1007 
1008     bool hasAttachments = false;
1009     Optional<unsigned int> colorbufferSize;
1010     Optional<int> samples;
1011     Optional<bool> fixedSampleLocations;
1012     bool hasRenderbuffer = false;
1013 
1014     const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
1015 
1016     Optional<bool> isLayered;
1017     Optional<TextureType> colorAttachmentsTextureType;
1018 
1019     for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
1020     {
1021         if (colorAttachment.isAttached())
1022         {
1023             if (!CheckAttachmentCompleteness(context, colorAttachment))
1024             {
1025                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1026             }
1027 
1028             const InternalFormat &format = *colorAttachment.getFormat().info;
1029             if (format.depthBits > 0 || format.stencilBits > 0)
1030             {
1031                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1032             }
1033 
1034             if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
1035                                                    &fixedSampleLocations))
1036             {
1037                 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1038             }
1039 
1040             // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
1041             // in GLES 3.0, there is no such restriction
1042             if (state.getClientMajorVersion() < 3)
1043             {
1044                 if (colorbufferSize.valid())
1045                 {
1046                     if (format.pixelBytes != colorbufferSize.value())
1047                     {
1048                         return GL_FRAMEBUFFER_UNSUPPORTED;
1049                     }
1050                 }
1051                 else
1052                 {
1053                     colorbufferSize = format.pixelBytes;
1054                 }
1055             }
1056 
1057             if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
1058             {
1059                 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
1060             }
1061 
1062             hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1063 
1064             if (!hasAttachments)
1065             {
1066                 isLayered = colorAttachment.isLayered();
1067                 if (isLayered.value())
1068                 {
1069                     colorAttachmentsTextureType = colorAttachment.getTextureImageIndex().getType();
1070                 }
1071                 hasAttachments = true;
1072             }
1073             else
1074             {
1075                 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1076                 // If any framebuffer attachment is layered, all populated attachments
1077                 // must be layered. Additionally, all populated color attachments must
1078                 // be from textures of the same target. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1079                 ASSERT(isLayered.valid());
1080                 if (isLayered.value() != colorAttachment.isLayered())
1081                 {
1082                     return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1083                 }
1084                 else if (isLayered.value())
1085                 {
1086                     ASSERT(colorAttachmentsTextureType.valid());
1087                     if (colorAttachmentsTextureType.value() !=
1088                         colorAttachment.getTextureImageIndex().getType())
1089                     {
1090                         return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1091                     }
1092                 }
1093             }
1094         }
1095     }
1096 
1097     const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
1098     if (depthAttachment.isAttached())
1099     {
1100         if (!CheckAttachmentCompleteness(context, depthAttachment))
1101         {
1102             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1103         }
1104 
1105         const InternalFormat &format = *depthAttachment.getFormat().info;
1106         if (format.depthBits == 0)
1107         {
1108             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1109         }
1110 
1111         if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1112                                                &fixedSampleLocations))
1113         {
1114             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1115         }
1116 
1117         if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1118         {
1119             return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
1120         }
1121 
1122         hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1123 
1124         if (!hasAttachments)
1125         {
1126             isLayered      = depthAttachment.isLayered();
1127             hasAttachments = true;
1128         }
1129         else
1130         {
1131             // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1132             // If any framebuffer attachment is layered, all populated attachments
1133             // must be layered. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1134             ASSERT(isLayered.valid());
1135             if (isLayered.value() != depthAttachment.isLayered())
1136             {
1137                 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1138             }
1139         }
1140     }
1141 
1142     const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
1143     if (stencilAttachment.isAttached())
1144     {
1145         if (!CheckAttachmentCompleteness(context, stencilAttachment))
1146         {
1147             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1148         }
1149 
1150         const InternalFormat &format = *stencilAttachment.getFormat().info;
1151         if (format.stencilBits == 0)
1152         {
1153             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1154         }
1155 
1156         if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1157                                                &fixedSampleLocations))
1158         {
1159             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1160         }
1161 
1162         if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1163         {
1164             return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
1165         }
1166 
1167         hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1168 
1169         if (!hasAttachments)
1170         {
1171             hasAttachments = true;
1172         }
1173         else
1174         {
1175             // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1176             // If any framebuffer attachment is layered, all populated attachments
1177             // must be layered.
1178             // {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1179             ASSERT(isLayered.valid());
1180             if (isLayered.value() != stencilAttachment.isLayered())
1181             {
1182                 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1183             }
1184         }
1185     }
1186 
1187     // Starting from ES 3.0 stencil and depth, if present, should be the same image
1188     if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1189         stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1190     {
1191         return GL_FRAMEBUFFER_UNSUPPORTED;
1192     }
1193 
1194     // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1195     if (state.isWebGL1())
1196     {
1197         if (!mState.mWebGLDepthStencilConsistent)
1198         {
1199             return GL_FRAMEBUFFER_UNSUPPORTED;
1200         }
1201 
1202         if (mState.mWebGLDepthStencilAttachment.isAttached())
1203         {
1204             if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1205                 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1206             {
1207                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1208             }
1209 
1210             if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1211                                                            &mState.mWebGLDepthStencilAttachment))
1212             {
1213                 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
1214             }
1215         }
1216         else if (mState.mStencilAttachment.isAttached() &&
1217                  mState.mStencilAttachment.getDepthSize() > 0)
1218         {
1219             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1220         }
1221         else if (mState.mDepthAttachment.isAttached() &&
1222                  mState.mDepthAttachment.getStencilSize() > 0)
1223         {
1224             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1225         }
1226     }
1227 
1228     // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1229     // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1230     // is zero, the framebuffer is considered incomplete.
1231     GLint defaultWidth  = mState.getDefaultWidth();
1232     GLint defaultHeight = mState.getDefaultHeight();
1233     if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
1234     {
1235         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
1236     }
1237 
1238     // In ES 2.0 and WebGL, all color attachments must have the same width and height.
1239     // In ES 3.0, there is no such restriction.
1240     if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1241         !mState.attachmentsHaveSameDimensions())
1242     {
1243         return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1244     }
1245 
1246     // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1247     // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
1248     if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1249     {
1250         return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1251     }
1252 
1253     // The WebGL conformance tests implicitly define that all framebuffer
1254     // attachments must be unique. For example, the same level of a texture can
1255     // not be attached to two different color attachments.
1256     if (state.getExtensions().webglCompatibility)
1257     {
1258         if (!mState.colorAttachmentsAreUniqueImages())
1259         {
1260             return GL_FRAMEBUFFER_UNSUPPORTED;
1261         }
1262     }
1263 
1264     return GL_FRAMEBUFFER_COMPLETE;
1265 }
1266 
discard(const Context * context,size_t count,const GLenum * attachments)1267 angle::Result Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
1268 {
1269     // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1270     // can be no-ops, so we should probably do that to ensure consistency.
1271     // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1272 
1273     return mImpl->discard(context, count, attachments);
1274 }
1275 
invalidate(const Context * context,size_t count,const GLenum * attachments)1276 angle::Result Framebuffer::invalidate(const Context *context,
1277                                       size_t count,
1278                                       const GLenum *attachments)
1279 {
1280     // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1281     // can be no-ops, so we should probably do that to ensure consistency.
1282     // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1283 
1284     return mImpl->invalidate(context, count, attachments);
1285 }
1286 
partialClearNeedsInit(const Context * context,bool color,bool depth,bool stencil)1287 bool Framebuffer::partialClearNeedsInit(const Context *context,
1288                                         bool color,
1289                                         bool depth,
1290                                         bool stencil)
1291 {
1292     const auto &glState = context->getState();
1293 
1294     if (!glState.isRobustResourceInitEnabled())
1295     {
1296         return false;
1297     }
1298 
1299     // Scissors can affect clearing.
1300     // TODO(jmadill): Check for complete scissor overlap.
1301     if (glState.isScissorTestEnabled())
1302     {
1303         return true;
1304     }
1305 
1306     // If colors masked, we must clear before we clear. Do a simple check.
1307     // TODO(jmadill): Filter out unused color channels from the test.
1308     if (color)
1309     {
1310         const auto &blend = glState.getBlendState();
1311         if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1312               blend.colorMaskAlpha))
1313         {
1314             return true;
1315         }
1316     }
1317 
1318     const auto &depthStencil = glState.getDepthStencilState();
1319     if (stencil && (depthStencil.stencilMask != depthStencil.stencilWritemask ||
1320                     depthStencil.stencilBackMask != depthStencil.stencilBackWritemask))
1321     {
1322         return true;
1323     }
1324 
1325     return false;
1326 }
1327 
invalidateSub(const Context * context,size_t count,const GLenum * attachments,const Rectangle & area)1328 angle::Result Framebuffer::invalidateSub(const Context *context,
1329                                          size_t count,
1330                                          const GLenum *attachments,
1331                                          const Rectangle &area)
1332 {
1333     // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1334     // can be no-ops, so we should probably do that to ensure consistency.
1335     // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1336 
1337     return mImpl->invalidateSub(context, count, attachments, area);
1338 }
1339 
clear(const Context * context,GLbitfield mask)1340 angle::Result Framebuffer::clear(const Context *context, GLbitfield mask)
1341 {
1342     const auto &glState = context->getState();
1343     if (glState.isRasterizerDiscardEnabled())
1344     {
1345         return angle::Result::Continue;
1346     }
1347 
1348     // Remove clear bits that are ineffective. An effective clear changes at least one fragment. If
1349     // color/depth/stencil masks make the clear ineffective we skip it altogether.
1350 
1351     // If all color channels are masked, don't attempt to clear color.
1352     if (context->getState().getBlendState().allChannelsMasked())
1353     {
1354         mask &= ~GL_COLOR_BUFFER_BIT;
1355     }
1356 
1357     // If depth write is disabled, don't attempt to clear depth.
1358     if (!context->getState().getDepthStencilState().depthMask)
1359     {
1360         mask &= ~GL_DEPTH_BUFFER_BIT;
1361     }
1362 
1363     // If all stencil bits are masked, don't attempt to clear stencil.
1364     if (context->getState().getDepthStencilState().stencilWritemask == 0)
1365     {
1366         mask &= ~GL_STENCIL_BUFFER_BIT;
1367     }
1368 
1369     if (mask != 0)
1370     {
1371         ANGLE_TRY(mImpl->clear(context, mask));
1372     }
1373 
1374     return angle::Result::Continue;
1375 }
1376 
clearBufferfv(const Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)1377 angle::Result Framebuffer::clearBufferfv(const Context *context,
1378                                          GLenum buffer,
1379                                          GLint drawbuffer,
1380                                          const GLfloat *values)
1381 {
1382     if (context->getState().isRasterizerDiscardEnabled() || IsClearBufferMaskedOut(context, buffer))
1383     {
1384         return angle::Result::Continue;
1385     }
1386 
1387     if (buffer == GL_DEPTH)
1388     {
1389         // If depth write is disabled, don't attempt to clear depth.
1390         if (!context->getState().getDepthStencilState().depthMask)
1391         {
1392             return angle::Result::Continue;
1393         }
1394     }
1395     else
1396     {
1397         // If all color channels are masked, don't attempt to clear color.
1398         if (context->getState().getBlendState().allChannelsMasked())
1399         {
1400             return angle::Result::Continue;
1401         }
1402     }
1403 
1404     ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1405 
1406     return angle::Result::Continue;
1407 }
1408 
clearBufferuiv(const Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)1409 angle::Result Framebuffer::clearBufferuiv(const Context *context,
1410                                           GLenum buffer,
1411                                           GLint drawbuffer,
1412                                           const GLuint *values)
1413 {
1414     if (context->getState().isRasterizerDiscardEnabled() || IsClearBufferMaskedOut(context, buffer))
1415     {
1416         return angle::Result::Continue;
1417     }
1418 
1419     // If all color channels are masked, don't attempt to clear color.
1420     if (context->getState().getBlendState().allChannelsMasked())
1421     {
1422         return angle::Result::Continue;
1423     }
1424 
1425     ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1426 
1427     return angle::Result::Continue;
1428 }
1429 
clearBufferiv(const Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)1430 angle::Result Framebuffer::clearBufferiv(const Context *context,
1431                                          GLenum buffer,
1432                                          GLint drawbuffer,
1433                                          const GLint *values)
1434 {
1435     if (context->getState().isRasterizerDiscardEnabled() || IsClearBufferMaskedOut(context, buffer))
1436     {
1437         return angle::Result::Continue;
1438     }
1439 
1440     if (buffer == GL_STENCIL)
1441     {
1442         // If all stencil bits are masked, don't attempt to clear stencil.
1443         if (context->getState().getDepthStencilState().stencilWritemask == 0)
1444         {
1445             return angle::Result::Continue;
1446         }
1447     }
1448     else
1449     {
1450         // If all color channels are masked, don't attempt to clear color.
1451         if (context->getState().getBlendState().allChannelsMasked())
1452         {
1453             return angle::Result::Continue;
1454         }
1455     }
1456 
1457     ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1458 
1459     return angle::Result::Continue;
1460 }
1461 
clearBufferfi(const Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)1462 angle::Result Framebuffer::clearBufferfi(const Context *context,
1463                                          GLenum buffer,
1464                                          GLint drawbuffer,
1465                                          GLfloat depth,
1466                                          GLint stencil)
1467 {
1468     if (context->getState().isRasterizerDiscardEnabled() || IsClearBufferMaskedOut(context, buffer))
1469     {
1470         return angle::Result::Continue;
1471     }
1472 
1473     bool clearDepth   = context->getState().getDepthStencilState().depthMask;
1474     bool clearStencil = context->getState().getDepthStencilState().stencilWritemask != 0;
1475 
1476     if (clearDepth && clearStencil)
1477     {
1478         ASSERT(buffer == GL_DEPTH_STENCIL);
1479         ANGLE_TRY(mImpl->clearBufferfi(context, GL_DEPTH_STENCIL, drawbuffer, depth, stencil));
1480     }
1481     else if (clearDepth && !clearStencil)
1482     {
1483         ANGLE_TRY(mImpl->clearBufferfv(context, GL_DEPTH, drawbuffer, &depth));
1484     }
1485     else if (!clearDepth && clearStencil)
1486     {
1487         ANGLE_TRY(mImpl->clearBufferiv(context, GL_STENCIL, drawbuffer, &stencil));
1488     }
1489 
1490     return angle::Result::Continue;
1491 }
1492 
getImplementationColorReadFormat(const Context * context,GLenum * formatOut)1493 angle::Result Framebuffer::getImplementationColorReadFormat(const Context *context,
1494                                                             GLenum *formatOut)
1495 {
1496     ANGLE_TRY(syncState(context));
1497     *formatOut = mImpl->getImplementationColorReadFormat(context);
1498     return angle::Result::Continue;
1499 }
1500 
getImplementationColorReadType(const Context * context,GLenum * typeOut)1501 angle::Result Framebuffer::getImplementationColorReadType(const Context *context, GLenum *typeOut)
1502 {
1503     ANGLE_TRY(syncState(context));
1504     *typeOut = mImpl->getImplementationColorReadType(context);
1505     return angle::Result::Continue;
1506 }
1507 
readPixels(const Context * context,const Rectangle & area,GLenum format,GLenum type,void * pixels)1508 angle::Result Framebuffer::readPixels(const Context *context,
1509                                       const Rectangle &area,
1510                                       GLenum format,
1511                                       GLenum type,
1512                                       void *pixels)
1513 {
1514     ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
1515 
1516     Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1517     if (unpackBuffer)
1518     {
1519         unpackBuffer->onDataChanged();
1520     }
1521 
1522     return angle::Result::Continue;
1523 }
1524 
blit(const Context * context,const Rectangle & sourceArea,const Rectangle & destArea,GLbitfield mask,GLenum filter)1525 angle::Result Framebuffer::blit(const Context *context,
1526                                 const Rectangle &sourceArea,
1527                                 const Rectangle &destArea,
1528                                 GLbitfield mask,
1529                                 GLenum filter)
1530 {
1531     GLbitfield blitMask = mask;
1532 
1533     // Note that blitting is called against draw framebuffer.
1534     // See the code in gl::Context::blitFramebuffer.
1535     if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1536     {
1537         blitMask &= ~GL_COLOR_BUFFER_BIT;
1538     }
1539 
1540     if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1541     {
1542         blitMask &= ~GL_STENCIL_BUFFER_BIT;
1543     }
1544 
1545     if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1546     {
1547         blitMask &= ~GL_DEPTH_BUFFER_BIT;
1548     }
1549 
1550     if (!blitMask)
1551     {
1552         return angle::Result::Continue;
1553     }
1554 
1555     return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
1556 }
1557 
isDefault() const1558 bool Framebuffer::isDefault() const
1559 {
1560     return id() == 0;
1561 }
1562 
getSamples(const Context * context)1563 int Framebuffer::getSamples(const Context *context)
1564 {
1565     return (isComplete(context) ? getCachedSamples(context) : 0);
1566 }
1567 
getCachedSamples(const Context * context) const1568 int Framebuffer::getCachedSamples(const Context *context) const
1569 {
1570     ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
1571 
1572     // For a complete framebuffer, all attachments must have the same sample count.
1573     // In this case return the first nonzero sample size.
1574     const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1575     if (firstNonNullAttachment)
1576     {
1577         ASSERT(firstNonNullAttachment->isAttached());
1578         return firstNonNullAttachment->getSamples();
1579     }
1580 
1581     // No attachments found.
1582     return 0;
1583 }
1584 
getSamplePosition(const Context * context,size_t index,GLfloat * xy) const1585 angle::Result Framebuffer::getSamplePosition(const Context *context,
1586                                              size_t index,
1587                                              GLfloat *xy) const
1588 {
1589     ANGLE_TRY(mImpl->getSamplePosition(context, index, xy));
1590     return angle::Result::Continue;
1591 }
1592 
hasValidDepthStencil() const1593 bool Framebuffer::hasValidDepthStencil() const
1594 {
1595     return mState.getDepthStencilAttachment() != nullptr;
1596 }
1597 
setAttachment(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource)1598 void Framebuffer::setAttachment(const Context *context,
1599                                 GLenum type,
1600                                 GLenum binding,
1601                                 const ImageIndex &textureIndex,
1602                                 FramebufferAttachmentObject *resource)
1603 {
1604     setAttachment(context, type, binding, textureIndex, resource,
1605                   FramebufferAttachment::kDefaultNumViews,
1606                   FramebufferAttachment::kDefaultBaseViewIndex, false);
1607 }
1608 
setAttachment(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLuint baseViewIndex,bool isMultiview)1609 void Framebuffer::setAttachment(const Context *context,
1610                                 GLenum type,
1611                                 GLenum binding,
1612                                 const ImageIndex &textureIndex,
1613                                 FramebufferAttachmentObject *resource,
1614                                 GLsizei numViews,
1615                                 GLuint baseViewIndex,
1616                                 bool isMultiview)
1617 {
1618     // Context may be null in unit tests.
1619     if (!context || !context->isWebGL1())
1620     {
1621         setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1622                           isMultiview);
1623         return;
1624     }
1625 
1626     switch (binding)
1627     {
1628         case GL_DEPTH_STENCIL:
1629         case GL_DEPTH_STENCIL_ATTACHMENT:
1630             mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
1631                                                        resource, numViews, baseViewIndex,
1632                                                        isMultiview);
1633             break;
1634         case GL_DEPTH:
1635         case GL_DEPTH_ATTACHMENT:
1636             mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1637                                                 numViews, baseViewIndex, isMultiview);
1638             break;
1639         case GL_STENCIL:
1640         case GL_STENCIL_ATTACHMENT:
1641             mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1642                                                   numViews, baseViewIndex, isMultiview);
1643             break;
1644         default:
1645             setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1646                               baseViewIndex, isMultiview);
1647             return;
1648     }
1649 
1650     commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, isMultiview);
1651 }
1652 
setAttachmentMultiview(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLint baseViewIndex)1653 void Framebuffer::setAttachmentMultiview(const Context *context,
1654                                          GLenum type,
1655                                          GLenum binding,
1656                                          const ImageIndex &textureIndex,
1657                                          FramebufferAttachmentObject *resource,
1658                                          GLsizei numViews,
1659                                          GLint baseViewIndex)
1660 {
1661     setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex, true);
1662 }
1663 
commitWebGL1DepthStencilIfConsistent(const Context * context,GLsizei numViews,GLuint baseViewIndex,bool isMultiview)1664 void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1665                                                        GLsizei numViews,
1666                                                        GLuint baseViewIndex,
1667                                                        bool isMultiview)
1668 {
1669     int count = 0;
1670 
1671     std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1672                                                            &mState.mWebGLDepthAttachment,
1673                                                            &mState.mWebGLStencilAttachment}};
1674     for (FramebufferAttachment *attachment : attachments)
1675     {
1676         if (attachment->isAttached())
1677         {
1678             count++;
1679         }
1680     }
1681 
1682     mState.mWebGLDepthStencilConsistent = (count <= 1);
1683     if (!mState.mWebGLDepthStencilConsistent)
1684     {
1685         // Inconsistent.
1686         return;
1687     }
1688 
1689     auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1690         if (attachment.type() == GL_TEXTURE)
1691         {
1692             return attachment.getTextureImageIndex();
1693         }
1694         else
1695         {
1696             return ImageIndex();
1697         }
1698     };
1699 
1700     if (mState.mWebGLDepthAttachment.isAttached())
1701     {
1702         const auto &depth = mState.mWebGLDepthAttachment;
1703         setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
1704                           getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1705                           baseViewIndex, isMultiview);
1706         setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1707                           baseViewIndex, isMultiview);
1708     }
1709     else if (mState.mWebGLStencilAttachment.isAttached())
1710     {
1711         const auto &stencil = mState.mWebGLStencilAttachment;
1712         setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1713                           baseViewIndex, isMultiview);
1714         setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
1715                           getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1716                           numViews, baseViewIndex, isMultiview);
1717     }
1718     else if (mState.mWebGLDepthStencilAttachment.isAttached())
1719     {
1720         const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
1721         setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
1722                           getImageIndexIfTextureAttachment(depthStencil),
1723                           depthStencil.getResource(), numViews, baseViewIndex, isMultiview);
1724         setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
1725                           getImageIndexIfTextureAttachment(depthStencil),
1726                           depthStencil.getResource(), numViews, baseViewIndex, isMultiview);
1727     }
1728     else
1729     {
1730         setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1731                           baseViewIndex, isMultiview);
1732         setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1733                           baseViewIndex, isMultiview);
1734     }
1735 }
1736 
setAttachmentImpl(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLuint baseViewIndex,bool isMultiview)1737 void Framebuffer::setAttachmentImpl(const Context *context,
1738                                     GLenum type,
1739                                     GLenum binding,
1740                                     const ImageIndex &textureIndex,
1741                                     FramebufferAttachmentObject *resource,
1742                                     GLsizei numViews,
1743                                     GLuint baseViewIndex,
1744                                     bool isMultiview)
1745 {
1746     switch (binding)
1747     {
1748         case GL_DEPTH_STENCIL:
1749         case GL_DEPTH_STENCIL_ATTACHMENT:
1750         {
1751             // ensure this is a legitimate depth+stencil format
1752             FramebufferAttachmentObject *attachmentObj = resource;
1753             if (resource)
1754             {
1755                 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
1756                 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1757                 {
1758                     // Attaching nullptr detaches the current attachment.
1759                     attachmentObj = nullptr;
1760                 }
1761             }
1762 
1763             updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1764                              &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
1765                              attachmentObj, numViews, baseViewIndex, isMultiview);
1766             updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1767                              &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1768                              attachmentObj, numViews, baseViewIndex, isMultiview);
1769             break;
1770         }
1771 
1772         case GL_DEPTH:
1773         case GL_DEPTH_ATTACHMENT:
1774             updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1775                              &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1776                              numViews, baseViewIndex, isMultiview);
1777             break;
1778 
1779         case GL_STENCIL:
1780         case GL_STENCIL_ATTACHMENT:
1781             updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1782                              &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1783                              numViews, baseViewIndex, isMultiview);
1784             break;
1785 
1786         case GL_BACK:
1787             updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1788                              &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1789                              resource, numViews, baseViewIndex, isMultiview);
1790             break;
1791 
1792         default:
1793         {
1794             size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1795             ASSERT(colorIndex < mState.mColorAttachments.size());
1796             size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
1797             updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
1798                              &mDirtyColorAttachmentBindings[colorIndex], type, binding,
1799                              textureIndex, resource, numViews, baseViewIndex, isMultiview);
1800 
1801             if (!resource)
1802             {
1803                 mColorAttachmentBits.reset(colorIndex);
1804                 mFloat32ColorAttachmentBits.reset(colorIndex);
1805             }
1806             else
1807             {
1808                 mColorAttachmentBits.set(colorIndex);
1809                 updateFloat32ColorAttachmentBits(
1810                     colorIndex, resource->getAttachmentFormat(binding, textureIndex).info);
1811             }
1812 
1813             // TODO(jmadill): ASSERT instead of checking the attachment exists in
1814             // formsRenderingFeedbackLoopWith
1815             bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1816             mState.mEnabledDrawBuffers.set(colorIndex, enabled);
1817             SetComponentTypeMask(getDrawbufferWriteType(colorIndex), colorIndex,
1818                                  &mState.mDrawBufferTypeMask);
1819         }
1820         break;
1821     }
1822 }
1823 
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)1824 void Framebuffer::updateAttachment(const Context *context,
1825                                    FramebufferAttachment *attachment,
1826                                    size_t dirtyBit,
1827                                    angle::ObserverBinding *onDirtyBinding,
1828                                    GLenum type,
1829                                    GLenum binding,
1830                                    const ImageIndex &textureIndex,
1831                                    FramebufferAttachmentObject *resource,
1832                                    GLsizei numViews,
1833                                    GLuint baseViewIndex,
1834                                    bool isMultiview)
1835 {
1836     attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1837                        isMultiview);
1838     mDirtyBits.set(dirtyBit);
1839     mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
1840     onDirtyBinding->bind(resource);
1841 
1842     invalidateCompletenessCache();
1843 }
1844 
resetAttachment(const Context * context,GLenum binding)1845 void Framebuffer::resetAttachment(const Context *context, GLenum binding)
1846 {
1847     setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr);
1848 }
1849 
syncState(const Context * context)1850 angle::Result Framebuffer::syncState(const Context *context)
1851 {
1852     if (mDirtyBits.any())
1853     {
1854         mDirtyBitsGuard = mDirtyBits;
1855         ANGLE_TRY(mImpl->syncState(context, mDirtyBits));
1856         mDirtyBits.reset();
1857         mDirtyBitsGuard.reset();
1858     }
1859     return angle::Result::Continue;
1860 }
1861 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1862 void Framebuffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1863 {
1864     if (message != angle::SubjectMessage::SubjectChanged)
1865     {
1866         // This can be triggered by SubImage calls for Textures.
1867         if (message == angle::SubjectMessage::ContentsChanged)
1868         {
1869             mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 + index);
1870             onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1871             return;
1872         }
1873 
1874         // This can be triggered by the GL back-end TextureGL class.
1875         ASSERT(message == angle::SubjectMessage::DirtyBitsFlagged);
1876         return;
1877     }
1878 
1879     ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
1880     mDirtyBits.set(index);
1881 
1882     invalidateCompletenessCache();
1883 
1884     FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
1885 
1886     // Mark the appropriate init flag.
1887     mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
1888 
1889     // Update mFloat32ColorAttachmentBits Cache
1890     if (index < DIRTY_BIT_COLOR_ATTACHMENT_MAX)
1891     {
1892         ASSERT(index != DIRTY_BIT_DEPTH_ATTACHMENT);
1893         ASSERT(index != DIRTY_BIT_STENCIL_ATTACHMENT);
1894         updateFloat32ColorAttachmentBits(index - DIRTY_BIT_COLOR_ATTACHMENT_0,
1895                                          attachment->getFormat().info);
1896     }
1897 }
1898 
getAttachmentFromSubjectIndex(angle::SubjectIndex index)1899 FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
1900 {
1901     switch (index)
1902     {
1903         case DIRTY_BIT_DEPTH_ATTACHMENT:
1904             return &mState.mDepthAttachment;
1905         case DIRTY_BIT_STENCIL_ATTACHMENT:
1906             return &mState.mStencilAttachment;
1907         default:
1908             size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
1909             ASSERT(colorIndex < mState.mColorAttachments.size());
1910             return &mState.mColorAttachments[colorIndex];
1911     }
1912 }
1913 
formsRenderingFeedbackLoopWith(const Context * context) const1914 bool Framebuffer::formsRenderingFeedbackLoopWith(const Context *context) const
1915 {
1916     const State &state     = context->getState();
1917     const Program *program = state.getProgram();
1918 
1919     // TODO(jmadill): Default framebuffer feedback loops.
1920     if (mState.mId == 0)
1921     {
1922         return false;
1923     }
1924 
1925     const FramebufferAttachment *depth   = getDepthAttachment();
1926     const FramebufferAttachment *stencil = getStencilAttachment();
1927 
1928     const bool checkDepth = depth && depth->type() == GL_TEXTURE;
1929     // Skip the feedback loop check for stencil if depth/stencil point to the same resource.
1930     const bool checkStencil =
1931         (stencil && stencil->type() == GL_TEXTURE) && (!depth || *stencil != *depth);
1932 
1933     const gl::ActiveTextureMask &activeTextures   = program->getActiveSamplersMask();
1934     const gl::ActiveTexturePointerArray &textures = state.getActiveTexturesCache();
1935 
1936     for (size_t textureUnit : activeTextures)
1937     {
1938         Texture *texture = textures[textureUnit];
1939 
1940         if (texture == nullptr)
1941         {
1942             continue;
1943         }
1944 
1945         // Depth and stencil attachment form feedback loops
1946         // Regardless of if enabled or masked.
1947         if (checkDepth)
1948         {
1949             if (texture->id() == depth->id())
1950             {
1951                 return true;
1952             }
1953         }
1954 
1955         if (checkStencil)
1956         {
1957             if (texture->id() == stencil->id())
1958             {
1959                 return true;
1960             }
1961         }
1962 
1963         // Check if any color attachment forms a feedback loop.
1964         for (size_t drawIndex : mColorAttachmentBits)
1965         {
1966             const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1967             ASSERT(attachment.isAttached());
1968 
1969             if (attachment.isTextureWithId(texture->id()))
1970             {
1971                 // TODO(jmadill): Check for appropriate overlap.
1972                 return true;
1973             }
1974         }
1975     }
1976 
1977     return false;
1978 }
1979 
formsCopyingFeedbackLoopWith(GLuint copyTextureID,GLint copyTextureLevel,GLint copyTextureLayer) const1980 bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1981                                                GLint copyTextureLevel,
1982                                                GLint copyTextureLayer) const
1983 {
1984     if (mState.mId == 0)
1985     {
1986         // It seems impossible to form a texture copying feedback loop with the default FBO.
1987         return false;
1988     }
1989 
1990     const FramebufferAttachment *readAttachment = getReadColorAttachment();
1991     ASSERT(readAttachment);
1992 
1993     if (readAttachment->isTextureWithId(copyTextureID))
1994     {
1995         const auto &imageIndex = readAttachment->getTextureImageIndex();
1996         if (imageIndex.getLevelIndex() == copyTextureLevel)
1997         {
1998             // Check 3D/Array texture layers.
1999             return !imageIndex.hasLayer() || copyTextureLayer == ImageIndex::kEntireLevel ||
2000                    imageIndex.getLayerIndex() == copyTextureLayer;
2001         }
2002     }
2003     return false;
2004 }
2005 
getDefaultWidth() const2006 GLint Framebuffer::getDefaultWidth() const
2007 {
2008     return mState.getDefaultWidth();
2009 }
2010 
getDefaultHeight() const2011 GLint Framebuffer::getDefaultHeight() const
2012 {
2013     return mState.getDefaultHeight();
2014 }
2015 
getDefaultSamples() const2016 GLint Framebuffer::getDefaultSamples() const
2017 {
2018     return mState.getDefaultSamples();
2019 }
2020 
getDefaultFixedSampleLocations() const2021 bool Framebuffer::getDefaultFixedSampleLocations() const
2022 {
2023     return mState.getDefaultFixedSampleLocations();
2024 }
2025 
getDefaultLayers() const2026 GLint Framebuffer::getDefaultLayers() const
2027 {
2028     return mState.getDefaultLayers();
2029 }
2030 
setDefaultWidth(const Context * context,GLint defaultWidth)2031 void Framebuffer::setDefaultWidth(const Context *context, GLint defaultWidth)
2032 {
2033     mState.mDefaultWidth = defaultWidth;
2034     mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
2035     invalidateCompletenessCache();
2036 }
2037 
setDefaultHeight(const Context * context,GLint defaultHeight)2038 void Framebuffer::setDefaultHeight(const Context *context, GLint defaultHeight)
2039 {
2040     mState.mDefaultHeight = defaultHeight;
2041     mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
2042     invalidateCompletenessCache();
2043 }
2044 
setDefaultSamples(const Context * context,GLint defaultSamples)2045 void Framebuffer::setDefaultSamples(const Context *context, GLint defaultSamples)
2046 {
2047     mState.mDefaultSamples = defaultSamples;
2048     mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
2049     invalidateCompletenessCache();
2050 }
2051 
setDefaultFixedSampleLocations(const Context * context,bool defaultFixedSampleLocations)2052 void Framebuffer::setDefaultFixedSampleLocations(const Context *context,
2053                                                  bool defaultFixedSampleLocations)
2054 {
2055     mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
2056     mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
2057     invalidateCompletenessCache();
2058 }
2059 
setDefaultLayers(GLint defaultLayers)2060 void Framebuffer::setDefaultLayers(GLint defaultLayers)
2061 {
2062     mState.mDefaultLayers = defaultLayers;
2063     mDirtyBits.set(DIRTY_BIT_DEFAULT_LAYERS);
2064 }
2065 
getNumViews() const2066 GLsizei Framebuffer::getNumViews() const
2067 {
2068     return mState.getNumViews();
2069 }
2070 
getBaseViewIndex() const2071 GLint Framebuffer::getBaseViewIndex() const
2072 {
2073     return mState.getBaseViewIndex();
2074 }
2075 
isMultiview() const2076 bool Framebuffer::isMultiview() const
2077 {
2078     return mState.isMultiview();
2079 }
2080 
readDisallowedByMultiview() const2081 bool Framebuffer::readDisallowedByMultiview() const
2082 {
2083     return (mState.isMultiview() && mState.getNumViews() > 1);
2084 }
2085 
ensureClearAttachmentsInitialized(const Context * context,GLbitfield mask)2086 angle::Result Framebuffer::ensureClearAttachmentsInitialized(const Context *context,
2087                                                              GLbitfield mask)
2088 {
2089     const auto &glState = context->getState();
2090     if (!context->isRobustResourceInitEnabled() || glState.isRasterizerDiscardEnabled())
2091     {
2092         return angle::Result::Continue;
2093     }
2094 
2095     const BlendState &blend               = glState.getBlendState();
2096     const DepthStencilState &depthStencil = glState.getDepthStencilState();
2097 
2098     bool color   = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
2099     bool depth   = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
2100     bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
2101 
2102     if (!color && !depth && !stencil)
2103     {
2104         return angle::Result::Continue;
2105     }
2106 
2107     if (partialClearNeedsInit(context, color, depth, stencil))
2108     {
2109         ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
2110     }
2111 
2112     // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2113     // still be marked initialized. This simplifies design, allowing this method to be called before
2114     // the clear.
2115     markDrawAttachmentsInitialized(color, depth, stencil);
2116 
2117     return angle::Result::Continue;
2118 }
2119 
ensureClearBufferAttachmentsInitialized(const Context * context,GLenum buffer,GLint drawbuffer)2120 angle::Result Framebuffer::ensureClearBufferAttachmentsInitialized(const Context *context,
2121                                                                    GLenum buffer,
2122                                                                    GLint drawbuffer)
2123 {
2124     if (!context->isRobustResourceInitEnabled() ||
2125         context->getState().isRasterizerDiscardEnabled() || IsClearBufferMaskedOut(context, buffer))
2126     {
2127         return angle::Result::Continue;
2128     }
2129 
2130     if (partialBufferClearNeedsInit(context, buffer))
2131     {
2132         ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
2133     }
2134 
2135     // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2136     // still be marked initialized. This simplifies design, allowing this method to be called before
2137     // the clear.
2138     markBufferInitialized(buffer, drawbuffer);
2139 
2140     return angle::Result::Continue;
2141 }
2142 
ensureDrawAttachmentsInitialized(const Context * context)2143 angle::Result Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
2144 {
2145     if (!context->isRobustResourceInitEnabled())
2146     {
2147         return angle::Result::Continue;
2148     }
2149 
2150     // Note: we don't actually filter by the draw attachment enum. Just init everything.
2151     for (size_t bit : mState.mResourceNeedsInit)
2152     {
2153         switch (bit)
2154         {
2155             case DIRTY_BIT_DEPTH_ATTACHMENT:
2156                 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2157                 break;
2158             case DIRTY_BIT_STENCIL_ATTACHMENT:
2159                 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2160                 break;
2161             default:
2162                 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2163                 break;
2164         }
2165     }
2166 
2167     mState.mResourceNeedsInit.reset();
2168     return angle::Result::Continue;
2169 }
2170 
ensureReadAttachmentsInitialized(const Context * context)2171 angle::Result Framebuffer::ensureReadAttachmentsInitialized(const Context *context)
2172 {
2173     ASSERT(context->isRobustResourceInitEnabled());
2174 
2175     if (mState.mResourceNeedsInit.none())
2176     {
2177         return angle::Result::Continue;
2178     }
2179 
2180     if (mState.mReadBufferState != GL_NONE)
2181     {
2182         size_t readIndex = mState.getReadIndex();
2183         if (mState.mResourceNeedsInit[readIndex])
2184         {
2185             ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2186             mState.mResourceNeedsInit.reset(readIndex);
2187         }
2188     }
2189 
2190     // Conservatively init depth since it can be read by BlitFramebuffer.
2191     if (hasDepth())
2192     {
2193         if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2194         {
2195             ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2196             mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2197         }
2198     }
2199 
2200     // Conservatively init stencil since it can be read by BlitFramebuffer.
2201     if (hasStencil())
2202     {
2203         if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2204         {
2205             ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2206             mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2207         }
2208     }
2209 
2210     return angle::Result::Continue;
2211 }
2212 
markDrawAttachmentsInitialized(bool color,bool depth,bool stencil)2213 void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2214 {
2215     // Mark attachments as initialized.
2216     if (color)
2217     {
2218         for (auto colorIndex : mState.mEnabledDrawBuffers)
2219         {
2220             auto &colorAttachment = mState.mColorAttachments[colorIndex];
2221             ASSERT(colorAttachment.isAttached());
2222             colorAttachment.setInitState(InitState::Initialized);
2223             mState.mResourceNeedsInit.reset(colorIndex);
2224         }
2225     }
2226 
2227     if (depth && mState.mDepthAttachment.isAttached())
2228     {
2229         mState.mDepthAttachment.setInitState(InitState::Initialized);
2230         mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2231     }
2232 
2233     if (stencil && mState.mStencilAttachment.isAttached())
2234     {
2235         mState.mStencilAttachment.setInitState(InitState::Initialized);
2236         mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2237     }
2238 }
2239 
markBufferInitialized(GLenum bufferType,GLint bufferIndex)2240 void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2241 {
2242     switch (bufferType)
2243     {
2244         case GL_COLOR:
2245         {
2246             ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2247             if (mState.mColorAttachments[bufferIndex].isAttached())
2248             {
2249                 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2250                 mState.mResourceNeedsInit.reset(bufferIndex);
2251             }
2252             break;
2253         }
2254         case GL_DEPTH:
2255         {
2256             if (mState.mDepthAttachment.isAttached())
2257             {
2258                 mState.mDepthAttachment.setInitState(InitState::Initialized);
2259                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2260             }
2261             break;
2262         }
2263         case GL_STENCIL:
2264         {
2265             if (mState.mStencilAttachment.isAttached())
2266             {
2267                 mState.mStencilAttachment.setInitState(InitState::Initialized);
2268                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2269             }
2270             break;
2271         }
2272         case GL_DEPTH_STENCIL:
2273         {
2274             if (mState.mDepthAttachment.isAttached())
2275             {
2276                 mState.mDepthAttachment.setInitState(InitState::Initialized);
2277                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2278             }
2279             if (mState.mStencilAttachment.isAttached())
2280             {
2281                 mState.mStencilAttachment.setInitState(InitState::Initialized);
2282                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2283             }
2284             break;
2285         }
2286         default:
2287             UNREACHABLE();
2288             break;
2289     }
2290 }
2291 
getDimensions() const2292 Box Framebuffer::getDimensions() const
2293 {
2294     return mState.getDimensions();
2295 }
2296 
getExtents() const2297 Extents Framebuffer::getExtents() const
2298 {
2299     return mState.getExtents();
2300 }
2301 
ensureBufferInitialized(const Context * context,GLenum bufferType,GLint bufferIndex)2302 angle::Result Framebuffer::ensureBufferInitialized(const Context *context,
2303                                                    GLenum bufferType,
2304                                                    GLint bufferIndex)
2305 {
2306     ASSERT(context->isRobustResourceInitEnabled());
2307 
2308     if (mState.mResourceNeedsInit.none())
2309     {
2310         return angle::Result::Continue;
2311     }
2312 
2313     switch (bufferType)
2314     {
2315         case GL_COLOR:
2316         {
2317             ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2318             if (mState.mResourceNeedsInit[bufferIndex])
2319             {
2320                 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2321                 mState.mResourceNeedsInit.reset(bufferIndex);
2322             }
2323             break;
2324         }
2325         case GL_DEPTH:
2326         {
2327             if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2328             {
2329                 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2330                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2331             }
2332             break;
2333         }
2334         case GL_STENCIL:
2335         {
2336             if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2337             {
2338                 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2339                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2340             }
2341             break;
2342         }
2343         case GL_DEPTH_STENCIL:
2344         {
2345             if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2346             {
2347                 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2348                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2349             }
2350             if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2351             {
2352                 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2353                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2354             }
2355             break;
2356         }
2357         default:
2358             UNREACHABLE();
2359             break;
2360     }
2361 
2362     return angle::Result::Continue;
2363 }
2364 
partialBufferClearNeedsInit(const Context * context,GLenum bufferType)2365 bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2366 {
2367     if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2368     {
2369         return false;
2370     }
2371 
2372     switch (bufferType)
2373     {
2374         case GL_COLOR:
2375             return partialClearNeedsInit(context, true, false, false);
2376         case GL_DEPTH:
2377             return partialClearNeedsInit(context, false, true, false);
2378         case GL_STENCIL:
2379             return partialClearNeedsInit(context, false, false, true);
2380         case GL_DEPTH_STENCIL:
2381             return partialClearNeedsInit(context, false, true, true);
2382         default:
2383             UNREACHABLE();
2384             return false;
2385     }
2386 }
2387 }  // namespace gl
2388