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