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