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