blob: 187733fc2a6a1b6b968121c165ad473215b32c40 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// 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
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Framebuffer.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040011
Jamie Madillcc86d642015-11-24 13:00:07 -050012#include "common/Optional.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040013#include "common/bitset_utils.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040014#include "common/utilities.h"
15#include "libANGLE/Config.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Context.h"
Jamie Madill6c1f6712017-02-14 19:08:04 -050017#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050018#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040019#include "libANGLE/Renderbuffer.h"
20#include "libANGLE/Surface.h"
21#include "libANGLE/Texture.h"
Brandon Jones76746f92017-11-22 11:44:41 -080022#include "libANGLE/angletypes.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040023#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040024#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050025#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040026#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050027#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040028#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040029
Jamie Madill362876b2016-06-16 14:46:59 -040030using namespace angle;
31
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000032namespace gl
33{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000034
Jamie Madilld1405e52015-03-05 15:41:39 -050035namespace
36{
Jamie Madill362876b2016-06-16 14:46:59 -040037
Jamie Madill1e5499d2017-04-05 11:22:16 -040038void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmentObject *resource)
Jamie Madilld1405e52015-03-05 15:41:39 -050039{
Jamie Madill362876b2016-06-16 14:46:59 -040040 binding->bind(resource ? resource->getDirtyChannel() : nullptr);
Jamie Madilld1405e52015-03-05 15:41:39 -050041}
Jamie Madill362876b2016-06-16 14:46:59 -040042
Martin Radev9bc9a322017-07-21 14:28:17 +030043bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
44 const FramebufferAttachment *secondAttachment)
45{
46 ASSERT(firstAttachment && secondAttachment);
47 ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
48
49 if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
50 {
51 return false;
52 }
53 if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
54 {
55 return false;
56 }
57 if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
58 {
59 return false;
60 }
61 if (firstAttachment->getMultiviewViewportOffsets() !=
62 secondAttachment->getMultiviewViewportOffsets())
63 {
64 return false;
65 }
66 return true;
67}
68
Geoff Lang9f10b772017-05-16 15:51:03 -040069bool CheckAttachmentCompleteness(const Context *context, 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 false;
77 }
78
79 const InternalFormat &format = *attachment.getFormat().info;
80 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
81 {
82 return false;
83 }
84
85 if (attachment.type() == GL_TEXTURE)
86 {
87 if (attachment.layer() >= size.depth)
88 {
89 return false;
90 }
91
92 // ES3 specifies that cube map texture attachments must be cube complete.
93 // This language is missing from the ES2 spec, but we enforce it here because some
94 // desktop OpenGL drivers also enforce this validation.
95 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
96 const Texture *texture = attachment.getTexture();
97 ASSERT(texture);
98 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
99 !texture->getTextureState().isCubeComplete())
100 {
101 return false;
102 }
Geoff Lang857c09d2017-05-16 15:55:04 -0400103
104 if (!texture->getImmutableFormat())
105 {
106 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
107
108 // From the ES 3.0 spec, pg 213:
109 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
110 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
111 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
112 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
113 // the effective maximum texture level defined in the Mipmapping discussion of
114 // section 3.8.10.4.
115 if (attachmentMipLevel < texture->getBaseLevel() ||
116 attachmentMipLevel > texture->getMipmapMaxLevel())
117 {
118 return false;
119 }
120
121 // Form the ES 3.0 spec, pg 213/214:
122 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
123 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
124 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
125 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
126 // a cubemap texture, the texture must also be cube complete.
127 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
128 {
129 return false;
130 }
131 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400132 }
133
134 return true;
135};
136
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400137bool CheckAttachmentSampleCompleteness(const Context *context,
138 const FramebufferAttachment &attachment,
139 bool colorAttachment,
140 Optional<int> *samples,
Geoff Lang92019432017-11-20 13:09:34 -0500141 Optional<bool> *fixedSampleLocations)
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400142{
143 ASSERT(attachment.isAttached());
144
145 if (attachment.type() == GL_TEXTURE)
146 {
147 const Texture *texture = attachment.getTexture();
148 ASSERT(texture);
149
150 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
151
152 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
153 // the same for all attached textures.
Geoff Lang92019432017-11-20 13:09:34 -0500154 bool fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type,
155 attachmentImageIndex.mipIndex);
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400156 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
157 {
158 return false;
159 }
160 else
161 {
162 *fixedSampleLocations = fixedSampleloc;
163 }
164 }
165
166 if (samples->valid())
167 {
168 if (attachment.getSamples() != samples->value())
169 {
170 if (colorAttachment)
171 {
172 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
173 // all color attachments have the same number of samples for the FBO to be complete.
174 return false;
175 }
176 else
177 {
178 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
179 // when its depth or stencil samples are a multiple of the number of color samples.
180 if (!context->getExtensions().framebufferMixedSamples)
181 {
182 return false;
183 }
184
185 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
186 {
187 return false;
188 }
189 }
190 }
191 }
192 else
193 {
194 *samples = attachment.getSamples();
195 }
196
197 return true;
198}
199
Jamie Madill05b35b22017-10-03 09:01:44 -0400200// Needed to index into the attachment arrays/bitsets.
Jamie Madill682efdc2017-10-03 14:10:29 -0400201static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madill05b35b22017-10-03 09:01:44 -0400202 gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
203 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400204static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madill05b35b22017-10-03 09:01:44 -0400205 gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
206 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400207static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
Jamie Madill05b35b22017-10-03 09:01:44 -0400208 gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
209 "Framebuffer Dirty bit mismatch");
210
211Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
212{
213 ASSERT(attachment->isAttached());
214 if (attachment->initState() == InitState::MayNeedInit)
215 {
216 ANGLE_TRY(attachment->initializeContents(context));
217 }
218 return NoError();
219}
220
221bool IsColorMaskedOut(const BlendState &blend)
222{
223 return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
224 !blend.colorMaskAlpha);
225}
226
227bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
228{
229 return !depthStencil.depthMask;
230}
231
232bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
233{
234 return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
235}
236
237bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
238{
239 switch (buffer)
240 {
241 case GL_COLOR:
242 return IsColorMaskedOut(context->getGLState().getBlendState());
243 case GL_DEPTH:
244 return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
245 case GL_STENCIL:
246 return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
247 case GL_DEPTH_STENCIL:
248 return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
249 IsStencilMaskedOut(context->getGLState().getDepthStencilState());
250 default:
251 UNREACHABLE();
252 return true;
253 }
254}
255
Jamie Madill362876b2016-06-16 14:46:59 -0400256} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500257
Jamie Madill6f60d052017-02-22 15:20:11 -0500258// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400259FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500260 : mLabel(),
261 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400262 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500263 mReadBufferState(GL_BACK),
Brandon Jones76746f92017-11-22 11:44:41 -0800264 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800265 mDefaultWidth(0),
266 mDefaultHeight(0),
267 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500268 mDefaultFixedSampleLocations(GL_FALSE),
269 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400270{
Geoff Langd90d3882017-03-21 10:49:54 -0400271 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500272 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400273}
274
Jamie Madill48ef11b2016-04-27 15:21:52 -0400275FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -0500276 : mLabel(),
277 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -0500278 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800279 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
Brandon Jones76746f92017-11-22 11:44:41 -0800280 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800281 mDefaultWidth(0),
282 mDefaultHeight(0),
283 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500284 mDefaultFixedSampleLocations(GL_FALSE),
285 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500286{
Geoff Langa15472a2015-08-11 11:48:03 -0400287 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500288 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
289}
290
Jamie Madill48ef11b2016-04-27 15:21:52 -0400291FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500292{
Jamie Madilld1405e52015-03-05 15:41:39 -0500293}
294
Jamie Madill48ef11b2016-04-27 15:21:52 -0400295const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500296{
297 return mLabel;
298}
299
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400300const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
301{
302 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
303 {
304 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
305 }
306
307 switch (attachment)
308 {
309 case GL_COLOR:
310 case GL_BACK:
311 return getColorAttachment(0);
312 case GL_DEPTH:
313 case GL_DEPTH_ATTACHMENT:
314 return getDepthAttachment();
315 case GL_STENCIL:
316 case GL_STENCIL_ATTACHMENT:
317 return getStencilAttachment();
318 case GL_DEPTH_STENCIL:
319 case GL_DEPTH_STENCIL_ATTACHMENT:
320 return getDepthStencilAttachment();
321 default:
322 UNREACHABLE();
323 return nullptr;
324 }
325}
326
Jamie Madill05b35b22017-10-03 09:01:44 -0400327size_t FramebufferState::getReadIndex() const
Jamie Madill7147f012015-03-05 15:41:40 -0500328{
Jamie Madill231c7f52017-04-26 13:45:37 -0400329 ASSERT(mReadBufferState == GL_BACK ||
330 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
331 size_t readIndex = (mReadBufferState == GL_BACK
332 ? 0
333 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500334 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill05b35b22017-10-03 09:01:44 -0400335 return readIndex;
336}
337
338const FramebufferAttachment *FramebufferState::getReadAttachment() const
339{
340 if (mReadBufferState == GL_NONE)
341 {
342 return nullptr;
343 }
344 size_t readIndex = getReadIndex();
Jamie Madill2d06b732015-04-20 12:53:28 -0400345 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500346}
347
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500348const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
349{
350 auto *colorAttachment = getFirstColorAttachment();
351 if (colorAttachment)
352 {
353 return colorAttachment;
354 }
355 return getDepthOrStencilAttachment();
356}
357
Jamie Madill48ef11b2016-04-27 15:21:52 -0400358const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500359{
Jamie Madill2d06b732015-04-20 12:53:28 -0400360 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500361 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400362 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500363 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400364 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500365 }
366 }
367
368 return nullptr;
369}
370
Jamie Madill48ef11b2016-04-27 15:21:52 -0400371const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500372{
Jamie Madill2d06b732015-04-20 12:53:28 -0400373 if (mDepthAttachment.isAttached())
374 {
375 return &mDepthAttachment;
376 }
377 if (mStencilAttachment.isAttached())
378 {
379 return &mStencilAttachment;
380 }
381 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500382}
383
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500384const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
385{
386 if (mStencilAttachment.isAttached())
387 {
388 return &mStencilAttachment;
389 }
390 return getDepthStencilAttachment();
391}
392
Jamie Madill48ef11b2016-04-27 15:21:52 -0400393const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400394{
395 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400396 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
397 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400398}
399
Jamie Madill48ef11b2016-04-27 15:21:52 -0400400const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400401{
Jamie Madill2d06b732015-04-20 12:53:28 -0400402 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400403}
404
Jamie Madill48ef11b2016-04-27 15:21:52 -0400405const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400406{
Jamie Madill2d06b732015-04-20 12:53:28 -0400407 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400408}
409
Jamie Madill48ef11b2016-04-27 15:21:52 -0400410const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400411{
412 // A valid depth-stencil attachment has the same resource bound to both the
413 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400414 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500415 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400416 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400417 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400418 }
419
420 return nullptr;
421}
422
Jamie Madill48ef11b2016-04-27 15:21:52 -0400423bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500424{
425 Optional<Extents> attachmentSize;
426
Jamie Madill231c7f52017-04-26 13:45:37 -0400427 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500428 if (!attachment.isAttached())
429 {
430 return false;
431 }
432
433 if (!attachmentSize.valid())
434 {
435 attachmentSize = attachment.getSize();
436 return false;
437 }
438
Jeff Gilbert8f8edd62017-10-31 14:26:30 -0700439 const auto &prevSize = attachmentSize.value();
440 const auto &curSize = attachment.getSize();
441 return (curSize.width != prevSize.width || curSize.height != prevSize.height);
Jamie Madillcc86d642015-11-24 13:00:07 -0500442 };
443
444 for (const auto &attachment : mColorAttachments)
445 {
446 if (hasMismatchedSize(attachment))
447 {
448 return false;
449 }
450 }
451
452 if (hasMismatchedSize(mDepthAttachment))
453 {
454 return false;
455 }
456
457 return !hasMismatchedSize(mStencilAttachment);
458}
459
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400460const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
461{
462 ASSERT(drawBufferIdx < mDrawBufferStates.size());
463 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
464 {
465 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
466 // must be COLOR_ATTACHMENTi or NONE"
467 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
468 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
469 return getAttachment(mDrawBufferStates[drawBufferIdx]);
470 }
471 else
472 {
473 return nullptr;
474 }
475}
476
477size_t FramebufferState::getDrawBufferCount() const
478{
479 return mDrawBufferStates.size();
480}
481
Geoff Langb21e20d2016-07-19 15:35:41 -0400482bool FramebufferState::colorAttachmentsAreUniqueImages() const
483{
484 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
485 firstAttachmentIdx++)
486 {
487 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
488 if (!firstAttachment.isAttached())
489 {
490 continue;
491 }
492
493 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
494 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
495 {
496 const gl::FramebufferAttachment &secondAttachment =
497 mColorAttachments[secondAttachmentIdx];
498 if (!secondAttachment.isAttached())
499 {
500 continue;
501 }
502
503 if (firstAttachment == secondAttachment)
504 {
505 return false;
506 }
507 }
508 }
509
510 return true;
511}
512
Jamie Madill9c335862017-07-18 11:51:38 -0400513bool FramebufferState::hasDepth() const
514{
515 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
516}
517
518bool FramebufferState::hasStencil() const
519{
520 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
521}
522
Martin Radev5c00d0d2017-08-07 10:06:59 +0300523GLsizei FramebufferState::getNumViews() const
524{
525 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
526 if (attachment == nullptr)
527 {
528 return FramebufferAttachment::kDefaultNumViews;
529 }
530 return attachment->getNumViews();
531}
532
533const std::vector<Offset> *FramebufferState::getViewportOffsets() const
534{
535 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
536 if (attachment == nullptr)
537 {
538 return nullptr;
539 }
540 return &attachment->getMultiviewViewportOffsets();
541}
542
543GLenum FramebufferState::getMultiviewLayout() const
544{
545 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
546 if (attachment == nullptr)
547 {
548 return GL_NONE;
549 }
550 return attachment->getMultiviewLayout();
551}
552
Martin Radev4e619f52017-08-09 11:50:06 +0300553int FramebufferState::getBaseViewIndex() const
554{
555 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
556 if (attachment == nullptr)
557 {
558 return GL_NONE;
559 }
560 return attachment->getBaseViewIndex();
561}
562
Jamie Madill05b35b22017-10-03 09:01:44 -0400563Box FramebufferState::getDimensions() const
564{
565 ASSERT(attachmentsHaveSameDimensions());
566 ASSERT(getFirstNonNullAttachment() != nullptr);
567 Extents extents = getFirstNonNullAttachment()->getSize();
568 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
569}
570
Jamie Madill7aea7e02016-05-10 10:39:45 -0400571Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400572 : mState(caps),
573 mImpl(factory->createFramebuffer(mState)),
574 mId(id),
575 mCachedStatus(),
576 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
577 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000578{
Corentin Wallez37c39792015-08-20 14:19:46 -0400579 ASSERT(mId != 0);
580 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400581 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
582
Jamie Madill1e5499d2017-04-05 11:22:16 -0400583 for (uint32_t colorIndex = 0;
584 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400585 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400586 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400587 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400588}
589
Jamie Madill4928b7c2017-06-20 12:57:39 -0400590Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400591 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500592 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400593 mId(0),
594 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
595 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
596 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400597{
Geoff Langda88add2014-12-01 10:22:01 -0500598 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400599 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500600
Jamie Madill4928b7c2017-06-20 12:57:39 -0400601 const Context *proxyContext = display->getProxyContext();
602
603 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +0300604 surface, FramebufferAttachment::kDefaultNumViews,
605 FramebufferAttachment::kDefaultBaseViewIndex,
606 FramebufferAttachment::kDefaultMultiviewLayout,
607 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500608
609 if (surface->getConfig()->depthSize > 0)
610 {
Martin Radev5dae57b2017-07-14 16:15:55 +0300611 setAttachmentImpl(
612 proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface,
613 FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex,
614 FramebufferAttachment::kDefaultMultiviewLayout,
615 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500616 }
617
618 if (surface->getConfig()->stencilSize > 0)
619 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400620 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL,
Martin Radev5dae57b2017-07-14 16:15:55 +0300621 gl::ImageIndex::MakeInvalid(), surface,
622 FramebufferAttachment::kDefaultNumViews,
623 FramebufferAttachment::kDefaultBaseViewIndex,
624 FramebufferAttachment::kDefaultMultiviewLayout,
625 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500626 }
Brandon Jones76746f92017-11-22 11:44:41 -0800627 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000628}
629
Corentin Wallezccab69d2017-01-27 16:57:15 -0500630Framebuffer::Framebuffer(rx::GLImplFactory *factory)
631 : mState(),
632 mImpl(factory->createFramebuffer(mState)),
633 mId(0),
634 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
635 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
636 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
637{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400638 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Brandon Jones76746f92017-11-22 11:44:41 -0800639 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500640}
641
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642Framebuffer::~Framebuffer()
643{
Geoff Langda88add2014-12-01 10:22:01 -0500644 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000645}
646
Jamie Madill4928b7c2017-06-20 12:57:39 -0400647void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500648{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400649 for (auto &attachment : mState.mColorAttachments)
650 {
651 attachment.detach(context);
652 }
653 mState.mDepthAttachment.detach(context);
654 mState.mStencilAttachment.detach(context);
655 mState.mWebGLDepthAttachment.detach(context);
656 mState.mWebGLStencilAttachment.detach(context);
657 mState.mWebGLDepthStencilAttachment.detach(context);
658
Jamie Madillc564c072017-06-01 12:45:42 -0400659 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500660}
661
662void Framebuffer::destroyDefault(const egl::Display *display)
663{
Jamie Madillc564c072017-06-01 12:45:42 -0400664 mImpl->destroyDefault(display);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500665}
666
Geoff Lang70d0f492015-12-10 17:45:46 -0500667void Framebuffer::setLabel(const std::string &label)
668{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400669 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500670}
671
672const std::string &Framebuffer::getLabel() const
673{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400674 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500675}
676
Jamie Madill8693bdb2017-09-02 15:32:14 -0400677bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000678{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400679 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680}
681
Jamie Madill8693bdb2017-09-02 15:32:14 -0400682bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000683{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400684 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500685}
Jamie Madille261b442014-06-25 12:42:21 -0400686
Jamie Madill8693bdb2017-09-02 15:32:14 -0400687bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500688{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400689 bool found = false;
690
Jamie Madill362876b2016-06-16 14:46:59 -0400691 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500692 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400693 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
694 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
695 {
696 found = true;
697 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000698 }
699
Jamie Madilla02315b2017-02-23 14:14:47 -0500700 if (context->isWebGL1())
701 {
702 const std::array<FramebufferAttachment *, 3> attachments = {
703 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
704 &mState.mWebGLStencilAttachment}};
705 for (FramebufferAttachment *attachment : attachments)
706 {
707 if (attachment->isAttached() && attachment->type() == resourceType &&
708 attachment->id() == resourceId)
709 {
710 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400711 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500712 }
713 }
714 }
715 else
716 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400717 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
718 DIRTY_BIT_DEPTH_ATTACHMENT))
719 {
720 found = true;
721 }
722 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
723 DIRTY_BIT_STENCIL_ATTACHMENT))
724 {
725 found = true;
726 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500727 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400728
729 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400730}
731
Jamie Madill8693bdb2017-09-02 15:32:14 -0400732bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400733 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400734 GLenum matchType,
735 GLuint matchId,
736 size_t dirtyBit)
737{
738 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
739 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400740 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400741 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -0400742 mState.mResourceNeedsInit.set(dirtyBit, false);
Jamie Madill8693bdb2017-09-02 15:32:14 -0400743 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400744 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400745
746 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000747}
748
Corentin Wallez37c39792015-08-20 14:19:46 -0400749const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000750{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400751 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000752}
753
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400754const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400755{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400756 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400757}
758
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400759const FramebufferAttachment *Framebuffer::getStencilbuffer() const
760{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400761 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400762}
763
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400764const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
765{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400766 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400767}
768
769const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000770{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400771 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000772}
773
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500774const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
775{
776 return mState.getStencilOrDepthStencilAttachment();
777}
778
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400779const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000780{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400781 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000782}
783
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000784GLenum Framebuffer::getReadColorbufferType() const
785{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400786 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400787 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000788}
789
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400790const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000791{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400792 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000793}
794
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400795const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
796{
797 return mState.getFirstNonNullAttachment();
798}
799
Jamie Madill2d06b732015-04-20 12:53:28 -0400800const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000801{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400802 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400803}
804
Geoff Langa15472a2015-08-11 11:48:03 -0400805size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000806{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400807 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400808}
809
810GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
811{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400812 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
813 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000814}
815
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500816const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
817{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400818 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500819}
820
Geoff Lang164d54e2014-12-01 10:55:33 -0500821void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000822{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400823 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500824
825 ASSERT(count <= drawStates.size());
826 std::copy(buffers, buffers + count, drawStates.begin());
827 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500828 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500829
830 mState.mEnabledDrawBuffers.reset();
Brandon Jones76746f92017-11-22 11:44:41 -0800831 mState.mDrawBufferTypeMask.reset();
832
Jamie Madilla4595b82017-01-11 17:36:34 -0500833 for (size_t index = 0; index < count; ++index)
834 {
Brandon Jones76746f92017-11-22 11:44:41 -0800835 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
836
Jamie Madilla4595b82017-01-11 17:36:34 -0500837 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
838 {
839 mState.mEnabledDrawBuffers.set(index);
840 }
841 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500842}
843
Geoff Langa15472a2015-08-11 11:48:03 -0400844const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
845{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400846 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400847}
848
Geoff Lange0cff192017-05-30 13:04:56 -0400849GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
850{
851 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
852 if (attachment == nullptr)
853 {
854 return GL_NONE;
855 }
856
857 GLenum componentType = attachment->getFormat().info->componentType;
858 switch (componentType)
859 {
860 case GL_INT:
861 case GL_UNSIGNED_INT:
862 return componentType;
863
864 default:
865 return GL_FLOAT;
866 }
867}
868
Brandon Jones76746f92017-11-22 11:44:41 -0800869DrawBufferTypeMask Framebuffer::getDrawBufferTypeMask() const
870{
871 return mState.mDrawBufferTypeMask;
872}
873
874DrawBufferMask Framebuffer::getDrawBufferMask() const
875{
876 return mState.mEnabledDrawBuffers;
877}
878
Geoff Langa15472a2015-08-11 11:48:03 -0400879bool Framebuffer::hasEnabledDrawBuffer() const
880{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400881 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400882 {
883 if (getDrawBuffer(drawbufferIdx) != nullptr)
884 {
885 return true;
886 }
887 }
888
889 return false;
890}
891
Geoff Lang9dd95802014-12-01 11:12:59 -0500892GLenum Framebuffer::getReadBufferState() const
893{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400894 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500895}
896
897void Framebuffer::setReadBuffer(GLenum buffer)
898{
Jamie Madillb885e572015-02-03 16:16:04 -0500899 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
900 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400901 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
902 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500903 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000904}
905
Corentin Wallez37c39792015-08-20 14:19:46 -0400906size_t Framebuffer::getNumColorBuffers() const
907{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400908 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400909}
910
Jamie Madill0df8fe42015-11-24 16:10:24 -0500911bool Framebuffer::hasDepth() const
912{
Jamie Madill9c335862017-07-18 11:51:38 -0400913 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500914}
915
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000916bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000917{
Jamie Madill9c335862017-07-18 11:51:38 -0400918 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000919}
920
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000921bool Framebuffer::usingExtendedDrawBuffers() const
922{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400923 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000924 {
Geoff Langa15472a2015-08-11 11:48:03 -0400925 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000926 {
927 return true;
928 }
929 }
930
931 return false;
932}
933
Geoff Lang9aded172017-04-05 11:07:56 -0400934void Framebuffer::invalidateCompletenessCache()
935{
936 if (mId != 0)
937 {
938 mCachedStatus.reset();
939 }
940}
941
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400942GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000943{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500944 // The default framebuffer is always complete except when it is surfaceless in which
945 // case it is always unsupported. We return early because the default framebuffer may
946 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500947 if (mId == 0)
948 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500949 ASSERT(mCachedStatus.valid());
950 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
951 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
952 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500953 }
954
Jamie Madill362876b2016-06-16 14:46:59 -0400955 if (hasAnyDirtyBit() || !mCachedStatus.valid())
956 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400957 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400958 }
959
960 return mCachedStatus.value();
961}
962
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400963GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400964{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400965 const ContextState &state = context->getContextState();
966
Jamie Madill362876b2016-06-16 14:46:59 -0400967 ASSERT(mId != 0);
968
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400969 bool hasAttachments = false;
970 Optional<unsigned int> colorbufferSize;
971 Optional<int> samples;
Geoff Lang92019432017-11-20 13:09:34 -0500972 Optional<bool> fixedSampleLocations;
JiangYizhou461d9a32017-01-04 16:37:26 +0800973 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000974
Martin Radev9bc9a322017-07-21 14:28:17 +0300975 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
976
Jamie Madill48ef11b2016-04-27 15:21:52 -0400977 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000978 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400979 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400981 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000982 {
983 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
984 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000985
Geoff Lang677bb6f2017-04-05 12:40:40 -0400986 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400987 if (format.depthBits > 0 || format.stencilBits > 0)
988 {
989 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
990 }
991
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400992 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
993 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000994 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400995 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000996 }
997
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400998 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
999 // in GLES 3.0, there is no such restriction
1000 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001001 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001002 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001003 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001004 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +00001005 {
1006 return GL_FRAMEBUFFER_UNSUPPORTED;
1007 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001008 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001009 else
1010 {
1011 colorbufferSize = format.pixelBytes;
1012 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001013 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001014
Martin Radev9bc9a322017-07-21 14:28:17 +03001015 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
1016 {
1017 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1018 }
1019
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001020 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1021 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001022 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001023 }
1024
Jamie Madill48ef11b2016-04-27 15:21:52 -04001025 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001026 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001027 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001028 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001030 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031 }
1032
Geoff Lang677bb6f2017-04-05 12:40:40 -04001033 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001034 if (format.depthBits == 0)
1035 {
1036 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001037 }
1038
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001039 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1040 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001041 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001042 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001043 }
Sami Väisänena797e062016-05-12 15:23:40 +03001044
Martin Radev9bc9a322017-07-21 14:28:17 +03001045 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1046 {
1047 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1048 }
1049
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001050 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1051 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001052 }
1053
Jamie Madill48ef11b2016-04-27 15:21:52 -04001054 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001055 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001056 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001057 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001058 {
1059 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1060 }
1061
Geoff Lang677bb6f2017-04-05 12:40:40 -04001062 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001063 if (format.stencilBits == 0)
1064 {
1065 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001066 }
1067
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001068 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1069 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001070 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001071 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001072 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001073
Martin Radev9bc9a322017-07-21 14:28:17 +03001074 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1075 {
1076 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1077 }
1078
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001079 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1080 hasAttachments = true;
1081 }
1082
1083 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1084 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1085 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1086 {
1087 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001088 }
1089
Jamie Madilla02315b2017-02-23 14:14:47 -05001090 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1091 if (state.isWebGL1())
1092 {
1093 if (!mState.mWebGLDepthStencilConsistent)
1094 {
1095 return GL_FRAMEBUFFER_UNSUPPORTED;
1096 }
1097
1098 if (mState.mWebGLDepthStencilAttachment.isAttached())
1099 {
1100 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1101 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1102 {
1103 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1104 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001105
1106 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1107 &mState.mWebGLDepthStencilAttachment))
1108 {
1109 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1110 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001111 }
1112 else if (mState.mStencilAttachment.isAttached() &&
1113 mState.mStencilAttachment.getDepthSize() > 0)
1114 {
1115 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1116 }
1117 else if (mState.mDepthAttachment.isAttached() &&
1118 mState.mDepthAttachment.getStencilSize() > 0)
1119 {
1120 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1121 }
1122 }
1123
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001124 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1125 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1126 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001127 GLint defaultWidth = mState.getDefaultWidth();
1128 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001129 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001130 {
1131 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001132 }
1133
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001134 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001135 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001136 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1137 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001138 {
1139 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1140 }
1141
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001142 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1143 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001144 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1145 {
1146 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1147 }
1148
Kenneth Russellce8602a2017-10-03 18:23:08 -07001149 // The WebGL conformance tests implicitly define that all framebuffer
1150 // attachments must be unique. For example, the same level of a texture can
1151 // not be attached to two different color attachments.
1152 if (state.getExtensions().webglCompatibility)
1153 {
1154 if (!mState.colorAttachmentsAreUniqueImages())
1155 {
1156 return GL_FRAMEBUFFER_UNSUPPORTED;
1157 }
1158 }
1159
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001160 syncState(context);
Kenneth Russellce8602a2017-10-03 18:23:08 -07001161 if (!mImpl->checkStatus(context))
Jamie Madillcc86d642015-11-24 13:00:07 -05001162 {
1163 return GL_FRAMEBUFFER_UNSUPPORTED;
1164 }
1165
1166 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001167}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001168
Jamie Madill4928b7c2017-06-20 12:57:39 -04001169Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001170{
Jamie Madill05b35b22017-10-03 09:01:44 -04001171 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1172 // can be no-ops, so we should probably do that to ensure consistency.
1173 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1174
Jamie Madill4928b7c2017-06-20 12:57:39 -04001175 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001176}
1177
Jamie Madill4928b7c2017-06-20 12:57:39 -04001178Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001179{
Jamie Madill05b35b22017-10-03 09:01:44 -04001180 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1181 // can be no-ops, so we should probably do that to ensure consistency.
1182 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1183
Jamie Madill4928b7c2017-06-20 12:57:39 -04001184 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001185}
1186
Jamie Madill05b35b22017-10-03 09:01:44 -04001187bool Framebuffer::partialClearNeedsInit(const Context *context,
1188 bool color,
1189 bool depth,
1190 bool stencil)
1191{
1192 const auto &glState = context->getGLState();
1193
1194 if (!glState.isRobustResourceInitEnabled())
1195 {
1196 return false;
1197 }
1198
1199 // Scissors can affect clearing.
1200 // TODO(jmadill): Check for complete scissor overlap.
1201 if (glState.isScissorTestEnabled())
1202 {
1203 return true;
1204 }
1205
1206 // If colors masked, we must clear before we clear. Do a simple check.
1207 // TODO(jmadill): Filter out unused color channels from the test.
1208 if (color)
1209 {
1210 const auto &blend = glState.getBlendState();
1211 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1212 blend.colorMaskAlpha))
1213 {
1214 return true;
1215 }
1216 }
1217
1218 const auto &depthStencil = glState.getDepthStencilState();
1219 ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
1220 if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
1221 {
1222 return true;
1223 }
1224
1225 return false;
1226}
1227
Jamie Madill4928b7c2017-06-20 12:57:39 -04001228Error Framebuffer::invalidateSub(const Context *context,
1229 size_t count,
1230 const GLenum *attachments,
1231 const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001232{
Jamie Madill05b35b22017-10-03 09:01:44 -04001233 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1234 // can be no-ops, so we should probably do that to ensure consistency.
1235 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1236
Jamie Madill4928b7c2017-06-20 12:57:39 -04001237 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001238}
1239
Jamie Madillc564c072017-06-01 12:45:42 -04001240Error Framebuffer::clear(const gl::Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001241{
Jamie Madill05b35b22017-10-03 09:01:44 -04001242 const auto &glState = context->getGLState();
1243 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001244 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001245 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001246 }
1247
Jamie Madill05b35b22017-10-03 09:01:44 -04001248 const auto &blend = glState.getBlendState();
1249 const auto &depthStencil = glState.getDepthStencilState();
1250
1251 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
1252 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
1253 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
1254
1255 if (partialClearNeedsInit(context, color, depth, stencil))
1256 {
1257 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1258 }
1259
1260 ANGLE_TRY(mImpl->clear(context, mask));
1261
1262 if (glState.isRobustResourceInitEnabled())
1263 {
1264 markDrawAttachmentsInitialized(color, depth, stencil);
1265 }
1266
1267 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001268}
1269
Jamie Madillc564c072017-06-01 12:45:42 -04001270Error Framebuffer::clearBufferfv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001271 GLenum buffer,
1272 GLint drawbuffer,
1273 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001274{
Jamie Madill05b35b22017-10-03 09:01:44 -04001275 if (context->getGLState().isRasterizerDiscardEnabled() ||
1276 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001277 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001278 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001279 }
1280
Jamie Madill05b35b22017-10-03 09:01:44 -04001281 if (partialBufferClearNeedsInit(context, buffer))
1282 {
1283 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1284 }
1285
1286 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1287
1288 if (context->isRobustResourceInitEnabled())
1289 {
1290 markBufferInitialized(buffer, drawbuffer);
1291 }
1292 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001293}
1294
Jamie Madillc564c072017-06-01 12:45:42 -04001295Error Framebuffer::clearBufferuiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001296 GLenum buffer,
1297 GLint drawbuffer,
1298 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001299{
Jamie Madill05b35b22017-10-03 09:01:44 -04001300 if (context->getGLState().isRasterizerDiscardEnabled() ||
1301 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001302 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001303 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001304 }
1305
Jamie Madill05b35b22017-10-03 09:01:44 -04001306 if (partialBufferClearNeedsInit(context, buffer))
1307 {
1308 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1309 }
1310
1311 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1312
1313 if (context->isRobustResourceInitEnabled())
1314 {
1315 markBufferInitialized(buffer, drawbuffer);
1316 }
1317 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001318}
1319
Jamie Madillc564c072017-06-01 12:45:42 -04001320Error Framebuffer::clearBufferiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001321 GLenum buffer,
1322 GLint drawbuffer,
1323 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001324{
Jamie Madill05b35b22017-10-03 09:01:44 -04001325 if (context->getGLState().isRasterizerDiscardEnabled() ||
1326 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001327 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001328 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001329 }
1330
Jamie Madill05b35b22017-10-03 09:01:44 -04001331 if (partialBufferClearNeedsInit(context, buffer))
1332 {
1333 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1334 }
1335
1336 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1337
1338 if (context->isRobustResourceInitEnabled())
1339 {
1340 markBufferInitialized(buffer, drawbuffer);
1341 }
1342 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001343}
1344
Jamie Madillc564c072017-06-01 12:45:42 -04001345Error Framebuffer::clearBufferfi(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001346 GLenum buffer,
1347 GLint drawbuffer,
1348 GLfloat depth,
1349 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001350{
Jamie Madill05b35b22017-10-03 09:01:44 -04001351 if (context->getGLState().isRasterizerDiscardEnabled() ||
1352 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001353 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001354 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001355 }
1356
Jamie Madill05b35b22017-10-03 09:01:44 -04001357 if (partialBufferClearNeedsInit(context, buffer))
1358 {
1359 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1360 }
1361
1362 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1363
1364 if (context->isRobustResourceInitEnabled())
1365 {
1366 markBufferInitialized(buffer, drawbuffer);
1367 }
1368 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001369}
1370
Jamie Madill4928b7c2017-06-20 12:57:39 -04001371GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001372{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001373 return mImpl->getImplementationColorReadFormat(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001374}
1375
Jamie Madill4928b7c2017-06-20 12:57:39 -04001376GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001377{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001378 return mImpl->getImplementationColorReadType(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001379}
1380
Jamie Madillc564c072017-06-01 12:45:42 -04001381Error Framebuffer::readPixels(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001382 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001383 GLenum format,
1384 GLenum type,
Jamie Madill05b35b22017-10-03 09:01:44 -04001385 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001386{
Jamie Madill05b35b22017-10-03 09:01:44 -04001387 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001388 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001389
Corentin Wallez336129f2017-10-17 15:55:40 -04001390 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001391 if (unpackBuffer)
1392 {
1393 unpackBuffer->onPixelUnpack();
1394 }
1395
Jamie Madill362876b2016-06-16 14:46:59 -04001396 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001397}
1398
Jamie Madillc564c072017-06-01 12:45:42 -04001399Error Framebuffer::blit(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001400 const Rectangle &sourceArea,
1401 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001402 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001403 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001404{
He Yunchao6be602d2016-12-22 14:33:07 +08001405 GLbitfield blitMask = mask;
1406
1407 // Note that blitting is called against draw framebuffer.
1408 // See the code in gl::Context::blitFramebuffer.
1409 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1410 {
1411 blitMask &= ~GL_COLOR_BUFFER_BIT;
1412 }
1413
1414 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1415 {
1416 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1417 }
1418
1419 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1420 {
1421 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1422 }
1423
1424 if (!blitMask)
1425 {
1426 return NoError();
1427 }
1428
Jamie Madill05b35b22017-10-03 09:01:44 -04001429 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1430 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1431
1432 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1433 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1434
He Yunchao6be602d2016-12-22 14:33:07 +08001435 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001436}
1437
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001438int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001439{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001440 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001441 {
Jamie Madill9c335862017-07-18 11:51:38 -04001442 return getCachedSamples(context);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001443 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001444
1445 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001446}
1447
Jamie Madill9c335862017-07-18 11:51:38 -04001448int Framebuffer::getCachedSamples(const Context *context)
1449{
1450 // For a complete framebuffer, all attachments must have the same sample count.
1451 // In this case return the first nonzero sample size.
1452 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1453 if (firstNonNullAttachment)
1454 {
1455 ASSERT(firstNonNullAttachment->isAttached());
1456 return firstNonNullAttachment->getSamples();
1457 }
1458
1459 // No attachments found.
1460 return 0;
1461}
1462
Corentin Wallezccab69d2017-01-27 16:57:15 -05001463Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1464{
1465 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001466 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001467}
1468
Jamie Madille261b442014-06-25 12:42:21 -04001469bool Framebuffer::hasValidDepthStencil() const
1470{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001471 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001472}
1473
Jamie Madilla02315b2017-02-23 14:14:47 -05001474void Framebuffer::setAttachment(const Context *context,
1475 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001476 GLenum binding,
1477 const ImageIndex &textureIndex,
1478 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001479{
Martin Radev5dae57b2017-07-14 16:15:55 +03001480 setAttachment(context, type, binding, textureIndex, resource,
1481 FramebufferAttachment::kDefaultNumViews,
1482 FramebufferAttachment::kDefaultBaseViewIndex,
1483 FramebufferAttachment::kDefaultMultiviewLayout,
1484 FramebufferAttachment::kDefaultViewportOffsets);
1485}
1486
1487void Framebuffer::setAttachment(const Context *context,
1488 GLenum type,
1489 GLenum binding,
1490 const ImageIndex &textureIndex,
1491 FramebufferAttachmentObject *resource,
1492 GLsizei numViews,
1493 GLuint baseViewIndex,
1494 GLenum multiviewLayout,
1495 const GLint *viewportOffsets)
1496{
Jamie Madilla02315b2017-02-23 14:14:47 -05001497 // Context may be null in unit tests.
1498 if (!context || !context->isWebGL1())
1499 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001500 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1501 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001502 return;
1503 }
1504
1505 switch (binding)
1506 {
1507 case GL_DEPTH_STENCIL:
1508 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001509 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001510 resource, numViews, baseViewIndex,
1511 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001512 break;
1513 case GL_DEPTH:
1514 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001515 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1516 numViews, baseViewIndex, multiviewLayout,
1517 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001518 break;
1519 case GL_STENCIL:
1520 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001521 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1522 numViews, baseViewIndex, multiviewLayout,
1523 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001524 break;
1525 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001526 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1527 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001528 return;
1529 }
1530
Martin Radev5dae57b2017-07-14 16:15:55 +03001531 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1532 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001533}
1534
Martin Radev82ef7742017-08-08 17:44:58 +03001535void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1536 GLenum type,
1537 GLenum binding,
1538 const ImageIndex &textureIndex,
1539 FramebufferAttachmentObject *resource,
1540 GLsizei numViews,
1541 GLint baseViewIndex)
1542{
1543 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1544 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1545 FramebufferAttachment::kDefaultViewportOffsets);
1546}
1547
Martin Radev5dae57b2017-07-14 16:15:55 +03001548void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1549 GLenum type,
1550 GLenum binding,
1551 const ImageIndex &textureIndex,
1552 FramebufferAttachmentObject *resource,
1553 GLsizei numViews,
1554 const GLint *viewportOffsets)
1555{
1556 setAttachment(context, type, binding, textureIndex, resource, numViews,
1557 FramebufferAttachment::kDefaultBaseViewIndex,
1558 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1559}
1560
1561void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1562 GLsizei numViews,
1563 GLuint baseViewIndex,
1564 GLenum multiviewLayout,
1565 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001566{
1567 int count = 0;
1568
1569 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1570 &mState.mWebGLDepthAttachment,
1571 &mState.mWebGLStencilAttachment}};
1572 for (FramebufferAttachment *attachment : attachments)
1573 {
1574 if (attachment->isAttached())
1575 {
1576 count++;
1577 }
1578 }
1579
1580 mState.mWebGLDepthStencilConsistent = (count <= 1);
1581 if (!mState.mWebGLDepthStencilConsistent)
1582 {
1583 // Inconsistent.
1584 return;
1585 }
1586
Geoff Lange466c552017-03-17 15:24:12 -04001587 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1588 if (attachment.type() == GL_TEXTURE)
1589 {
1590 return attachment.getTextureImageIndex();
1591 }
1592 else
1593 {
1594 return ImageIndex::MakeInvalid();
1595 }
1596 };
1597
Jamie Madilla02315b2017-02-23 14:14:47 -05001598 if (mState.mWebGLDepthAttachment.isAttached())
1599 {
1600 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001601 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001602 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1603 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001604 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001605 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001606 }
1607 else if (mState.mWebGLStencilAttachment.isAttached())
1608 {
1609 const auto &stencil = mState.mWebGLStencilAttachment;
Martin Radev5dae57b2017-07-14 16:15:55 +03001610 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1611 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001612 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001613 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1614 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001615 }
1616 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1617 {
1618 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001619 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001620 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001621 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1622 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001623 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001624 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001625 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1626 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001627 }
1628 else
1629 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001630 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1631 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001632 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001633 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001634 }
1635}
1636
Jamie Madill4928b7c2017-06-20 12:57:39 -04001637void Framebuffer::setAttachmentImpl(const Context *context,
1638 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001639 GLenum binding,
1640 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001641 FramebufferAttachmentObject *resource,
1642 GLsizei numViews,
1643 GLuint baseViewIndex,
1644 GLenum multiviewLayout,
1645 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001646{
Jamie Madilla02315b2017-02-23 14:14:47 -05001647 switch (binding)
1648 {
Jamie Madillb8126692017-04-05 11:22:17 -04001649 case GL_DEPTH_STENCIL:
1650 case GL_DEPTH_STENCIL_ATTACHMENT:
1651 {
1652 // ensure this is a legitimate depth+stencil format
1653 FramebufferAttachmentObject *attachmentObj = resource;
1654 if (resource)
1655 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001656 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001657 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1658 {
1659 // Attaching nullptr detaches the current attachment.
1660 attachmentObj = nullptr;
1661 }
1662 }
1663
Jamie Madill4928b7c2017-06-20 12:57:39 -04001664 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001665 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001666 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1667 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001668 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001669 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001670 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1671 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001672 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001673 }
1674
Jamie Madilla02315b2017-02-23 14:14:47 -05001675 case GL_DEPTH:
1676 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001677 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001678 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1679 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001680 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001681
Jamie Madilla02315b2017-02-23 14:14:47 -05001682 case GL_STENCIL:
1683 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001684 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001685 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1686 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001687 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001688
Jamie Madilla02315b2017-02-23 14:14:47 -05001689 case GL_BACK:
Martin Radev5dae57b2017-07-14 16:15:55 +03001690 mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource,
1691 numViews, baseViewIndex, multiviewLayout,
1692 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001693 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1694 // No need for a resource binding for the default FBO, it's always complete.
1695 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001696
Jamie Madilla02315b2017-02-23 14:14:47 -05001697 default:
1698 {
1699 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1700 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001701 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001702 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001703 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001704 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1705 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001706
Corentin Walleze7557742017-06-01 13:09:57 -04001707 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1708 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001709 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1710 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Brandon Jones76746f92017-11-22 11:44:41 -08001711 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -04001712 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001713 break;
Geoff Langab75a052014-10-15 12:56:37 -04001714 }
Jamie Madill42975642017-10-12 12:31:51 -04001715
1716 mAttachedTextures.reset();
Geoff Langab75a052014-10-15 12:56:37 -04001717}
1718
Jamie Madill4928b7c2017-06-20 12:57:39 -04001719void Framebuffer::updateAttachment(const Context *context,
1720 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001721 size_t dirtyBit,
1722 OnAttachmentDirtyBinding *onDirtyBinding,
1723 GLenum type,
1724 GLenum binding,
1725 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001726 FramebufferAttachmentObject *resource,
1727 GLsizei numViews,
1728 GLuint baseViewIndex,
1729 GLenum multiviewLayout,
1730 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001731{
Martin Radev5dae57b2017-07-14 16:15:55 +03001732 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1733 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001734 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001735 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madillb8126692017-04-05 11:22:17 -04001736 BindResourceChannel(onDirtyBinding, resource);
1737}
1738
Jamie Madilla02315b2017-02-23 14:14:47 -05001739void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001740{
Jamie Madilla02315b2017-02-23 14:14:47 -05001741 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001742}
1743
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001744void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001745{
1746 if (mDirtyBits.any())
1747 {
Jamie Madillc564c072017-06-01 12:45:42 -04001748 mImpl->syncState(context, mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001749 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001750 if (mId != 0)
1751 {
1752 mCachedStatus.reset();
1753 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001754 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001755}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001756
Jamie Madill05b35b22017-10-03 09:01:44 -04001757void Framebuffer::signal(size_t dirtyBit, InitState state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001758{
Jamie Madill362876b2016-06-16 14:46:59 -04001759 // TOOD(jmadill): Make this only update individual attachments to do less work.
1760 mCachedStatus.reset();
Jamie Madill05b35b22017-10-03 09:01:44 -04001761
1762 // Mark the appropriate init flag.
1763 mState.mResourceNeedsInit.set(dirtyBit, state == InitState::MayNeedInit);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001764}
1765
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001766bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001767{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001768 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1769}
1770
1771bool Framebuffer::cachedComplete() const
1772{
1773 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001774}
1775
Jamie Madilla4595b82017-01-11 17:36:34 -05001776bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1777{
1778 const Program *program = state.getProgram();
1779
1780 // TODO(jmadill): Default framebuffer feedback loops.
1781 if (mId == 0)
1782 {
1783 return false;
1784 }
1785
1786 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001787 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001788 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001789 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1790 ASSERT(attachment.isAttached());
1791 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001792 {
1793 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001794 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001795 {
1796 return true;
1797 }
1798 }
1799 }
1800
Jamie Madill1d37bc52017-02-02 19:59:58 -05001801 // Validate depth-stencil feedback loop.
1802 const auto &dsState = state.getDepthStencilState();
1803
1804 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1805 const FramebufferAttachment *depth = getDepthbuffer();
1806 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1807 {
1808 if (program->samplesFromTexture(state, depth->id()))
1809 {
1810 return true;
1811 }
1812 }
1813
1814 // Note: we assume the front and back masks are the same for WebGL.
1815 const FramebufferAttachment *stencil = getStencilbuffer();
1816 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1817 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1818 dsState.stencilWritemask != 0)
1819 {
1820 // Skip the feedback loop check if depth/stencil point to the same resource.
1821 if (!depth || *stencil != *depth)
1822 {
1823 if (program->samplesFromTexture(state, stencil->id()))
1824 {
1825 return true;
1826 }
1827 }
1828 }
1829
Jamie Madilla4595b82017-01-11 17:36:34 -05001830 return false;
1831}
1832
Jamie Madillfd3dd432017-02-02 19:59:59 -05001833bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1834 GLint copyTextureLevel,
1835 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001836{
1837 if (mId == 0)
1838 {
1839 // It seems impossible to form a texture copying feedback loop with the default FBO.
1840 return false;
1841 }
1842
1843 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1844 ASSERT(readAttachment);
1845
1846 if (readAttachment->isTextureWithId(copyTextureID))
1847 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001848 const auto &imageIndex = readAttachment->getTextureImageIndex();
1849 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001850 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001851 // Check 3D/Array texture layers.
1852 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1853 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1854 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001855 }
1856 }
1857 return false;
1858}
1859
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001860GLint Framebuffer::getDefaultWidth() const
1861{
1862 return mState.getDefaultWidth();
1863}
1864
1865GLint Framebuffer::getDefaultHeight() const
1866{
1867 return mState.getDefaultHeight();
1868}
1869
1870GLint Framebuffer::getDefaultSamples() const
1871{
1872 return mState.getDefaultSamples();
1873}
1874
Geoff Lang92019432017-11-20 13:09:34 -05001875bool Framebuffer::getDefaultFixedSampleLocations() const
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001876{
1877 return mState.getDefaultFixedSampleLocations();
1878}
1879
1880void Framebuffer::setDefaultWidth(GLint defaultWidth)
1881{
1882 mState.mDefaultWidth = defaultWidth;
1883 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1884}
1885
1886void Framebuffer::setDefaultHeight(GLint defaultHeight)
1887{
1888 mState.mDefaultHeight = defaultHeight;
1889 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1890}
1891
1892void Framebuffer::setDefaultSamples(GLint defaultSamples)
1893{
1894 mState.mDefaultSamples = defaultSamples;
1895 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1896}
1897
Geoff Lang92019432017-11-20 13:09:34 -05001898void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001899{
1900 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1901 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1902}
1903
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001904// TODO(jmadill): Remove this kludge.
1905GLenum Framebuffer::checkStatus(const ValidationContext *context)
1906{
1907 return checkStatus(static_cast<const Context *>(context));
1908}
1909
1910int Framebuffer::getSamples(const ValidationContext *context)
1911{
1912 return getSamples(static_cast<const Context *>(context));
1913}
1914
Martin Radev14a26ae2017-07-24 15:56:29 +03001915GLsizei Framebuffer::getNumViews() const
1916{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001917 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03001918}
1919
Martin Radev4e619f52017-08-09 11:50:06 +03001920GLint Framebuffer::getBaseViewIndex() const
1921{
1922 return mState.getBaseViewIndex();
1923}
1924
Martin Radev878c8b12017-07-28 09:51:04 +03001925const std::vector<Offset> *Framebuffer::getViewportOffsets() const
1926{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001927 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03001928}
1929
1930GLenum Framebuffer::getMultiviewLayout() const
1931{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001932 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03001933}
1934
Jamie Madill05b35b22017-10-03 09:01:44 -04001935Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
1936{
1937 if (!context->isRobustResourceInitEnabled())
1938 {
1939 return NoError();
1940 }
1941
1942 // Note: we don't actually filter by the draw attachment enum. Just init everything.
1943 for (size_t bit : mState.mResourceNeedsInit)
1944 {
1945 switch (bit)
1946 {
1947 case DIRTY_BIT_DEPTH_ATTACHMENT:
1948 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
1949 break;
1950 case DIRTY_BIT_STENCIL_ATTACHMENT:
1951 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
1952 break;
1953 default:
1954 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
1955 break;
1956 }
1957 }
1958
1959 mState.mResourceNeedsInit.reset();
1960 return NoError();
1961}
1962
1963Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
1964{
1965 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
1966 {
1967 return NoError();
1968 }
1969
1970 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
1971 {
1972 size_t readIndex = mState.getReadIndex();
1973 if (mState.mResourceNeedsInit[readIndex])
1974 {
1975 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
1976 mState.mResourceNeedsInit.reset(readIndex);
1977 }
1978 }
1979
1980 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
1981 {
1982 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
1983 {
1984 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
1985 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
1986 }
1987 }
1988
1989 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
1990 {
1991 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
1992 {
1993 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
1994 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
1995 }
1996 }
1997
1998 return NoError();
1999}
2000
2001void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2002{
2003 // Mark attachments as initialized.
2004 if (color)
2005 {
2006 for (auto colorIndex : mState.mEnabledDrawBuffers)
2007 {
2008 auto &colorAttachment = mState.mColorAttachments[colorIndex];
2009 ASSERT(colorAttachment.isAttached());
2010 colorAttachment.setInitState(InitState::Initialized);
2011 mState.mResourceNeedsInit.reset(colorIndex);
2012 }
2013 }
2014
2015 if (depth && mState.mDepthAttachment.isAttached())
2016 {
2017 mState.mDepthAttachment.setInitState(InitState::Initialized);
2018 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2019 }
2020
2021 if (stencil && mState.mStencilAttachment.isAttached())
2022 {
2023 mState.mStencilAttachment.setInitState(InitState::Initialized);
2024 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2025 }
2026}
2027
2028void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2029{
2030 switch (bufferType)
2031 {
2032 case GL_COLOR:
2033 {
2034 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2035 if (mState.mColorAttachments[bufferIndex].isAttached())
2036 {
2037 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2038 mState.mResourceNeedsInit.reset(bufferIndex);
2039 }
2040 break;
2041 }
2042 case GL_DEPTH:
2043 {
2044 if (mState.mDepthAttachment.isAttached())
2045 {
2046 mState.mDepthAttachment.setInitState(InitState::Initialized);
2047 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2048 }
2049 break;
2050 }
2051 case GL_STENCIL:
2052 {
2053 if (mState.mStencilAttachment.isAttached())
2054 {
2055 mState.mStencilAttachment.setInitState(InitState::Initialized);
2056 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2057 }
2058 break;
2059 }
2060 case GL_DEPTH_STENCIL:
2061 {
2062 if (mState.mDepthAttachment.isAttached())
2063 {
2064 mState.mDepthAttachment.setInitState(InitState::Initialized);
2065 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2066 }
2067 if (mState.mStencilAttachment.isAttached())
2068 {
2069 mState.mStencilAttachment.setInitState(InitState::Initialized);
2070 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2071 }
2072 break;
2073 }
2074 default:
2075 UNREACHABLE();
2076 break;
2077 }
2078}
2079
2080Box Framebuffer::getDimensions() const
2081{
2082 return mState.getDimensions();
2083}
2084
2085Error Framebuffer::ensureBufferInitialized(const Context *context,
2086 GLenum bufferType,
2087 GLint bufferIndex)
2088{
2089 ASSERT(context->isRobustResourceInitEnabled());
2090
2091 if (mState.mResourceNeedsInit.none())
2092 {
2093 return NoError();
2094 }
2095
2096 switch (bufferType)
2097 {
2098 case GL_COLOR:
2099 {
2100 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2101 if (mState.mResourceNeedsInit[bufferIndex])
2102 {
2103 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2104 mState.mResourceNeedsInit.reset(bufferIndex);
2105 }
2106 break;
2107 }
2108 case GL_DEPTH:
2109 {
2110 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2111 {
2112 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2113 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2114 }
2115 break;
2116 }
2117 case GL_STENCIL:
2118 {
2119 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2120 {
2121 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2122 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2123 }
2124 break;
2125 }
2126 case GL_DEPTH_STENCIL:
2127 {
2128 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2129 {
2130 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2131 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2132 }
2133 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2134 {
2135 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2136 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2137 }
2138 break;
2139 }
2140 default:
2141 UNREACHABLE();
2142 break;
2143 }
2144
2145 return NoError();
2146}
2147
2148bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2149{
2150 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2151 {
2152 return false;
2153 }
2154
2155 switch (bufferType)
2156 {
2157 case GL_COLOR:
2158 return partialClearNeedsInit(context, true, false, false);
2159 case GL_DEPTH:
2160 return partialClearNeedsInit(context, false, true, false);
2161 case GL_STENCIL:
2162 return partialClearNeedsInit(context, false, false, true);
2163 case GL_DEPTH_STENCIL:
2164 return partialClearNeedsInit(context, false, true, true);
2165 default:
2166 UNREACHABLE();
2167 return false;
2168 }
2169}
2170
Jamie Madill42975642017-10-12 12:31:51 -04002171bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2172{
2173 if (!mAttachedTextures.valid())
2174 {
2175 std::set<const FramebufferAttachmentObject *> attachedTextures;
2176
2177 for (const auto &colorAttachment : mState.mColorAttachments)
2178 {
2179 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2180 {
2181 attachedTextures.insert(colorAttachment.getResource());
2182 }
2183 }
2184
2185 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2186 {
2187 attachedTextures.insert(mState.mDepthAttachment.getResource());
2188 }
2189
2190 if (mState.mStencilAttachment.isAttached() &&
2191 mState.mStencilAttachment.type() == GL_TEXTURE)
2192 {
2193 attachedTextures.insert(mState.mStencilAttachment.getResource());
2194 }
2195
2196 mAttachedTextures = std::move(attachedTextures);
2197 }
2198
2199 return (mAttachedTextures.value().count(texture) > 0);
2200}
2201
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002202} // namespace gl