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