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