blob: 48e71685b32a1bfa57c077cc8faa520a3937d615 [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,
Geoff Lang92019432017-11-20 13:09:34 -0500140 Optional<bool> *fixedSampleLocations)
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400141{
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.
Geoff Lang92019432017-11-20 13:09:34 -0500153 bool fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type,
154 attachmentImageIndex.mipIndex);
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400155 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
Jeff Gilbert8f8edd62017-10-31 14:26:30 -0700436 const auto &prevSize = attachmentSize.value();
437 const auto &curSize = attachment.getSize();
438 return (curSize.width != prevSize.width || curSize.height != prevSize.height);
Jamie Madillcc86d642015-11-24 13:00:07 -0500439 };
440
441 for (const auto &attachment : mColorAttachments)
442 {
443 if (hasMismatchedSize(attachment))
444 {
445 return false;
446 }
447 }
448
449 if (hasMismatchedSize(mDepthAttachment))
450 {
451 return false;
452 }
453
454 return !hasMismatchedSize(mStencilAttachment);
455}
456
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400457const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
458{
459 ASSERT(drawBufferIdx < mDrawBufferStates.size());
460 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
461 {
462 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
463 // must be COLOR_ATTACHMENTi or NONE"
464 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
465 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
466 return getAttachment(mDrawBufferStates[drawBufferIdx]);
467 }
468 else
469 {
470 return nullptr;
471 }
472}
473
474size_t FramebufferState::getDrawBufferCount() const
475{
476 return mDrawBufferStates.size();
477}
478
Geoff Langb21e20d2016-07-19 15:35:41 -0400479bool FramebufferState::colorAttachmentsAreUniqueImages() const
480{
481 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
482 firstAttachmentIdx++)
483 {
484 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
485 if (!firstAttachment.isAttached())
486 {
487 continue;
488 }
489
490 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
491 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
492 {
493 const gl::FramebufferAttachment &secondAttachment =
494 mColorAttachments[secondAttachmentIdx];
495 if (!secondAttachment.isAttached())
496 {
497 continue;
498 }
499
500 if (firstAttachment == secondAttachment)
501 {
502 return false;
503 }
504 }
505 }
506
507 return true;
508}
509
Jamie Madill9c335862017-07-18 11:51:38 -0400510bool FramebufferState::hasDepth() const
511{
512 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
513}
514
515bool FramebufferState::hasStencil() const
516{
517 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
518}
519
Martin Radev5c00d0d2017-08-07 10:06:59 +0300520GLsizei FramebufferState::getNumViews() const
521{
522 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
523 if (attachment == nullptr)
524 {
525 return FramebufferAttachment::kDefaultNumViews;
526 }
527 return attachment->getNumViews();
528}
529
530const std::vector<Offset> *FramebufferState::getViewportOffsets() const
531{
532 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
533 if (attachment == nullptr)
534 {
535 return nullptr;
536 }
537 return &attachment->getMultiviewViewportOffsets();
538}
539
540GLenum FramebufferState::getMultiviewLayout() const
541{
542 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
543 if (attachment == nullptr)
544 {
545 return GL_NONE;
546 }
547 return attachment->getMultiviewLayout();
548}
549
Martin Radev4e619f52017-08-09 11:50:06 +0300550int FramebufferState::getBaseViewIndex() const
551{
552 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
553 if (attachment == nullptr)
554 {
555 return GL_NONE;
556 }
557 return attachment->getBaseViewIndex();
558}
559
Jamie Madill05b35b22017-10-03 09:01:44 -0400560Box FramebufferState::getDimensions() const
561{
562 ASSERT(attachmentsHaveSameDimensions());
563 ASSERT(getFirstNonNullAttachment() != nullptr);
564 Extents extents = getFirstNonNullAttachment()->getSize();
565 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
566}
567
Jamie Madill7aea7e02016-05-10 10:39:45 -0400568Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400569 : mState(caps),
570 mImpl(factory->createFramebuffer(mState)),
571 mId(id),
572 mCachedStatus(),
573 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
574 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000575{
Corentin Wallez37c39792015-08-20 14:19:46 -0400576 ASSERT(mId != 0);
577 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400578 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
579
Jamie Madill1e5499d2017-04-05 11:22:16 -0400580 for (uint32_t colorIndex = 0;
581 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400582 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400583 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400584 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400585}
586
Jamie Madill4928b7c2017-06-20 12:57:39 -0400587Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400588 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500589 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400590 mId(0),
591 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
592 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
593 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400594{
Geoff Langda88add2014-12-01 10:22:01 -0500595 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400596 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500597
Jamie Madill4928b7c2017-06-20 12:57:39 -0400598 const Context *proxyContext = display->getProxyContext();
599
600 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +0300601 surface, FramebufferAttachment::kDefaultNumViews,
602 FramebufferAttachment::kDefaultBaseViewIndex,
603 FramebufferAttachment::kDefaultMultiviewLayout,
604 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500605
606 if (surface->getConfig()->depthSize > 0)
607 {
Martin Radev5dae57b2017-07-14 16:15:55 +0300608 setAttachmentImpl(
609 proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface,
610 FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex,
611 FramebufferAttachment::kDefaultMultiviewLayout,
612 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500613 }
614
615 if (surface->getConfig()->stencilSize > 0)
616 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400617 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL,
Martin Radev5dae57b2017-07-14 16:15:55 +0300618 gl::ImageIndex::MakeInvalid(), surface,
619 FramebufferAttachment::kDefaultNumViews,
620 FramebufferAttachment::kDefaultBaseViewIndex,
621 FramebufferAttachment::kDefaultMultiviewLayout,
622 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500623 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624}
625
Corentin Wallezccab69d2017-01-27 16:57:15 -0500626Framebuffer::Framebuffer(rx::GLImplFactory *factory)
627 : mState(),
628 mImpl(factory->createFramebuffer(mState)),
629 mId(0),
630 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
631 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
632 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
633{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400634 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500635}
636
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000637Framebuffer::~Framebuffer()
638{
Geoff Langda88add2014-12-01 10:22:01 -0500639 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000640}
641
Jamie Madill4928b7c2017-06-20 12:57:39 -0400642void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500643{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400644 for (auto &attachment : mState.mColorAttachments)
645 {
646 attachment.detach(context);
647 }
648 mState.mDepthAttachment.detach(context);
649 mState.mStencilAttachment.detach(context);
650 mState.mWebGLDepthAttachment.detach(context);
651 mState.mWebGLStencilAttachment.detach(context);
652 mState.mWebGLDepthStencilAttachment.detach(context);
653
Jamie Madillc564c072017-06-01 12:45:42 -0400654 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500655}
656
657void Framebuffer::destroyDefault(const egl::Display *display)
658{
Jamie Madillc564c072017-06-01 12:45:42 -0400659 mImpl->destroyDefault(display);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500660}
661
Geoff Lang70d0f492015-12-10 17:45:46 -0500662void Framebuffer::setLabel(const std::string &label)
663{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400664 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500665}
666
667const std::string &Framebuffer::getLabel() const
668{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400669 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500670}
671
Jamie Madill8693bdb2017-09-02 15:32:14 -0400672bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400674 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000675}
676
Jamie Madill8693bdb2017-09-02 15:32:14 -0400677bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000678{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400679 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500680}
Jamie Madille261b442014-06-25 12:42:21 -0400681
Jamie Madill8693bdb2017-09-02 15:32:14 -0400682bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500683{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400684 bool found = false;
685
Jamie Madill362876b2016-06-16 14:46:59 -0400686 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500687 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400688 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
689 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
690 {
691 found = true;
692 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000693 }
694
Jamie Madilla02315b2017-02-23 14:14:47 -0500695 if (context->isWebGL1())
696 {
697 const std::array<FramebufferAttachment *, 3> attachments = {
698 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
699 &mState.mWebGLStencilAttachment}};
700 for (FramebufferAttachment *attachment : attachments)
701 {
702 if (attachment->isAttached() && attachment->type() == resourceType &&
703 attachment->id() == resourceId)
704 {
705 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400706 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500707 }
708 }
709 }
710 else
711 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400712 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
713 DIRTY_BIT_DEPTH_ATTACHMENT))
714 {
715 found = true;
716 }
717 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
718 DIRTY_BIT_STENCIL_ATTACHMENT))
719 {
720 found = true;
721 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500722 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400723
724 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400725}
726
Jamie Madill8693bdb2017-09-02 15:32:14 -0400727bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400728 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400729 GLenum matchType,
730 GLuint matchId,
731 size_t dirtyBit)
732{
733 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
734 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400735 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400736 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -0400737 mState.mResourceNeedsInit.set(dirtyBit, false);
Jamie Madill8693bdb2017-09-02 15:32:14 -0400738 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400739 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400740
741 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000742}
743
Corentin Wallez37c39792015-08-20 14:19:46 -0400744const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000745{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400746 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000747}
748
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400749const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400750{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400751 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400752}
753
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400754const FramebufferAttachment *Framebuffer::getStencilbuffer() const
755{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400756 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400757}
758
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400759const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
760{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400761 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400762}
763
764const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000765{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400766 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000767}
768
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500769const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
770{
771 return mState.getStencilOrDepthStencilAttachment();
772}
773
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400774const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000775{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400776 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000777}
778
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000779GLenum Framebuffer::getReadColorbufferType() const
780{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400781 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400782 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000783}
784
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400785const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000786{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400787 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000788}
789
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400790const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
791{
792 return mState.getFirstNonNullAttachment();
793}
794
Jamie Madill2d06b732015-04-20 12:53:28 -0400795const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000796{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400797 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400798}
799
Geoff Langa15472a2015-08-11 11:48:03 -0400800size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000801{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400802 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400803}
804
805GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
806{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400807 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
808 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000809}
810
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500811const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
812{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400813 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500814}
815
Geoff Lang164d54e2014-12-01 10:55:33 -0500816void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000817{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400818 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500819
820 ASSERT(count <= drawStates.size());
821 std::copy(buffers, buffers + count, drawStates.begin());
822 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500823 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500824
825 mState.mEnabledDrawBuffers.reset();
826 for (size_t index = 0; index < count; ++index)
827 {
828 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
829 {
830 mState.mEnabledDrawBuffers.set(index);
831 }
832 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500833}
834
Geoff Langa15472a2015-08-11 11:48:03 -0400835const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
836{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400837 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400838}
839
Geoff Lange0cff192017-05-30 13:04:56 -0400840GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
841{
842 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
843 if (attachment == nullptr)
844 {
845 return GL_NONE;
846 }
847
848 GLenum componentType = attachment->getFormat().info->componentType;
849 switch (componentType)
850 {
851 case GL_INT:
852 case GL_UNSIGNED_INT:
853 return componentType;
854
855 default:
856 return GL_FLOAT;
857 }
858}
859
Geoff Langa15472a2015-08-11 11:48:03 -0400860bool Framebuffer::hasEnabledDrawBuffer() const
861{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400862 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400863 {
864 if (getDrawBuffer(drawbufferIdx) != nullptr)
865 {
866 return true;
867 }
868 }
869
870 return false;
871}
872
Geoff Lang9dd95802014-12-01 11:12:59 -0500873GLenum Framebuffer::getReadBufferState() const
874{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400875 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500876}
877
878void Framebuffer::setReadBuffer(GLenum buffer)
879{
Jamie Madillb885e572015-02-03 16:16:04 -0500880 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
881 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400882 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
883 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500884 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000885}
886
Corentin Wallez37c39792015-08-20 14:19:46 -0400887size_t Framebuffer::getNumColorBuffers() const
888{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400889 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400890}
891
Jamie Madill0df8fe42015-11-24 16:10:24 -0500892bool Framebuffer::hasDepth() const
893{
Jamie Madill9c335862017-07-18 11:51:38 -0400894 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500895}
896
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000897bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000898{
Jamie Madill9c335862017-07-18 11:51:38 -0400899 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000900}
901
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000902bool Framebuffer::usingExtendedDrawBuffers() const
903{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400904 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000905 {
Geoff Langa15472a2015-08-11 11:48:03 -0400906 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000907 {
908 return true;
909 }
910 }
911
912 return false;
913}
914
Geoff Lang9aded172017-04-05 11:07:56 -0400915void Framebuffer::invalidateCompletenessCache()
916{
917 if (mId != 0)
918 {
919 mCachedStatus.reset();
920 }
921}
922
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400923GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500925 // The default framebuffer is always complete except when it is surfaceless in which
926 // case it is always unsupported. We return early because the default framebuffer may
927 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500928 if (mId == 0)
929 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500930 ASSERT(mCachedStatus.valid());
931 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
932 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
933 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500934 }
935
Jamie Madill362876b2016-06-16 14:46:59 -0400936 if (hasAnyDirtyBit() || !mCachedStatus.valid())
937 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400938 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400939 }
940
941 return mCachedStatus.value();
942}
943
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400944GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400945{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400946 const ContextState &state = context->getContextState();
947
Jamie Madill362876b2016-06-16 14:46:59 -0400948 ASSERT(mId != 0);
949
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400950 bool hasAttachments = false;
951 Optional<unsigned int> colorbufferSize;
952 Optional<int> samples;
Geoff Lang92019432017-11-20 13:09:34 -0500953 Optional<bool> fixedSampleLocations;
JiangYizhou461d9a32017-01-04 16:37:26 +0800954 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000955
Martin Radev9bc9a322017-07-21 14:28:17 +0300956 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
957
Jamie Madill48ef11b2016-04-27 15:21:52 -0400958 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000959 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400960 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000961 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400962 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000963 {
964 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
965 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000966
Geoff Lang677bb6f2017-04-05 12:40:40 -0400967 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400968 if (format.depthBits > 0 || format.stencilBits > 0)
969 {
970 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
971 }
972
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400973 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
974 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000975 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400976 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000977 }
978
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400979 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
980 // in GLES 3.0, there is no such restriction
981 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000982 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400983 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000984 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400985 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000986 {
987 return GL_FRAMEBUFFER_UNSUPPORTED;
988 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000989 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400990 else
991 {
992 colorbufferSize = format.pixelBytes;
993 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000994 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400995
Martin Radev9bc9a322017-07-21 14:28:17 +0300996 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
997 {
998 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
999 }
1000
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001001 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1002 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001003 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001004 }
1005
Jamie Madill48ef11b2016-04-27 15:21:52 -04001006 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001007 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001008 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001009 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001010 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001011 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001012 }
1013
Geoff Lang677bb6f2017-04-05 12:40:40 -04001014 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001015 if (format.depthBits == 0)
1016 {
1017 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001018 }
1019
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001020 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1021 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001022 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001023 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001024 }
Sami Väisänena797e062016-05-12 15:23:40 +03001025
Martin Radev9bc9a322017-07-21 14:28:17 +03001026 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1027 {
1028 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1029 }
1030
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001031 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1032 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001033 }
1034
Jamie Madill48ef11b2016-04-27 15:21:52 -04001035 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001036 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001037 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001038 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001039 {
1040 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1041 }
1042
Geoff Lang677bb6f2017-04-05 12:40:40 -04001043 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001044 if (format.stencilBits == 0)
1045 {
1046 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001047 }
1048
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001049 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1050 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001051 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001052 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001053 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001054
Martin Radev9bc9a322017-07-21 14:28:17 +03001055 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1056 {
1057 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1058 }
1059
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001060 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1061 hasAttachments = true;
1062 }
1063
1064 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1065 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1066 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1067 {
1068 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001069 }
1070
Jamie Madilla02315b2017-02-23 14:14:47 -05001071 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1072 if (state.isWebGL1())
1073 {
1074 if (!mState.mWebGLDepthStencilConsistent)
1075 {
1076 return GL_FRAMEBUFFER_UNSUPPORTED;
1077 }
1078
1079 if (mState.mWebGLDepthStencilAttachment.isAttached())
1080 {
1081 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1082 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1083 {
1084 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1085 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001086
1087 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1088 &mState.mWebGLDepthStencilAttachment))
1089 {
1090 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1091 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001092 }
1093 else if (mState.mStencilAttachment.isAttached() &&
1094 mState.mStencilAttachment.getDepthSize() > 0)
1095 {
1096 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1097 }
1098 else if (mState.mDepthAttachment.isAttached() &&
1099 mState.mDepthAttachment.getStencilSize() > 0)
1100 {
1101 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1102 }
1103 }
1104
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001105 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1106 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1107 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001108 GLint defaultWidth = mState.getDefaultWidth();
1109 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001110 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001111 {
1112 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001113 }
1114
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001115 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001116 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001117 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1118 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001119 {
1120 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1121 }
1122
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001123 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1124 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001125 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1126 {
1127 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1128 }
1129
Kenneth Russellce8602a2017-10-03 18:23:08 -07001130 // The WebGL conformance tests implicitly define that all framebuffer
1131 // attachments must be unique. For example, the same level of a texture can
1132 // not be attached to two different color attachments.
1133 if (state.getExtensions().webglCompatibility)
1134 {
1135 if (!mState.colorAttachmentsAreUniqueImages())
1136 {
1137 return GL_FRAMEBUFFER_UNSUPPORTED;
1138 }
1139 }
1140
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001141 syncState(context);
Kenneth Russellce8602a2017-10-03 18:23:08 -07001142 if (!mImpl->checkStatus(context))
Jamie Madillcc86d642015-11-24 13:00:07 -05001143 {
1144 return GL_FRAMEBUFFER_UNSUPPORTED;
1145 }
1146
1147 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001148}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001149
Jamie Madill4928b7c2017-06-20 12:57:39 -04001150Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001151{
Jamie Madill05b35b22017-10-03 09:01:44 -04001152 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1153 // can be no-ops, so we should probably do that to ensure consistency.
1154 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1155
Jamie Madill4928b7c2017-06-20 12:57:39 -04001156 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001157}
1158
Jamie Madill4928b7c2017-06-20 12:57:39 -04001159Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001160{
Jamie Madill05b35b22017-10-03 09:01:44 -04001161 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1162 // can be no-ops, so we should probably do that to ensure consistency.
1163 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1164
Jamie Madill4928b7c2017-06-20 12:57:39 -04001165 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001166}
1167
Jamie Madill05b35b22017-10-03 09:01:44 -04001168bool Framebuffer::partialClearNeedsInit(const Context *context,
1169 bool color,
1170 bool depth,
1171 bool stencil)
1172{
1173 const auto &glState = context->getGLState();
1174
1175 if (!glState.isRobustResourceInitEnabled())
1176 {
1177 return false;
1178 }
1179
1180 // Scissors can affect clearing.
1181 // TODO(jmadill): Check for complete scissor overlap.
1182 if (glState.isScissorTestEnabled())
1183 {
1184 return true;
1185 }
1186
1187 // If colors masked, we must clear before we clear. Do a simple check.
1188 // TODO(jmadill): Filter out unused color channels from the test.
1189 if (color)
1190 {
1191 const auto &blend = glState.getBlendState();
1192 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1193 blend.colorMaskAlpha))
1194 {
1195 return true;
1196 }
1197 }
1198
1199 const auto &depthStencil = glState.getDepthStencilState();
1200 ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
1201 if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
1202 {
1203 return true;
1204 }
1205
1206 return false;
1207}
1208
Jamie Madill4928b7c2017-06-20 12:57:39 -04001209Error Framebuffer::invalidateSub(const Context *context,
1210 size_t count,
1211 const GLenum *attachments,
1212 const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001213{
Jamie Madill05b35b22017-10-03 09:01:44 -04001214 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1215 // can be no-ops, so we should probably do that to ensure consistency.
1216 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1217
Jamie Madill4928b7c2017-06-20 12:57:39 -04001218 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001219}
1220
Jamie Madillc564c072017-06-01 12:45:42 -04001221Error Framebuffer::clear(const gl::Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001222{
Jamie Madill05b35b22017-10-03 09:01:44 -04001223 const auto &glState = context->getGLState();
1224 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001225 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001226 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001227 }
1228
Jamie Madill05b35b22017-10-03 09:01:44 -04001229 const auto &blend = glState.getBlendState();
1230 const auto &depthStencil = glState.getDepthStencilState();
1231
1232 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
1233 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
1234 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
1235
1236 if (partialClearNeedsInit(context, color, depth, stencil))
1237 {
1238 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1239 }
1240
1241 ANGLE_TRY(mImpl->clear(context, mask));
1242
1243 if (glState.isRobustResourceInitEnabled())
1244 {
1245 markDrawAttachmentsInitialized(color, depth, stencil);
1246 }
1247
1248 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001249}
1250
Jamie Madillc564c072017-06-01 12:45:42 -04001251Error Framebuffer::clearBufferfv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001252 GLenum buffer,
1253 GLint drawbuffer,
1254 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001255{
Jamie Madill05b35b22017-10-03 09:01:44 -04001256 if (context->getGLState().isRasterizerDiscardEnabled() ||
1257 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001258 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001259 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001260 }
1261
Jamie Madill05b35b22017-10-03 09:01:44 -04001262 if (partialBufferClearNeedsInit(context, buffer))
1263 {
1264 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1265 }
1266
1267 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1268
1269 if (context->isRobustResourceInitEnabled())
1270 {
1271 markBufferInitialized(buffer, drawbuffer);
1272 }
1273 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001274}
1275
Jamie Madillc564c072017-06-01 12:45:42 -04001276Error Framebuffer::clearBufferuiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001277 GLenum buffer,
1278 GLint drawbuffer,
1279 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001280{
Jamie Madill05b35b22017-10-03 09:01:44 -04001281 if (context->getGLState().isRasterizerDiscardEnabled() ||
1282 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001283 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001284 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001285 }
1286
Jamie Madill05b35b22017-10-03 09:01:44 -04001287 if (partialBufferClearNeedsInit(context, buffer))
1288 {
1289 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1290 }
1291
1292 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1293
1294 if (context->isRobustResourceInitEnabled())
1295 {
1296 markBufferInitialized(buffer, drawbuffer);
1297 }
1298 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001299}
1300
Jamie Madillc564c072017-06-01 12:45:42 -04001301Error Framebuffer::clearBufferiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001302 GLenum buffer,
1303 GLint drawbuffer,
1304 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001305{
Jamie Madill05b35b22017-10-03 09:01:44 -04001306 if (context->getGLState().isRasterizerDiscardEnabled() ||
1307 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001308 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001309 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001310 }
1311
Jamie Madill05b35b22017-10-03 09:01:44 -04001312 if (partialBufferClearNeedsInit(context, buffer))
1313 {
1314 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1315 }
1316
1317 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1318
1319 if (context->isRobustResourceInitEnabled())
1320 {
1321 markBufferInitialized(buffer, drawbuffer);
1322 }
1323 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001324}
1325
Jamie Madillc564c072017-06-01 12:45:42 -04001326Error Framebuffer::clearBufferfi(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001327 GLenum buffer,
1328 GLint drawbuffer,
1329 GLfloat depth,
1330 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001331{
Jamie Madill05b35b22017-10-03 09:01:44 -04001332 if (context->getGLState().isRasterizerDiscardEnabled() ||
1333 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001334 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001335 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001336 }
1337
Jamie Madill05b35b22017-10-03 09:01:44 -04001338 if (partialBufferClearNeedsInit(context, buffer))
1339 {
1340 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
1341 }
1342
1343 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1344
1345 if (context->isRobustResourceInitEnabled())
1346 {
1347 markBufferInitialized(buffer, drawbuffer);
1348 }
1349 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001350}
1351
Jamie Madill4928b7c2017-06-20 12:57:39 -04001352GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001353{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001354 return mImpl->getImplementationColorReadFormat(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001355}
1356
Jamie Madill4928b7c2017-06-20 12:57:39 -04001357GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001358{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001359 return mImpl->getImplementationColorReadType(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001360}
1361
Jamie Madillc564c072017-06-01 12:45:42 -04001362Error Framebuffer::readPixels(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001363 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001364 GLenum format,
1365 GLenum type,
Jamie Madill05b35b22017-10-03 09:01:44 -04001366 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001367{
Jamie Madill05b35b22017-10-03 09:01:44 -04001368 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001369 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001370
Corentin Wallez336129f2017-10-17 15:55:40 -04001371 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001372 if (unpackBuffer)
1373 {
1374 unpackBuffer->onPixelUnpack();
1375 }
1376
Jamie Madill362876b2016-06-16 14:46:59 -04001377 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001378}
1379
Jamie Madillc564c072017-06-01 12:45:42 -04001380Error Framebuffer::blit(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001381 const Rectangle &sourceArea,
1382 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001383 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001384 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001385{
He Yunchao6be602d2016-12-22 14:33:07 +08001386 GLbitfield blitMask = mask;
1387
1388 // Note that blitting is called against draw framebuffer.
1389 // See the code in gl::Context::blitFramebuffer.
1390 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1391 {
1392 blitMask &= ~GL_COLOR_BUFFER_BIT;
1393 }
1394
1395 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1396 {
1397 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1398 }
1399
1400 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1401 {
1402 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1403 }
1404
1405 if (!blitMask)
1406 {
1407 return NoError();
1408 }
1409
Jamie Madill05b35b22017-10-03 09:01:44 -04001410 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1411 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1412
1413 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1414 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1415
He Yunchao6be602d2016-12-22 14:33:07 +08001416 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001417}
1418
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001419int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001420{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001421 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001422 {
Jamie Madill9c335862017-07-18 11:51:38 -04001423 return getCachedSamples(context);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001424 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001425
1426 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001427}
1428
Jamie Madill9c335862017-07-18 11:51:38 -04001429int Framebuffer::getCachedSamples(const Context *context)
1430{
1431 // For a complete framebuffer, all attachments must have the same sample count.
1432 // In this case return the first nonzero sample size.
1433 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1434 if (firstNonNullAttachment)
1435 {
1436 ASSERT(firstNonNullAttachment->isAttached());
1437 return firstNonNullAttachment->getSamples();
1438 }
1439
1440 // No attachments found.
1441 return 0;
1442}
1443
Corentin Wallezccab69d2017-01-27 16:57:15 -05001444Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1445{
1446 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001447 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001448}
1449
Jamie Madille261b442014-06-25 12:42:21 -04001450bool Framebuffer::hasValidDepthStencil() const
1451{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001452 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001453}
1454
Jamie Madilla02315b2017-02-23 14:14:47 -05001455void Framebuffer::setAttachment(const Context *context,
1456 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001457 GLenum binding,
1458 const ImageIndex &textureIndex,
1459 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001460{
Martin Radev5dae57b2017-07-14 16:15:55 +03001461 setAttachment(context, type, binding, textureIndex, resource,
1462 FramebufferAttachment::kDefaultNumViews,
1463 FramebufferAttachment::kDefaultBaseViewIndex,
1464 FramebufferAttachment::kDefaultMultiviewLayout,
1465 FramebufferAttachment::kDefaultViewportOffsets);
1466}
1467
1468void Framebuffer::setAttachment(const Context *context,
1469 GLenum type,
1470 GLenum binding,
1471 const ImageIndex &textureIndex,
1472 FramebufferAttachmentObject *resource,
1473 GLsizei numViews,
1474 GLuint baseViewIndex,
1475 GLenum multiviewLayout,
1476 const GLint *viewportOffsets)
1477{
Jamie Madilla02315b2017-02-23 14:14:47 -05001478 // Context may be null in unit tests.
1479 if (!context || !context->isWebGL1())
1480 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001481 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1482 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001483 return;
1484 }
1485
1486 switch (binding)
1487 {
1488 case GL_DEPTH_STENCIL:
1489 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001490 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001491 resource, numViews, baseViewIndex,
1492 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001493 break;
1494 case GL_DEPTH:
1495 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001496 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1497 numViews, baseViewIndex, multiviewLayout,
1498 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001499 break;
1500 case GL_STENCIL:
1501 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001502 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1503 numViews, baseViewIndex, multiviewLayout,
1504 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001505 break;
1506 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001507 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1508 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001509 return;
1510 }
1511
Martin Radev5dae57b2017-07-14 16:15:55 +03001512 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1513 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001514}
1515
Martin Radev82ef7742017-08-08 17:44:58 +03001516void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1517 GLenum type,
1518 GLenum binding,
1519 const ImageIndex &textureIndex,
1520 FramebufferAttachmentObject *resource,
1521 GLsizei numViews,
1522 GLint baseViewIndex)
1523{
1524 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1525 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1526 FramebufferAttachment::kDefaultViewportOffsets);
1527}
1528
Martin Radev5dae57b2017-07-14 16:15:55 +03001529void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1530 GLenum type,
1531 GLenum binding,
1532 const ImageIndex &textureIndex,
1533 FramebufferAttachmentObject *resource,
1534 GLsizei numViews,
1535 const GLint *viewportOffsets)
1536{
1537 setAttachment(context, type, binding, textureIndex, resource, numViews,
1538 FramebufferAttachment::kDefaultBaseViewIndex,
1539 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1540}
1541
1542void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1543 GLsizei numViews,
1544 GLuint baseViewIndex,
1545 GLenum multiviewLayout,
1546 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001547{
1548 int count = 0;
1549
1550 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1551 &mState.mWebGLDepthAttachment,
1552 &mState.mWebGLStencilAttachment}};
1553 for (FramebufferAttachment *attachment : attachments)
1554 {
1555 if (attachment->isAttached())
1556 {
1557 count++;
1558 }
1559 }
1560
1561 mState.mWebGLDepthStencilConsistent = (count <= 1);
1562 if (!mState.mWebGLDepthStencilConsistent)
1563 {
1564 // Inconsistent.
1565 return;
1566 }
1567
Geoff Lange466c552017-03-17 15:24:12 -04001568 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1569 if (attachment.type() == GL_TEXTURE)
1570 {
1571 return attachment.getTextureImageIndex();
1572 }
1573 else
1574 {
1575 return ImageIndex::MakeInvalid();
1576 }
1577 };
1578
Jamie Madilla02315b2017-02-23 14:14:47 -05001579 if (mState.mWebGLDepthAttachment.isAttached())
1580 {
1581 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001582 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001583 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1584 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001585 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001586 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001587 }
1588 else if (mState.mWebGLStencilAttachment.isAttached())
1589 {
1590 const auto &stencil = mState.mWebGLStencilAttachment;
Martin Radev5dae57b2017-07-14 16:15:55 +03001591 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1592 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001593 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001594 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1595 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001596 }
1597 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1598 {
1599 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001600 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001601 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001602 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1603 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001604 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001605 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001606 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1607 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001608 }
1609 else
1610 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001611 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1612 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001613 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001614 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001615 }
1616}
1617
Jamie Madill4928b7c2017-06-20 12:57:39 -04001618void Framebuffer::setAttachmentImpl(const Context *context,
1619 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001620 GLenum binding,
1621 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001622 FramebufferAttachmentObject *resource,
1623 GLsizei numViews,
1624 GLuint baseViewIndex,
1625 GLenum multiviewLayout,
1626 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001627{
Jamie Madilla02315b2017-02-23 14:14:47 -05001628 switch (binding)
1629 {
Jamie Madillb8126692017-04-05 11:22:17 -04001630 case GL_DEPTH_STENCIL:
1631 case GL_DEPTH_STENCIL_ATTACHMENT:
1632 {
1633 // ensure this is a legitimate depth+stencil format
1634 FramebufferAttachmentObject *attachmentObj = resource;
1635 if (resource)
1636 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001637 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001638 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1639 {
1640 // Attaching nullptr detaches the current attachment.
1641 attachmentObj = nullptr;
1642 }
1643 }
1644
Jamie Madill4928b7c2017-06-20 12:57:39 -04001645 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001646 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001647 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1648 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001649 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001650 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001651 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1652 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001653 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001654 }
1655
Jamie Madilla02315b2017-02-23 14:14:47 -05001656 case GL_DEPTH:
1657 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001658 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001659 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1660 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001661 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001662
Jamie Madilla02315b2017-02-23 14:14:47 -05001663 case GL_STENCIL:
1664 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001665 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001666 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1667 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001668 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001669
Jamie Madilla02315b2017-02-23 14:14:47 -05001670 case GL_BACK:
Martin Radev5dae57b2017-07-14 16:15:55 +03001671 mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource,
1672 numViews, baseViewIndex, multiviewLayout,
1673 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001674 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1675 // No need for a resource binding for the default FBO, it's always complete.
1676 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001677
Jamie Madilla02315b2017-02-23 14:14:47 -05001678 default:
1679 {
1680 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1681 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001682 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001683 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001684 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001685 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1686 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001687
Corentin Walleze7557742017-06-01 13:09:57 -04001688 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1689 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001690 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1691 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001692 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001693 break;
Geoff Langab75a052014-10-15 12:56:37 -04001694 }
Jamie Madill42975642017-10-12 12:31:51 -04001695
1696 mAttachedTextures.reset();
Geoff Langab75a052014-10-15 12:56:37 -04001697}
1698
Jamie Madill4928b7c2017-06-20 12:57:39 -04001699void Framebuffer::updateAttachment(const Context *context,
1700 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001701 size_t dirtyBit,
1702 OnAttachmentDirtyBinding *onDirtyBinding,
1703 GLenum type,
1704 GLenum binding,
1705 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001706 FramebufferAttachmentObject *resource,
1707 GLsizei numViews,
1708 GLuint baseViewIndex,
1709 GLenum multiviewLayout,
1710 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001711{
Martin Radev5dae57b2017-07-14 16:15:55 +03001712 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1713 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001714 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001715 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madillb8126692017-04-05 11:22:17 -04001716 BindResourceChannel(onDirtyBinding, resource);
1717}
1718
Jamie Madilla02315b2017-02-23 14:14:47 -05001719void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001720{
Jamie Madilla02315b2017-02-23 14:14:47 -05001721 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001722}
1723
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001724void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001725{
1726 if (mDirtyBits.any())
1727 {
Jamie Madillc564c072017-06-01 12:45:42 -04001728 mImpl->syncState(context, mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001729 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001730 if (mId != 0)
1731 {
1732 mCachedStatus.reset();
1733 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001734 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001735}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001736
Jamie Madill05b35b22017-10-03 09:01:44 -04001737void Framebuffer::signal(size_t dirtyBit, InitState state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001738{
Jamie Madill362876b2016-06-16 14:46:59 -04001739 // TOOD(jmadill): Make this only update individual attachments to do less work.
1740 mCachedStatus.reset();
Jamie Madill05b35b22017-10-03 09:01:44 -04001741
1742 // Mark the appropriate init flag.
1743 mState.mResourceNeedsInit.set(dirtyBit, state == InitState::MayNeedInit);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001744}
1745
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001746bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001747{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001748 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1749}
1750
1751bool Framebuffer::cachedComplete() const
1752{
1753 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001754}
1755
Jamie Madilla4595b82017-01-11 17:36:34 -05001756bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1757{
1758 const Program *program = state.getProgram();
1759
1760 // TODO(jmadill): Default framebuffer feedback loops.
1761 if (mId == 0)
1762 {
1763 return false;
1764 }
1765
1766 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001767 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001768 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001769 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1770 ASSERT(attachment.isAttached());
1771 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001772 {
1773 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001774 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001775 {
1776 return true;
1777 }
1778 }
1779 }
1780
Jamie Madill1d37bc52017-02-02 19:59:58 -05001781 // Validate depth-stencil feedback loop.
1782 const auto &dsState = state.getDepthStencilState();
1783
1784 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1785 const FramebufferAttachment *depth = getDepthbuffer();
1786 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1787 {
1788 if (program->samplesFromTexture(state, depth->id()))
1789 {
1790 return true;
1791 }
1792 }
1793
1794 // Note: we assume the front and back masks are the same for WebGL.
1795 const FramebufferAttachment *stencil = getStencilbuffer();
1796 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1797 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1798 dsState.stencilWritemask != 0)
1799 {
1800 // Skip the feedback loop check if depth/stencil point to the same resource.
1801 if (!depth || *stencil != *depth)
1802 {
1803 if (program->samplesFromTexture(state, stencil->id()))
1804 {
1805 return true;
1806 }
1807 }
1808 }
1809
Jamie Madilla4595b82017-01-11 17:36:34 -05001810 return false;
1811}
1812
Jamie Madillfd3dd432017-02-02 19:59:59 -05001813bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1814 GLint copyTextureLevel,
1815 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001816{
1817 if (mId == 0)
1818 {
1819 // It seems impossible to form a texture copying feedback loop with the default FBO.
1820 return false;
1821 }
1822
1823 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1824 ASSERT(readAttachment);
1825
1826 if (readAttachment->isTextureWithId(copyTextureID))
1827 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001828 const auto &imageIndex = readAttachment->getTextureImageIndex();
1829 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001830 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001831 // Check 3D/Array texture layers.
1832 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1833 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1834 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001835 }
1836 }
1837 return false;
1838}
1839
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001840GLint Framebuffer::getDefaultWidth() const
1841{
1842 return mState.getDefaultWidth();
1843}
1844
1845GLint Framebuffer::getDefaultHeight() const
1846{
1847 return mState.getDefaultHeight();
1848}
1849
1850GLint Framebuffer::getDefaultSamples() const
1851{
1852 return mState.getDefaultSamples();
1853}
1854
Geoff Lang92019432017-11-20 13:09:34 -05001855bool Framebuffer::getDefaultFixedSampleLocations() const
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001856{
1857 return mState.getDefaultFixedSampleLocations();
1858}
1859
1860void Framebuffer::setDefaultWidth(GLint defaultWidth)
1861{
1862 mState.mDefaultWidth = defaultWidth;
1863 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1864}
1865
1866void Framebuffer::setDefaultHeight(GLint defaultHeight)
1867{
1868 mState.mDefaultHeight = defaultHeight;
1869 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1870}
1871
1872void Framebuffer::setDefaultSamples(GLint defaultSamples)
1873{
1874 mState.mDefaultSamples = defaultSamples;
1875 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1876}
1877
Geoff Lang92019432017-11-20 13:09:34 -05001878void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001879{
1880 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1881 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1882}
1883
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001884// TODO(jmadill): Remove this kludge.
1885GLenum Framebuffer::checkStatus(const ValidationContext *context)
1886{
1887 return checkStatus(static_cast<const Context *>(context));
1888}
1889
1890int Framebuffer::getSamples(const ValidationContext *context)
1891{
1892 return getSamples(static_cast<const Context *>(context));
1893}
1894
Martin Radev14a26ae2017-07-24 15:56:29 +03001895GLsizei Framebuffer::getNumViews() const
1896{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001897 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03001898}
1899
Martin Radev4e619f52017-08-09 11:50:06 +03001900GLint Framebuffer::getBaseViewIndex() const
1901{
1902 return mState.getBaseViewIndex();
1903}
1904
Martin Radev878c8b12017-07-28 09:51:04 +03001905const std::vector<Offset> *Framebuffer::getViewportOffsets() const
1906{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001907 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03001908}
1909
1910GLenum Framebuffer::getMultiviewLayout() const
1911{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001912 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03001913}
1914
Jamie Madill05b35b22017-10-03 09:01:44 -04001915Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
1916{
1917 if (!context->isRobustResourceInitEnabled())
1918 {
1919 return NoError();
1920 }
1921
1922 // Note: we don't actually filter by the draw attachment enum. Just init everything.
1923 for (size_t bit : mState.mResourceNeedsInit)
1924 {
1925 switch (bit)
1926 {
1927 case DIRTY_BIT_DEPTH_ATTACHMENT:
1928 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
1929 break;
1930 case DIRTY_BIT_STENCIL_ATTACHMENT:
1931 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
1932 break;
1933 default:
1934 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
1935 break;
1936 }
1937 }
1938
1939 mState.mResourceNeedsInit.reset();
1940 return NoError();
1941}
1942
1943Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
1944{
1945 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
1946 {
1947 return NoError();
1948 }
1949
1950 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
1951 {
1952 size_t readIndex = mState.getReadIndex();
1953 if (mState.mResourceNeedsInit[readIndex])
1954 {
1955 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
1956 mState.mResourceNeedsInit.reset(readIndex);
1957 }
1958 }
1959
1960 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
1961 {
1962 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
1963 {
1964 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
1965 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
1966 }
1967 }
1968
1969 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
1970 {
1971 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
1972 {
1973 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
1974 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
1975 }
1976 }
1977
1978 return NoError();
1979}
1980
1981void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
1982{
1983 // Mark attachments as initialized.
1984 if (color)
1985 {
1986 for (auto colorIndex : mState.mEnabledDrawBuffers)
1987 {
1988 auto &colorAttachment = mState.mColorAttachments[colorIndex];
1989 ASSERT(colorAttachment.isAttached());
1990 colorAttachment.setInitState(InitState::Initialized);
1991 mState.mResourceNeedsInit.reset(colorIndex);
1992 }
1993 }
1994
1995 if (depth && mState.mDepthAttachment.isAttached())
1996 {
1997 mState.mDepthAttachment.setInitState(InitState::Initialized);
1998 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
1999 }
2000
2001 if (stencil && mState.mStencilAttachment.isAttached())
2002 {
2003 mState.mStencilAttachment.setInitState(InitState::Initialized);
2004 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2005 }
2006}
2007
2008void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2009{
2010 switch (bufferType)
2011 {
2012 case GL_COLOR:
2013 {
2014 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2015 if (mState.mColorAttachments[bufferIndex].isAttached())
2016 {
2017 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2018 mState.mResourceNeedsInit.reset(bufferIndex);
2019 }
2020 break;
2021 }
2022 case GL_DEPTH:
2023 {
2024 if (mState.mDepthAttachment.isAttached())
2025 {
2026 mState.mDepthAttachment.setInitState(InitState::Initialized);
2027 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2028 }
2029 break;
2030 }
2031 case GL_STENCIL:
2032 {
2033 if (mState.mStencilAttachment.isAttached())
2034 {
2035 mState.mStencilAttachment.setInitState(InitState::Initialized);
2036 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2037 }
2038 break;
2039 }
2040 case GL_DEPTH_STENCIL:
2041 {
2042 if (mState.mDepthAttachment.isAttached())
2043 {
2044 mState.mDepthAttachment.setInitState(InitState::Initialized);
2045 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2046 }
2047 if (mState.mStencilAttachment.isAttached())
2048 {
2049 mState.mStencilAttachment.setInitState(InitState::Initialized);
2050 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2051 }
2052 break;
2053 }
2054 default:
2055 UNREACHABLE();
2056 break;
2057 }
2058}
2059
2060Box Framebuffer::getDimensions() const
2061{
2062 return mState.getDimensions();
2063}
2064
2065Error Framebuffer::ensureBufferInitialized(const Context *context,
2066 GLenum bufferType,
2067 GLint bufferIndex)
2068{
2069 ASSERT(context->isRobustResourceInitEnabled());
2070
2071 if (mState.mResourceNeedsInit.none())
2072 {
2073 return NoError();
2074 }
2075
2076 switch (bufferType)
2077 {
2078 case GL_COLOR:
2079 {
2080 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2081 if (mState.mResourceNeedsInit[bufferIndex])
2082 {
2083 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2084 mState.mResourceNeedsInit.reset(bufferIndex);
2085 }
2086 break;
2087 }
2088 case GL_DEPTH:
2089 {
2090 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2091 {
2092 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2093 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2094 }
2095 break;
2096 }
2097 case GL_STENCIL:
2098 {
2099 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2100 {
2101 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2102 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2103 }
2104 break;
2105 }
2106 case GL_DEPTH_STENCIL:
2107 {
2108 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2109 {
2110 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2111 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2112 }
2113 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2114 {
2115 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2116 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2117 }
2118 break;
2119 }
2120 default:
2121 UNREACHABLE();
2122 break;
2123 }
2124
2125 return NoError();
2126}
2127
2128bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2129{
2130 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2131 {
2132 return false;
2133 }
2134
2135 switch (bufferType)
2136 {
2137 case GL_COLOR:
2138 return partialClearNeedsInit(context, true, false, false);
2139 case GL_DEPTH:
2140 return partialClearNeedsInit(context, false, true, false);
2141 case GL_STENCIL:
2142 return partialClearNeedsInit(context, false, false, true);
2143 case GL_DEPTH_STENCIL:
2144 return partialClearNeedsInit(context, false, true, true);
2145 default:
2146 UNREACHABLE();
2147 return false;
2148 }
2149}
2150
Jamie Madill42975642017-10-12 12:31:51 -04002151bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2152{
2153 if (!mAttachedTextures.valid())
2154 {
2155 std::set<const FramebufferAttachmentObject *> attachedTextures;
2156
2157 for (const auto &colorAttachment : mState.mColorAttachments)
2158 {
2159 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2160 {
2161 attachedTextures.insert(colorAttachment.getResource());
2162 }
2163 }
2164
2165 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2166 {
2167 attachedTextures.insert(mState.mDepthAttachment.getResource());
2168 }
2169
2170 if (mState.mStencilAttachment.isAttached() &&
2171 mState.mStencilAttachment.type() == GL_TEXTURE)
2172 {
2173 attachedTextures.insert(mState.mStencilAttachment.getResource());
2174 }
2175
2176 mAttachedTextures = std::move(attachedTextures);
2177 }
2178
2179 return (mAttachedTextures.value().count(texture) > 0);
2180}
2181
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002182} // namespace gl