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