1 //
2 // Copyright (c) 2002-2014 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->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
53 {
54 return false;
55 }
56 if (firstAttachment->getMultiviewViewportOffsets() !=
57 secondAttachment->getMultiviewViewportOffsets())
58 {
59 return false;
60 }
61 return true;
62 }
63
CheckAttachmentCompleteness(const Context * context,const FramebufferAttachment & attachment)64 bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
65 {
66 ASSERT(attachment.isAttached());
67
68 const Extents &size = attachment.getSize();
69 if (size.width == 0 || size.height == 0)
70 {
71 return false;
72 }
73
74 const InternalFormat &format = *attachment.getFormat().info;
75 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
76 {
77 return false;
78 }
79
80 if (attachment.type() == GL_TEXTURE)
81 {
82 if (attachment.layer() >= size.depth)
83 {
84 return false;
85 }
86
87 // ES3 specifies that cube map texture attachments must be cube complete.
88 // This language is missing from the ES2 spec, but we enforce it here because some
89 // desktop OpenGL drivers also enforce this validation.
90 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
91 const Texture *texture = attachment.getTexture();
92 ASSERT(texture);
93 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
94 !texture->getTextureState().isCubeComplete())
95 {
96 return false;
97 }
98
99 if (!texture->getImmutableFormat())
100 {
101 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
102
103 // From the ES 3.0 spec, pg 213:
104 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
105 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
106 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
107 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
108 // the effective maximum texture level defined in the Mipmapping discussion of
109 // section 3.8.10.4.
110 if (attachmentMipLevel < texture->getBaseLevel() ||
111 attachmentMipLevel > texture->getMipmapMaxLevel())
112 {
113 return false;
114 }
115
116 // Form the ES 3.0 spec, pg 213/214:
117 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
118 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
119 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
120 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
121 // a cubemap texture, the texture must also be cube complete.
122 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
123 {
124 return false;
125 }
126 }
127 }
128
129 return true;
130 };
131
CheckAttachmentSampleCompleteness(const Context * context,const FramebufferAttachment & attachment,bool colorAttachment,Optional<int> * samples,Optional<bool> * fixedSampleLocations)132 bool CheckAttachmentSampleCompleteness(const Context *context,
133 const FramebufferAttachment &attachment,
134 bool colorAttachment,
135 Optional<int> *samples,
136 Optional<bool> *fixedSampleLocations)
137 {
138 ASSERT(attachment.isAttached());
139
140 if (attachment.type() == GL_TEXTURE)
141 {
142 const Texture *texture = attachment.getTexture();
143 ASSERT(texture);
144
145 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
146
147 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
148 // the same for all attached textures.
149 bool fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.target,
150 attachmentImageIndex.mipIndex);
151 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
152 {
153 return false;
154 }
155 else
156 {
157 *fixedSampleLocations = fixedSampleloc;
158 }
159 }
160
161 if (samples->valid())
162 {
163 if (attachment.getSamples() != samples->value())
164 {
165 if (colorAttachment)
166 {
167 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
168 // all color attachments have the same number of samples for the FBO to be complete.
169 return false;
170 }
171 else
172 {
173 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
174 // when its depth or stencil samples are a multiple of the number of color samples.
175 if (!context->getExtensions().framebufferMixedSamples)
176 {
177 return false;
178 }
179
180 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
181 {
182 return false;
183 }
184 }
185 }
186 }
187 else
188 {
189 *samples = attachment.getSamples();
190 }
191
192 return true;
193 }
194
195 // Needed to index into the attachment arrays/bitsets.
196 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
197 Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
198 "Framebuffer Dirty bit mismatch");
199 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
200 Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
201 "Framebuffer Dirty bit mismatch");
202 static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
203 Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
204 "Framebuffer Dirty bit mismatch");
205
InitAttachment(const Context * context,FramebufferAttachment * attachment)206 Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
207 {
208 ASSERT(attachment->isAttached());
209 if (attachment->initState() == InitState::MayNeedInit)
210 {
211 ANGLE_TRY(attachment->initializeContents(context));
212 }
213 return NoError();
214 }
215
IsColorMaskedOut(const BlendState & blend)216 bool IsColorMaskedOut(const BlendState &blend)
217 {
218 return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
219 !blend.colorMaskAlpha);
220 }
221
IsDepthMaskedOut(const DepthStencilState & depthStencil)222 bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
223 {
224 return !depthStencil.depthMask;
225 }
226
IsStencilMaskedOut(const DepthStencilState & depthStencil)227 bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
228 {
229 return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
230 }
231
IsClearBufferMaskedOut(const Context * context,GLenum buffer)232 bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
233 {
234 switch (buffer)
235 {
236 case GL_COLOR:
237 return IsColorMaskedOut(context->getGLState().getBlendState());
238 case GL_DEPTH:
239 return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
240 case GL_STENCIL:
241 return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
242 case GL_DEPTH_STENCIL:
243 return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
244 IsStencilMaskedOut(context->getGLState().getDepthStencilState());
245 default:
246 UNREACHABLE();
247 return true;
248 }
249 }
250
251 } // anonymous namespace
252
253 // This constructor is only used for default framebuffers.
FramebufferState()254 FramebufferState::FramebufferState()
255 : mLabel(),
256 mColorAttachments(1),
257 mDrawBufferStates(1, GL_BACK),
258 mReadBufferState(GL_BACK),
259 mDrawBufferTypeMask(),
260 mDefaultWidth(0),
261 mDefaultHeight(0),
262 mDefaultSamples(0),
263 mDefaultFixedSampleLocations(GL_FALSE),
264 mWebGLDepthStencilConsistent(true)
265 {
266 ASSERT(mDrawBufferStates.size() > 0);
267 mEnabledDrawBuffers.set(0);
268 }
269
FramebufferState(const Caps & caps)270 FramebufferState::FramebufferState(const Caps &caps)
271 : mLabel(),
272 mColorAttachments(caps.maxColorAttachments),
273 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
274 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
275 mDrawBufferTypeMask(),
276 mDefaultWidth(0),
277 mDefaultHeight(0),
278 mDefaultSamples(0),
279 mDefaultFixedSampleLocations(GL_FALSE),
280 mWebGLDepthStencilConsistent(true)
281 {
282 ASSERT(mDrawBufferStates.size() > 0);
283 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
284 }
285
~FramebufferState()286 FramebufferState::~FramebufferState()
287 {
288 }
289
getLabel()290 const std::string &FramebufferState::getLabel()
291 {
292 return mLabel;
293 }
294
getAttachment(const Context * context,GLenum attachment) const295 const FramebufferAttachment *FramebufferState::getAttachment(const Context *context,
296 GLenum attachment) const
297 {
298 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
299 {
300 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
301 }
302
303 // WebGL1 allows a developer to query for attachment parameters even when "inconsistant" (i.e.
304 // multiple conflicting attachment points) and requires us to return the framebuffer attachment
305 // associated with WebGL.
306 switch (attachment)
307 {
308 case GL_COLOR:
309 case GL_BACK:
310 return getColorAttachment(0);
311 case GL_DEPTH:
312 case GL_DEPTH_ATTACHMENT:
313 if (context->isWebGL1())
314 {
315 return getWebGLDepthAttachment();
316 }
317 else
318 {
319 return getDepthAttachment();
320 }
321 case GL_STENCIL:
322 case GL_STENCIL_ATTACHMENT:
323 if (context->isWebGL1())
324 {
325 return getWebGLStencilAttachment();
326 }
327 else
328 {
329 return getStencilAttachment();
330 }
331 case GL_DEPTH_STENCIL:
332 case GL_DEPTH_STENCIL_ATTACHMENT:
333 if (context->isWebGL1())
334 {
335 return getWebGLDepthStencilAttachment();
336 }
337 else
338 {
339 return getDepthStencilAttachment();
340 }
341 default:
342 UNREACHABLE();
343 return nullptr;
344 }
345 }
346
getReadIndex() const347 size_t FramebufferState::getReadIndex() const
348 {
349 ASSERT(mReadBufferState == GL_BACK ||
350 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
351 size_t readIndex = (mReadBufferState == GL_BACK
352 ? 0
353 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
354 ASSERT(readIndex < mColorAttachments.size());
355 return readIndex;
356 }
357
getReadAttachment() const358 const FramebufferAttachment *FramebufferState::getReadAttachment() const
359 {
360 if (mReadBufferState == GL_NONE)
361 {
362 return nullptr;
363 }
364 size_t readIndex = getReadIndex();
365 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
366 }
367
getFirstNonNullAttachment() const368 const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
369 {
370 auto *colorAttachment = getFirstColorAttachment();
371 if (colorAttachment)
372 {
373 return colorAttachment;
374 }
375 return getDepthOrStencilAttachment();
376 }
377
getFirstColorAttachment() const378 const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
379 {
380 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
381 {
382 if (colorAttachment.isAttached())
383 {
384 return &colorAttachment;
385 }
386 }
387
388 return nullptr;
389 }
390
getDepthOrStencilAttachment() const391 const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
392 {
393 if (mDepthAttachment.isAttached())
394 {
395 return &mDepthAttachment;
396 }
397 if (mStencilAttachment.isAttached())
398 {
399 return &mStencilAttachment;
400 }
401 return nullptr;
402 }
403
getStencilOrDepthStencilAttachment() const404 const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
405 {
406 if (mStencilAttachment.isAttached())
407 {
408 return &mStencilAttachment;
409 }
410 return getDepthStencilAttachment();
411 }
412
getColorAttachment(size_t colorAttachment) const413 const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
414 {
415 ASSERT(colorAttachment < mColorAttachments.size());
416 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
417 : nullptr;
418 }
419
getDepthAttachment() const420 const FramebufferAttachment *FramebufferState::getDepthAttachment() const
421 {
422 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
423 }
424
getWebGLDepthAttachment() const425 const FramebufferAttachment *FramebufferState::getWebGLDepthAttachment() const
426 {
427 return mWebGLDepthAttachment.isAttached() ? &mWebGLDepthAttachment : nullptr;
428 }
429
getWebGLDepthStencilAttachment() const430 const FramebufferAttachment *FramebufferState::getWebGLDepthStencilAttachment() const
431 {
432 return mWebGLDepthStencilAttachment.isAttached() ? &mWebGLDepthStencilAttachment : nullptr;
433 }
434
getStencilAttachment() const435 const FramebufferAttachment *FramebufferState::getStencilAttachment() const
436 {
437 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
438 }
439
getWebGLStencilAttachment() const440 const FramebufferAttachment *FramebufferState::getWebGLStencilAttachment() const
441 {
442 return mWebGLStencilAttachment.isAttached() ? &mWebGLStencilAttachment : nullptr;
443 }
444
getDepthStencilAttachment() const445 const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
446 {
447 // A valid depth-stencil attachment has the same resource bound to both the
448 // depth and stencil attachment points.
449 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
450 mDepthAttachment == mStencilAttachment)
451 {
452 return &mDepthAttachment;
453 }
454
455 return nullptr;
456 }
457
attachmentsHaveSameDimensions() const458 bool FramebufferState::attachmentsHaveSameDimensions() const
459 {
460 Optional<Extents> attachmentSize;
461
462 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
463 if (!attachment.isAttached())
464 {
465 return false;
466 }
467
468 if (!attachmentSize.valid())
469 {
470 attachmentSize = attachment.getSize();
471 return false;
472 }
473
474 const auto &prevSize = attachmentSize.value();
475 const auto &curSize = attachment.getSize();
476 return (curSize.width != prevSize.width || curSize.height != prevSize.height);
477 };
478
479 for (const auto &attachment : mColorAttachments)
480 {
481 if (hasMismatchedSize(attachment))
482 {
483 return false;
484 }
485 }
486
487 if (hasMismatchedSize(mDepthAttachment))
488 {
489 return false;
490 }
491
492 return !hasMismatchedSize(mStencilAttachment);
493 }
494
getDrawBuffer(size_t drawBufferIdx) const495 const FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
496 {
497 ASSERT(drawBufferIdx < mDrawBufferStates.size());
498 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
499 {
500 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
501 // must be COLOR_ATTACHMENTi or NONE"
502 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
503 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
504
505 if (mDrawBufferStates[drawBufferIdx] == GL_BACK)
506 {
507 return getColorAttachment(0);
508 }
509 else
510 {
511 return getColorAttachment(mDrawBufferStates[drawBufferIdx] - GL_COLOR_ATTACHMENT0);
512 }
513 }
514 else
515 {
516 return nullptr;
517 }
518 }
519
getDrawBufferCount() const520 size_t FramebufferState::getDrawBufferCount() const
521 {
522 return mDrawBufferStates.size();
523 }
524
colorAttachmentsAreUniqueImages() const525 bool FramebufferState::colorAttachmentsAreUniqueImages() const
526 {
527 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
528 firstAttachmentIdx++)
529 {
530 const FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
531 if (!firstAttachment.isAttached())
532 {
533 continue;
534 }
535
536 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
537 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
538 {
539 const FramebufferAttachment &secondAttachment = mColorAttachments[secondAttachmentIdx];
540 if (!secondAttachment.isAttached())
541 {
542 continue;
543 }
544
545 if (firstAttachment == secondAttachment)
546 {
547 return false;
548 }
549 }
550 }
551
552 return true;
553 }
554
hasDepth() const555 bool FramebufferState::hasDepth() const
556 {
557 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
558 }
559
hasStencil() const560 bool FramebufferState::hasStencil() const
561 {
562 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
563 }
564
getNumViews() const565 GLsizei FramebufferState::getNumViews() const
566 {
567 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
568 if (attachment == nullptr)
569 {
570 return FramebufferAttachment::kDefaultNumViews;
571 }
572 return attachment->getNumViews();
573 }
574
getViewportOffsets() const575 const std::vector<Offset> *FramebufferState::getViewportOffsets() const
576 {
577 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
578 if (attachment == nullptr)
579 {
580 return nullptr;
581 }
582 return &attachment->getMultiviewViewportOffsets();
583 }
584
getMultiviewLayout() const585 GLenum FramebufferState::getMultiviewLayout() const
586 {
587 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
588 if (attachment == nullptr)
589 {
590 return GL_NONE;
591 }
592 return attachment->getMultiviewLayout();
593 }
594
getBaseViewIndex() const595 int FramebufferState::getBaseViewIndex() const
596 {
597 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
598 if (attachment == nullptr)
599 {
600 return GL_NONE;
601 }
602 return attachment->getBaseViewIndex();
603 }
604
getDimensions() const605 Box FramebufferState::getDimensions() const
606 {
607 ASSERT(attachmentsHaveSameDimensions());
608 ASSERT(getFirstNonNullAttachment() != nullptr);
609 Extents extents = getFirstNonNullAttachment()->getSize();
610 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
611 }
612
Framebuffer(const Caps & caps,rx::GLImplFactory * factory,GLuint id)613 Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
614 : mState(caps),
615 mImpl(factory->createFramebuffer(mState)),
616 mId(id),
617 mCachedStatus(),
618 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
619 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
620 {
621 ASSERT(mId != 0);
622 ASSERT(mImpl != nullptr);
623 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
624
625 for (uint32_t colorIndex = 0;
626 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
627 {
628 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
629 }
630 }
631
Framebuffer(const egl::Display * display,egl::Surface * surface)632 Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
633 : mState(),
634 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
635 mId(0),
636 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
637 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
638 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
639 {
640 ASSERT(mImpl != nullptr);
641 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
642
643 const Context *proxyContext = display->getProxyContext();
644
645 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex::MakeInvalid(),
646 surface, FramebufferAttachment::kDefaultNumViews,
647 FramebufferAttachment::kDefaultBaseViewIndex,
648 FramebufferAttachment::kDefaultMultiviewLayout,
649 FramebufferAttachment::kDefaultViewportOffsets);
650
651 if (surface->getConfig()->depthSize > 0)
652 {
653 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex::MakeInvalid(),
654 surface, FramebufferAttachment::kDefaultNumViews,
655 FramebufferAttachment::kDefaultBaseViewIndex,
656 FramebufferAttachment::kDefaultMultiviewLayout,
657 FramebufferAttachment::kDefaultViewportOffsets);
658 }
659
660 if (surface->getConfig()->stencilSize > 0)
661 {
662 setAttachmentImpl(
663 proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex::MakeInvalid(), surface,
664 FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex,
665 FramebufferAttachment::kDefaultMultiviewLayout,
666 FramebufferAttachment::kDefaultViewportOffsets);
667 }
668 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
669 }
670
Framebuffer(rx::GLImplFactory * factory)671 Framebuffer::Framebuffer(rx::GLImplFactory *factory)
672 : mState(),
673 mImpl(factory->createFramebuffer(mState)),
674 mId(0),
675 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
676 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
677 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
678 {
679 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
680 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
681 }
682
~Framebuffer()683 Framebuffer::~Framebuffer()
684 {
685 SafeDelete(mImpl);
686 }
687
onDestroy(const Context * context)688 void Framebuffer::onDestroy(const Context *context)
689 {
690 for (auto &attachment : mState.mColorAttachments)
691 {
692 attachment.detach(context);
693 }
694 mState.mDepthAttachment.detach(context);
695 mState.mStencilAttachment.detach(context);
696 mState.mWebGLDepthAttachment.detach(context);
697 mState.mWebGLStencilAttachment.detach(context);
698 mState.mWebGLDepthStencilAttachment.detach(context);
699
700 mImpl->destroy(context);
701 }
702
destroyDefault(const egl::Display * display)703 void Framebuffer::destroyDefault(const egl::Display *display)
704 {
705 mImpl->destroyDefault(display);
706 }
707
setLabel(const std::string & label)708 void Framebuffer::setLabel(const std::string &label)
709 {
710 mState.mLabel = label;
711 }
712
getLabel() const713 const std::string &Framebuffer::getLabel() const
714 {
715 return mState.mLabel;
716 }
717
detachTexture(const Context * context,GLuint textureId)718 bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
719 {
720 return detachResourceById(context, GL_TEXTURE, textureId);
721 }
722
detachRenderbuffer(const Context * context,GLuint renderbufferId)723 bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
724 {
725 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
726 }
727
detachResourceById(const Context * context,GLenum resourceType,GLuint resourceId)728 bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
729 {
730 bool found = false;
731
732 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
733 {
734 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
735 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
736 {
737 found = true;
738 }
739 }
740
741 if (context->isWebGL1())
742 {
743 const std::array<FramebufferAttachment *, 3> attachments = {
744 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
745 &mState.mWebGLStencilAttachment}};
746 for (FramebufferAttachment *attachment : attachments)
747 {
748 if (attachment->isAttached() && attachment->type() == resourceType &&
749 attachment->id() == resourceId)
750 {
751 resetAttachment(context, attachment->getBinding());
752 found = true;
753 }
754 }
755 }
756 else
757 {
758 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
759 DIRTY_BIT_DEPTH_ATTACHMENT))
760 {
761 found = true;
762 }
763 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
764 DIRTY_BIT_STENCIL_ATTACHMENT))
765 {
766 found = true;
767 }
768 }
769
770 return found;
771 }
772
detachMatchingAttachment(const Context * context,FramebufferAttachment * attachment,GLenum matchType,GLuint matchId,size_t dirtyBit)773 bool Framebuffer::detachMatchingAttachment(const Context *context,
774 FramebufferAttachment *attachment,
775 GLenum matchType,
776 GLuint matchId,
777 size_t dirtyBit)
778 {
779 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
780 {
781 attachment->detach(context);
782 mDirtyBits.set(dirtyBit);
783 mState.mResourceNeedsInit.set(dirtyBit, false);
784 return true;
785 }
786
787 return false;
788 }
789
getColorbuffer(size_t colorAttachment) const790 const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
791 {
792 return mState.getColorAttachment(colorAttachment);
793 }
794
getDepthbuffer() const795 const FramebufferAttachment *Framebuffer::getDepthbuffer() const
796 {
797 return mState.getDepthAttachment();
798 }
799
getStencilbuffer() const800 const FramebufferAttachment *Framebuffer::getStencilbuffer() const
801 {
802 return mState.getStencilAttachment();
803 }
804
getDepthStencilBuffer() const805 const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
806 {
807 return mState.getDepthStencilAttachment();
808 }
809
getDepthOrStencilbuffer() const810 const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
811 {
812 return mState.getDepthOrStencilAttachment();
813 }
814
getStencilOrDepthStencilAttachment() const815 const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
816 {
817 return mState.getStencilOrDepthStencilAttachment();
818 }
819
getReadColorbuffer() const820 const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
821 {
822 return mState.getReadAttachment();
823 }
824
getReadColorbufferType() const825 GLenum Framebuffer::getReadColorbufferType() const
826 {
827 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
828 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
829 }
830
getFirstColorbuffer() const831 const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
832 {
833 return mState.getFirstColorAttachment();
834 }
835
getFirstNonNullAttachment() const836 const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
837 {
838 return mState.getFirstNonNullAttachment();
839 }
840
getAttachment(const Context * context,GLenum attachment) const841 const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
842 GLenum attachment) const
843 {
844 return mState.getAttachment(context, attachment);
845 }
846
getDrawbufferStateCount() const847 size_t Framebuffer::getDrawbufferStateCount() const
848 {
849 return mState.mDrawBufferStates.size();
850 }
851
getDrawBufferState(size_t drawBuffer) const852 GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
853 {
854 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
855 return mState.mDrawBufferStates[drawBuffer];
856 }
857
getDrawBufferStates() const858 const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
859 {
860 return mState.getDrawBufferStates();
861 }
862
setDrawBuffers(size_t count,const GLenum * buffers)863 void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
864 {
865 auto &drawStates = mState.mDrawBufferStates;
866
867 ASSERT(count <= drawStates.size());
868 std::copy(buffers, buffers + count, drawStates.begin());
869 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
870 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
871
872 mState.mEnabledDrawBuffers.reset();
873 mState.mDrawBufferTypeMask.reset();
874
875 for (size_t index = 0; index < count; ++index)
876 {
877 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
878
879 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
880 {
881 mState.mEnabledDrawBuffers.set(index);
882 }
883 }
884 }
885
getDrawBuffer(size_t drawBuffer) const886 const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
887 {
888 return mState.getDrawBuffer(drawBuffer);
889 }
890
getDrawbufferWriteType(size_t drawBuffer) const891 GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
892 {
893 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
894 if (attachment == nullptr)
895 {
896 return GL_NONE;
897 }
898
899 GLenum componentType = attachment->getFormat().info->componentType;
900 switch (componentType)
901 {
902 case GL_INT:
903 case GL_UNSIGNED_INT:
904 return componentType;
905
906 default:
907 return GL_FLOAT;
908 }
909 }
910
getDrawBufferTypeMask() const911 ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
912 {
913 return mState.mDrawBufferTypeMask;
914 }
915
getDrawBufferMask() const916 DrawBufferMask Framebuffer::getDrawBufferMask() const
917 {
918 return mState.mEnabledDrawBuffers;
919 }
920
hasEnabledDrawBuffer() const921 bool Framebuffer::hasEnabledDrawBuffer() const
922 {
923 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
924 {
925 if (getDrawBuffer(drawbufferIdx) != nullptr)
926 {
927 return true;
928 }
929 }
930
931 return false;
932 }
933
getReadBufferState() const934 GLenum Framebuffer::getReadBufferState() const
935 {
936 return mState.mReadBufferState;
937 }
938
setReadBuffer(GLenum buffer)939 void Framebuffer::setReadBuffer(GLenum buffer)
940 {
941 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
942 (buffer >= GL_COLOR_ATTACHMENT0 &&
943 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
944 mState.mReadBufferState = buffer;
945 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
946 }
947
getNumColorBuffers() const948 size_t Framebuffer::getNumColorBuffers() const
949 {
950 return mState.mColorAttachments.size();
951 }
952
hasDepth() const953 bool Framebuffer::hasDepth() const
954 {
955 return mState.hasDepth();
956 }
957
hasStencil() const958 bool Framebuffer::hasStencil() const
959 {
960 return mState.hasStencil();
961 }
962
usingExtendedDrawBuffers() const963 bool Framebuffer::usingExtendedDrawBuffers() const
964 {
965 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
966 {
967 if (getDrawBuffer(drawbufferIdx) != nullptr)
968 {
969 return true;
970 }
971 }
972
973 return false;
974 }
975
invalidateCompletenessCache()976 void Framebuffer::invalidateCompletenessCache()
977 {
978 if (mId != 0)
979 {
980 mCachedStatus.reset();
981 }
982 }
983
checkStatus(const Context * context)984 GLenum Framebuffer::checkStatus(const Context *context)
985 {
986 // The default framebuffer is always complete except when it is surfaceless in which
987 // case it is always unsupported. We return early because the default framebuffer may
988 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
989 if (mId == 0)
990 {
991 ASSERT(mCachedStatus.valid());
992 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
993 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
994 return mCachedStatus.value();
995 }
996
997 if (hasAnyDirtyBit() || !mCachedStatus.valid())
998 {
999 mCachedStatus = checkStatusImpl(context);
1000 }
1001
1002 return mCachedStatus.value();
1003 }
1004
checkStatusImpl(const Context * context)1005 GLenum Framebuffer::checkStatusImpl(const Context *context)
1006 {
1007 const ContextState &state = context->getContextState();
1008
1009 ASSERT(mId != 0);
1010
1011 bool hasAttachments = false;
1012 Optional<unsigned int> colorbufferSize;
1013 Optional<int> samples;
1014 Optional<bool> fixedSampleLocations;
1015 bool hasRenderbuffer = false;
1016
1017 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
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_ANGLE;
1060 }
1061
1062 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1063 hasAttachments = true;
1064 }
1065 }
1066
1067 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
1068 if (depthAttachment.isAttached())
1069 {
1070 if (!CheckAttachmentCompleteness(context, depthAttachment))
1071 {
1072 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1073 }
1074
1075 const InternalFormat &format = *depthAttachment.getFormat().info;
1076 if (format.depthBits == 0)
1077 {
1078 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1079 }
1080
1081 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1082 &fixedSampleLocations))
1083 {
1084 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1085 }
1086
1087 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1088 {
1089 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1090 }
1091
1092 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1093 hasAttachments = true;
1094 }
1095
1096 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
1097 if (stencilAttachment.isAttached())
1098 {
1099 if (!CheckAttachmentCompleteness(context, stencilAttachment))
1100 {
1101 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1102 }
1103
1104 const InternalFormat &format = *stencilAttachment.getFormat().info;
1105 if (format.stencilBits == 0)
1106 {
1107 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1108 }
1109
1110 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1111 &fixedSampleLocations))
1112 {
1113 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1114 }
1115
1116 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1117 {
1118 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1119 }
1120
1121 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1122 hasAttachments = true;
1123 }
1124
1125 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1126 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1127 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1128 {
1129 return GL_FRAMEBUFFER_UNSUPPORTED;
1130 }
1131
1132 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1133 if (state.isWebGL1())
1134 {
1135 if (!mState.mWebGLDepthStencilConsistent)
1136 {
1137 return GL_FRAMEBUFFER_UNSUPPORTED;
1138 }
1139
1140 if (mState.mWebGLDepthStencilAttachment.isAttached())
1141 {
1142 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1143 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1144 {
1145 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1146 }
1147
1148 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1149 &mState.mWebGLDepthStencilAttachment))
1150 {
1151 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1152 }
1153 }
1154 else if (mState.mStencilAttachment.isAttached() &&
1155 mState.mStencilAttachment.getDepthSize() > 0)
1156 {
1157 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1158 }
1159 else if (mState.mDepthAttachment.isAttached() &&
1160 mState.mDepthAttachment.getStencilSize() > 0)
1161 {
1162 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1163 }
1164 }
1165
1166 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1167 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1168 // is zero, the framebuffer is considered incomplete.
1169 GLint defaultWidth = mState.getDefaultWidth();
1170 GLint defaultHeight = mState.getDefaultHeight();
1171 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
1172 {
1173 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
1174 }
1175
1176 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
1177 // In ES 3.0, there is no such restriction.
1178 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1179 !mState.attachmentsHaveSameDimensions())
1180 {
1181 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1182 }
1183
1184 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1185 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
1186 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1187 {
1188 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1189 }
1190
1191 // The WebGL conformance tests implicitly define that all framebuffer
1192 // attachments must be unique. For example, the same level of a texture can
1193 // not be attached to two different color attachments.
1194 if (state.getExtensions().webglCompatibility)
1195 {
1196 if (!mState.colorAttachmentsAreUniqueImages())
1197 {
1198 return GL_FRAMEBUFFER_UNSUPPORTED;
1199 }
1200 }
1201
1202 syncState(context);
1203 if (!mImpl->checkStatus(context))
1204 {
1205 return GL_FRAMEBUFFER_UNSUPPORTED;
1206 }
1207
1208 return GL_FRAMEBUFFER_COMPLETE;
1209 }
1210
discard(const Context * context,size_t count,const GLenum * attachments)1211 Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
1212 {
1213 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1214 // can be no-ops, so we should probably do that to ensure consistency.
1215 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1216
1217 return mImpl->discard(context, count, attachments);
1218 }
1219
invalidate(const Context * context,size_t count,const GLenum * attachments)1220 Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
1221 {
1222 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1223 // can be no-ops, so we should probably do that to ensure consistency.
1224 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1225
1226 return mImpl->invalidate(context, count, attachments);
1227 }
1228
partialClearNeedsInit(const Context * context,bool color,bool depth,bool stencil)1229 bool Framebuffer::partialClearNeedsInit(const Context *context,
1230 bool color,
1231 bool depth,
1232 bool stencil)
1233 {
1234 const auto &glState = context->getGLState();
1235
1236 if (!glState.isRobustResourceInitEnabled())
1237 {
1238 return false;
1239 }
1240
1241 // Scissors can affect clearing.
1242 // TODO(jmadill): Check for complete scissor overlap.
1243 if (glState.isScissorTestEnabled())
1244 {
1245 return true;
1246 }
1247
1248 // If colors masked, we must clear before we clear. Do a simple check.
1249 // TODO(jmadill): Filter out unused color channels from the test.
1250 if (color)
1251 {
1252 const auto &blend = glState.getBlendState();
1253 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1254 blend.colorMaskAlpha))
1255 {
1256 return true;
1257 }
1258 }
1259
1260 const auto &depthStencil = glState.getDepthStencilState();
1261 ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
1262 if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
1263 {
1264 return true;
1265 }
1266
1267 return false;
1268 }
1269
invalidateSub(const Context * context,size_t count,const GLenum * attachments,const Rectangle & area)1270 Error Framebuffer::invalidateSub(const Context *context,
1271 size_t count,
1272 const GLenum *attachments,
1273 const Rectangle &area)
1274 {
1275 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1276 // can be no-ops, so we should probably do that to ensure consistency.
1277 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1278
1279 return mImpl->invalidateSub(context, count, attachments, area);
1280 }
1281
clear(const Context * context,GLbitfield mask)1282 Error Framebuffer::clear(const Context *context, GLbitfield mask)
1283 {
1284 const auto &glState = context->getGLState();
1285 if (glState.isRasterizerDiscardEnabled())
1286 {
1287 return NoError();
1288 }
1289
1290 const auto &blend = glState.getBlendState();
1291 const auto &depthStencil = glState.getDepthStencilState();
1292
1293 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
1294 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
1295 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
1296
1297 if (partialClearNeedsInit(context, color, depth, stencil))
1298 {
1299 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1300 }
1301
1302 ANGLE_TRY(mImpl->clear(context, mask));
1303
1304 if (glState.isRobustResourceInitEnabled())
1305 {
1306 markDrawAttachmentsInitialized(color, depth, stencil);
1307 }
1308
1309 return NoError();
1310 }
1311
clearBufferfv(const Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)1312 Error Framebuffer::clearBufferfv(const Context *context,
1313 GLenum buffer,
1314 GLint drawbuffer,
1315 const GLfloat *values)
1316 {
1317 if (context->getGLState().isRasterizerDiscardEnabled() ||
1318 IsClearBufferMaskedOut(context, buffer))
1319 {
1320 return NoError();
1321 }
1322
1323 if (partialBufferClearNeedsInit(context, buffer))
1324 {
1325 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1326 }
1327
1328 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1329
1330 if (context->isRobustResourceInitEnabled())
1331 {
1332 markBufferInitialized(buffer, drawbuffer);
1333 }
1334 return NoError();
1335 }
1336
clearBufferuiv(const Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)1337 Error Framebuffer::clearBufferuiv(const Context *context,
1338 GLenum buffer,
1339 GLint drawbuffer,
1340 const GLuint *values)
1341 {
1342 if (context->getGLState().isRasterizerDiscardEnabled() ||
1343 IsClearBufferMaskedOut(context, buffer))
1344 {
1345 return NoError();
1346 }
1347
1348 if (partialBufferClearNeedsInit(context, buffer))
1349 {
1350 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1351 }
1352
1353 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1354
1355 if (context->isRobustResourceInitEnabled())
1356 {
1357 markBufferInitialized(buffer, drawbuffer);
1358 }
1359 return NoError();
1360 }
1361
clearBufferiv(const Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)1362 Error Framebuffer::clearBufferiv(const Context *context,
1363 GLenum buffer,
1364 GLint drawbuffer,
1365 const GLint *values)
1366 {
1367 if (context->getGLState().isRasterizerDiscardEnabled() ||
1368 IsClearBufferMaskedOut(context, buffer))
1369 {
1370 return NoError();
1371 }
1372
1373 if (partialBufferClearNeedsInit(context, buffer))
1374 {
1375 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1376 }
1377
1378 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1379
1380 if (context->isRobustResourceInitEnabled())
1381 {
1382 markBufferInitialized(buffer, drawbuffer);
1383 }
1384 return NoError();
1385 }
1386
clearBufferfi(const Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)1387 Error Framebuffer::clearBufferfi(const Context *context,
1388 GLenum buffer,
1389 GLint drawbuffer,
1390 GLfloat depth,
1391 GLint stencil)
1392 {
1393 if (context->getGLState().isRasterizerDiscardEnabled() ||
1394 IsClearBufferMaskedOut(context, buffer))
1395 {
1396 return NoError();
1397 }
1398
1399 if (partialBufferClearNeedsInit(context, buffer))
1400 {
1401 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1402 }
1403
1404 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1405
1406 if (context->isRobustResourceInitEnabled())
1407 {
1408 markBufferInitialized(buffer, drawbuffer);
1409 }
1410 return NoError();
1411 }
1412
getImplementationColorReadFormat(const Context * context) const1413 GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
1414 {
1415 return mImpl->getImplementationColorReadFormat(context);
1416 }
1417
getImplementationColorReadType(const Context * context) const1418 GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
1419 {
1420 return mImpl->getImplementationColorReadType(context);
1421 }
1422
readPixels(const Context * context,const Rectangle & area,GLenum format,GLenum type,void * pixels)1423 Error Framebuffer::readPixels(const Context *context,
1424 const Rectangle &area,
1425 GLenum format,
1426 GLenum type,
1427 void *pixels)
1428 {
1429 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
1430 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
1431
1432 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack);
1433 if (unpackBuffer)
1434 {
1435 unpackBuffer->onPixelUnpack();
1436 }
1437
1438 return NoError();
1439 }
1440
blit(const Context * context,const Rectangle & sourceArea,const Rectangle & destArea,GLbitfield mask,GLenum filter)1441 Error Framebuffer::blit(const Context *context,
1442 const Rectangle &sourceArea,
1443 const Rectangle &destArea,
1444 GLbitfield mask,
1445 GLenum filter)
1446 {
1447 GLbitfield blitMask = mask;
1448
1449 // Note that blitting is called against draw framebuffer.
1450 // See the code in gl::Context::blitFramebuffer.
1451 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1452 {
1453 blitMask &= ~GL_COLOR_BUFFER_BIT;
1454 }
1455
1456 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1457 {
1458 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1459 }
1460
1461 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1462 {
1463 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1464 }
1465
1466 if (!blitMask)
1467 {
1468 return NoError();
1469 }
1470
1471 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1472 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1473
1474 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1475 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1476
1477 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
1478 }
1479
getSamples(const Context * context)1480 int Framebuffer::getSamples(const Context *context)
1481 {
1482 if (complete(context))
1483 {
1484 return getCachedSamples(context);
1485 }
1486
1487 return 0;
1488 }
1489
getCachedSamples(const Context * context)1490 int Framebuffer::getCachedSamples(const Context *context)
1491 {
1492 // For a complete framebuffer, all attachments must have the same sample count.
1493 // In this case return the first nonzero sample size.
1494 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1495 if (firstNonNullAttachment)
1496 {
1497 ASSERT(firstNonNullAttachment->isAttached());
1498 return firstNonNullAttachment->getSamples();
1499 }
1500
1501 // No attachments found.
1502 return 0;
1503 }
1504
getSamplePosition(size_t index,GLfloat * xy) const1505 Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1506 {
1507 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
1508 return NoError();
1509 }
1510
hasValidDepthStencil() const1511 bool Framebuffer::hasValidDepthStencil() const
1512 {
1513 return mState.getDepthStencilAttachment() != nullptr;
1514 }
1515
setAttachment(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource)1516 void Framebuffer::setAttachment(const Context *context,
1517 GLenum type,
1518 GLenum binding,
1519 const ImageIndex &textureIndex,
1520 FramebufferAttachmentObject *resource)
1521 {
1522 setAttachment(context, type, binding, textureIndex, resource,
1523 FramebufferAttachment::kDefaultNumViews,
1524 FramebufferAttachment::kDefaultBaseViewIndex,
1525 FramebufferAttachment::kDefaultMultiviewLayout,
1526 FramebufferAttachment::kDefaultViewportOffsets);
1527 }
1528
setAttachment(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLuint baseViewIndex,GLenum multiviewLayout,const GLint * viewportOffsets)1529 void Framebuffer::setAttachment(const Context *context,
1530 GLenum type,
1531 GLenum binding,
1532 const ImageIndex &textureIndex,
1533 FramebufferAttachmentObject *resource,
1534 GLsizei numViews,
1535 GLuint baseViewIndex,
1536 GLenum multiviewLayout,
1537 const GLint *viewportOffsets)
1538 {
1539 // Context may be null in unit tests.
1540 if (!context || !context->isWebGL1())
1541 {
1542 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1543 multiviewLayout, viewportOffsets);
1544 return;
1545 }
1546
1547 switch (binding)
1548 {
1549 case GL_DEPTH_STENCIL:
1550 case GL_DEPTH_STENCIL_ATTACHMENT:
1551 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
1552 resource, numViews, baseViewIndex,
1553 multiviewLayout, viewportOffsets);
1554 break;
1555 case GL_DEPTH:
1556 case GL_DEPTH_ATTACHMENT:
1557 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1558 numViews, baseViewIndex, multiviewLayout,
1559 viewportOffsets);
1560 break;
1561 case GL_STENCIL:
1562 case GL_STENCIL_ATTACHMENT:
1563 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1564 numViews, baseViewIndex, multiviewLayout,
1565 viewportOffsets);
1566 break;
1567 default:
1568 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1569 baseViewIndex, multiviewLayout, viewportOffsets);
1570 return;
1571 }
1572
1573 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1574 viewportOffsets);
1575 }
1576
setAttachmentMultiviewLayered(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLint baseViewIndex)1577 void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1578 GLenum type,
1579 GLenum binding,
1580 const ImageIndex &textureIndex,
1581 FramebufferAttachmentObject *resource,
1582 GLsizei numViews,
1583 GLint baseViewIndex)
1584 {
1585 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1586 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1587 FramebufferAttachment::kDefaultViewportOffsets);
1588 }
1589
setAttachmentMultiviewSideBySide(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,const GLint * viewportOffsets)1590 void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1591 GLenum type,
1592 GLenum binding,
1593 const ImageIndex &textureIndex,
1594 FramebufferAttachmentObject *resource,
1595 GLsizei numViews,
1596 const GLint *viewportOffsets)
1597 {
1598 setAttachment(context, type, binding, textureIndex, resource, numViews,
1599 FramebufferAttachment::kDefaultBaseViewIndex,
1600 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1601 }
1602
commitWebGL1DepthStencilIfConsistent(const Context * context,GLsizei numViews,GLuint baseViewIndex,GLenum multiviewLayout,const GLint * viewportOffsets)1603 void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1604 GLsizei numViews,
1605 GLuint baseViewIndex,
1606 GLenum multiviewLayout,
1607 const GLint *viewportOffsets)
1608 {
1609 int count = 0;
1610
1611 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1612 &mState.mWebGLDepthAttachment,
1613 &mState.mWebGLStencilAttachment}};
1614 for (FramebufferAttachment *attachment : attachments)
1615 {
1616 if (attachment->isAttached())
1617 {
1618 count++;
1619 }
1620 }
1621
1622 mState.mWebGLDepthStencilConsistent = (count <= 1);
1623 if (!mState.mWebGLDepthStencilConsistent)
1624 {
1625 // Inconsistent.
1626 return;
1627 }
1628
1629 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1630 if (attachment.type() == GL_TEXTURE)
1631 {
1632 return attachment.getTextureImageIndex();
1633 }
1634 else
1635 {
1636 return ImageIndex::MakeInvalid();
1637 }
1638 };
1639
1640 if (mState.mWebGLDepthAttachment.isAttached())
1641 {
1642 const auto &depth = mState.mWebGLDepthAttachment;
1643 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
1644 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1645 baseViewIndex, multiviewLayout, viewportOffsets);
1646 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1647 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1648 }
1649 else if (mState.mWebGLStencilAttachment.isAttached())
1650 {
1651 const auto &stencil = mState.mWebGLStencilAttachment;
1652 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1653 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1654 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
1655 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1656 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1657 }
1658 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1659 {
1660 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
1661 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
1662 getImageIndexIfTextureAttachment(depthStencil),
1663 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1664 viewportOffsets);
1665 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
1666 getImageIndexIfTextureAttachment(depthStencil),
1667 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1668 viewportOffsets);
1669 }
1670 else
1671 {
1672 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1673 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1674 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1675 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1676 }
1677 }
1678
setAttachmentImpl(const Context * context,GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource,GLsizei numViews,GLuint baseViewIndex,GLenum multiviewLayout,const GLint * viewportOffsets)1679 void Framebuffer::setAttachmentImpl(const Context *context,
1680 GLenum type,
1681 GLenum binding,
1682 const ImageIndex &textureIndex,
1683 FramebufferAttachmentObject *resource,
1684 GLsizei numViews,
1685 GLuint baseViewIndex,
1686 GLenum multiviewLayout,
1687 const GLint *viewportOffsets)
1688 {
1689 switch (binding)
1690 {
1691 case GL_DEPTH_STENCIL:
1692 case GL_DEPTH_STENCIL_ATTACHMENT:
1693 {
1694 // ensure this is a legitimate depth+stencil format
1695 FramebufferAttachmentObject *attachmentObj = resource;
1696 if (resource)
1697 {
1698 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
1699 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1700 {
1701 // Attaching nullptr detaches the current attachment.
1702 attachmentObj = nullptr;
1703 }
1704 }
1705
1706 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1707 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
1708 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1709 viewportOffsets);
1710 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1711 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1712 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1713 viewportOffsets);
1714 break;
1715 }
1716
1717 case GL_DEPTH:
1718 case GL_DEPTH_ATTACHMENT:
1719 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1720 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1721 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1722 break;
1723
1724 case GL_STENCIL:
1725 case GL_STENCIL_ATTACHMENT:
1726 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1727 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1728 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1729 break;
1730
1731 case GL_BACK:
1732 updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1733 &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1734 resource, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
1735 break;
1736
1737 default:
1738 {
1739 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1740 ASSERT(colorIndex < mState.mColorAttachments.size());
1741 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
1742 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
1743 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
1744 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1745 viewportOffsets);
1746
1747 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1748 // formsRenderingFeedbackLoopWith
1749 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1750 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
1751 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
1752 }
1753 break;
1754 }
1755
1756 mAttachedTextures.reset();
1757 }
1758
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,GLenum multiviewLayout,const GLint * viewportOffsets)1759 void Framebuffer::updateAttachment(const Context *context,
1760 FramebufferAttachment *attachment,
1761 size_t dirtyBit,
1762 angle::ObserverBinding *onDirtyBinding,
1763 GLenum type,
1764 GLenum binding,
1765 const ImageIndex &textureIndex,
1766 FramebufferAttachmentObject *resource,
1767 GLsizei numViews,
1768 GLuint baseViewIndex,
1769 GLenum multiviewLayout,
1770 const GLint *viewportOffsets)
1771 {
1772 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1773 multiviewLayout, viewportOffsets);
1774 mDirtyBits.set(dirtyBit);
1775 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
1776 onDirtyBinding->bind(resource);
1777 }
1778
resetAttachment(const Context * context,GLenum binding)1779 void Framebuffer::resetAttachment(const Context *context, GLenum binding)
1780 {
1781 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
1782 }
1783
syncState(const Context * context)1784 void Framebuffer::syncState(const Context *context)
1785 {
1786 if (mDirtyBits.any())
1787 {
1788 mImpl->syncState(context, mDirtyBits);
1789 mDirtyBits.reset();
1790 if (mId != 0)
1791 {
1792 mCachedStatus.reset();
1793 }
1794 }
1795 }
1796
onSubjectStateChange(const Context * context,angle::SubjectIndex index,angle::SubjectMessage message)1797 void Framebuffer::onSubjectStateChange(const Context *context,
1798 angle::SubjectIndex index,
1799 angle::SubjectMessage message)
1800 {
1801 // Only reset the cached status if this is not the default framebuffer. The default framebuffer
1802 // will still use this channel to mark itself dirty.
1803 if (mId != 0)
1804 {
1805 // TOOD(jmadill): Make this only update individual attachments to do less work.
1806 mCachedStatus.reset();
1807 }
1808
1809 FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
1810
1811 // Mark the appropriate init flag.
1812 mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
1813 }
1814
getAttachmentFromSubjectIndex(angle::SubjectIndex index)1815 FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
1816 {
1817 switch (index)
1818 {
1819 case DIRTY_BIT_DEPTH_ATTACHMENT:
1820 return &mState.mDepthAttachment;
1821 case DIRTY_BIT_STENCIL_ATTACHMENT:
1822 return &mState.mStencilAttachment;
1823 default:
1824 size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
1825 ASSERT(colorIndex < mState.mColorAttachments.size());
1826 return &mState.mColorAttachments[colorIndex];
1827 }
1828 }
1829
complete(const Context * context)1830 bool Framebuffer::complete(const Context *context)
1831 {
1832 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1833 }
1834
cachedComplete() const1835 bool Framebuffer::cachedComplete() const
1836 {
1837 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
1838 }
1839
formsRenderingFeedbackLoopWith(const State & state) const1840 bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1841 {
1842 const Program *program = state.getProgram();
1843
1844 // TODO(jmadill): Default framebuffer feedback loops.
1845 if (mId == 0)
1846 {
1847 return false;
1848 }
1849
1850 // The bitset will skip inactive draw buffers.
1851 for (size_t drawIndex : mState.mEnabledDrawBuffers)
1852 {
1853 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1854 ASSERT(attachment.isAttached());
1855 if (attachment.type() == GL_TEXTURE)
1856 {
1857 // Validate the feedback loop.
1858 if (program->samplesFromTexture(state, attachment.id()))
1859 {
1860 return true;
1861 }
1862 }
1863 }
1864
1865 // Validate depth-stencil feedback loop.
1866 const auto &dsState = state.getDepthStencilState();
1867
1868 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1869 const FramebufferAttachment *depth = getDepthbuffer();
1870 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1871 {
1872 if (program->samplesFromTexture(state, depth->id()))
1873 {
1874 return true;
1875 }
1876 }
1877
1878 // Note: we assume the front and back masks are the same for WebGL.
1879 const FramebufferAttachment *stencil = getStencilbuffer();
1880 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1881 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1882 dsState.stencilWritemask != 0)
1883 {
1884 // Skip the feedback loop check if depth/stencil point to the same resource.
1885 if (!depth || *stencil != *depth)
1886 {
1887 if (program->samplesFromTexture(state, stencil->id()))
1888 {
1889 return true;
1890 }
1891 }
1892 }
1893
1894 return false;
1895 }
1896
formsCopyingFeedbackLoopWith(GLuint copyTextureID,GLint copyTextureLevel,GLint copyTextureLayer) const1897 bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1898 GLint copyTextureLevel,
1899 GLint copyTextureLayer) const
1900 {
1901 if (mId == 0)
1902 {
1903 // It seems impossible to form a texture copying feedback loop with the default FBO.
1904 return false;
1905 }
1906
1907 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1908 ASSERT(readAttachment);
1909
1910 if (readAttachment->isTextureWithId(copyTextureID))
1911 {
1912 const auto &imageIndex = readAttachment->getTextureImageIndex();
1913 if (imageIndex.mipIndex == copyTextureLevel)
1914 {
1915 // Check 3D/Array texture layers.
1916 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1917 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1918 imageIndex.layerIndex == copyTextureLayer;
1919 }
1920 }
1921 return false;
1922 }
1923
getDefaultWidth() const1924 GLint Framebuffer::getDefaultWidth() const
1925 {
1926 return mState.getDefaultWidth();
1927 }
1928
getDefaultHeight() const1929 GLint Framebuffer::getDefaultHeight() const
1930 {
1931 return mState.getDefaultHeight();
1932 }
1933
getDefaultSamples() const1934 GLint Framebuffer::getDefaultSamples() const
1935 {
1936 return mState.getDefaultSamples();
1937 }
1938
getDefaultFixedSampleLocations() const1939 bool Framebuffer::getDefaultFixedSampleLocations() const
1940 {
1941 return mState.getDefaultFixedSampleLocations();
1942 }
1943
setDefaultWidth(GLint defaultWidth)1944 void Framebuffer::setDefaultWidth(GLint defaultWidth)
1945 {
1946 mState.mDefaultWidth = defaultWidth;
1947 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1948 }
1949
setDefaultHeight(GLint defaultHeight)1950 void Framebuffer::setDefaultHeight(GLint defaultHeight)
1951 {
1952 mState.mDefaultHeight = defaultHeight;
1953 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1954 }
1955
setDefaultSamples(GLint defaultSamples)1956 void Framebuffer::setDefaultSamples(GLint defaultSamples)
1957 {
1958 mState.mDefaultSamples = defaultSamples;
1959 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1960 }
1961
setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)1962 void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)
1963 {
1964 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1965 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1966 }
1967
1968 // TODO(jmadill): Remove this kludge.
checkStatus(const ValidationContext * context)1969 GLenum Framebuffer::checkStatus(const ValidationContext *context)
1970 {
1971 return checkStatus(static_cast<const Context *>(context));
1972 }
1973
getSamples(const ValidationContext * context)1974 int Framebuffer::getSamples(const ValidationContext *context)
1975 {
1976 return getSamples(static_cast<const Context *>(context));
1977 }
1978
getNumViews() const1979 GLsizei Framebuffer::getNumViews() const
1980 {
1981 return mState.getNumViews();
1982 }
1983
getBaseViewIndex() const1984 GLint Framebuffer::getBaseViewIndex() const
1985 {
1986 return mState.getBaseViewIndex();
1987 }
1988
getViewportOffsets() const1989 const std::vector<Offset> *Framebuffer::getViewportOffsets() const
1990 {
1991 return mState.getViewportOffsets();
1992 }
1993
getMultiviewLayout() const1994 GLenum Framebuffer::getMultiviewLayout() const
1995 {
1996 return mState.getMultiviewLayout();
1997 }
1998
ensureDrawAttachmentsInitialized(const Context * context)1999 Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
2000 {
2001 if (!context->isRobustResourceInitEnabled())
2002 {
2003 return NoError();
2004 }
2005
2006 // Note: we don't actually filter by the draw attachment enum. Just init everything.
2007 for (size_t bit : mState.mResourceNeedsInit)
2008 {
2009 switch (bit)
2010 {
2011 case DIRTY_BIT_DEPTH_ATTACHMENT:
2012 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2013 break;
2014 case DIRTY_BIT_STENCIL_ATTACHMENT:
2015 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2016 break;
2017 default:
2018 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2019 break;
2020 }
2021 }
2022
2023 mState.mResourceNeedsInit.reset();
2024 return NoError();
2025 }
2026
ensureReadAttachmentInitialized(const Context * context,GLbitfield blitMask)2027 Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
2028 {
2029 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2030 {
2031 return NoError();
2032 }
2033
2034 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
2035 {
2036 size_t readIndex = mState.getReadIndex();
2037 if (mState.mResourceNeedsInit[readIndex])
2038 {
2039 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2040 mState.mResourceNeedsInit.reset(readIndex);
2041 }
2042 }
2043
2044 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
2045 {
2046 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2047 {
2048 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2049 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2050 }
2051 }
2052
2053 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
2054 {
2055 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2056 {
2057 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2058 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2059 }
2060 }
2061
2062 return NoError();
2063 }
2064
markDrawAttachmentsInitialized(bool color,bool depth,bool stencil)2065 void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2066 {
2067 // Mark attachments as initialized.
2068 if (color)
2069 {
2070 for (auto colorIndex : mState.mEnabledDrawBuffers)
2071 {
2072 auto &colorAttachment = mState.mColorAttachments[colorIndex];
2073 ASSERT(colorAttachment.isAttached());
2074 colorAttachment.setInitState(InitState::Initialized);
2075 mState.mResourceNeedsInit.reset(colorIndex);
2076 }
2077 }
2078
2079 if (depth && mState.mDepthAttachment.isAttached())
2080 {
2081 mState.mDepthAttachment.setInitState(InitState::Initialized);
2082 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2083 }
2084
2085 if (stencil && mState.mStencilAttachment.isAttached())
2086 {
2087 mState.mStencilAttachment.setInitState(InitState::Initialized);
2088 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2089 }
2090 }
2091
markBufferInitialized(GLenum bufferType,GLint bufferIndex)2092 void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2093 {
2094 switch (bufferType)
2095 {
2096 case GL_COLOR:
2097 {
2098 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2099 if (mState.mColorAttachments[bufferIndex].isAttached())
2100 {
2101 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2102 mState.mResourceNeedsInit.reset(bufferIndex);
2103 }
2104 break;
2105 }
2106 case GL_DEPTH:
2107 {
2108 if (mState.mDepthAttachment.isAttached())
2109 {
2110 mState.mDepthAttachment.setInitState(InitState::Initialized);
2111 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2112 }
2113 break;
2114 }
2115 case GL_STENCIL:
2116 {
2117 if (mState.mStencilAttachment.isAttached())
2118 {
2119 mState.mStencilAttachment.setInitState(InitState::Initialized);
2120 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2121 }
2122 break;
2123 }
2124 case GL_DEPTH_STENCIL:
2125 {
2126 if (mState.mDepthAttachment.isAttached())
2127 {
2128 mState.mDepthAttachment.setInitState(InitState::Initialized);
2129 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2130 }
2131 if (mState.mStencilAttachment.isAttached())
2132 {
2133 mState.mStencilAttachment.setInitState(InitState::Initialized);
2134 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2135 }
2136 break;
2137 }
2138 default:
2139 UNREACHABLE();
2140 break;
2141 }
2142 }
2143
getDimensions() const2144 Box Framebuffer::getDimensions() const
2145 {
2146 return mState.getDimensions();
2147 }
2148
ensureBufferInitialized(const Context * context,GLenum bufferType,GLint bufferIndex)2149 Error Framebuffer::ensureBufferInitialized(const Context *context,
2150 GLenum bufferType,
2151 GLint bufferIndex)
2152 {
2153 ASSERT(context->isRobustResourceInitEnabled());
2154
2155 if (mState.mResourceNeedsInit.none())
2156 {
2157 return NoError();
2158 }
2159
2160 switch (bufferType)
2161 {
2162 case GL_COLOR:
2163 {
2164 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2165 if (mState.mResourceNeedsInit[bufferIndex])
2166 {
2167 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2168 mState.mResourceNeedsInit.reset(bufferIndex);
2169 }
2170 break;
2171 }
2172 case GL_DEPTH:
2173 {
2174 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2175 {
2176 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2177 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2178 }
2179 break;
2180 }
2181 case GL_STENCIL:
2182 {
2183 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2184 {
2185 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2186 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2187 }
2188 break;
2189 }
2190 case GL_DEPTH_STENCIL:
2191 {
2192 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2193 {
2194 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2195 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2196 }
2197 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2198 {
2199 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2200 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2201 }
2202 break;
2203 }
2204 default:
2205 UNREACHABLE();
2206 break;
2207 }
2208
2209 return NoError();
2210 }
2211
partialBufferClearNeedsInit(const Context * context,GLenum bufferType)2212 bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2213 {
2214 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2215 {
2216 return false;
2217 }
2218
2219 switch (bufferType)
2220 {
2221 case GL_COLOR:
2222 return partialClearNeedsInit(context, true, false, false);
2223 case GL_DEPTH:
2224 return partialClearNeedsInit(context, false, true, false);
2225 case GL_STENCIL:
2226 return partialClearNeedsInit(context, false, false, true);
2227 case GL_DEPTH_STENCIL:
2228 return partialClearNeedsInit(context, false, true, true);
2229 default:
2230 UNREACHABLE();
2231 return false;
2232 }
2233 }
2234
hasTextureAttachment(const Texture * texture) const2235 bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2236 {
2237 if (!mAttachedTextures.valid())
2238 {
2239 std::set<const FramebufferAttachmentObject *> attachedTextures;
2240
2241 for (const auto &colorAttachment : mState.mColorAttachments)
2242 {
2243 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2244 {
2245 attachedTextures.insert(colorAttachment.getResource());
2246 }
2247 }
2248
2249 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2250 {
2251 attachedTextures.insert(mState.mDepthAttachment.getResource());
2252 }
2253
2254 if (mState.mStencilAttachment.isAttached() &&
2255 mState.mStencilAttachment.type() == GL_TEXTURE)
2256 {
2257 attachedTextures.insert(mState.mStencilAttachment.getResource());
2258 }
2259
2260 mAttachedTextures = std::move(attachedTextures);
2261 }
2262
2263 return (mAttachedTextures.value().count(texture) > 0);
2264 }
2265
2266 } // namespace gl
2267