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