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