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