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