blob: 3fc2193cef23b53859e57397ca69ecdf9f03316a [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"
22#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040023#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050024#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040025#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050026#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040027#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040028
Jamie Madill362876b2016-06-16 14:46:59 -040029using namespace angle;
30
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000031namespace gl
32{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000033
Jamie Madilld1405e52015-03-05 15:41:39 -050034namespace
35{
Jamie Madill362876b2016-06-16 14:46:59 -040036
Jamie Madill1e5499d2017-04-05 11:22:16 -040037void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmentObject *resource)
Jamie Madilld1405e52015-03-05 15:41:39 -050038{
Jamie Madill362876b2016-06-16 14:46:59 -040039 binding->bind(resource ? resource->getDirtyChannel() : nullptr);
Jamie Madilld1405e52015-03-05 15:41:39 -050040}
Jamie Madill362876b2016-06-16 14:46:59 -040041
Martin Radev9bc9a322017-07-21 14:28:17 +030042bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
43 const FramebufferAttachment *secondAttachment)
44{
45 ASSERT(firstAttachment && secondAttachment);
46 ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
47
48 if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
49 {
50 return false;
51 }
52 if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
53 {
54 return false;
55 }
56 if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
57 {
58 return false;
59 }
60 if (firstAttachment->getMultiviewViewportOffsets() !=
61 secondAttachment->getMultiviewViewportOffsets())
62 {
63 return false;
64 }
65 return true;
66}
67
Geoff Lang9f10b772017-05-16 15:51:03 -040068bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
69{
70 ASSERT(attachment.isAttached());
71
72 const Extents &size = attachment.getSize();
73 if (size.width == 0 || size.height == 0)
74 {
75 return false;
76 }
77
78 const InternalFormat &format = *attachment.getFormat().info;
79 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
80 {
81 return false;
82 }
83
84 if (attachment.type() == GL_TEXTURE)
85 {
86 if (attachment.layer() >= size.depth)
87 {
88 return false;
89 }
90
91 // ES3 specifies that cube map texture attachments must be cube complete.
92 // This language is missing from the ES2 spec, but we enforce it here because some
93 // desktop OpenGL drivers also enforce this validation.
94 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
95 const Texture *texture = attachment.getTexture();
96 ASSERT(texture);
97 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
98 !texture->getTextureState().isCubeComplete())
99 {
100 return false;
101 }
Geoff Lang857c09d2017-05-16 15:55:04 -0400102
103 if (!texture->getImmutableFormat())
104 {
105 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
106
107 // From the ES 3.0 spec, pg 213:
108 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
109 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
110 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
111 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
112 // the effective maximum texture level defined in the Mipmapping discussion of
113 // section 3.8.10.4.
114 if (attachmentMipLevel < texture->getBaseLevel() ||
115 attachmentMipLevel > texture->getMipmapMaxLevel())
116 {
117 return false;
118 }
119
120 // Form the ES 3.0 spec, pg 213/214:
121 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
122 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
123 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
124 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
125 // a cubemap texture, the texture must also be cube complete.
126 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
127 {
128 return false;
129 }
130 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400131 }
132
133 return true;
134};
135
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400136bool CheckAttachmentSampleCompleteness(const Context *context,
137 const FramebufferAttachment &attachment,
138 bool colorAttachment,
139 Optional<int> *samples,
140 Optional<GLboolean> *fixedSampleLocations)
141{
142 ASSERT(attachment.isAttached());
143
144 if (attachment.type() == GL_TEXTURE)
145 {
146 const Texture *texture = attachment.getTexture();
147 ASSERT(texture);
148
149 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
150
151 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
152 // the same for all attached textures.
153 GLboolean fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type,
154 attachmentImageIndex.mipIndex);
155 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
156 {
157 return false;
158 }
159 else
160 {
161 *fixedSampleLocations = fixedSampleloc;
162 }
163 }
164
165 if (samples->valid())
166 {
167 if (attachment.getSamples() != samples->value())
168 {
169 if (colorAttachment)
170 {
171 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
172 // all color attachments have the same number of samples for the FBO to be complete.
173 return false;
174 }
175 else
176 {
177 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
178 // when its depth or stencil samples are a multiple of the number of color samples.
179 if (!context->getExtensions().framebufferMixedSamples)
180 {
181 return false;
182 }
183
184 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
185 {
186 return false;
187 }
188 }
189 }
190 }
191 else
192 {
193 *samples = attachment.getSamples();
194 }
195
196 return true;
197}
198
Jamie Madill05b35b22017-10-03 09:01:44 -0400199// Needed to index into the attachment arrays/bitsets.
Jamie Madill682efdc2017-10-03 14:10:29 -0400200static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madill05b35b22017-10-03 09:01:44 -0400201 gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
202 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400203static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madill05b35b22017-10-03 09:01:44 -0400204 gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
205 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400206static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
Jamie Madill05b35b22017-10-03 09:01:44 -0400207 gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
208 "Framebuffer Dirty bit mismatch");
209
210Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
211{
212 ASSERT(attachment->isAttached());
213 if (attachment->initState() == InitState::MayNeedInit)
214 {
215 ANGLE_TRY(attachment->initializeContents(context));
216 }
217 return NoError();
218}
219
220bool IsColorMaskedOut(const BlendState &blend)
221{
222 return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
223 !blend.colorMaskAlpha);
224}
225
226bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
227{
228 return !depthStencil.depthMask;
229}
230
231bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
232{
233 return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
234}
235
236bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
237{
238 switch (buffer)
239 {
240 case GL_COLOR:
241 return IsColorMaskedOut(context->getGLState().getBlendState());
242 case GL_DEPTH:
243 return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
244 case GL_STENCIL:
245 return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
246 case GL_DEPTH_STENCIL:
247 return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
248 IsStencilMaskedOut(context->getGLState().getDepthStencilState());
249 default:
250 UNREACHABLE();
251 return true;
252 }
253}
254
Jamie Madill362876b2016-06-16 14:46:59 -0400255} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500256
Jamie Madill6f60d052017-02-22 15:20:11 -0500257// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400258FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500259 : mLabel(),
260 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400261 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500262 mReadBufferState(GL_BACK),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800263 mDefaultWidth(0),
264 mDefaultHeight(0),
265 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500266 mDefaultFixedSampleLocations(GL_FALSE),
267 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400268{
Geoff Langd90d3882017-03-21 10:49:54 -0400269 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500270 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400271}
272
Jamie Madill48ef11b2016-04-27 15:21:52 -0400273FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -0500274 : mLabel(),
275 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -0500276 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800277 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
278 mDefaultWidth(0),
279 mDefaultHeight(0),
280 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500281 mDefaultFixedSampleLocations(GL_FALSE),
282 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500283{
Geoff Langa15472a2015-08-11 11:48:03 -0400284 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500285 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
286}
287
Jamie Madill48ef11b2016-04-27 15:21:52 -0400288FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500289{
Jamie Madilld1405e52015-03-05 15:41:39 -0500290}
291
Jamie Madill48ef11b2016-04-27 15:21:52 -0400292const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500293{
294 return mLabel;
295}
296
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400297const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
298{
299 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
300 {
301 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
302 }
303
304 switch (attachment)
305 {
306 case GL_COLOR:
307 case GL_BACK:
308 return getColorAttachment(0);
309 case GL_DEPTH:
310 case GL_DEPTH_ATTACHMENT:
311 return getDepthAttachment();
312 case GL_STENCIL:
313 case GL_STENCIL_ATTACHMENT:
314 return getStencilAttachment();
315 case GL_DEPTH_STENCIL:
316 case GL_DEPTH_STENCIL_ATTACHMENT:
317 return getDepthStencilAttachment();
318 default:
319 UNREACHABLE();
320 return nullptr;
321 }
322}
323
Jamie Madill05b35b22017-10-03 09:01:44 -0400324size_t FramebufferState::getReadIndex() const
Jamie Madill7147f012015-03-05 15:41:40 -0500325{
Jamie Madill231c7f52017-04-26 13:45:37 -0400326 ASSERT(mReadBufferState == GL_BACK ||
327 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
328 size_t readIndex = (mReadBufferState == GL_BACK
329 ? 0
330 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500331 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill05b35b22017-10-03 09:01:44 -0400332 return readIndex;
333}
334
335const FramebufferAttachment *FramebufferState::getReadAttachment() const
336{
337 if (mReadBufferState == GL_NONE)
338 {
339 return nullptr;
340 }
341 size_t readIndex = getReadIndex();
Jamie Madill2d06b732015-04-20 12:53:28 -0400342 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500343}
344
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500345const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
346{
347 auto *colorAttachment = getFirstColorAttachment();
348 if (colorAttachment)
349 {
350 return colorAttachment;
351 }
352 return getDepthOrStencilAttachment();
353}
354
Jamie Madill48ef11b2016-04-27 15:21:52 -0400355const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500356{
Jamie Madill2d06b732015-04-20 12:53:28 -0400357 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500358 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400359 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500360 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400361 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500362 }
363 }
364
365 return nullptr;
366}
367
Jamie Madill48ef11b2016-04-27 15:21:52 -0400368const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500369{
Jamie Madill2d06b732015-04-20 12:53:28 -0400370 if (mDepthAttachment.isAttached())
371 {
372 return &mDepthAttachment;
373 }
374 if (mStencilAttachment.isAttached())
375 {
376 return &mStencilAttachment;
377 }
378 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500379}
380
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500381const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
382{
383 if (mStencilAttachment.isAttached())
384 {
385 return &mStencilAttachment;
386 }
387 return getDepthStencilAttachment();
388}
389
Jamie Madill48ef11b2016-04-27 15:21:52 -0400390const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400391{
392 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400393 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
394 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400395}
396
Jamie Madill48ef11b2016-04-27 15:21:52 -0400397const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400398{
Jamie Madill2d06b732015-04-20 12:53:28 -0400399 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400400}
401
Jamie Madill48ef11b2016-04-27 15:21:52 -0400402const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400403{
Jamie Madill2d06b732015-04-20 12:53:28 -0400404 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400405}
406
Jamie Madill48ef11b2016-04-27 15:21:52 -0400407const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400408{
409 // A valid depth-stencil attachment has the same resource bound to both the
410 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400411 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500412 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400413 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400414 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400415 }
416
417 return nullptr;
418}
419
Jamie Madill48ef11b2016-04-27 15:21:52 -0400420bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500421{
422 Optional<Extents> attachmentSize;
423
Jamie Madill231c7f52017-04-26 13:45:37 -0400424 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500425 if (!attachment.isAttached())
426 {
427 return false;
428 }
429
430 if (!attachmentSize.valid())
431 {
432 attachmentSize = attachment.getSize();
433 return false;
434 }
435
436 return (attachment.getSize() != attachmentSize.value());
437 };
438
439 for (const auto &attachment : mColorAttachments)
440 {
441 if (hasMismatchedSize(attachment))
442 {
443 return false;
444 }
445 }
446
447 if (hasMismatchedSize(mDepthAttachment))
448 {
449 return false;
450 }
451
452 return !hasMismatchedSize(mStencilAttachment);
453}
454
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400455const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
456{
457 ASSERT(drawBufferIdx < mDrawBufferStates.size());
458 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
459 {
460 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
461 // must be COLOR_ATTACHMENTi or NONE"
462 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
463 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
464 return getAttachment(mDrawBufferStates[drawBufferIdx]);
465 }
466 else
467 {
468 return nullptr;
469 }
470}
471
472size_t FramebufferState::getDrawBufferCount() const
473{
474 return mDrawBufferStates.size();
475}
476
Geoff Langb21e20d2016-07-19 15:35:41 -0400477bool FramebufferState::colorAttachmentsAreUniqueImages() const
478{
479 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
480 firstAttachmentIdx++)
481 {
482 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
483 if (!firstAttachment.isAttached())
484 {
485 continue;
486 }
487
488 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
489 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
490 {
491 const gl::FramebufferAttachment &secondAttachment =
492 mColorAttachments[secondAttachmentIdx];
493 if (!secondAttachment.isAttached())
494 {
495 continue;
496 }
497
498 if (firstAttachment == secondAttachment)
499 {
500 return false;
501 }
502 }
503 }
504
505 return true;
506}
507
Jamie Madill9c335862017-07-18 11:51:38 -0400508bool FramebufferState::hasDepth() const
509{
510 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
511}
512
513bool FramebufferState::hasStencil() const
514{
515 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
516}
517
Martin Radev5c00d0d2017-08-07 10:06:59 +0300518GLsizei FramebufferState::getNumViews() const
519{
520 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
521 if (attachment == nullptr)
522 {
523 return FramebufferAttachment::kDefaultNumViews;
524 }
525 return attachment->getNumViews();
526}
527
528const std::vector<Offset> *FramebufferState::getViewportOffsets() const
529{
530 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
531 if (attachment == nullptr)
532 {
533 return nullptr;
534 }
535 return &attachment->getMultiviewViewportOffsets();
536}
537
538GLenum FramebufferState::getMultiviewLayout() const
539{
540 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
541 if (attachment == nullptr)
542 {
543 return GL_NONE;
544 }
545 return attachment->getMultiviewLayout();
546}
547
Martin Radev4e619f52017-08-09 11:50:06 +0300548int FramebufferState::getBaseViewIndex() const
549{
550 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
551 if (attachment == nullptr)
552 {
553 return GL_NONE;
554 }
555 return attachment->getBaseViewIndex();
556}
557
Jamie Madill05b35b22017-10-03 09:01:44 -0400558Box FramebufferState::getDimensions() const
559{
560 ASSERT(attachmentsHaveSameDimensions());
561 ASSERT(getFirstNonNullAttachment() != nullptr);
562 Extents extents = getFirstNonNullAttachment()->getSize();
563 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
564}
565
Jamie Madill7aea7e02016-05-10 10:39:45 -0400566Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400567 : mState(caps),
568 mImpl(factory->createFramebuffer(mState)),
569 mId(id),
570 mCachedStatus(),
571 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
572 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000573{
Corentin Wallez37c39792015-08-20 14:19:46 -0400574 ASSERT(mId != 0);
575 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400576 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
577
Jamie Madill1e5499d2017-04-05 11:22:16 -0400578 for (uint32_t colorIndex = 0;
579 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400580 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400581 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400582 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400583}
584
Jamie Madill4928b7c2017-06-20 12:57:39 -0400585Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400586 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500587 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400588 mId(0),
589 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
590 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
591 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400592{
Geoff Langda88add2014-12-01 10:22:01 -0500593 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400594 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500595
Jamie Madill4928b7c2017-06-20 12:57:39 -0400596 const Context *proxyContext = display->getProxyContext();
597
598 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +0300599 surface, FramebufferAttachment::kDefaultNumViews,
600 FramebufferAttachment::kDefaultBaseViewIndex,
601 FramebufferAttachment::kDefaultMultiviewLayout,
602 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500603
604 if (surface->getConfig()->depthSize > 0)
605 {
Martin Radev5dae57b2017-07-14 16:15:55 +0300606 setAttachmentImpl(
607 proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface,
608 FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex,
609 FramebufferAttachment::kDefaultMultiviewLayout,
610 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500611 }
612
613 if (surface->getConfig()->stencilSize > 0)
614 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400615 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL,
Martin Radev5dae57b2017-07-14 16:15:55 +0300616 gl::ImageIndex::MakeInvalid(), surface,
617 FramebufferAttachment::kDefaultNumViews,
618 FramebufferAttachment::kDefaultBaseViewIndex,
619 FramebufferAttachment::kDefaultMultiviewLayout,
620 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500621 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000622}
623
Corentin Wallezccab69d2017-01-27 16:57:15 -0500624Framebuffer::Framebuffer(rx::GLImplFactory *factory)
625 : mState(),
626 mImpl(factory->createFramebuffer(mState)),
627 mId(0),
628 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
629 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
630 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
631{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400632 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500633}
634
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000635Framebuffer::~Framebuffer()
636{
Geoff Langda88add2014-12-01 10:22:01 -0500637 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000638}
639
Jamie Madill4928b7c2017-06-20 12:57:39 -0400640void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500641{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400642 for (auto &attachment : mState.mColorAttachments)
643 {
644 attachment.detach(context);
645 }
646 mState.mDepthAttachment.detach(context);
647 mState.mStencilAttachment.detach(context);
648 mState.mWebGLDepthAttachment.detach(context);
649 mState.mWebGLStencilAttachment.detach(context);
650 mState.mWebGLDepthStencilAttachment.detach(context);
651
Jamie Madillc564c072017-06-01 12:45:42 -0400652 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500653}
654
655void Framebuffer::destroyDefault(const egl::Display *display)
656{
Jamie Madillc564c072017-06-01 12:45:42 -0400657 mImpl->destroyDefault(display);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500658}
659
Geoff Lang70d0f492015-12-10 17:45:46 -0500660void Framebuffer::setLabel(const std::string &label)
661{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400662 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500663}
664
665const std::string &Framebuffer::getLabel() const
666{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400667 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500668}
669
Jamie Madill8693bdb2017-09-02 15:32:14 -0400670bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000671{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400672 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673}
674
Jamie Madill8693bdb2017-09-02 15:32:14 -0400675bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000676{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400677 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500678}
Jamie Madille261b442014-06-25 12:42:21 -0400679
Jamie Madill8693bdb2017-09-02 15:32:14 -0400680bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500681{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400682 bool found = false;
683
Jamie Madill362876b2016-06-16 14:46:59 -0400684 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500685 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400686 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
687 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
688 {
689 found = true;
690 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000691 }
692
Jamie Madilla02315b2017-02-23 14:14:47 -0500693 if (context->isWebGL1())
694 {
695 const std::array<FramebufferAttachment *, 3> attachments = {
696 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
697 &mState.mWebGLStencilAttachment}};
698 for (FramebufferAttachment *attachment : attachments)
699 {
700 if (attachment->isAttached() && attachment->type() == resourceType &&
701 attachment->id() == resourceId)
702 {
703 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400704 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500705 }
706 }
707 }
708 else
709 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400710 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
711 DIRTY_BIT_DEPTH_ATTACHMENT))
712 {
713 found = true;
714 }
715 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
716 DIRTY_BIT_STENCIL_ATTACHMENT))
717 {
718 found = true;
719 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500720 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400721
722 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400723}
724
Jamie Madill8693bdb2017-09-02 15:32:14 -0400725bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400726 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400727 GLenum matchType,
728 GLuint matchId,
729 size_t dirtyBit)
730{
731 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
732 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400733 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400734 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -0400735 mState.mResourceNeedsInit.set(dirtyBit, false);
Jamie Madill8693bdb2017-09-02 15:32:14 -0400736 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400737 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400738
739 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000740}
741
Corentin Wallez37c39792015-08-20 14:19:46 -0400742const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400744 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000745}
746
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400747const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400748{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400749 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400750}
751
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400752const FramebufferAttachment *Framebuffer::getStencilbuffer() const
753{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400754 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400755}
756
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400757const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
758{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400759 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400760}
761
762const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000763{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400764 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000765}
766
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500767const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
768{
769 return mState.getStencilOrDepthStencilAttachment();
770}
771
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400772const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000773{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400774 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000775}
776
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000777GLenum Framebuffer::getReadColorbufferType() const
778{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400779 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400780 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000781}
782
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400783const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000784{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400785 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000786}
787
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400788const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
789{
790 return mState.getFirstNonNullAttachment();
791}
792
Jamie Madill2d06b732015-04-20 12:53:28 -0400793const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000794{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400795 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400796}
797
Geoff Langa15472a2015-08-11 11:48:03 -0400798size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000799{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400800 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400801}
802
803GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
804{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400805 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
806 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000807}
808
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500809const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
810{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400811 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500812}
813
Geoff Lang164d54e2014-12-01 10:55:33 -0500814void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000815{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400816 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500817
818 ASSERT(count <= drawStates.size());
819 std::copy(buffers, buffers + count, drawStates.begin());
820 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500821 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500822
823 mState.mEnabledDrawBuffers.reset();
824 for (size_t index = 0; index < count; ++index)
825 {
826 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
827 {
828 mState.mEnabledDrawBuffers.set(index);
829 }
830 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500831}
832
Geoff Langa15472a2015-08-11 11:48:03 -0400833const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
834{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400835 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400836}
837
Geoff Lange0cff192017-05-30 13:04:56 -0400838GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
839{
840 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
841 if (attachment == nullptr)
842 {
843 return GL_NONE;
844 }
845
846 GLenum componentType = attachment->getFormat().info->componentType;
847 switch (componentType)
848 {
849 case GL_INT:
850 case GL_UNSIGNED_INT:
851 return componentType;
852
853 default:
854 return GL_FLOAT;
855 }
856}
857
Geoff Langa15472a2015-08-11 11:48:03 -0400858bool Framebuffer::hasEnabledDrawBuffer() const
859{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400860 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400861 {
862 if (getDrawBuffer(drawbufferIdx) != nullptr)
863 {
864 return true;
865 }
866 }
867
868 return false;
869}
870
Geoff Lang9dd95802014-12-01 11:12:59 -0500871GLenum Framebuffer::getReadBufferState() const
872{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400873 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500874}
875
876void Framebuffer::setReadBuffer(GLenum buffer)
877{
Jamie Madillb885e572015-02-03 16:16:04 -0500878 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
879 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400880 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
881 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500882 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000883}
884
Corentin Wallez37c39792015-08-20 14:19:46 -0400885size_t Framebuffer::getNumColorBuffers() const
886{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400887 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400888}
889
Jamie Madill0df8fe42015-11-24 16:10:24 -0500890bool Framebuffer::hasDepth() const
891{
Jamie Madill9c335862017-07-18 11:51:38 -0400892 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500893}
894
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000895bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000896{
Jamie Madill9c335862017-07-18 11:51:38 -0400897 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000898}
899
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000900bool Framebuffer::usingExtendedDrawBuffers() const
901{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400902 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000903 {
Geoff Langa15472a2015-08-11 11:48:03 -0400904 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000905 {
906 return true;
907 }
908 }
909
910 return false;
911}
912
Geoff Lang9aded172017-04-05 11:07:56 -0400913void Framebuffer::invalidateCompletenessCache()
914{
915 if (mId != 0)
916 {
917 mCachedStatus.reset();
918 }
919}
920
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400921GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000922{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500923 // The default framebuffer is always complete except when it is surfaceless in which
924 // case it is always unsupported. We return early because the default framebuffer may
925 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500926 if (mId == 0)
927 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500928 ASSERT(mCachedStatus.valid());
929 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
930 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
931 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500932 }
933
Jamie Madill362876b2016-06-16 14:46:59 -0400934 if (hasAnyDirtyBit() || !mCachedStatus.valid())
935 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400936 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400937 }
938
939 return mCachedStatus.value();
940}
941
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400942GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400943{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400944 const ContextState &state = context->getContextState();
945
Jamie Madill362876b2016-06-16 14:46:59 -0400946 ASSERT(mId != 0);
947
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400948 bool hasAttachments = false;
949 Optional<unsigned int> colorbufferSize;
950 Optional<int> samples;
JiangYizhou461d9a32017-01-04 16:37:26 +0800951 Optional<GLboolean> fixedSampleLocations;
952 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000953
Martin Radev9bc9a322017-07-21 14:28:17 +0300954 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
955
Jamie Madill48ef11b2016-04-27 15:21:52 -0400956 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000957 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400958 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000959 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400960 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000961 {
962 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
963 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000964
Geoff Lang677bb6f2017-04-05 12:40:40 -0400965 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400966 if (format.depthBits > 0 || format.stencilBits > 0)
967 {
968 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
969 }
970
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400971 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
972 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000973 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400974 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000975 }
976
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400977 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
978 // in GLES 3.0, there is no such restriction
979 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000980 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400981 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000982 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400983 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000984 {
985 return GL_FRAMEBUFFER_UNSUPPORTED;
986 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000987 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400988 else
989 {
990 colorbufferSize = format.pixelBytes;
991 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000992 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400993
Martin Radev9bc9a322017-07-21 14:28:17 +0300994 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
995 {
996 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
997 }
998
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400999 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1000 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001001 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001002 }
1003
Jamie Madill48ef11b2016-04-27 15:21:52 -04001004 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001005 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001006 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001007 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001009 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001010 }
1011
Geoff Lang677bb6f2017-04-05 12:40:40 -04001012 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001013 if (format.depthBits == 0)
1014 {
1015 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001016 }
1017
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001018 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1019 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001020 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001021 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001022 }
Sami Väisänena797e062016-05-12 15:23:40 +03001023
Martin Radev9bc9a322017-07-21 14:28:17 +03001024 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1025 {
1026 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1027 }
1028
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001029 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1030 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001031 }
1032
Jamie Madill48ef11b2016-04-27 15:21:52 -04001033 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001034 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001035 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001036 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001037 {
1038 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1039 }
1040
Geoff Lang677bb6f2017-04-05 12:40:40 -04001041 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001042 if (format.stencilBits == 0)
1043 {
1044 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001045 }
1046
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001047 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1048 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001049 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001050 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001051 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001052
Martin Radev9bc9a322017-07-21 14:28:17 +03001053 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1054 {
1055 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1056 }
1057
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001058 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1059 hasAttachments = true;
1060 }
1061
1062 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1063 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1064 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1065 {
1066 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001067 }
1068
Jamie Madilla02315b2017-02-23 14:14:47 -05001069 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1070 if (state.isWebGL1())
1071 {
1072 if (!mState.mWebGLDepthStencilConsistent)
1073 {
1074 return GL_FRAMEBUFFER_UNSUPPORTED;
1075 }
1076
1077 if (mState.mWebGLDepthStencilAttachment.isAttached())
1078 {
1079 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1080 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1081 {
1082 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1083 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001084
1085 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1086 &mState.mWebGLDepthStencilAttachment))
1087 {
1088 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1089 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001090 }
1091 else if (mState.mStencilAttachment.isAttached() &&
1092 mState.mStencilAttachment.getDepthSize() > 0)
1093 {
1094 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1095 }
1096 else if (mState.mDepthAttachment.isAttached() &&
1097 mState.mDepthAttachment.getStencilSize() > 0)
1098 {
1099 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1100 }
1101 }
1102
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001103 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1104 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1105 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001106 GLint defaultWidth = mState.getDefaultWidth();
1107 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001108 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001109 {
1110 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001111 }
1112
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001113 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001114 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001115 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1116 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001117 {
1118 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1119 }
1120
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001121 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1122 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001123 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1124 {
1125 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1126 }
1127
Kenneth Russellce8602a2017-10-03 18:23:08 -07001128 // The WebGL conformance tests implicitly define that all framebuffer
1129 // attachments must be unique. For example, the same level of a texture can
1130 // not be attached to two different color attachments.
1131 if (state.getExtensions().webglCompatibility)
1132 {
1133 if (!mState.colorAttachmentsAreUniqueImages())
1134 {
1135 return GL_FRAMEBUFFER_UNSUPPORTED;
1136 }
1137 }
1138
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001139 syncState(context);
Kenneth Russellce8602a2017-10-03 18:23:08 -07001140 if (!mImpl->checkStatus(context))
Jamie Madillcc86d642015-11-24 13:00:07 -05001141 {
1142 return GL_FRAMEBUFFER_UNSUPPORTED;
1143 }
1144
1145 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001146}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001147
Jamie Madill4928b7c2017-06-20 12:57:39 -04001148Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001149{
Jamie Madill05b35b22017-10-03 09:01:44 -04001150 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1151 // can be no-ops, so we should probably do that to ensure consistency.
1152 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1153
Jamie Madill4928b7c2017-06-20 12:57:39 -04001154 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001155}
1156
Jamie Madill4928b7c2017-06-20 12:57:39 -04001157Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001158{
Jamie Madill05b35b22017-10-03 09:01:44 -04001159 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1160 // can be no-ops, so we should probably do that to ensure consistency.
1161 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1162
Jamie Madill4928b7c2017-06-20 12:57:39 -04001163 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001164}
1165
Jamie Madill05b35b22017-10-03 09:01:44 -04001166bool Framebuffer::partialClearNeedsInit(const Context *context,
1167 bool color,
1168 bool depth,
1169 bool stencil)
1170{
1171 const auto &glState = context->getGLState();
1172
1173 if (!glState.isRobustResourceInitEnabled())
1174 {
1175 return false;
1176 }
1177
1178 // Scissors can affect clearing.
1179 // TODO(jmadill): Check for complete scissor overlap.
1180 if (glState.isScissorTestEnabled())
1181 {
1182 return true;
1183 }
1184
1185 // If colors masked, we must clear before we clear. Do a simple check.
1186 // TODO(jmadill): Filter out unused color channels from the test.
1187 if (color)
1188 {
1189 const auto &blend = glState.getBlendState();
1190 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1191 blend.colorMaskAlpha))
1192 {
1193 return true;
1194 }
1195 }
1196
1197 const auto &depthStencil = glState.getDepthStencilState();
1198 ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
1199 if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
1200 {
1201 return true;
1202 }
1203
1204 return false;
1205}
1206
Jamie Madill4928b7c2017-06-20 12:57:39 -04001207Error Framebuffer::invalidateSub(const Context *context,
1208 size_t count,
1209 const GLenum *attachments,
1210 const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001211{
Jamie Madill05b35b22017-10-03 09:01:44 -04001212 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1213 // can be no-ops, so we should probably do that to ensure consistency.
1214 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1215
Jamie Madill4928b7c2017-06-20 12:57:39 -04001216 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001217}
1218
Jamie Madillc564c072017-06-01 12:45:42 -04001219Error Framebuffer::clear(const gl::Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001220{
Jamie Madill05b35b22017-10-03 09:01:44 -04001221 const auto &glState = context->getGLState();
1222 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001223 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001224 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001225 }
1226
Jamie Madill05b35b22017-10-03 09:01:44 -04001227 const auto &blend = glState.getBlendState();
1228 const auto &depthStencil = glState.getDepthStencilState();
1229
1230 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
1231 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
1232 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
1233
1234 if (partialClearNeedsInit(context, color, depth, stencil))
1235 {
1236 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1237 }
1238
1239 ANGLE_TRY(mImpl->clear(context, mask));
1240
1241 if (glState.isRobustResourceInitEnabled())
1242 {
1243 markDrawAttachmentsInitialized(color, depth, stencil);
1244 }
1245
1246 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001247}
1248
Jamie Madillc564c072017-06-01 12:45:42 -04001249Error Framebuffer::clearBufferfv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001250 GLenum buffer,
1251 GLint drawbuffer,
1252 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001253{
Jamie Madill05b35b22017-10-03 09:01:44 -04001254 if (context->getGLState().isRasterizerDiscardEnabled() ||
1255 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001256 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001257 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001258 }
1259
Jamie Madill05b35b22017-10-03 09:01:44 -04001260 if (partialBufferClearNeedsInit(context, buffer))
1261 {
1262 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1263 }
1264
1265 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1266
1267 if (context->isRobustResourceInitEnabled())
1268 {
1269 markBufferInitialized(buffer, drawbuffer);
1270 }
1271 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001272}
1273
Jamie Madillc564c072017-06-01 12:45:42 -04001274Error Framebuffer::clearBufferuiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001275 GLenum buffer,
1276 GLint drawbuffer,
1277 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001278{
Jamie Madill05b35b22017-10-03 09:01:44 -04001279 if (context->getGLState().isRasterizerDiscardEnabled() ||
1280 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001281 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001282 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001283 }
1284
Jamie Madill05b35b22017-10-03 09:01:44 -04001285 if (partialBufferClearNeedsInit(context, buffer))
1286 {
1287 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1288 }
1289
1290 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1291
1292 if (context->isRobustResourceInitEnabled())
1293 {
1294 markBufferInitialized(buffer, drawbuffer);
1295 }
1296 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001297}
1298
Jamie Madillc564c072017-06-01 12:45:42 -04001299Error Framebuffer::clearBufferiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001300 GLenum buffer,
1301 GLint drawbuffer,
1302 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001303{
Jamie Madill05b35b22017-10-03 09:01:44 -04001304 if (context->getGLState().isRasterizerDiscardEnabled() ||
1305 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001306 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001307 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001308 }
1309
Jamie Madill05b35b22017-10-03 09:01:44 -04001310 if (partialBufferClearNeedsInit(context, buffer))
1311 {
1312 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1313 }
1314
1315 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1316
1317 if (context->isRobustResourceInitEnabled())
1318 {
1319 markBufferInitialized(buffer, drawbuffer);
1320 }
1321 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001322}
1323
Jamie Madillc564c072017-06-01 12:45:42 -04001324Error Framebuffer::clearBufferfi(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001325 GLenum buffer,
1326 GLint drawbuffer,
1327 GLfloat depth,
1328 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001329{
Jamie Madill05b35b22017-10-03 09:01:44 -04001330 if (context->getGLState().isRasterizerDiscardEnabled() ||
1331 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001332 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001333 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001334 }
1335
Jamie Madill05b35b22017-10-03 09:01:44 -04001336 if (partialBufferClearNeedsInit(context, buffer))
1337 {
1338 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1339 }
1340
1341 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1342
1343 if (context->isRobustResourceInitEnabled())
1344 {
1345 markBufferInitialized(buffer, drawbuffer);
1346 }
1347 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001348}
1349
Jamie Madill4928b7c2017-06-20 12:57:39 -04001350GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001351{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001352 return mImpl->getImplementationColorReadFormat(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001353}
1354
Jamie Madill4928b7c2017-06-20 12:57:39 -04001355GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001356{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001357 return mImpl->getImplementationColorReadType(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001358}
1359
Jamie Madillc564c072017-06-01 12:45:42 -04001360Error Framebuffer::readPixels(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001361 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001362 GLenum format,
1363 GLenum type,
Jamie Madill05b35b22017-10-03 09:01:44 -04001364 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001365{
Jamie Madill05b35b22017-10-03 09:01:44 -04001366 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001367 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001368
Corentin Wallezcda6af12017-10-30 19:20:37 -04001369 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001370 if (unpackBuffer)
1371 {
1372 unpackBuffer->onPixelUnpack();
1373 }
1374
Jamie Madill362876b2016-06-16 14:46:59 -04001375 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001376}
1377
Jamie Madillc564c072017-06-01 12:45:42 -04001378Error Framebuffer::blit(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001379 const Rectangle &sourceArea,
1380 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001381 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001382 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001383{
He Yunchao6be602d2016-12-22 14:33:07 +08001384 GLbitfield blitMask = mask;
1385
1386 // Note that blitting is called against draw framebuffer.
1387 // See the code in gl::Context::blitFramebuffer.
1388 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1389 {
1390 blitMask &= ~GL_COLOR_BUFFER_BIT;
1391 }
1392
1393 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1394 {
1395 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1396 }
1397
1398 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1399 {
1400 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1401 }
1402
1403 if (!blitMask)
1404 {
1405 return NoError();
1406 }
1407
Jamie Madill05b35b22017-10-03 09:01:44 -04001408 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1409 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1410
1411 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1412 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1413
He Yunchao6be602d2016-12-22 14:33:07 +08001414 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001415}
1416
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001417int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001418{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001419 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001420 {
Jamie Madill9c335862017-07-18 11:51:38 -04001421 return getCachedSamples(context);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001422 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001423
1424 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001425}
1426
Jamie Madill9c335862017-07-18 11:51:38 -04001427int Framebuffer::getCachedSamples(const Context *context)
1428{
1429 // For a complete framebuffer, all attachments must have the same sample count.
1430 // In this case return the first nonzero sample size.
1431 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1432 if (firstNonNullAttachment)
1433 {
1434 ASSERT(firstNonNullAttachment->isAttached());
1435 return firstNonNullAttachment->getSamples();
1436 }
1437
1438 // No attachments found.
1439 return 0;
1440}
1441
Corentin Wallezccab69d2017-01-27 16:57:15 -05001442Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1443{
1444 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001445 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001446}
1447
Jamie Madille261b442014-06-25 12:42:21 -04001448bool Framebuffer::hasValidDepthStencil() const
1449{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001450 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001451}
1452
Jamie Madilla02315b2017-02-23 14:14:47 -05001453void Framebuffer::setAttachment(const Context *context,
1454 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001455 GLenum binding,
1456 const ImageIndex &textureIndex,
1457 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001458{
Martin Radev5dae57b2017-07-14 16:15:55 +03001459 setAttachment(context, type, binding, textureIndex, resource,
1460 FramebufferAttachment::kDefaultNumViews,
1461 FramebufferAttachment::kDefaultBaseViewIndex,
1462 FramebufferAttachment::kDefaultMultiviewLayout,
1463 FramebufferAttachment::kDefaultViewportOffsets);
1464}
1465
1466void Framebuffer::setAttachment(const Context *context,
1467 GLenum type,
1468 GLenum binding,
1469 const ImageIndex &textureIndex,
1470 FramebufferAttachmentObject *resource,
1471 GLsizei numViews,
1472 GLuint baseViewIndex,
1473 GLenum multiviewLayout,
1474 const GLint *viewportOffsets)
1475{
Jamie Madilla02315b2017-02-23 14:14:47 -05001476 // Context may be null in unit tests.
1477 if (!context || !context->isWebGL1())
1478 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001479 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1480 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001481 return;
1482 }
1483
1484 switch (binding)
1485 {
1486 case GL_DEPTH_STENCIL:
1487 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001488 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001489 resource, numViews, baseViewIndex,
1490 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001491 break;
1492 case GL_DEPTH:
1493 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001494 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1495 numViews, baseViewIndex, multiviewLayout,
1496 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001497 break;
1498 case GL_STENCIL:
1499 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001500 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1501 numViews, baseViewIndex, multiviewLayout,
1502 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001503 break;
1504 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001505 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1506 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001507 return;
1508 }
1509
Martin Radev5dae57b2017-07-14 16:15:55 +03001510 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1511 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001512}
1513
Martin Radev82ef7742017-08-08 17:44:58 +03001514void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1515 GLenum type,
1516 GLenum binding,
1517 const ImageIndex &textureIndex,
1518 FramebufferAttachmentObject *resource,
1519 GLsizei numViews,
1520 GLint baseViewIndex)
1521{
1522 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1523 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1524 FramebufferAttachment::kDefaultViewportOffsets);
1525}
1526
Martin Radev5dae57b2017-07-14 16:15:55 +03001527void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1528 GLenum type,
1529 GLenum binding,
1530 const ImageIndex &textureIndex,
1531 FramebufferAttachmentObject *resource,
1532 GLsizei numViews,
1533 const GLint *viewportOffsets)
1534{
1535 setAttachment(context, type, binding, textureIndex, resource, numViews,
1536 FramebufferAttachment::kDefaultBaseViewIndex,
1537 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1538}
1539
1540void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1541 GLsizei numViews,
1542 GLuint baseViewIndex,
1543 GLenum multiviewLayout,
1544 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001545{
1546 int count = 0;
1547
1548 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1549 &mState.mWebGLDepthAttachment,
1550 &mState.mWebGLStencilAttachment}};
1551 for (FramebufferAttachment *attachment : attachments)
1552 {
1553 if (attachment->isAttached())
1554 {
1555 count++;
1556 }
1557 }
1558
1559 mState.mWebGLDepthStencilConsistent = (count <= 1);
1560 if (!mState.mWebGLDepthStencilConsistent)
1561 {
1562 // Inconsistent.
1563 return;
1564 }
1565
Geoff Lange466c552017-03-17 15:24:12 -04001566 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1567 if (attachment.type() == GL_TEXTURE)
1568 {
1569 return attachment.getTextureImageIndex();
1570 }
1571 else
1572 {
1573 return ImageIndex::MakeInvalid();
1574 }
1575 };
1576
Jamie Madilla02315b2017-02-23 14:14:47 -05001577 if (mState.mWebGLDepthAttachment.isAttached())
1578 {
1579 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001580 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001581 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1582 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001583 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001584 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001585 }
1586 else if (mState.mWebGLStencilAttachment.isAttached())
1587 {
1588 const auto &stencil = mState.mWebGLStencilAttachment;
Martin Radev5dae57b2017-07-14 16:15:55 +03001589 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1590 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001591 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001592 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1593 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001594 }
1595 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1596 {
1597 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001598 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001599 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001600 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1601 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001602 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001603 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001604 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1605 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001606 }
1607 else
1608 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001609 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1610 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001611 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001612 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001613 }
1614}
1615
Jamie Madill4928b7c2017-06-20 12:57:39 -04001616void Framebuffer::setAttachmentImpl(const Context *context,
1617 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001618 GLenum binding,
1619 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001620 FramebufferAttachmentObject *resource,
1621 GLsizei numViews,
1622 GLuint baseViewIndex,
1623 GLenum multiviewLayout,
1624 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001625{
Jamie Madilla02315b2017-02-23 14:14:47 -05001626 switch (binding)
1627 {
Jamie Madillb8126692017-04-05 11:22:17 -04001628 case GL_DEPTH_STENCIL:
1629 case GL_DEPTH_STENCIL_ATTACHMENT:
1630 {
1631 // ensure this is a legitimate depth+stencil format
1632 FramebufferAttachmentObject *attachmentObj = resource;
1633 if (resource)
1634 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001635 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001636 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1637 {
1638 // Attaching nullptr detaches the current attachment.
1639 attachmentObj = nullptr;
1640 }
1641 }
1642
Jamie Madill4928b7c2017-06-20 12:57:39 -04001643 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001644 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001645 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1646 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001647 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001648 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001649 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1650 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001651 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001652 }
1653
Jamie Madilla02315b2017-02-23 14:14:47 -05001654 case GL_DEPTH:
1655 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001656 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001657 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1658 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001659 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001660
Jamie Madilla02315b2017-02-23 14:14:47 -05001661 case GL_STENCIL:
1662 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001663 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001664 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1665 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001666 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001667
Jamie Madilla02315b2017-02-23 14:14:47 -05001668 case GL_BACK:
Martin Radev5dae57b2017-07-14 16:15:55 +03001669 mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource,
1670 numViews, baseViewIndex, multiviewLayout,
1671 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001672 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1673 // No need for a resource binding for the default FBO, it's always complete.
1674 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001675
Jamie Madilla02315b2017-02-23 14:14:47 -05001676 default:
1677 {
1678 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1679 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001680 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001681 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001682 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001683 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1684 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001685
Corentin Walleze7557742017-06-01 13:09:57 -04001686 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1687 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001688 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1689 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001690 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001691 break;
Geoff Langab75a052014-10-15 12:56:37 -04001692 }
Jamie Madill42975642017-10-12 12:31:51 -04001693
1694 mAttachedTextures.reset();
Geoff Langab75a052014-10-15 12:56:37 -04001695}
1696
Jamie Madill4928b7c2017-06-20 12:57:39 -04001697void Framebuffer::updateAttachment(const Context *context,
1698 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001699 size_t dirtyBit,
1700 OnAttachmentDirtyBinding *onDirtyBinding,
1701 GLenum type,
1702 GLenum binding,
1703 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001704 FramebufferAttachmentObject *resource,
1705 GLsizei numViews,
1706 GLuint baseViewIndex,
1707 GLenum multiviewLayout,
1708 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001709{
Martin Radev5dae57b2017-07-14 16:15:55 +03001710 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1711 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001712 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001713 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madillb8126692017-04-05 11:22:17 -04001714 BindResourceChannel(onDirtyBinding, resource);
1715}
1716
Jamie Madilla02315b2017-02-23 14:14:47 -05001717void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001718{
Jamie Madilla02315b2017-02-23 14:14:47 -05001719 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001720}
1721
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001722void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001723{
1724 if (mDirtyBits.any())
1725 {
Jamie Madillc564c072017-06-01 12:45:42 -04001726 mImpl->syncState(context, mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001727 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001728 if (mId != 0)
1729 {
1730 mCachedStatus.reset();
1731 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001732 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001733}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001734
Jamie Madill05b35b22017-10-03 09:01:44 -04001735void Framebuffer::signal(size_t dirtyBit, InitState state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001736{
Jamie Madill362876b2016-06-16 14:46:59 -04001737 // TOOD(jmadill): Make this only update individual attachments to do less work.
1738 mCachedStatus.reset();
Jamie Madill05b35b22017-10-03 09:01:44 -04001739
1740 // Mark the appropriate init flag.
1741 mState.mResourceNeedsInit.set(dirtyBit, state == InitState::MayNeedInit);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001742}
1743
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001744bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001745{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001746 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1747}
1748
1749bool Framebuffer::cachedComplete() const
1750{
1751 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001752}
1753
Jamie Madilla4595b82017-01-11 17:36:34 -05001754bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1755{
1756 const Program *program = state.getProgram();
1757
1758 // TODO(jmadill): Default framebuffer feedback loops.
1759 if (mId == 0)
1760 {
1761 return false;
1762 }
1763
1764 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001765 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001766 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001767 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1768 ASSERT(attachment.isAttached());
1769 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001770 {
1771 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001772 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001773 {
1774 return true;
1775 }
1776 }
1777 }
1778
Jamie Madill1d37bc52017-02-02 19:59:58 -05001779 // Validate depth-stencil feedback loop.
1780 const auto &dsState = state.getDepthStencilState();
1781
1782 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1783 const FramebufferAttachment *depth = getDepthbuffer();
1784 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1785 {
1786 if (program->samplesFromTexture(state, depth->id()))
1787 {
1788 return true;
1789 }
1790 }
1791
1792 // Note: we assume the front and back masks are the same for WebGL.
1793 const FramebufferAttachment *stencil = getStencilbuffer();
1794 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1795 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1796 dsState.stencilWritemask != 0)
1797 {
1798 // Skip the feedback loop check if depth/stencil point to the same resource.
1799 if (!depth || *stencil != *depth)
1800 {
1801 if (program->samplesFromTexture(state, stencil->id()))
1802 {
1803 return true;
1804 }
1805 }
1806 }
1807
Jamie Madilla4595b82017-01-11 17:36:34 -05001808 return false;
1809}
1810
Jamie Madillfd3dd432017-02-02 19:59:59 -05001811bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1812 GLint copyTextureLevel,
1813 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001814{
1815 if (mId == 0)
1816 {
1817 // It seems impossible to form a texture copying feedback loop with the default FBO.
1818 return false;
1819 }
1820
1821 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1822 ASSERT(readAttachment);
1823
1824 if (readAttachment->isTextureWithId(copyTextureID))
1825 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001826 const auto &imageIndex = readAttachment->getTextureImageIndex();
1827 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001828 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001829 // Check 3D/Array texture layers.
1830 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1831 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1832 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001833 }
1834 }
1835 return false;
1836}
1837
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001838GLint Framebuffer::getDefaultWidth() const
1839{
1840 return mState.getDefaultWidth();
1841}
1842
1843GLint Framebuffer::getDefaultHeight() const
1844{
1845 return mState.getDefaultHeight();
1846}
1847
1848GLint Framebuffer::getDefaultSamples() const
1849{
1850 return mState.getDefaultSamples();
1851}
1852
1853GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1854{
1855 return mState.getDefaultFixedSampleLocations();
1856}
1857
1858void Framebuffer::setDefaultWidth(GLint defaultWidth)
1859{
1860 mState.mDefaultWidth = defaultWidth;
1861 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1862}
1863
1864void Framebuffer::setDefaultHeight(GLint defaultHeight)
1865{
1866 mState.mDefaultHeight = defaultHeight;
1867 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1868}
1869
1870void Framebuffer::setDefaultSamples(GLint defaultSamples)
1871{
1872 mState.mDefaultSamples = defaultSamples;
1873 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1874}
1875
1876void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1877{
1878 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1879 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1880}
1881
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001882// TODO(jmadill): Remove this kludge.
1883GLenum Framebuffer::checkStatus(const ValidationContext *context)
1884{
1885 return checkStatus(static_cast<const Context *>(context));
1886}
1887
1888int Framebuffer::getSamples(const ValidationContext *context)
1889{
1890 return getSamples(static_cast<const Context *>(context));
1891}
1892
Martin Radev14a26ae2017-07-24 15:56:29 +03001893GLsizei Framebuffer::getNumViews() const
1894{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001895 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03001896}
1897
Martin Radev4e619f52017-08-09 11:50:06 +03001898GLint Framebuffer::getBaseViewIndex() const
1899{
1900 return mState.getBaseViewIndex();
1901}
1902
Martin Radev878c8b12017-07-28 09:51:04 +03001903const std::vector<Offset> *Framebuffer::getViewportOffsets() const
1904{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001905 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03001906}
1907
1908GLenum Framebuffer::getMultiviewLayout() const
1909{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001910 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03001911}
1912
Jamie Madill05b35b22017-10-03 09:01:44 -04001913Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
1914{
1915 if (!context->isRobustResourceInitEnabled())
1916 {
1917 return NoError();
1918 }
1919
1920 // Note: we don't actually filter by the draw attachment enum. Just init everything.
1921 for (size_t bit : mState.mResourceNeedsInit)
1922 {
1923 switch (bit)
1924 {
1925 case DIRTY_BIT_DEPTH_ATTACHMENT:
1926 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
1927 break;
1928 case DIRTY_BIT_STENCIL_ATTACHMENT:
1929 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
1930 break;
1931 default:
1932 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
1933 break;
1934 }
1935 }
1936
1937 mState.mResourceNeedsInit.reset();
1938 return NoError();
1939}
1940
1941Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
1942{
1943 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
1944 {
1945 return NoError();
1946 }
1947
1948 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
1949 {
1950 size_t readIndex = mState.getReadIndex();
1951 if (mState.mResourceNeedsInit[readIndex])
1952 {
1953 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
1954 mState.mResourceNeedsInit.reset(readIndex);
1955 }
1956 }
1957
1958 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
1959 {
1960 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
1961 {
1962 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
1963 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
1964 }
1965 }
1966
1967 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
1968 {
1969 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
1970 {
1971 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
1972 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
1973 }
1974 }
1975
1976 return NoError();
1977}
1978
1979void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
1980{
1981 // Mark attachments as initialized.
1982 if (color)
1983 {
1984 for (auto colorIndex : mState.mEnabledDrawBuffers)
1985 {
1986 auto &colorAttachment = mState.mColorAttachments[colorIndex];
1987 ASSERT(colorAttachment.isAttached());
1988 colorAttachment.setInitState(InitState::Initialized);
1989 mState.mResourceNeedsInit.reset(colorIndex);
1990 }
1991 }
1992
1993 if (depth && mState.mDepthAttachment.isAttached())
1994 {
1995 mState.mDepthAttachment.setInitState(InitState::Initialized);
1996 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
1997 }
1998
1999 if (stencil && mState.mStencilAttachment.isAttached())
2000 {
2001 mState.mStencilAttachment.setInitState(InitState::Initialized);
2002 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2003 }
2004}
2005
2006void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2007{
2008 switch (bufferType)
2009 {
2010 case GL_COLOR:
2011 {
2012 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2013 if (mState.mColorAttachments[bufferIndex].isAttached())
2014 {
2015 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2016 mState.mResourceNeedsInit.reset(bufferIndex);
2017 }
2018 break;
2019 }
2020 case GL_DEPTH:
2021 {
2022 if (mState.mDepthAttachment.isAttached())
2023 {
2024 mState.mDepthAttachment.setInitState(InitState::Initialized);
2025 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2026 }
2027 break;
2028 }
2029 case GL_STENCIL:
2030 {
2031 if (mState.mStencilAttachment.isAttached())
2032 {
2033 mState.mStencilAttachment.setInitState(InitState::Initialized);
2034 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2035 }
2036 break;
2037 }
2038 case GL_DEPTH_STENCIL:
2039 {
2040 if (mState.mDepthAttachment.isAttached())
2041 {
2042 mState.mDepthAttachment.setInitState(InitState::Initialized);
2043 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2044 }
2045 if (mState.mStencilAttachment.isAttached())
2046 {
2047 mState.mStencilAttachment.setInitState(InitState::Initialized);
2048 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2049 }
2050 break;
2051 }
2052 default:
2053 UNREACHABLE();
2054 break;
2055 }
2056}
2057
2058Box Framebuffer::getDimensions() const
2059{
2060 return mState.getDimensions();
2061}
2062
2063Error Framebuffer::ensureBufferInitialized(const Context *context,
2064 GLenum bufferType,
2065 GLint bufferIndex)
2066{
2067 ASSERT(context->isRobustResourceInitEnabled());
2068
2069 if (mState.mResourceNeedsInit.none())
2070 {
2071 return NoError();
2072 }
2073
2074 switch (bufferType)
2075 {
2076 case GL_COLOR:
2077 {
2078 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2079 if (mState.mResourceNeedsInit[bufferIndex])
2080 {
2081 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2082 mState.mResourceNeedsInit.reset(bufferIndex);
2083 }
2084 break;
2085 }
2086 case GL_DEPTH:
2087 {
2088 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2089 {
2090 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2091 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2092 }
2093 break;
2094 }
2095 case GL_STENCIL:
2096 {
2097 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2098 {
2099 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2100 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2101 }
2102 break;
2103 }
2104 case GL_DEPTH_STENCIL:
2105 {
2106 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2107 {
2108 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2109 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2110 }
2111 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2112 {
2113 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2114 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2115 }
2116 break;
2117 }
2118 default:
2119 UNREACHABLE();
2120 break;
2121 }
2122
2123 return NoError();
2124}
2125
2126bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2127{
2128 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2129 {
2130 return false;
2131 }
2132
2133 switch (bufferType)
2134 {
2135 case GL_COLOR:
2136 return partialClearNeedsInit(context, true, false, false);
2137 case GL_DEPTH:
2138 return partialClearNeedsInit(context, false, true, false);
2139 case GL_STENCIL:
2140 return partialClearNeedsInit(context, false, false, true);
2141 case GL_DEPTH_STENCIL:
2142 return partialClearNeedsInit(context, false, true, true);
2143 default:
2144 UNREACHABLE();
2145 return false;
2146 }
2147}
2148
Jamie Madill42975642017-10-12 12:31:51 -04002149bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2150{
2151 if (!mAttachedTextures.valid())
2152 {
2153 std::set<const FramebufferAttachmentObject *> attachedTextures;
2154
2155 for (const auto &colorAttachment : mState.mColorAttachments)
2156 {
2157 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2158 {
2159 attachedTextures.insert(colorAttachment.getResource());
2160 }
2161 }
2162
2163 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2164 {
2165 attachedTextures.insert(mState.mDepthAttachment.getResource());
2166 }
2167
2168 if (mState.mStencilAttachment.isAttached() &&
2169 mState.mStencilAttachment.type() == GL_TEXTURE)
2170 {
2171 attachedTextures.insert(mState.mStencilAttachment.getResource());
2172 }
2173
2174 mAttachedTextures = std::move(attachedTextures);
2175 }
2176
2177 return (mAttachedTextures.value().count(texture) > 0);
2178}
2179
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002180} // namespace gl