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