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