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