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