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