• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9 
10 #include "libANGLE/Framebuffer.h"
11 
12 #include "common/Optional.h"
13 #include "common/bitset_utils.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Config.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Display.h"
18 #include "libANGLE/ErrorStrings.h"
19 #include "libANGLE/FramebufferAttachment.h"
20 #include "libANGLE/Renderbuffer.h"
21 #include "libANGLE/Surface.h"
22 #include "libANGLE/Texture.h"
23 #include "libANGLE/angletypes.h"
24 #include "libANGLE/formatutils.h"
25 #include "libANGLE/renderer/ContextImpl.h"
26 #include "libANGLE/renderer/FramebufferImpl.h"
27 #include "libANGLE/renderer/GLImplFactory.h"
28 #include "libANGLE/renderer/RenderbufferImpl.h"
29 #include "libANGLE/renderer/SurfaceImpl.h"
30 
31 using namespace angle;
32 
33 namespace gl
34 {
35 
36 namespace
37 {
38 
39 // Check the |checkAttachment| in reference to |firstAttachment| for the sake of multiview
40 // framebuffer completeness.
CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment * firstAttachment,const FramebufferAttachment * checkAttachment)41 FramebufferStatus CheckMultiviewStateMatchesForCompleteness(
42     const FramebufferAttachment *firstAttachment,
43     const FramebufferAttachment *checkAttachment)
44 {
45     ASSERT(firstAttachment && checkAttachment);
46     ASSERT(firstAttachment->isAttached() && checkAttachment->isAttached());
47 
48     if (firstAttachment->isMultiview() != checkAttachment->isMultiview())
49     {
50         return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
51                                              err::kFramebufferIncompleteMultiviewMismatch);
52     }
53     if (firstAttachment->getNumViews() != checkAttachment->getNumViews())
54     {
55         return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
56                                              err::kFramebufferIncompleteMultiviewViewsMismatch);
57     }
58     if (checkAttachment->getBaseViewIndex() + checkAttachment->getNumViews() >
59         checkAttachment->getSize().depth)
60     {
61         return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
62                                              err::kFramebufferIncompleteMultiviewBaseViewMismatch);
63     }
64 
65     return FramebufferStatus::Complete();
66 }
67 
CheckAttachmentCompleteness(const Context * context,const FramebufferAttachment & attachment)68 FramebufferStatus CheckAttachmentCompleteness(const Context *context,
69                                               const FramebufferAttachment &attachment)
70 {
71     ASSERT(attachment.isAttached());
72 
73     const Extents &size = attachment.getSize();
74     if (size.width == 0 || size.height == 0)
75     {
76         return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
77                                              err::kFramebufferIncompleteAttachmentZeroSize);
78     }
79 
80     if (!attachment.isRenderable(context))
81     {
82         return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
83                                              err::kFramebufferIncompleteAttachmentNotRenderable);
84     }
85 
86     if (attachment.type() == GL_TEXTURE)
87     {
88         // [EXT_geometry_shader] Section 9.4.1, "Framebuffer Completeness"
89         // If <image> is a three-dimensional texture or a two-dimensional array texture and the
90         // attachment is not layered, the selected layer is less than the depth or layer count,
91         // respectively, of the texture.
92         if (!attachment.isLayered())
93         {
94             if (attachment.layer() >= size.depth)
95             {
96                 return FramebufferStatus::Incomplete(
97                     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
98                     err::kFramebufferIncompleteAttachmentLayerGreaterThanDepth);
99             }
100         }
101         // If <image> is a three-dimensional texture or a two-dimensional array texture and the
102         // attachment is layered, the depth or layer count, respectively, of the texture is less
103         // than or equal to the value of MAX_FRAMEBUFFER_LAYERS_EXT.
104         else
105         {
106             if (size.depth >= context->getCaps().maxFramebufferLayers)
107             {
108                 return FramebufferStatus::Incomplete(
109                     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
110                     err::kFramebufferIncompleteAttachmentDepthGreaterThanMaxLayers);
111             }
112         }
113 
114         // ES3 specifies that cube map texture attachments must be cube complete.
115         // This language is missing from the ES2 spec, but we enforce it here because some
116         // desktop OpenGL drivers also enforce this validation.
117         // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
118         const Texture *texture = attachment.getTexture();
119         ASSERT(texture);
120         if (texture->getType() == TextureType::CubeMap &&
121             !texture->getTextureState().isCubeComplete())
122         {
123             return FramebufferStatus::Incomplete(
124                 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
125                 err::kFramebufferIncompleteAttachmentNotCubeComplete);
126         }
127 
128         if (!texture->getImmutableFormat())
129         {
130             GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
131 
132             // From the ES 3.0 spec, pg 213:
133             // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
134             // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
135             // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
136             // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
137             // the effective maximum texture level defined in the Mipmapping discussion of
138             // section 3.8.10.4.
139             if (attachmentMipLevel < texture->getBaseLevel() ||
140                 attachmentMipLevel > texture->getMipmapMaxLevel())
141             {
142                 return FramebufferStatus::Incomplete(
143                     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
144                     err::kFramebufferIncompleteAttachmentLevelOutOfBaseMaxLevelRange);
145             }
146 
147             // Form the ES 3.0 spec, pg 213/214:
148             // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
149             // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
150             // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
151             // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
152             // a cubemap texture, the texture must also be cube complete.
153             if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
154             {
155                 return FramebufferStatus::Incomplete(
156                     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
157                     err::kFramebufferIncompleteAttachmentLevelNotBaseLevelForIncompleteMipTexture);
158             }
159         }
160     }
161 
162     return FramebufferStatus::Complete();
163 }
164 
CheckAttachmentSampleCounts(const Context * context,GLsizei currAttachmentSamples,GLsizei samples,bool colorAttachment)165 FramebufferStatus CheckAttachmentSampleCounts(const Context *context,
166                                               GLsizei currAttachmentSamples,
167                                               GLsizei samples,
168                                               bool colorAttachment)
169 {
170     if (currAttachmentSamples != samples)
171     {
172         if (colorAttachment)
173         {
174             // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
175             // all color attachments have the same number of samples for the FBO to be complete.
176             return FramebufferStatus::Incomplete(
177                 GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
178                 err::kFramebufferIncompleteMultisampleInconsistentSampleCounts);
179         }
180         else
181         {
182             // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
183             // when its depth or stencil samples are a multiple of the number of color samples.
184             if (!context->getExtensions().framebufferMixedSamplesCHROMIUM)
185             {
186                 return FramebufferStatus::Incomplete(
187                     GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
188                     err::kFramebufferIncompleteMultisampleInconsistentSampleCounts);
189             }
190 
191             if ((currAttachmentSamples % std::max(samples, 1)) != 0)
192             {
193                 return FramebufferStatus::Incomplete(
194                     GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
195                     err::
196                         kFramebufferIncompleteMultisampleDepthStencilSampleCountDivisibleByColorSampleCount);
197             }
198         }
199     }
200 
201     return FramebufferStatus::Complete();
202 }
203 
CheckAttachmentSampleCompleteness(const Context * context,const FramebufferAttachment & attachment,bool colorAttachment,Optional<int> * samples,Optional<bool> * fixedSampleLocations,Optional<int> * renderToTextureSamples)204 FramebufferStatus CheckAttachmentSampleCompleteness(const Context *context,
205                                                     const FramebufferAttachment &attachment,
206                                                     bool colorAttachment,
207                                                     Optional<int> *samples,
208                                                     Optional<bool> *fixedSampleLocations,
209                                                     Optional<int> *renderToTextureSamples)
210 {
211     ASSERT(attachment.isAttached());
212 
213     if (attachment.type() == GL_TEXTURE)
214     {
215         const Texture *texture = attachment.getTexture();
216         ASSERT(texture);
217         GLenum sizedInternalFormat    = attachment.getFormat().info->sizedInternalFormat;
218         const TextureCaps &formatCaps = context->getTextureCaps().get(sizedInternalFormat);
219         if (static_cast<GLuint>(attachment.getSamples()) > formatCaps.getMaxSamples())
220         {
221             return FramebufferStatus::Incomplete(
222                 GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
223                 err::kFramebufferIncompleteAttachmentSamplesGreaterThanMaxSupportedSamples);
224         }
225 
226         const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
227         bool fixedSampleloc = texture->getAttachmentFixedSampleLocations(attachmentImageIndex);
228         if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
229         {
230             return FramebufferStatus::Incomplete(
231                 GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
232                 err::kFramebufferIncompleteMultisampleInconsistentFixedSampleLocations);
233         }
234         else
235         {
236             *fixedSampleLocations = fixedSampleloc;
237         }
238     }
239 
240     if (renderToTextureSamples->valid())
241     {
242         // Only check against RenderToTextureSamples if they actually exist.
243         if (renderToTextureSamples->value() !=
244             FramebufferAttachment::kDefaultRenderToTextureSamples)
245         {
246             FramebufferStatus sampleCountStatus =
247                 CheckAttachmentSampleCounts(context, attachment.getRenderToTextureSamples(),
248                                             renderToTextureSamples->value(), colorAttachment);
249             if (!sampleCountStatus.isComplete())
250             {
251                 return sampleCountStatus;
252             }
253         }
254     }
255     else
256     {
257         *renderToTextureSamples = attachment.getRenderToTextureSamples();
258     }
259 
260     if (samples->valid())
261     {
262         // RenderToTextureSamples takes precedence if they exist.
263         if (renderToTextureSamples->value() ==
264             FramebufferAttachment::kDefaultRenderToTextureSamples)
265         {
266 
267             FramebufferStatus sampleCountStatus = CheckAttachmentSampleCounts(
268                 context, attachment.getSamples(), samples->value(), colorAttachment);
269             if (!sampleCountStatus.isComplete())
270             {
271                 return sampleCountStatus;
272             }
273         }
274     }
275     else
276     {
277         *samples = attachment.getSamples();
278     }
279 
280     return FramebufferStatus::Complete();
281 }
282 
283 // Needed to index into the attachment arrays/bitsets.
284 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_DRAW_BUFFERS) ==
285                   Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
286               "Framebuffer Dirty bit mismatch");
287 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_DRAW_BUFFERS) ==
288                   Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
289               "Framebuffer Dirty bit mismatch");
290 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_DRAW_BUFFERS + 1) ==
291                   Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
292               "Framebuffer Dirty bit mismatch");
293 
InitAttachment(const Context * context,FramebufferAttachment * attachment)294 angle::Result InitAttachment(const Context *context, FramebufferAttachment *attachment)
295 {
296     ASSERT(attachment->isAttached());
297     if (attachment->initState() == InitState::MayNeedInit)
298     {
299         ANGLE_TRY(attachment->initializeContents(context));
300     }
301     return angle::Result::Continue;
302 }
303 
AttachmentOverlapsWithTexture(const FramebufferAttachment & attachment,const Texture * texture,const Sampler * sampler)304 bool AttachmentOverlapsWithTexture(const FramebufferAttachment &attachment,
305                                    const Texture *texture,
306                                    const Sampler *sampler)
307 {
308     if (!attachment.isTextureWithId(texture->id()))
309     {
310         return false;
311     }
312 
313     const gl::ImageIndex &index      = attachment.getTextureImageIndex();
314     GLuint attachmentLevel           = static_cast<GLuint>(index.getLevelIndex());
315     GLuint textureEffectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
316     GLuint textureMaxLevel           = textureEffectiveBaseLevel;
317     if ((sampler && IsMipmapFiltered(sampler->getSamplerState().getMinFilter())) ||
318         IsMipmapFiltered(texture->getSamplerState().getMinFilter()))
319     {
320         textureMaxLevel = texture->getMipmapMaxLevel();
321     }
322 
323     return attachmentLevel >= textureEffectiveBaseLevel && attachmentLevel <= textureMaxLevel;
324 }
325 
326 }  // anonymous namespace
327 
isComplete() const328 bool FramebufferStatus::isComplete() const
329 {
330     return status == GL_FRAMEBUFFER_COMPLETE;
331 }
332 
Complete()333 FramebufferStatus FramebufferStatus::Complete()
334 {
335     FramebufferStatus result;
336     result.status = GL_FRAMEBUFFER_COMPLETE;
337     result.reason = nullptr;
338     return result;
339 }
340 
Incomplete(GLenum status,const char * reason)341 FramebufferStatus FramebufferStatus::Incomplete(GLenum status, const char *reason)
342 {
343     ASSERT(status != GL_FRAMEBUFFER_COMPLETE);
344 
345     FramebufferStatus result;
346     result.status = status;
347     result.reason = reason;
348     return result;
349 }
350 
351 // This constructor is only used for default framebuffers.
FramebufferState(rx::Serial serial)352 FramebufferState::FramebufferState(rx::Serial serial)
353     : mId(Framebuffer::kDefaultDrawFramebufferHandle),
354       mFramebufferSerial(serial),
355       mLabel(),
356       mColorAttachments(1),
357       mColorAttachmentsMask(0),
358       mDrawBufferStates(1, GL_BACK),
359       mReadBufferState(GL_BACK),
360       mDrawBufferTypeMask(),
361       mDefaultWidth(0),
362       mDefaultHeight(0),
363       mDefaultSamples(0),
364       mDefaultFixedSampleLocations(GL_FALSE),
365       mDefaultLayers(0),
366       mWebGLDepthStencilConsistent(true),
367       mDefaultFramebufferReadAttachmentInitialized(false),
368       mSrgbWriteControlMode(SrgbWriteControlMode::Default)
369 {
370     ASSERT(mDrawBufferStates.size() > 0);
371     mEnabledDrawBuffers.set(0);
372 }
373 
FramebufferState(const Caps & caps,FramebufferID id,rx::Serial serial)374 FramebufferState::FramebufferState(const Caps &caps, FramebufferID id, rx::Serial serial)
375     : mId(id),
376       mFramebufferSerial(serial),
377       mLabel(),
378       mColorAttachments(caps.maxColorAttachments),
379       mColorAttachmentsMask(0),
380       mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
381       mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
382       mDrawBufferTypeMask(),
383       mDefaultWidth(0),
384       mDefaultHeight(0),
385       mDefaultSamples(0),
386       mDefaultFixedSampleLocations(GL_FALSE),
387       mDefaultLayers(0),
388       mWebGLDepthStencilConsistent(true),
389       mDefaultFramebufferReadAttachmentInitialized(false),
390       mSrgbWriteControlMode(SrgbWriteControlMode::Default)
391 {
392     ASSERT(mId != Framebuffer::kDefaultDrawFramebufferHandle);
393     ASSERT(mDrawBufferStates.size() > 0);
394     mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
395 }
396 
~FramebufferState()397 FramebufferState::~FramebufferState() {}
398 
getLabel() const399 const std::string &FramebufferState::getLabel() const
400 {
401     return mLabel;
402 }
403 
getAttachment(const Context * context,GLenum attachment) const404 const FramebufferAttachment *FramebufferState::getAttachment(const Context *context,
405                                                              GLenum attachment) const
406 {
407     if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
408     {
409         return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
410     }
411 
412     // WebGL1 allows a developer to query for attachment parameters even when "inconsistant" (i.e.
413     // multiple conflicting attachment points) and requires us to return the framebuffer attachment
414     // associated with WebGL.
415     switch (attachment)
416     {
417         case GL_COLOR:
418         case GL_BACK:
419             return getColorAttachment(0);
420         case GL_DEPTH:
421         case GL_DEPTH_ATTACHMENT:
422             if (context->isWebGL1())
423             {
424                 return getWebGLDepthAttachment();
425             }
426             else
427             {
428                 return getDepthAttachment();
429             }
430         case GL_STENCIL:
431         case GL_STENCIL_ATTACHMENT:
432             if (context->isWebGL1())
433             {
434                 return getWebGLStencilAttachment();
435             }
436             else
437             {
438                 return getStencilAttachment();
439             }
440         case GL_DEPTH_STENCIL:
441         case GL_DEPTH_STENCIL_ATTACHMENT:
442             if (context->isWebGL1())
443             {
444                 return getWebGLDepthStencilAttachment();
445             }
446             else
447             {
448                 return getDepthStencilAttachment();
449             }
450         default:
451             UNREACHABLE();
452             return nullptr;
453     }
454 }
455 
getReadIndex() const456 uint32_t FramebufferState::getReadIndex() const
457 {
458     ASSERT(mReadBufferState == GL_BACK ||
459            (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
460     uint32_t readIndex = mReadBufferState == GL_BACK ? 0 : mReadBufferState - GL_COLOR_ATTACHMENT0;
461     ASSERT(readIndex < mColorAttachments.size());
462     return readIndex;
463 }
464 
getReadAttachment() const465 const FramebufferAttachment *FramebufferState::getReadAttachment() const
466 {
467     if (mReadBufferState == GL_NONE)
468     {
469         return nullptr;
470     }
471 
472     uint32_t readIndex = getReadIndex();
473     const gl::FramebufferAttachment &framebufferAttachment =
474         isDefault() ? mDefaultFramebufferReadAttachment : mColorAttachments[readIndex];
475 
476     return framebufferAttachment.isAttached() ? &framebufferAttachment : nullptr;
477 }
478 
getReadPixelsAttachment(GLenum readFormat) const479 const FramebufferAttachment *FramebufferState::getReadPixelsAttachment(GLenum readFormat) const
480 {
481     switch (readFormat)
482     {
483         case GL_DEPTH_COMPONENT:
484             return getDepthAttachment();
485         case GL_STENCIL_INDEX_OES:
486             return getStencilOrDepthStencilAttachment();
487         default:
488             return getReadAttachment();
489     }
490 }
491 
getFirstNonNullAttachment() const492 const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
493 {
494     auto *colorAttachment = getFirstColorAttachment();
495     if (colorAttachment)
496     {
497         return colorAttachment;
498     }
499     return getDepthOrStencilAttachment();
500 }
501 
getFirstColorAttachment() const502 const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
503 {
504     for (const FramebufferAttachment &colorAttachment : mColorAttachments)
505     {
506         if (colorAttachment.isAttached())
507         {
508             return &colorAttachment;
509         }
510     }
511 
512     return nullptr;
513 }
514 
getDepthOrStencilAttachment() const515 const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
516 {
517     if (mDepthAttachment.isAttached())
518     {
519         return &mDepthAttachment;
520     }
521     if (mStencilAttachment.isAttached())
522     {
523         return &mStencilAttachment;
524     }
525     return nullptr;
526 }
527 
getStencilOrDepthStencilAttachment() const528 const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
529 {
530     if (mStencilAttachment.isAttached())
531     {
532         return &mStencilAttachment;
533     }
534     return getDepthStencilAttachment();
535 }
536 
getColorAttachment(size_t colorAttachment) const537 const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
538 {
539     ASSERT(colorAttachment < mColorAttachments.size());
540     return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
541                                                            : nullptr;
542 }
543 
getDepthAttachment() const544 const FramebufferAttachment *FramebufferState::getDepthAttachment() const
545 {
546     return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
547 }
548 
getWebGLDepthAttachment() const549 const FramebufferAttachment *FramebufferState::getWebGLDepthAttachment() const
550 {
551     return mWebGLDepthAttachment.isAttached() ? &mWebGLDepthAttachment : nullptr;
552 }
553 
getWebGLDepthStencilAttachment() const554 const FramebufferAttachment *FramebufferState::getWebGLDepthStencilAttachment() const
555 {
556     return mWebGLDepthStencilAttachment.isAttached() ? &mWebGLDepthStencilAttachment : nullptr;
557 }
558 
getStencilAttachment() const559 const FramebufferAttachment *FramebufferState::getStencilAttachment() const
560 {
561     return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
562 }
563 
getWebGLStencilAttachment() const564 const FramebufferAttachment *FramebufferState::getWebGLStencilAttachment() const
565 {
566     return mWebGLStencilAttachment.isAttached() ? &mWebGLStencilAttachment : nullptr;
567 }
568 
getDepthStencilAttachment() const569 const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
570 {
571     // A valid depth-stencil attachment has the same resource bound to both the
572     // depth and stencil attachment points.
573     if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
574         mDepthAttachment == mStencilAttachment)
575     {
576         return &mDepthAttachment;
577     }
578 
579     return nullptr;
580 }
581 
getAttachmentExtentsIntersection() const582 const Extents FramebufferState::getAttachmentExtentsIntersection() const
583 {
584     int32_t width  = std::numeric_limits<int32_t>::max();
585     int32_t height = std::numeric_limits<int32_t>::max();
586     for (const FramebufferAttachment &attachment : mColorAttachments)
587     {
588         if (attachment.isAttached())
589         {
590             width  = std::min(width, attachment.getSize().width);
591             height = std::min(height, attachment.getSize().height);
592         }
593     }
594 
595     if (mDepthAttachment.isAttached())
596     {
597         width  = std::min(width, mDepthAttachment.getSize().width);
598         height = std::min(height, mDepthAttachment.getSize().height);
599     }
600 
601     if (mStencilAttachment.isAttached())
602     {
603         width  = std::min(width, mStencilAttachment.getSize().width);
604         height = std::min(height, mStencilAttachment.getSize().height);
605     }
606 
607     return Extents(width, height, 0);
608 }
609 
attachmentsHaveSameDimensions() const610 bool FramebufferState::attachmentsHaveSameDimensions() const
611 {
612     Optional<Extents> attachmentSize;
613 
614     auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
615         if (!attachment.isAttached())
616         {
617             return false;
618         }
619 
620         if (!attachmentSize.valid())
621         {
622             attachmentSize = attachment.getSize();
623             return false;
624         }
625 
626         const auto &prevSize = attachmentSize.value();
627         const auto &curSize  = attachment.getSize();
628         return (curSize.width != prevSize.width || curSize.height != prevSize.height);
629     };
630 
631     for (const auto &attachment : mColorAttachments)
632     {
633         if (hasMismatchedSize(attachment))
634         {
635             return false;
636         }
637     }
638 
639     if (hasMismatchedSize(mDepthAttachment))
640     {
641         return false;
642     }
643 
644     return !hasMismatchedSize(mStencilAttachment);
645 }
646 
hasSeparateDepthAndStencilAttachments() const647 bool FramebufferState::hasSeparateDepthAndStencilAttachments() const
648 {
649     // if we have both a depth and stencil buffer, they must refer to the same object
650     // since we only support packed_depth_stencil and not separate depth and stencil
651     return (getDepthAttachment() != nullptr && getStencilAttachment() != nullptr &&
652             getDepthStencilAttachment() == nullptr);
653 }
654 
getDrawBuffer(size_t drawBufferIdx) const655 const FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
656 {
657     ASSERT(drawBufferIdx < mDrawBufferStates.size());
658     if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
659     {
660         // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
661         // must be COLOR_ATTACHMENTi or NONE"
662         ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
663                (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
664 
665         if (mDrawBufferStates[drawBufferIdx] == GL_BACK)
666         {
667             return getColorAttachment(0);
668         }
669         else
670         {
671             return getColorAttachment(mDrawBufferStates[drawBufferIdx] - GL_COLOR_ATTACHMENT0);
672         }
673     }
674     else
675     {
676         return nullptr;
677     }
678 }
679 
getDrawBufferCount() const680 size_t FramebufferState::getDrawBufferCount() const
681 {
682     return mDrawBufferStates.size();
683 }
684 
colorAttachmentsAreUniqueImages() const685 bool FramebufferState::colorAttachmentsAreUniqueImages() const
686 {
687     for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
688          firstAttachmentIdx++)
689     {
690         const FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
691         if (!firstAttachment.isAttached())
692         {
693             continue;
694         }
695 
696         for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
697              secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
698         {
699             const FramebufferAttachment &secondAttachment = mColorAttachments[secondAttachmentIdx];
700             if (!secondAttachment.isAttached())
701             {
702                 continue;
703             }
704 
705             if (firstAttachment == secondAttachment)
706             {
707                 return false;
708             }
709         }
710     }
711 
712     return true;
713 }
714 
hasDepth() const715 bool FramebufferState::hasDepth() const
716 {
717     return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
718 }
719 
hasStencil() const720 bool FramebufferState::hasStencil() const
721 {
722     return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
723 }
724 
hasExternalTextureAttachment() const725 bool FramebufferState::hasExternalTextureAttachment() const
726 {
727     // External textures can only be bound to color attachment 0
728     return (mColorAttachments[0].isAttached() && mColorAttachments[0].isExternalTexture());
729 }
730 
hasYUVAttachment() const731 bool FramebufferState::hasYUVAttachment() const
732 {
733     // The only attachments that can be YUV are external textures and surfaces, both are attached at
734     // color attachment 0.
735     return (mColorAttachments[0].isAttached() && mColorAttachments[0].isYUV());
736 }
737 
isMultiview() const738 bool FramebufferState::isMultiview() const
739 {
740     const FramebufferAttachment *attachment = getFirstNonNullAttachment();
741     if (attachment == nullptr)
742     {
743         return false;
744     }
745     return attachment->isMultiview();
746 }
747 
getBaseViewIndex() const748 int FramebufferState::getBaseViewIndex() const
749 {
750     const FramebufferAttachment *attachment = getFirstNonNullAttachment();
751     if (attachment == nullptr)
752     {
753         return GL_NONE;
754     }
755     return attachment->getBaseViewIndex();
756 }
757 
getDimensions() const758 Box FramebufferState::getDimensions() const
759 {
760     Extents extents = getExtents();
761     return Box(0, 0, 0, extents.width, extents.height, extents.depth);
762 }
763 
getExtents() const764 Extents FramebufferState::getExtents() const
765 {
766     // OpenGLES3.0 (https://www.khronos.org/registry/OpenGL/specs/es/3.0/es_spec_3.0.pdf
767     // section 4.4.4.2) allows attachments have unequal size.
768     const FramebufferAttachment *first = getFirstNonNullAttachment();
769     if (first)
770     {
771         return getAttachmentExtentsIntersection();
772     }
773     return Extents(getDefaultWidth(), getDefaultHeight(), 0);
774 }
775 
isDefault() const776 bool FramebufferState::isDefault() const
777 {
778     return mId == Framebuffer::kDefaultDrawFramebufferHandle;
779 }
780 
isBoundAsDrawFramebuffer(const Context * context) const781 bool FramebufferState::isBoundAsDrawFramebuffer(const Context *context) const
782 {
783     return context->getState().getDrawFramebuffer()->id() == mId;
784 }
785 
786 const FramebufferID Framebuffer::kDefaultDrawFramebufferHandle = {0};
787 
Framebuffer(const Caps & caps,rx::GLImplFactory * factory,FramebufferID id,egl::ShareGroup * shareGroup)788 Framebuffer::Framebuffer(const Caps &caps,
789                          rx::GLImplFactory *factory,
790                          FramebufferID id,
791                          egl::ShareGroup *shareGroup)
792     : mState(caps, id, shareGroup->generateFramebufferSerial()),
793       mImpl(factory->createFramebuffer(mState)),
794       mCachedStatus(),
795       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
796       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
797 {
798     ASSERT(mImpl != nullptr);
799     ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
800 
801     for (uint32_t colorIndex = 0;
802          colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
803     {
804         mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
805     }
806     if (caps.maxDrawBuffers > 1)
807     {
808         mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
809     }
810 }
811 
Framebuffer(const Context * context,egl::Surface * surface,egl::Surface * readSurface)812 Framebuffer::Framebuffer(const Context *context, egl::Surface *surface, egl::Surface *readSurface)
813     : mState(context->getShareGroup()->generateFramebufferSerial()),
814       mImpl(surface->getImplementation()->createDefaultFramebuffer(context, mState)),
815       mCachedStatus(FramebufferStatus::Complete()),
816       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
817       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
818 {
819     ASSERT(mImpl != nullptr);
820 
821     mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
822     setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
823                       FramebufferAttachment::kDefaultNumViews,
824                       FramebufferAttachment::kDefaultBaseViewIndex, false,
825                       FramebufferAttachment::kDefaultRenderToTextureSamples);
826 
827     setReadSurface(context, readSurface);
828 
829     if (surface->getConfig()->depthSize > 0)
830     {
831         setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
832                           FramebufferAttachment::kDefaultNumViews,
833                           FramebufferAttachment::kDefaultBaseViewIndex, false,
834                           FramebufferAttachment::kDefaultRenderToTextureSamples);
835     }
836 
837     if (surface->getConfig()->stencilSize > 0)
838     {
839         setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
840                           FramebufferAttachment::kDefaultNumViews,
841                           FramebufferAttachment::kDefaultBaseViewIndex, false,
842                           FramebufferAttachment::kDefaultRenderToTextureSamples);
843     }
844     SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
845 
846     mState.mSurfaceTextureOffset = surface->getTextureOffset();
847 
848     // Ensure the backend has a chance to synchronize its content for a new backbuffer.
849     mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
850 }
851 
Framebuffer(const Context * context,rx::GLImplFactory * factory,egl::Surface * readSurface)852 Framebuffer::Framebuffer(const Context *context,
853                          rx::GLImplFactory *factory,
854                          egl::Surface *readSurface)
855     : mState(context->getShareGroup()->generateFramebufferSerial()),
856       mImpl(factory->createFramebuffer(mState)),
857       mCachedStatus(FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNDEFINED_OES,
858                                                   err::kFramebufferIncompleteSurfaceless)),
859       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
860       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
861 {
862     mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
863     SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
864 
865     setReadSurface(context, readSurface);
866 }
867 
~Framebuffer()868 Framebuffer::~Framebuffer()
869 {
870     SafeDelete(mImpl);
871 }
872 
onDestroy(const Context * context)873 void Framebuffer::onDestroy(const Context *context)
874 {
875     if (isDefault())
876     {
877         mState.mDefaultFramebufferReadAttachment.detach(context, mState.mFramebufferSerial);
878         mState.mDefaultFramebufferReadAttachmentInitialized = false;
879     }
880 
881     for (auto &attachment : mState.mColorAttachments)
882     {
883         attachment.detach(context, mState.mFramebufferSerial);
884     }
885     mState.mDepthAttachment.detach(context, mState.mFramebufferSerial);
886     mState.mStencilAttachment.detach(context, mState.mFramebufferSerial);
887     mState.mWebGLDepthAttachment.detach(context, mState.mFramebufferSerial);
888     mState.mWebGLStencilAttachment.detach(context, mState.mFramebufferSerial);
889     mState.mWebGLDepthStencilAttachment.detach(context, mState.mFramebufferSerial);
890 
891     mImpl->destroy(context);
892 }
893 
setReadSurface(const Context * context,egl::Surface * readSurface)894 void Framebuffer::setReadSurface(const Context *context, egl::Surface *readSurface)
895 {
896     // updateAttachment() without mState.mResourceNeedsInit.set()
897     mState.mDefaultFramebufferReadAttachment.attach(
898         context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), readSurface,
899         FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex,
900         false, FramebufferAttachment::kDefaultRenderToTextureSamples, mState.mFramebufferSerial);
901     mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
902 }
903 
setLabel(const Context * context,const std::string & label)904 void Framebuffer::setLabel(const Context *context, const std::string &label)
905 {
906     mState.mLabel = label;
907 }
908 
getLabel() const909 const std::string &Framebuffer::getLabel() const
910 {
911     return mState.mLabel;
912 }
913 
detachTexture(const Context * context,TextureID textureId)914 bool Framebuffer::detachTexture(const Context *context, TextureID textureId)
915 {
916     return detachResourceById(context, GL_TEXTURE, textureId.value);
917 }
918 
detachRenderbuffer(const Context * context,RenderbufferID renderbufferId)919 bool Framebuffer::detachRenderbuffer(const Context *context, RenderbufferID renderbufferId)
920 {
921     return detachResourceById(context, GL_RENDERBUFFER, renderbufferId.value);
922 }
923 
detachResourceById(const Context * context,GLenum resourceType,GLuint resourceId)924 bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
925 {
926     bool found = false;
927 
928     for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
929     {
930         if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
931                                      resourceId))
932         {
933             found = true;
934         }
935     }
936 
937     if (context->isWebGL1())
938     {
939         const std::array<FramebufferAttachment *, 3> attachments = {
940             {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
941              &mState.mWebGLStencilAttachment}};
942         for (FramebufferAttachment *attachment : attachments)
943         {
944             if (detachMatchingAttachment(context, attachment, resourceType, resourceId))
945             {
946                 found = true;
947             }
948         }
949     }
950     else
951     {
952         if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId))
953         {
954             found = true;
955         }
956         if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId))
957         {
958             found = true;
959         }
960     }
961 
962     return found;
963 }
964 
detachMatchingAttachment(const Context * context,FramebufferAttachment * attachment,GLenum matchType,GLuint matchId)965 bool Framebuffer::detachMatchingAttachment(const Context *context,
966                                            FramebufferAttachment *attachment,
967                                            GLenum matchType,
968                                            GLuint matchId)
969 {
970     if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
971     {
972         // We go through resetAttachment to make sure that all the required bookkeeping will be done
973         // such as updating enabled draw buffer state.
974         resetAttachment(context, attachment->getBinding());
975         return true;
976     }
977 
978     return false;
979 }
980 
getColorAttachment(size_t colorAttachment) const981 const FramebufferAttachment *Framebuffer::getColorAttachment(size_t colorAttachment) const
982 {
983     return mState.getColorAttachment(colorAttachment);
984 }
985 
getDepthAttachment() const986 const FramebufferAttachment *Framebuffer::getDepthAttachment() const
987 {
988     return mState.getDepthAttachment();
989 }
990 
getStencilAttachment() const991 const FramebufferAttachment *Framebuffer::getStencilAttachment() const
992 {
993     return mState.getStencilAttachment();
994 }
995 
getDepthStencilAttachment() const996 const FramebufferAttachment *Framebuffer::getDepthStencilAttachment() const
997 {
998     return mState.getDepthStencilAttachment();
999 }
1000 
getDepthOrStencilAttachment() const1001 const FramebufferAttachment *Framebuffer::getDepthOrStencilAttachment() const
1002 {
1003     return mState.getDepthOrStencilAttachment();
1004 }
1005 
getStencilOrDepthStencilAttachment() const1006 const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
1007 {
1008     return mState.getStencilOrDepthStencilAttachment();
1009 }
1010 
getReadColorAttachment() const1011 const FramebufferAttachment *Framebuffer::getReadColorAttachment() const
1012 {
1013     return mState.getReadAttachment();
1014 }
1015 
getReadColorAttachmentType() const1016 GLenum Framebuffer::getReadColorAttachmentType() const
1017 {
1018     const FramebufferAttachment *readAttachment = mState.getReadAttachment();
1019     return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
1020 }
1021 
getFirstColorAttachment() const1022 const FramebufferAttachment *Framebuffer::getFirstColorAttachment() const
1023 {
1024     return mState.getFirstColorAttachment();
1025 }
1026 
getFirstNonNullAttachment() const1027 const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
1028 {
1029     return mState.getFirstNonNullAttachment();
1030 }
1031 
getAttachment(const Context * context,GLenum attachment) const1032 const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
1033                                                         GLenum attachment) const
1034 {
1035     return mState.getAttachment(context, attachment);
1036 }
1037 
getDrawbufferStateCount() const1038 size_t Framebuffer::getDrawbufferStateCount() const
1039 {
1040     return mState.mDrawBufferStates.size();
1041 }
1042 
getDrawBufferState(size_t drawBuffer) const1043 GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
1044 {
1045     ASSERT(drawBuffer < mState.mDrawBufferStates.size());
1046     return mState.mDrawBufferStates[drawBuffer];
1047 }
1048 
getDrawBufferStates() const1049 const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
1050 {
1051     return mState.getDrawBufferStates();
1052 }
1053 
setDrawBuffers(size_t count,const GLenum * buffers)1054 void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
1055 {
1056     auto &drawStates = mState.mDrawBufferStates;
1057 
1058     ASSERT(count <= drawStates.size());
1059     std::copy(buffers, buffers + count, drawStates.begin());
1060     std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
1061     mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
1062 
1063     mState.mEnabledDrawBuffers.reset();
1064     mState.mDrawBufferTypeMask.reset();
1065 
1066     for (size_t index = 0; index < count; ++index)
1067     {
1068         SetComponentTypeMask(getDrawbufferWriteType(index), index, &mState.mDrawBufferTypeMask);
1069 
1070         if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
1071         {
1072             mState.mEnabledDrawBuffers.set(index);
1073         }
1074     }
1075 }
1076 
getDrawBuffer(size_t drawBuffer) const1077 const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
1078 {
1079     return mState.getDrawBuffer(drawBuffer);
1080 }
1081 
getDrawbufferWriteType(size_t drawBuffer) const1082 ComponentType Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
1083 {
1084     const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
1085     if (attachment == nullptr)
1086     {
1087         return ComponentType::NoType;
1088     }
1089 
1090     GLenum componentType = attachment->getFormat().info->componentType;
1091     switch (componentType)
1092     {
1093         case GL_INT:
1094             return ComponentType::Int;
1095         case GL_UNSIGNED_INT:
1096             return ComponentType::UnsignedInt;
1097 
1098         default:
1099             return ComponentType::Float;
1100     }
1101 }
1102 
getDrawBufferTypeMask() const1103 ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
1104 {
1105     return mState.mDrawBufferTypeMask;
1106 }
1107 
getDrawBufferMask() const1108 DrawBufferMask Framebuffer::getDrawBufferMask() const
1109 {
1110     return mState.mEnabledDrawBuffers;
1111 }
1112 
hasEnabledDrawBuffer() const1113 bool Framebuffer::hasEnabledDrawBuffer() const
1114 {
1115     for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
1116     {
1117         if (getDrawBuffer(drawbufferIdx) != nullptr)
1118         {
1119             return true;
1120         }
1121     }
1122 
1123     return false;
1124 }
1125 
getReadBufferState() const1126 GLenum Framebuffer::getReadBufferState() const
1127 {
1128     return mState.mReadBufferState;
1129 }
1130 
setReadBuffer(GLenum buffer)1131 void Framebuffer::setReadBuffer(GLenum buffer)
1132 {
1133     ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
1134            (buffer >= GL_COLOR_ATTACHMENT0 &&
1135             (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
1136     mState.mReadBufferState = buffer;
1137     mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
1138 }
1139 
getNumColorAttachments() const1140 size_t Framebuffer::getNumColorAttachments() const
1141 {
1142     return mState.mColorAttachments.size();
1143 }
1144 
hasDepth() const1145 bool Framebuffer::hasDepth() const
1146 {
1147     return mState.hasDepth();
1148 }
1149 
hasStencil() const1150 bool Framebuffer::hasStencil() const
1151 {
1152     return mState.hasStencil();
1153 }
1154 
hasExternalTextureAttachment() const1155 bool Framebuffer::hasExternalTextureAttachment() const
1156 {
1157     return mState.hasExternalTextureAttachment();
1158 }
1159 
hasYUVAttachment() const1160 bool Framebuffer::hasYUVAttachment() const
1161 {
1162     return mState.hasYUVAttachment();
1163 }
1164 
usingExtendedDrawBuffers() const1165 bool Framebuffer::usingExtendedDrawBuffers() const
1166 {
1167     for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
1168     {
1169         if (getDrawBuffer(drawbufferIdx) != nullptr)
1170         {
1171             return true;
1172         }
1173     }
1174 
1175     return false;
1176 }
1177 
invalidateCompletenessCache()1178 void Framebuffer::invalidateCompletenessCache()
1179 {
1180     if (!isDefault())
1181     {
1182         mCachedStatus.reset();
1183     }
1184     onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1185 }
1186 
checkStatusImpl(const Context * context) const1187 const FramebufferStatus &Framebuffer::checkStatusImpl(const Context *context) const
1188 {
1189     ASSERT(!isDefault());
1190     ASSERT(hasAnyDirtyBit() || !mCachedStatus.valid());
1191 
1192     mCachedStatus = checkStatusWithGLFrontEnd(context);
1193 
1194     if (mCachedStatus.value().isComplete())
1195     {
1196         // We can skip syncState on several back-ends.
1197         if (mImpl->shouldSyncStateBeforeCheckStatus())
1198         {
1199             // This binding is not totally correct. It is ok because the parameter isn't used in
1200             // the GL back-end and the GL back-end is the only user of syncStateBeforeCheckStatus.
1201             angle::Result err = syncState(context, GL_FRAMEBUFFER, Command::Other);
1202             if (err != angle::Result::Continue)
1203             {
1204                 mCachedStatus =
1205                     FramebufferStatus::Incomplete(0, err::kFramebufferIncompleteInternalError);
1206                 return mCachedStatus.value();
1207             }
1208         }
1209 
1210         mCachedStatus = mImpl->checkStatus(context);
1211     }
1212 
1213     return mCachedStatus.value();
1214 }
1215 
checkStatusWithGLFrontEnd(const Context * context) const1216 FramebufferStatus Framebuffer::checkStatusWithGLFrontEnd(const Context *context) const
1217 {
1218     const State &state = context->getState();
1219 
1220     ASSERT(!isDefault());
1221 
1222     bool hasAttachments = false;
1223     Optional<unsigned int> colorbufferSize;
1224     Optional<int> samples;
1225     Optional<bool> fixedSampleLocations;
1226     bool hasRenderbuffer = false;
1227     Optional<int> renderToTextureSamples;
1228 
1229     const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
1230 
1231     Optional<bool> isLayered;
1232     Optional<TextureType> colorAttachmentsTextureType;
1233 
1234     for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
1235     {
1236         if (colorAttachment.isAttached())
1237         {
1238             FramebufferStatus attachmentCompleteness =
1239                 CheckAttachmentCompleteness(context, colorAttachment);
1240             if (!attachmentCompleteness.isComplete())
1241             {
1242                 return attachmentCompleteness;
1243             }
1244 
1245             const InternalFormat &format = *colorAttachment.getFormat().info;
1246             if (format.depthBits > 0 || format.stencilBits > 0)
1247             {
1248                 return FramebufferStatus::Incomplete(
1249                     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
1250                     err::kFramebufferIncompleteDepthStencilInColorBuffer);
1251             }
1252 
1253             FramebufferStatus attachmentSampleCompleteness =
1254                 CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
1255                                                   &fixedSampleLocations, &renderToTextureSamples);
1256             if (!attachmentSampleCompleteness.isComplete())
1257             {
1258                 return attachmentSampleCompleteness;
1259             }
1260 
1261             // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
1262             // in GLES 3.0, there is no such restriction
1263             if (state.getClientMajorVersion() < 3)
1264             {
1265                 if (colorbufferSize.valid())
1266                 {
1267                     if (format.pixelBytes != colorbufferSize.value())
1268                     {
1269                         return FramebufferStatus::Incomplete(
1270                             GL_FRAMEBUFFER_UNSUPPORTED,
1271                             err::kFramebufferIncompleteAttachmentInconsistantBitPlanes);
1272                     }
1273                 }
1274                 else
1275                 {
1276                     colorbufferSize = format.pixelBytes;
1277                 }
1278             }
1279 
1280             FramebufferStatus attachmentMultiviewCompleteness =
1281                 CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment);
1282             if (!attachmentMultiviewCompleteness.isComplete())
1283             {
1284                 return attachmentMultiviewCompleteness;
1285             }
1286 
1287             hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1288 
1289             if (!hasAttachments)
1290             {
1291                 isLayered = colorAttachment.isLayered();
1292                 if (isLayered.value())
1293                 {
1294                     colorAttachmentsTextureType = colorAttachment.getTextureImageIndex().getType();
1295                 }
1296                 hasAttachments = true;
1297             }
1298             else
1299             {
1300                 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1301                 // If any framebuffer attachment is layered, all populated attachments
1302                 // must be layered. Additionally, all populated color attachments must
1303                 // be from textures of the same target. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1304                 ASSERT(isLayered.valid());
1305                 if (isLayered.value() != colorAttachment.isLayered())
1306                 {
1307                     return FramebufferStatus::Incomplete(
1308                         GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
1309                         err::kFramebufferIncompleteMismatchedLayeredAttachments);
1310                 }
1311                 else if (isLayered.value())
1312                 {
1313                     ASSERT(colorAttachmentsTextureType.valid());
1314                     if (colorAttachmentsTextureType.value() !=
1315                         colorAttachment.getTextureImageIndex().getType())
1316                     {
1317                         return FramebufferStatus::Incomplete(
1318                             GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
1319                             err::kFramebufferIncompleteMismatchedLayeredTexturetypes);
1320                     }
1321                 }
1322             }
1323         }
1324     }
1325 
1326     const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
1327     if (depthAttachment.isAttached())
1328     {
1329         FramebufferStatus attachmentCompleteness =
1330             CheckAttachmentCompleteness(context, depthAttachment);
1331         if (!attachmentCompleteness.isComplete())
1332         {
1333             return attachmentCompleteness;
1334         }
1335 
1336         const InternalFormat &format = *depthAttachment.getFormat().info;
1337         if (format.depthBits == 0)
1338         {
1339             return FramebufferStatus::Incomplete(
1340                 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
1341                 err::kFramebufferIncompleteAttachmentNoDepthBitsInDepthBuffer);
1342         }
1343 
1344         FramebufferStatus attachmentSampleCompleteness =
1345             CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1346                                               &fixedSampleLocations, &renderToTextureSamples);
1347         if (!attachmentSampleCompleteness.isComplete())
1348         {
1349             return attachmentSampleCompleteness;
1350         }
1351 
1352         FramebufferStatus attachmentMultiviewCompleteness =
1353             CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment);
1354         if (!attachmentMultiviewCompleteness.isComplete())
1355         {
1356             return attachmentMultiviewCompleteness;
1357         }
1358 
1359         hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1360 
1361         if (!hasAttachments)
1362         {
1363             isLayered      = depthAttachment.isLayered();
1364             hasAttachments = true;
1365         }
1366         else
1367         {
1368             // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1369             // If any framebuffer attachment is layered, all populated attachments
1370             // must be layered. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1371             ASSERT(isLayered.valid());
1372             if (isLayered.value() != depthAttachment.isLayered())
1373             {
1374                 return FramebufferStatus::Incomplete(
1375                     GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
1376                     err::kFramebufferIncompleteMismatchedLayeredAttachments);
1377             }
1378         }
1379     }
1380 
1381     const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
1382     if (stencilAttachment.isAttached())
1383     {
1384         FramebufferStatus attachmentCompleteness =
1385             CheckAttachmentCompleteness(context, stencilAttachment);
1386         if (!attachmentCompleteness.isComplete())
1387         {
1388             return attachmentCompleteness;
1389         }
1390 
1391         const InternalFormat &format = *stencilAttachment.getFormat().info;
1392         if (format.stencilBits == 0)
1393         {
1394             return FramebufferStatus::Incomplete(
1395                 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
1396                 err::kFramebufferIncompleteAttachmentNoStencilBitsInStencilBuffer);
1397         }
1398 
1399         FramebufferStatus attachmentSampleCompleteness =
1400             CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1401                                               &fixedSampleLocations, &renderToTextureSamples);
1402         if (!attachmentSampleCompleteness.isComplete())
1403         {
1404             return attachmentSampleCompleteness;
1405         }
1406 
1407         FramebufferStatus attachmentMultiviewCompleteness =
1408             CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment);
1409         if (!attachmentMultiviewCompleteness.isComplete())
1410         {
1411             return attachmentMultiviewCompleteness;
1412         }
1413 
1414         hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1415 
1416         if (!hasAttachments)
1417         {
1418             hasAttachments = true;
1419         }
1420         else
1421         {
1422             // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1423             // If any framebuffer attachment is layered, all populated attachments
1424             // must be layered.
1425             // {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1426             ASSERT(isLayered.valid());
1427             if (isLayered.value() != stencilAttachment.isLayered())
1428             {
1429                 return FramebufferStatus::Incomplete(
1430                     GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT,
1431                     err::kFramebufferIncompleteMismatchedLayeredAttachments);
1432             }
1433         }
1434     }
1435 
1436     // Starting from ES 3.0 stencil and depth, if present, should be the same image
1437     if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1438         stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1439     {
1440         return FramebufferStatus::Incomplete(
1441             GL_FRAMEBUFFER_UNSUPPORTED,
1442             err::kFramebufferIncompleteDepthAndStencilBuffersNotTheSame);
1443     }
1444 
1445     // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1446     if (state.isWebGL1())
1447     {
1448         if (!mState.mWebGLDepthStencilConsistent)
1449         {
1450             return FramebufferStatus::Incomplete(
1451                 GL_FRAMEBUFFER_UNSUPPORTED,
1452                 err::kFramebufferIncompleteWebGLDepthStencilInconsistant);
1453         }
1454 
1455         if (mState.mWebGLDepthStencilAttachment.isAttached())
1456         {
1457             if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1458                 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1459             {
1460                 return FramebufferStatus::Incomplete(
1461                     GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
1462                     err::kFramebufferIncompleteAttachmentWebGLDepthStencilNoDepthOrStencilBits);
1463             }
1464 
1465             FramebufferStatus attachmentMultiviewCompleteness =
1466                 CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1467                                                           &mState.mWebGLDepthStencilAttachment);
1468             if (!attachmentMultiviewCompleteness.isComplete())
1469             {
1470                 return attachmentMultiviewCompleteness;
1471             }
1472         }
1473         else if (mState.mStencilAttachment.isAttached() &&
1474                  mState.mStencilAttachment.getDepthSize() > 0)
1475         {
1476             return FramebufferStatus::Incomplete(
1477                 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
1478                 err::kFramebufferIncompleteAttachmentWebGLStencilBufferHasDepthBits);
1479         }
1480         else if (mState.mDepthAttachment.isAttached() &&
1481                  mState.mDepthAttachment.getStencilSize() > 0)
1482         {
1483             return FramebufferStatus::Incomplete(
1484                 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
1485                 err::kFramebufferIncompleteAttachmentWebGLDepthBufferHasStencilBits);
1486         }
1487     }
1488 
1489     // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1490     // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1491     // is zero, the framebuffer is considered incomplete.
1492     GLint defaultWidth  = mState.getDefaultWidth();
1493     GLint defaultHeight = mState.getDefaultHeight();
1494     if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
1495     {
1496         return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
1497                                              err::kFramebufferIncompleteDefaultZeroSize);
1498     }
1499 
1500     // In ES 2.0 and WebGL, all color attachments must have the same width and height.
1501     // In ES 3.0, there is no such restriction.
1502     if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibilityANGLE) &&
1503         !mState.attachmentsHaveSameDimensions())
1504     {
1505         return FramebufferStatus::Incomplete(
1506             GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1507             err::kFramebufferIncompleteInconsistantAttachmentSizes);
1508     }
1509 
1510     // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1511     // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
1512     if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1513     {
1514         return FramebufferStatus::Incomplete(
1515             GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
1516             err::kFramebufferIncompleteMultisampleNonFixedSamplesWithRenderbuffers);
1517     }
1518 
1519     // The WebGL conformance tests implicitly define that all framebuffer
1520     // attachments must be unique. For example, the same level of a texture can
1521     // not be attached to two different color attachments.
1522     if (state.getExtensions().webglCompatibilityANGLE)
1523     {
1524         if (!mState.colorAttachmentsAreUniqueImages())
1525         {
1526             return FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNSUPPORTED,
1527                                                  err::kFramebufferIncompleteAttachmentsNotUnique);
1528         }
1529     }
1530 
1531     return FramebufferStatus::Complete();
1532 }
1533 
discard(const Context * context,size_t count,const GLenum * attachments)1534 angle::Result Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
1535 {
1536     // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1537     // can be no-ops, so we should probably do that to ensure consistency.
1538     // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1539 
1540     return mImpl->discard(context, count, attachments);
1541 }
1542 
invalidate(const Context * context,size_t count,const GLenum * attachments)1543 angle::Result Framebuffer::invalidate(const Context *context,
1544                                       size_t count,
1545                                       const GLenum *attachments)
1546 {
1547     // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1548     // can be no-ops, so we should probably do that to ensure consistency.
1549     // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1550 
1551     return mImpl->invalidate(context, count, attachments);
1552 }
1553 
partialClearNeedsInit(const Context * context,bool color,bool depth,bool stencil)1554 bool Framebuffer::partialClearNeedsInit(const Context *context,
1555                                         bool color,
1556                                         bool depth,
1557                                         bool stencil)
1558 {
1559     const auto &glState = context->getState();
1560 
1561     if (!glState.isRobustResourceInitEnabled())
1562     {
1563         return false;
1564     }
1565 
1566     // Scissors can affect clearing.
1567     // TODO(jmadill): Check for complete scissor overlap.
1568     if (glState.isScissorTestEnabled())
1569     {
1570         return true;
1571     }
1572 
1573     // If colors masked, we must clear before we clear. Do a simple check.
1574     // TODO(jmadill): Filter out unused color channels from the test.
1575     if (color && glState.anyActiveDrawBufferChannelMasked())
1576     {
1577         return true;
1578     }
1579 
1580     const auto &depthStencil = glState.getDepthStencilState();
1581     if (stencil && (depthStencil.stencilMask != depthStencil.stencilWritemask ||
1582                     depthStencil.stencilBackMask != depthStencil.stencilBackWritemask))
1583     {
1584         return true;
1585     }
1586 
1587     return false;
1588 }
1589 
invalidateSub(const Context * context,size_t count,const GLenum * attachments,const Rectangle & area)1590 angle::Result Framebuffer::invalidateSub(const Context *context,
1591                                          size_t count,
1592                                          const GLenum *attachments,
1593                                          const Rectangle &area)
1594 {
1595     // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1596     // can be no-ops, so we should probably do that to ensure consistency.
1597     // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1598 
1599     return mImpl->invalidateSub(context, count, attachments, area);
1600 }
1601 
clear(const Context * context,GLbitfield mask)1602 angle::Result Framebuffer::clear(const Context *context, GLbitfield mask)
1603 {
1604     ASSERT(mask && !context->getState().isRasterizerDiscardEnabled());
1605 
1606     return mImpl->clear(context, mask);
1607 }
1608 
clearBufferfv(const Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)1609 angle::Result Framebuffer::clearBufferfv(const Context *context,
1610                                          GLenum buffer,
1611                                          GLint drawbuffer,
1612                                          const GLfloat *values)
1613 {
1614     return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
1615 }
1616 
clearBufferuiv(const Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)1617 angle::Result Framebuffer::clearBufferuiv(const Context *context,
1618                                           GLenum buffer,
1619                                           GLint drawbuffer,
1620                                           const GLuint *values)
1621 {
1622     return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
1623 }
1624 
clearBufferiv(const Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)1625 angle::Result Framebuffer::clearBufferiv(const Context *context,
1626                                          GLenum buffer,
1627                                          GLint drawbuffer,
1628                                          const GLint *values)
1629 {
1630     return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
1631 }
1632 
clearBufferfi(const Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)1633 angle::Result Framebuffer::clearBufferfi(const Context *context,
1634                                          GLenum buffer,
1635                                          GLint drawbuffer,
1636                                          GLfloat depth,
1637                                          GLint stencil)
1638 {
1639     const bool clearDepth =
1640         getDepthAttachment() != nullptr && context->getState().getDepthStencilState().depthMask;
1641     const bool clearStencil = getStencilAttachment() != nullptr &&
1642                               context->getState().getDepthStencilState().stencilWritemask != 0;
1643 
1644     if (clearDepth && clearStencil)
1645     {
1646         ASSERT(buffer == GL_DEPTH_STENCIL);
1647         ANGLE_TRY(mImpl->clearBufferfi(context, GL_DEPTH_STENCIL, drawbuffer, depth, stencil));
1648     }
1649     else if (clearDepth && !clearStencil)
1650     {
1651         ANGLE_TRY(mImpl->clearBufferfv(context, GL_DEPTH, drawbuffer, &depth));
1652     }
1653     else if (!clearDepth && clearStencil)
1654     {
1655         ANGLE_TRY(mImpl->clearBufferiv(context, GL_STENCIL, drawbuffer, &stencil));
1656     }
1657 
1658     return angle::Result::Continue;
1659 }
1660 
getImplementationColorReadFormat(const Context * context)1661 GLenum Framebuffer::getImplementationColorReadFormat(const Context *context)
1662 {
1663     const gl::InternalFormat &format = mImpl->getImplementationColorReadFormat(context);
1664     return format.getReadPixelsFormat(context->getExtensions());
1665 }
1666 
getImplementationColorReadType(const Context * context)1667 GLenum Framebuffer::getImplementationColorReadType(const Context *context)
1668 {
1669     const gl::InternalFormat &format = mImpl->getImplementationColorReadFormat(context);
1670     return format.getReadPixelsType(context->getClientVersion());
1671 }
1672 
readPixels(const Context * context,const Rectangle & area,GLenum format,GLenum type,const PixelPackState & pack,Buffer * packBuffer,void * pixels)1673 angle::Result Framebuffer::readPixels(const Context *context,
1674                                       const Rectangle &area,
1675                                       GLenum format,
1676                                       GLenum type,
1677                                       const PixelPackState &pack,
1678                                       Buffer *packBuffer,
1679                                       void *pixels)
1680 {
1681     ANGLE_TRY(mImpl->readPixels(context, area, format, type, pack, packBuffer, pixels));
1682 
1683     if (packBuffer)
1684     {
1685         packBuffer->onDataChanged();
1686     }
1687 
1688     return angle::Result::Continue;
1689 }
1690 
blit(const Context * context,const Rectangle & sourceArea,const Rectangle & destArea,GLbitfield mask,GLenum filter)1691 angle::Result Framebuffer::blit(const Context *context,
1692                                 const Rectangle &sourceArea,
1693                                 const Rectangle &destArea,
1694                                 GLbitfield mask,
1695                                 GLenum filter)
1696 {
1697     ASSERT(mask != 0);
1698 
1699     ANGLE_TRY(mImpl->blit(context, sourceArea, destArea, mask, filter));
1700 
1701     // Mark the contents of the attachments dirty
1702     if ((mask & GL_COLOR_BUFFER_BIT) != 0)
1703     {
1704         for (size_t colorIndex : mState.mEnabledDrawBuffers)
1705         {
1706             mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 + colorIndex);
1707         }
1708     }
1709     if ((mask & GL_DEPTH_BUFFER_BIT) != 0)
1710     {
1711         mDirtyBits.set(DIRTY_BIT_DEPTH_BUFFER_CONTENTS);
1712     }
1713     if ((mask & GL_STENCIL_BUFFER_BIT) != 0)
1714     {
1715         mDirtyBits.set(DIRTY_BIT_STENCIL_BUFFER_CONTENTS);
1716     }
1717     onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1718 
1719     return angle::Result::Continue;
1720 }
1721 
getSamples(const Context * context) const1722 int Framebuffer::getSamples(const Context *context) const
1723 {
1724     if (!isComplete(context))
1725     {
1726         return 0;
1727     }
1728 
1729     ASSERT(mCachedStatus.valid() && mCachedStatus.value().isComplete());
1730 
1731     // For a complete framebuffer, all attachments must have the same sample count.
1732     // In this case return the first nonzero sample size.
1733     const FramebufferAttachment *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1734     ASSERT(firstNonNullAttachment == nullptr || firstNonNullAttachment->isAttached());
1735 
1736     return firstNonNullAttachment ? firstNonNullAttachment->getSamples() : 0;
1737 }
1738 
getReadBufferResourceSamples(const Context * context) const1739 int Framebuffer::getReadBufferResourceSamples(const Context *context) const
1740 {
1741     if (!isComplete(context))
1742     {
1743         return 0;
1744     }
1745 
1746     ASSERT(mCachedStatus.valid() && mCachedStatus.value().isComplete());
1747 
1748     const FramebufferAttachment *readAttachment = mState.getReadAttachment();
1749     ASSERT(readAttachment == nullptr || readAttachment->isAttached());
1750 
1751     return readAttachment ? readAttachment->getResourceSamples() : 0;
1752 }
1753 
getSamplePosition(const Context * context,size_t index,GLfloat * xy) const1754 angle::Result Framebuffer::getSamplePosition(const Context *context,
1755                                              size_t index,
1756                                              GLfloat *xy) const
1757 {
1758     ANGLE_TRY(mImpl->getSamplePosition(context, index, xy));
1759     return angle::Result::Continue;
1760 }
1761 
hasValidDepthStencil() const1762 bool Framebuffer::hasValidDepthStencil() const
1763 {
1764     return mState.getDepthStencilAttachment() != nullptr;
1765 }
1766 
getSurfaceTextureOffset() const1767 const gl::Offset &Framebuffer::getSurfaceTextureOffset() const
1768 {
1769     return mState.getSurfaceTextureOffset();
1770 }
1771 
setAttachment(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource)1772 void Framebuffer::setAttachment(const Context *context,
1773                                 GLenum type,
1774                                 GLenum binding,
1775                                 const ImageIndex &textureIndex,
1776                                 FramebufferAttachmentObject *resource)
1777 {
1778     setAttachment(context, type, binding, textureIndex, resource,
1779                   FramebufferAttachment::kDefaultNumViews,
1780                   FramebufferAttachment::kDefaultBaseViewIndex, false,
1781                   FramebufferAttachment::kDefaultRenderToTextureSamples);
1782 }
1783 
setAttachmentMultisample(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei samples)1784 void Framebuffer::setAttachmentMultisample(const Context *context,
1785                                            GLenum type,
1786                                            GLenum binding,
1787                                            const ImageIndex &textureIndex,
1788                                            FramebufferAttachmentObject *resource,
1789                                            GLsizei samples)
1790 {
1791     setAttachment(context, type, binding, textureIndex, resource,
1792                   FramebufferAttachment::kDefaultNumViews,
1793                   FramebufferAttachment::kDefaultBaseViewIndex, false, samples);
1794 }
1795 
setAttachment(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLuint baseViewIndex,bool isMultiview,GLsizei samplesIn)1796 void Framebuffer::setAttachment(const Context *context,
1797                                 GLenum type,
1798                                 GLenum binding,
1799                                 const ImageIndex &textureIndex,
1800                                 FramebufferAttachmentObject *resource,
1801                                 GLsizei numViews,
1802                                 GLuint baseViewIndex,
1803                                 bool isMultiview,
1804                                 GLsizei samplesIn)
1805 {
1806     GLsizei samples = samplesIn;
1807     // Match the sample count to the attachment's sample count.
1808     if (resource)
1809     {
1810         const InternalFormat *info = resource->getAttachmentFormat(binding, textureIndex).info;
1811         ASSERT(info);
1812         GLenum sizedInternalFormat    = info->sizedInternalFormat;
1813         const TextureCaps &formatCaps = context->getTextureCaps().get(sizedInternalFormat);
1814         samples                       = formatCaps.getNearestSamples(samples);
1815     }
1816 
1817     // Context may be null in unit tests.
1818     if (!context || !context->isWebGL1())
1819     {
1820         setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1821                           isMultiview, samples);
1822         return;
1823     }
1824 
1825     switch (binding)
1826     {
1827         case GL_DEPTH_STENCIL:
1828         case GL_DEPTH_STENCIL_ATTACHMENT:
1829             mState.mWebGLDepthStencilAttachment.attach(
1830                 context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1831                 isMultiview, samples, mState.mFramebufferSerial);
1832             break;
1833         case GL_DEPTH:
1834         case GL_DEPTH_ATTACHMENT:
1835             mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1836                                                 numViews, baseViewIndex, isMultiview, samples,
1837                                                 mState.mFramebufferSerial);
1838             break;
1839         case GL_STENCIL:
1840         case GL_STENCIL_ATTACHMENT:
1841             mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1842                                                   numViews, baseViewIndex, isMultiview, samples,
1843                                                   mState.mFramebufferSerial);
1844             break;
1845         default:
1846             setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1847                               baseViewIndex, isMultiview, samples);
1848             return;
1849     }
1850 
1851     commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, isMultiview, samples);
1852 }
1853 
setAttachmentMultiview(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLint baseViewIndex)1854 void Framebuffer::setAttachmentMultiview(const Context *context,
1855                                          GLenum type,
1856                                          GLenum binding,
1857                                          const ImageIndex &textureIndex,
1858                                          FramebufferAttachmentObject *resource,
1859                                          GLsizei numViews,
1860                                          GLint baseViewIndex)
1861 {
1862     setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex, true,
1863                   FramebufferAttachment::kDefaultRenderToTextureSamples);
1864 }
1865 
commitWebGL1DepthStencilIfConsistent(const Context * context,GLsizei numViews,GLuint baseViewIndex,bool isMultiview,GLsizei samples)1866 void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1867                                                        GLsizei numViews,
1868                                                        GLuint baseViewIndex,
1869                                                        bool isMultiview,
1870                                                        GLsizei samples)
1871 {
1872     int count = 0;
1873 
1874     std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1875                                                            &mState.mWebGLDepthAttachment,
1876                                                            &mState.mWebGLStencilAttachment}};
1877     for (FramebufferAttachment *attachment : attachments)
1878     {
1879         if (attachment->isAttached())
1880         {
1881             count++;
1882         }
1883     }
1884 
1885     mState.mWebGLDepthStencilConsistent = (count <= 1);
1886     if (!mState.mWebGLDepthStencilConsistent)
1887     {
1888         // Inconsistent.
1889         return;
1890     }
1891 
1892     auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1893         if (attachment.type() == GL_TEXTURE)
1894         {
1895             return attachment.getTextureImageIndex();
1896         }
1897         else
1898         {
1899             return ImageIndex();
1900         }
1901     };
1902 
1903     if (mState.mWebGLDepthAttachment.isAttached())
1904     {
1905         const auto &depth = mState.mWebGLDepthAttachment;
1906         setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
1907                           getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1908                           baseViewIndex, isMultiview, samples);
1909         setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1910                           baseViewIndex, isMultiview, samples);
1911     }
1912     else if (mState.mWebGLStencilAttachment.isAttached())
1913     {
1914         const auto &stencil = mState.mWebGLStencilAttachment;
1915         setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1916                           baseViewIndex, isMultiview, samples);
1917         setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
1918                           getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1919                           numViews, baseViewIndex, isMultiview, samples);
1920     }
1921     else if (mState.mWebGLDepthStencilAttachment.isAttached())
1922     {
1923         const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
1924         setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
1925                           getImageIndexIfTextureAttachment(depthStencil),
1926                           depthStencil.getResource(), numViews, baseViewIndex, isMultiview,
1927                           samples);
1928         setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
1929                           getImageIndexIfTextureAttachment(depthStencil),
1930                           depthStencil.getResource(), numViews, baseViewIndex, isMultiview,
1931                           samples);
1932     }
1933     else
1934     {
1935         setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1936                           baseViewIndex, isMultiview, samples);
1937         setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1938                           baseViewIndex, isMultiview, samples);
1939     }
1940 }
1941 
setAttachmentImpl(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLuint baseViewIndex,bool isMultiview,GLsizei samples)1942 void Framebuffer::setAttachmentImpl(const Context *context,
1943                                     GLenum type,
1944                                     GLenum binding,
1945                                     const ImageIndex &textureIndex,
1946                                     FramebufferAttachmentObject *resource,
1947                                     GLsizei numViews,
1948                                     GLuint baseViewIndex,
1949                                     bool isMultiview,
1950                                     GLsizei samples)
1951 {
1952     switch (binding)
1953     {
1954         case GL_DEPTH_STENCIL:
1955         case GL_DEPTH_STENCIL_ATTACHMENT:
1956             updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1957                              &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1958                              numViews, baseViewIndex, isMultiview, samples);
1959             updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1960                              &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1961                              numViews, baseViewIndex, isMultiview, samples);
1962             break;
1963 
1964         case GL_DEPTH:
1965         case GL_DEPTH_ATTACHMENT:
1966             updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1967                              &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1968                              numViews, baseViewIndex, isMultiview, samples);
1969             break;
1970 
1971         case GL_STENCIL:
1972         case GL_STENCIL_ATTACHMENT:
1973             updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1974                              &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1975                              numViews, baseViewIndex, isMultiview, samples);
1976             break;
1977 
1978         case GL_BACK:
1979             updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1980                              &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1981                              resource, numViews, baseViewIndex, isMultiview, samples);
1982             mState.mColorAttachmentsMask.set(0);
1983 
1984             break;
1985 
1986         default:
1987         {
1988             size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1989             ASSERT(colorIndex < mState.mColorAttachments.size());
1990             size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
1991             updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
1992                              &mDirtyColorAttachmentBindings[colorIndex], type, binding,
1993                              textureIndex, resource, numViews, baseViewIndex, isMultiview, samples);
1994 
1995             if (!resource)
1996             {
1997                 mFloat32ColorAttachmentBits.reset(colorIndex);
1998                 mState.mColorAttachmentsMask.reset(colorIndex);
1999             }
2000             else
2001             {
2002                 updateFloat32ColorAttachmentBits(
2003                     colorIndex, resource->getAttachmentFormat(binding, textureIndex).info);
2004                 mState.mColorAttachmentsMask.set(colorIndex);
2005             }
2006 
2007             bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
2008             mState.mEnabledDrawBuffers.set(colorIndex, enabled);
2009             SetComponentTypeMask(getDrawbufferWriteType(colorIndex), colorIndex,
2010                                  &mState.mDrawBufferTypeMask);
2011         }
2012         break;
2013     }
2014 }
2015 
updateAttachment(const Context * context,FramebufferAttachment * attachment,size_t dirtyBit,angle::ObserverBinding * onDirtyBinding,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLuint baseViewIndex,bool isMultiview,GLsizei samples)2016 void Framebuffer::updateAttachment(const Context *context,
2017                                    FramebufferAttachment *attachment,
2018                                    size_t dirtyBit,
2019                                    angle::ObserverBinding *onDirtyBinding,
2020                                    GLenum type,
2021                                    GLenum binding,
2022                                    const ImageIndex &textureIndex,
2023                                    FramebufferAttachmentObject *resource,
2024                                    GLsizei numViews,
2025                                    GLuint baseViewIndex,
2026                                    bool isMultiview,
2027                                    GLsizei samples)
2028 {
2029     attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
2030                        isMultiview, samples, mState.mFramebufferSerial);
2031     mDirtyBits.set(dirtyBit);
2032     mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
2033     onDirtyBinding->bind(resource);
2034 
2035     invalidateCompletenessCache();
2036 }
2037 
resetAttachment(const Context * context,GLenum binding)2038 void Framebuffer::resetAttachment(const Context *context, GLenum binding)
2039 {
2040     setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr);
2041 }
2042 
setWriteControlMode(SrgbWriteControlMode srgbWriteControlMode)2043 void Framebuffer::setWriteControlMode(SrgbWriteControlMode srgbWriteControlMode)
2044 {
2045     if (srgbWriteControlMode != mState.getWriteControlMode())
2046     {
2047         mState.mSrgbWriteControlMode = srgbWriteControlMode;
2048         mDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE);
2049     }
2050 }
2051 
syncState(const Context * context,GLenum framebufferBinding,Command command) const2052 angle::Result Framebuffer::syncState(const Context *context,
2053                                      GLenum framebufferBinding,
2054                                      Command command) const
2055 {
2056     if (mDirtyBits.any())
2057     {
2058         mDirtyBitsGuard = mDirtyBits;
2059         ANGLE_TRY(mImpl->syncState(context, framebufferBinding, mDirtyBits, command));
2060         mDirtyBits.reset();
2061         mDirtyBitsGuard.reset();
2062     }
2063     return angle::Result::Continue;
2064 }
2065 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)2066 void Framebuffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
2067 {
2068     if (message != angle::SubjectMessage::SubjectChanged)
2069     {
2070         // This can be triggered by SubImage calls for Textures.
2071         if (message == angle::SubjectMessage::ContentsChanged)
2072         {
2073             mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 + index);
2074             onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
2075             return;
2076         }
2077 
2078         ASSERT(message != angle::SubjectMessage::BindingChanged);
2079 
2080         // This can be triggered by external changes to the default framebuffer.
2081         if (message == angle::SubjectMessage::SurfaceChanged)
2082         {
2083             onStateChange(angle::SubjectMessage::SurfaceChanged);
2084             return;
2085         }
2086 
2087         // This can be triggered by freeing TextureStorage in D3D back-end.
2088         if (message == angle::SubjectMessage::StorageReleased)
2089         {
2090             mDirtyBits.set(index);
2091             invalidateCompletenessCache();
2092             return;
2093         }
2094 
2095         // This can be triggered by the GL back-end TextureGL class.
2096         ASSERT(message == angle::SubjectMessage::DirtyBitsFlagged);
2097         return;
2098     }
2099 
2100     ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
2101     mDirtyBits.set(index);
2102 
2103     invalidateCompletenessCache();
2104 
2105     FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
2106 
2107     // Mark the appropriate init flag.
2108     mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
2109 
2110     // Update mFloat32ColorAttachmentBits Cache
2111     if (index < DIRTY_BIT_COLOR_ATTACHMENT_MAX)
2112     {
2113         ASSERT(index != DIRTY_BIT_DEPTH_ATTACHMENT);
2114         ASSERT(index != DIRTY_BIT_STENCIL_ATTACHMENT);
2115         updateFloat32ColorAttachmentBits(index - DIRTY_BIT_COLOR_ATTACHMENT_0,
2116                                          attachment->getFormat().info);
2117     }
2118 }
2119 
getAttachmentFromSubjectIndex(angle::SubjectIndex index)2120 FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
2121 {
2122     switch (index)
2123     {
2124         case DIRTY_BIT_DEPTH_ATTACHMENT:
2125             return &mState.mDepthAttachment;
2126         case DIRTY_BIT_STENCIL_ATTACHMENT:
2127             return &mState.mStencilAttachment;
2128         default:
2129             size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
2130             ASSERT(colorIndex < mState.mColorAttachments.size());
2131             return &mState.mColorAttachments[colorIndex];
2132     }
2133 }
2134 
formsRenderingFeedbackLoopWith(const Context * context) const2135 bool Framebuffer::formsRenderingFeedbackLoopWith(const Context *context) const
2136 {
2137     const State &glState                = context->getState();
2138     const ProgramExecutable *executable = glState.getProgramExecutable();
2139 
2140     // In some error cases there may be no bound program or executable.
2141     if (!executable)
2142         return false;
2143 
2144     const ActiveTextureMask &activeTextures    = executable->getActiveSamplersMask();
2145     const ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
2146 
2147     for (size_t textureIndex : activeTextures)
2148     {
2149         unsigned int uintIndex = static_cast<unsigned int>(textureIndex);
2150         Texture *texture       = glState.getSamplerTexture(uintIndex, textureTypes[textureIndex]);
2151         const Sampler *sampler = glState.getSampler(uintIndex);
2152         if (texture && texture->isSamplerComplete(context, sampler) &&
2153             texture->isBoundToFramebuffer(mState.mFramebufferSerial))
2154         {
2155             // Check for level overlap.
2156             for (const FramebufferAttachment &attachment : mState.mColorAttachments)
2157             {
2158                 if (AttachmentOverlapsWithTexture(attachment, texture, sampler))
2159                 {
2160                     return true;
2161                 }
2162             }
2163 
2164             if (AttachmentOverlapsWithTexture(mState.mDepthAttachment, texture, sampler))
2165             {
2166                 return true;
2167             }
2168 
2169             if (AttachmentOverlapsWithTexture(mState.mStencilAttachment, texture, sampler))
2170             {
2171                 return true;
2172             }
2173         }
2174     }
2175 
2176     return false;
2177 }
2178 
formsCopyingFeedbackLoopWith(TextureID copyTextureID,GLint copyTextureLevel,GLint copyTextureLayer) const2179 bool Framebuffer::formsCopyingFeedbackLoopWith(TextureID copyTextureID,
2180                                                GLint copyTextureLevel,
2181                                                GLint copyTextureLayer) const
2182 {
2183     if (mState.isDefault())
2184     {
2185         // It seems impossible to form a texture copying feedback loop with the default FBO.
2186         return false;
2187     }
2188 
2189     const FramebufferAttachment *readAttachment = getReadColorAttachment();
2190     ASSERT(readAttachment);
2191 
2192     if (readAttachment->isTextureWithId(copyTextureID))
2193     {
2194         const auto &imageIndex = readAttachment->getTextureImageIndex();
2195         if (imageIndex.getLevelIndex() == copyTextureLevel)
2196         {
2197             // Check 3D/Array texture layers.
2198             return !imageIndex.hasLayer() || copyTextureLayer == ImageIndex::kEntireLevel ||
2199                    imageIndex.getLayerIndex() == copyTextureLayer;
2200         }
2201     }
2202     return false;
2203 }
2204 
getDefaultWidth() const2205 GLint Framebuffer::getDefaultWidth() const
2206 {
2207     return mState.getDefaultWidth();
2208 }
2209 
getDefaultHeight() const2210 GLint Framebuffer::getDefaultHeight() const
2211 {
2212     return mState.getDefaultHeight();
2213 }
2214 
getDefaultSamples() const2215 GLint Framebuffer::getDefaultSamples() const
2216 {
2217     return mState.getDefaultSamples();
2218 }
2219 
getDefaultFixedSampleLocations() const2220 bool Framebuffer::getDefaultFixedSampleLocations() const
2221 {
2222     return mState.getDefaultFixedSampleLocations();
2223 }
2224 
getDefaultLayers() const2225 GLint Framebuffer::getDefaultLayers() const
2226 {
2227     return mState.getDefaultLayers();
2228 }
2229 
setDefaultWidth(const Context * context,GLint defaultWidth)2230 void Framebuffer::setDefaultWidth(const Context *context, GLint defaultWidth)
2231 {
2232     mState.mDefaultWidth = defaultWidth;
2233     mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
2234     invalidateCompletenessCache();
2235 }
2236 
setDefaultHeight(const Context * context,GLint defaultHeight)2237 void Framebuffer::setDefaultHeight(const Context *context, GLint defaultHeight)
2238 {
2239     mState.mDefaultHeight = defaultHeight;
2240     mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
2241     invalidateCompletenessCache();
2242 }
2243 
setDefaultSamples(const Context * context,GLint defaultSamples)2244 void Framebuffer::setDefaultSamples(const Context *context, GLint defaultSamples)
2245 {
2246     mState.mDefaultSamples = defaultSamples;
2247     mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
2248     invalidateCompletenessCache();
2249 }
2250 
setDefaultFixedSampleLocations(const Context * context,bool defaultFixedSampleLocations)2251 void Framebuffer::setDefaultFixedSampleLocations(const Context *context,
2252                                                  bool defaultFixedSampleLocations)
2253 {
2254     mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
2255     mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
2256     invalidateCompletenessCache();
2257 }
2258 
setDefaultLayers(GLint defaultLayers)2259 void Framebuffer::setDefaultLayers(GLint defaultLayers)
2260 {
2261     mState.mDefaultLayers = defaultLayers;
2262     mDirtyBits.set(DIRTY_BIT_DEFAULT_LAYERS);
2263 }
2264 
getNumViews() const2265 GLsizei Framebuffer::getNumViews() const
2266 {
2267     return mState.getNumViews();
2268 }
2269 
getBaseViewIndex() const2270 GLint Framebuffer::getBaseViewIndex() const
2271 {
2272     return mState.getBaseViewIndex();
2273 }
2274 
isMultiview() const2275 bool Framebuffer::isMultiview() const
2276 {
2277     return mState.isMultiview();
2278 }
2279 
readDisallowedByMultiview() const2280 bool Framebuffer::readDisallowedByMultiview() const
2281 {
2282     return (mState.isMultiview() && mState.getNumViews() > 1);
2283 }
2284 
ensureClearAttachmentsInitialized(const Context * context,GLbitfield mask)2285 angle::Result Framebuffer::ensureClearAttachmentsInitialized(const Context *context,
2286                                                              GLbitfield mask)
2287 {
2288     const auto &glState = context->getState();
2289     if (!context->isRobustResourceInitEnabled() || glState.isRasterizerDiscardEnabled())
2290     {
2291         return angle::Result::Continue;
2292     }
2293 
2294     const DepthStencilState &depthStencil = glState.getDepthStencilState();
2295 
2296     bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !glState.allActiveDrawBufferChannelsMasked();
2297     bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !depthStencil.isDepthMaskedOut();
2298     bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !depthStencil.isStencilMaskedOut();
2299 
2300     if (!color && !depth && !stencil)
2301     {
2302         return angle::Result::Continue;
2303     }
2304 
2305     if (partialClearNeedsInit(context, color, depth, stencil))
2306     {
2307         ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
2308     }
2309 
2310     // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2311     // still be marked initialized. This simplifies design, allowing this method to be called before
2312     // the clear.
2313     markDrawAttachmentsInitialized(color, depth, stencil);
2314 
2315     return angle::Result::Continue;
2316 }
2317 
ensureClearBufferAttachmentsInitialized(const Context * context,GLenum buffer,GLint drawbuffer)2318 angle::Result Framebuffer::ensureClearBufferAttachmentsInitialized(const Context *context,
2319                                                                    GLenum buffer,
2320                                                                    GLint drawbuffer)
2321 {
2322     if (!context->isRobustResourceInitEnabled() ||
2323         context->getState().isRasterizerDiscardEnabled() ||
2324         context->isClearBufferMaskedOut(buffer, drawbuffer))
2325     {
2326         return angle::Result::Continue;
2327     }
2328 
2329     if (partialBufferClearNeedsInit(context, buffer))
2330     {
2331         ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
2332     }
2333 
2334     // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2335     // still be marked initialized. This simplifies design, allowing this method to be called before
2336     // the clear.
2337     markBufferInitialized(buffer, drawbuffer);
2338 
2339     return angle::Result::Continue;
2340 }
2341 
ensureDrawAttachmentsInitialized(const Context * context)2342 angle::Result Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
2343 {
2344     if (!context->isRobustResourceInitEnabled())
2345     {
2346         return angle::Result::Continue;
2347     }
2348 
2349     // Note: we don't actually filter by the draw attachment enum. Just init everything.
2350     for (size_t bit : mState.mResourceNeedsInit)
2351     {
2352         switch (bit)
2353         {
2354             case DIRTY_BIT_DEPTH_ATTACHMENT:
2355                 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2356                 break;
2357             case DIRTY_BIT_STENCIL_ATTACHMENT:
2358                 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2359                 break;
2360             default:
2361                 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2362                 break;
2363         }
2364     }
2365 
2366     mState.mResourceNeedsInit.reset();
2367     return angle::Result::Continue;
2368 }
2369 
ensureReadAttachmentsInitialized(const Context * context)2370 angle::Result Framebuffer::ensureReadAttachmentsInitialized(const Context *context)
2371 {
2372     ASSERT(context->isRobustResourceInitEnabled());
2373 
2374     if (mState.mResourceNeedsInit.none())
2375     {
2376         return angle::Result::Continue;
2377     }
2378 
2379     if (mState.mReadBufferState != GL_NONE)
2380     {
2381         if (isDefault())
2382         {
2383             if (!mState.mDefaultFramebufferReadAttachmentInitialized)
2384             {
2385                 ANGLE_TRY(InitAttachment(context, &mState.mDefaultFramebufferReadAttachment));
2386                 mState.mDefaultFramebufferReadAttachmentInitialized = true;
2387             }
2388         }
2389         else
2390         {
2391             size_t readIndex = mState.getReadIndex();
2392             if (mState.mResourceNeedsInit[readIndex])
2393             {
2394                 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2395                 mState.mResourceNeedsInit.reset(readIndex);
2396             }
2397         }
2398     }
2399 
2400     // Conservatively init depth since it can be read by BlitFramebuffer.
2401     if (hasDepth())
2402     {
2403         if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2404         {
2405             ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2406             mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2407         }
2408     }
2409 
2410     // Conservatively init stencil since it can be read by BlitFramebuffer.
2411     if (hasStencil())
2412     {
2413         if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2414         {
2415             ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2416             mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2417         }
2418     }
2419 
2420     return angle::Result::Continue;
2421 }
2422 
markDrawAttachmentsInitialized(bool color,bool depth,bool stencil)2423 void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2424 {
2425     // Mark attachments as initialized.
2426     if (color)
2427     {
2428         for (auto colorIndex : mState.mEnabledDrawBuffers)
2429         {
2430             auto &colorAttachment = mState.mColorAttachments[colorIndex];
2431             ASSERT(colorAttachment.isAttached());
2432             colorAttachment.setInitState(InitState::Initialized);
2433             mState.mResourceNeedsInit.reset(colorIndex);
2434         }
2435     }
2436 
2437     if (depth && mState.mDepthAttachment.isAttached())
2438     {
2439         mState.mDepthAttachment.setInitState(InitState::Initialized);
2440         mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2441     }
2442 
2443     if (stencil && mState.mStencilAttachment.isAttached())
2444     {
2445         mState.mStencilAttachment.setInitState(InitState::Initialized);
2446         mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2447     }
2448 }
2449 
markBufferInitialized(GLenum bufferType,GLint bufferIndex)2450 void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2451 {
2452     switch (bufferType)
2453     {
2454         case GL_COLOR:
2455         {
2456             ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2457             if (mState.mColorAttachments[bufferIndex].isAttached())
2458             {
2459                 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2460                 mState.mResourceNeedsInit.reset(bufferIndex);
2461             }
2462             break;
2463         }
2464         case GL_DEPTH:
2465         {
2466             if (mState.mDepthAttachment.isAttached())
2467             {
2468                 mState.mDepthAttachment.setInitState(InitState::Initialized);
2469                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2470             }
2471             break;
2472         }
2473         case GL_STENCIL:
2474         {
2475             if (mState.mStencilAttachment.isAttached())
2476             {
2477                 mState.mStencilAttachment.setInitState(InitState::Initialized);
2478                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2479             }
2480             break;
2481         }
2482         case GL_DEPTH_STENCIL:
2483         {
2484             if (mState.mDepthAttachment.isAttached())
2485             {
2486                 mState.mDepthAttachment.setInitState(InitState::Initialized);
2487                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2488             }
2489             if (mState.mStencilAttachment.isAttached())
2490             {
2491                 mState.mStencilAttachment.setInitState(InitState::Initialized);
2492                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2493             }
2494             break;
2495         }
2496         default:
2497             UNREACHABLE();
2498             break;
2499     }
2500 }
2501 
getDimensions() const2502 Box Framebuffer::getDimensions() const
2503 {
2504     return mState.getDimensions();
2505 }
2506 
getExtents() const2507 Extents Framebuffer::getExtents() const
2508 {
2509     return mState.getExtents();
2510 }
2511 
ensureBufferInitialized(const Context * context,GLenum bufferType,GLint bufferIndex)2512 angle::Result Framebuffer::ensureBufferInitialized(const Context *context,
2513                                                    GLenum bufferType,
2514                                                    GLint bufferIndex)
2515 {
2516     ASSERT(context->isRobustResourceInitEnabled());
2517 
2518     if (mState.mResourceNeedsInit.none())
2519     {
2520         return angle::Result::Continue;
2521     }
2522 
2523     switch (bufferType)
2524     {
2525         case GL_COLOR:
2526         {
2527             ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2528             if (mState.mResourceNeedsInit[bufferIndex])
2529             {
2530                 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2531                 mState.mResourceNeedsInit.reset(bufferIndex);
2532             }
2533             break;
2534         }
2535         case GL_DEPTH:
2536         {
2537             if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2538             {
2539                 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2540                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2541             }
2542             break;
2543         }
2544         case GL_STENCIL:
2545         {
2546             if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2547             {
2548                 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2549                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2550             }
2551             break;
2552         }
2553         case GL_DEPTH_STENCIL:
2554         {
2555             if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2556             {
2557                 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2558                 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2559             }
2560             if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2561             {
2562                 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2563                 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2564             }
2565             break;
2566         }
2567         default:
2568             UNREACHABLE();
2569             break;
2570     }
2571 
2572     return angle::Result::Continue;
2573 }
2574 
partialBufferClearNeedsInit(const Context * context,GLenum bufferType)2575 bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2576 {
2577     if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2578     {
2579         return false;
2580     }
2581 
2582     switch (bufferType)
2583     {
2584         case GL_COLOR:
2585             return partialClearNeedsInit(context, true, false, false);
2586         case GL_DEPTH:
2587             return partialClearNeedsInit(context, false, true, false);
2588         case GL_STENCIL:
2589             return partialClearNeedsInit(context, false, false, true);
2590         case GL_DEPTH_STENCIL:
2591             return partialClearNeedsInit(context, false, true, true);
2592         default:
2593             UNREACHABLE();
2594             return false;
2595     }
2596 }
2597 }  // namespace gl
2598