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