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