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