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