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