blob: 0df4d7baf3780e142928fcbd6f1a8c93680e5962 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Framebuffer.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040011
Jamie Madillcc86d642015-11-24 13:00:07 -050012#include "common/Optional.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040013#include "common/bitset_utils.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040014#include "common/utilities.h"
15#include "libANGLE/Config.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Context.h"
Jamie Madill6c1f6712017-02-14 19:08:04 -050017#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050018#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040019#include "libANGLE/Renderbuffer.h"
20#include "libANGLE/Surface.h"
21#include "libANGLE/Texture.h"
Brandon Jones76746f92017-11-22 11:44:41 -080022#include "libANGLE/angletypes.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040023#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040024#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050025#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040026#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050027#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040028#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040029
Jamie Madill362876b2016-06-16 14:46:59 -040030using namespace angle;
31
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000032namespace gl
33{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000034
Jamie Madilld1405e52015-03-05 15:41:39 -050035namespace
36{
Jamie Madill362876b2016-06-16 14:46:59 -040037
Martin Radev9bc9a322017-07-21 14:28:17 +030038bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
39 const FramebufferAttachment *secondAttachment)
40{
41 ASSERT(firstAttachment && secondAttachment);
42 ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
43
44 if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
45 {
46 return false;
47 }
48 if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
49 {
50 return false;
51 }
52 if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
53 {
54 return false;
55 }
56 if (firstAttachment->getMultiviewViewportOffsets() !=
57 secondAttachment->getMultiviewViewportOffsets())
58 {
59 return false;
60 }
61 return true;
62}
63
Geoff Lang9f10b772017-05-16 15:51:03 -040064bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
65{
66 ASSERT(attachment.isAttached());
67
68 const Extents &size = attachment.getSize();
69 if (size.width == 0 || size.height == 0)
70 {
71 return false;
72 }
73
74 const InternalFormat &format = *attachment.getFormat().info;
75 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
76 {
77 return false;
78 }
79
80 if (attachment.type() == GL_TEXTURE)
81 {
82 if (attachment.layer() >= size.depth)
83 {
84 return false;
85 }
86
87 // ES3 specifies that cube map texture attachments must be cube complete.
88 // This language is missing from the ES2 spec, but we enforce it here because some
89 // desktop OpenGL drivers also enforce this validation.
90 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
91 const Texture *texture = attachment.getTexture();
92 ASSERT(texture);
Corentin Wallez99d492c2018-02-27 15:17:10 -050093 if (texture->getType() == TextureType::CubeMap &&
Geoff Lang9f10b772017-05-16 15:51:03 -040094 !texture->getTextureState().isCubeComplete())
95 {
96 return false;
97 }
Geoff Lang857c09d2017-05-16 15:55:04 -040098
99 if (!texture->getImmutableFormat())
100 {
101 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
102
103 // From the ES 3.0 spec, pg 213:
104 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
105 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
106 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
107 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
108 // the effective maximum texture level defined in the Mipmapping discussion of
109 // section 3.8.10.4.
110 if (attachmentMipLevel < texture->getBaseLevel() ||
111 attachmentMipLevel > texture->getMipmapMaxLevel())
112 {
113 return false;
114 }
115
116 // Form the ES 3.0 spec, pg 213/214:
117 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
118 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
119 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
120 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
121 // a cubemap texture, the texture must also be cube complete.
122 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
123 {
124 return false;
125 }
126 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400127 }
128
129 return true;
130};
131
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400132bool CheckAttachmentSampleCompleteness(const Context *context,
133 const FramebufferAttachment &attachment,
134 bool colorAttachment,
135 Optional<int> *samples,
Geoff Lang92019432017-11-20 13:09:34 -0500136 Optional<bool> *fixedSampleLocations)
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400137{
138 ASSERT(attachment.isAttached());
139
140 if (attachment.type() == GL_TEXTURE)
141 {
142 const Texture *texture = attachment.getTexture();
143 ASSERT(texture);
144
145 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
146
147 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
148 // the same for all attached textures.
Jamie Madillcc129372018-04-12 09:13:18 -0400149 bool fixedSampleloc = texture->getFixedSampleLocations(
150 attachmentImageIndex.getTarget(), attachmentImageIndex.getLevelIndex());
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400151 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
152 {
153 return false;
154 }
155 else
156 {
157 *fixedSampleLocations = fixedSampleloc;
158 }
159 }
160
161 if (samples->valid())
162 {
163 if (attachment.getSamples() != samples->value())
164 {
165 if (colorAttachment)
166 {
167 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
168 // all color attachments have the same number of samples for the FBO to be complete.
169 return false;
170 }
171 else
172 {
173 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
174 // when its depth or stencil samples are a multiple of the number of color samples.
175 if (!context->getExtensions().framebufferMixedSamples)
176 {
177 return false;
178 }
179
180 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
181 {
182 return false;
183 }
184 }
185 }
186 }
187 else
188 {
189 *samples = attachment.getSamples();
190 }
191
192 return true;
193}
194
Jamie Madill05b35b22017-10-03 09:01:44 -0400195// Needed to index into the attachment arrays/bitsets.
Jamie Madill682efdc2017-10-03 14:10:29 -0400196static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500197 Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
Jamie Madill05b35b22017-10-03 09:01:44 -0400198 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400199static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500200 Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400201 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400202static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500203 Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400204 "Framebuffer Dirty bit mismatch");
205
206Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
207{
208 ASSERT(attachment->isAttached());
209 if (attachment->initState() == InitState::MayNeedInit)
210 {
211 ANGLE_TRY(attachment->initializeContents(context));
212 }
213 return NoError();
214}
215
216bool IsColorMaskedOut(const BlendState &blend)
217{
218 return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
219 !blend.colorMaskAlpha);
220}
221
222bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
223{
224 return !depthStencil.depthMask;
225}
226
227bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
228{
229 return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
230}
231
232bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
233{
234 switch (buffer)
235 {
236 case GL_COLOR:
237 return IsColorMaskedOut(context->getGLState().getBlendState());
238 case GL_DEPTH:
239 return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
240 case GL_STENCIL:
241 return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
242 case GL_DEPTH_STENCIL:
243 return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
244 IsStencilMaskedOut(context->getGLState().getDepthStencilState());
245 default:
246 UNREACHABLE();
247 return true;
248 }
249}
250
Jamie Madill362876b2016-06-16 14:46:59 -0400251} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500252
Jamie Madill6f60d052017-02-22 15:20:11 -0500253// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400254FramebufferState::FramebufferState()
Jamie Madill2274b652018-05-31 10:56:08 -0400255 : mId(0),
256 mLabel(),
Geoff Lang70d0f492015-12-10 17:45:46 -0500257 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400258 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500259 mReadBufferState(GL_BACK),
Brandon Jones76746f92017-11-22 11:44:41 -0800260 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800261 mDefaultWidth(0),
262 mDefaultHeight(0),
263 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500264 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800265 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500266 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400267{
Geoff Langd90d3882017-03-21 10:49:54 -0400268 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500269 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400270}
271
Jamie Madill2274b652018-05-31 10:56:08 -0400272FramebufferState::FramebufferState(const Caps &caps, GLuint id)
273 : mId(id),
274 mLabel(),
Geoff Lang70d0f492015-12-10 17:45:46 -0500275 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),
Brandon Jones76746f92017-11-22 11:44:41 -0800278 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800279 mDefaultWidth(0),
280 mDefaultHeight(0),
281 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500282 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800283 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500284 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500285{
Jamie Madill2274b652018-05-31 10:56:08 -0400286 ASSERT(mId != 0);
Geoff Langa15472a2015-08-11 11:48:03 -0400287 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500288 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
289}
290
Jamie Madill48ef11b2016-04-27 15:21:52 -0400291FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500292{
Jamie Madilld1405e52015-03-05 15:41:39 -0500293}
294
Jamie Madill48ef11b2016-04-27 15:21:52 -0400295const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500296{
297 return mLabel;
298}
299
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800300const FramebufferAttachment *FramebufferState::getAttachment(const Context *context,
301 GLenum attachment) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400302{
303 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
304 {
305 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
306 }
307
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800308 // WebGL1 allows a developer to query for attachment parameters even when "inconsistant" (i.e.
309 // multiple conflicting attachment points) and requires us to return the framebuffer attachment
310 // associated with WebGL.
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400311 switch (attachment)
312 {
313 case GL_COLOR:
314 case GL_BACK:
315 return getColorAttachment(0);
316 case GL_DEPTH:
317 case GL_DEPTH_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800318 if (context->isWebGL1())
319 {
320 return getWebGLDepthAttachment();
321 }
322 else
323 {
324 return getDepthAttachment();
325 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400326 case GL_STENCIL:
327 case GL_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800328 if (context->isWebGL1())
329 {
330 return getWebGLStencilAttachment();
331 }
332 else
333 {
334 return getStencilAttachment();
335 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400336 case GL_DEPTH_STENCIL:
337 case GL_DEPTH_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800338 if (context->isWebGL1())
339 {
340 return getWebGLDepthStencilAttachment();
341 }
342 else
343 {
344 return getDepthStencilAttachment();
345 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400346 default:
347 UNREACHABLE();
348 return nullptr;
349 }
350}
351
Jamie Madill05b35b22017-10-03 09:01:44 -0400352size_t FramebufferState::getReadIndex() const
Jamie Madill7147f012015-03-05 15:41:40 -0500353{
Jamie Madill231c7f52017-04-26 13:45:37 -0400354 ASSERT(mReadBufferState == GL_BACK ||
355 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
356 size_t readIndex = (mReadBufferState == GL_BACK
357 ? 0
358 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500359 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill05b35b22017-10-03 09:01:44 -0400360 return readIndex;
361}
362
363const FramebufferAttachment *FramebufferState::getReadAttachment() const
364{
365 if (mReadBufferState == GL_NONE)
366 {
367 return nullptr;
368 }
369 size_t readIndex = getReadIndex();
Jamie Madill2d06b732015-04-20 12:53:28 -0400370 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500371}
372
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500373const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
374{
375 auto *colorAttachment = getFirstColorAttachment();
376 if (colorAttachment)
377 {
378 return colorAttachment;
379 }
380 return getDepthOrStencilAttachment();
381}
382
Jamie Madill48ef11b2016-04-27 15:21:52 -0400383const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500384{
Jamie Madill2d06b732015-04-20 12:53:28 -0400385 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500386 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400387 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500388 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400389 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500390 }
391 }
392
393 return nullptr;
394}
395
Jamie Madill48ef11b2016-04-27 15:21:52 -0400396const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500397{
Jamie Madill2d06b732015-04-20 12:53:28 -0400398 if (mDepthAttachment.isAttached())
399 {
400 return &mDepthAttachment;
401 }
402 if (mStencilAttachment.isAttached())
403 {
404 return &mStencilAttachment;
405 }
406 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500407}
408
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500409const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
410{
411 if (mStencilAttachment.isAttached())
412 {
413 return &mStencilAttachment;
414 }
415 return getDepthStencilAttachment();
416}
417
Jamie Madill48ef11b2016-04-27 15:21:52 -0400418const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400419{
420 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400421 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
422 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400423}
424
Jamie Madill48ef11b2016-04-27 15:21:52 -0400425const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400426{
Jamie Madill2d06b732015-04-20 12:53:28 -0400427 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400428}
429
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800430const FramebufferAttachment *FramebufferState::getWebGLDepthAttachment() const
431{
432 return mWebGLDepthAttachment.isAttached() ? &mWebGLDepthAttachment : nullptr;
433}
434
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800435const FramebufferAttachment *FramebufferState::getWebGLDepthStencilAttachment() const
436{
437 return mWebGLDepthStencilAttachment.isAttached() ? &mWebGLDepthStencilAttachment : nullptr;
438}
439
Jamie Madill48ef11b2016-04-27 15:21:52 -0400440const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400441{
Jamie Madill2d06b732015-04-20 12:53:28 -0400442 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400443}
444
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800445const FramebufferAttachment *FramebufferState::getWebGLStencilAttachment() const
446{
447 return mWebGLStencilAttachment.isAttached() ? &mWebGLStencilAttachment : nullptr;
448}
449
Jamie Madill48ef11b2016-04-27 15:21:52 -0400450const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400451{
452 // A valid depth-stencil attachment has the same resource bound to both the
453 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400454 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500455 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400456 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400457 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400458 }
459
460 return nullptr;
461}
462
Jamie Madill48ef11b2016-04-27 15:21:52 -0400463bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500464{
465 Optional<Extents> attachmentSize;
466
Jamie Madill231c7f52017-04-26 13:45:37 -0400467 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500468 if (!attachment.isAttached())
469 {
470 return false;
471 }
472
473 if (!attachmentSize.valid())
474 {
475 attachmentSize = attachment.getSize();
476 return false;
477 }
478
Jeff Gilbert8f8edd62017-10-31 14:26:30 -0700479 const auto &prevSize = attachmentSize.value();
480 const auto &curSize = attachment.getSize();
481 return (curSize.width != prevSize.width || curSize.height != prevSize.height);
Jamie Madillcc86d642015-11-24 13:00:07 -0500482 };
483
484 for (const auto &attachment : mColorAttachments)
485 {
486 if (hasMismatchedSize(attachment))
487 {
488 return false;
489 }
490 }
491
492 if (hasMismatchedSize(mDepthAttachment))
493 {
494 return false;
495 }
496
497 return !hasMismatchedSize(mStencilAttachment);
498}
499
Jamie Madilld4442552018-02-27 22:03:47 -0500500const FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400501{
502 ASSERT(drawBufferIdx < mDrawBufferStates.size());
503 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
504 {
505 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
506 // must be COLOR_ATTACHMENTi or NONE"
507 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
508 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800509
510 if (mDrawBufferStates[drawBufferIdx] == GL_BACK)
511 {
512 return getColorAttachment(0);
513 }
514 else
515 {
516 return getColorAttachment(mDrawBufferStates[drawBufferIdx] - GL_COLOR_ATTACHMENT0);
517 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400518 }
519 else
520 {
521 return nullptr;
522 }
523}
524
525size_t FramebufferState::getDrawBufferCount() const
526{
527 return mDrawBufferStates.size();
528}
529
Geoff Langb21e20d2016-07-19 15:35:41 -0400530bool FramebufferState::colorAttachmentsAreUniqueImages() const
531{
532 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
533 firstAttachmentIdx++)
534 {
Jamie Madilld4442552018-02-27 22:03:47 -0500535 const FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400536 if (!firstAttachment.isAttached())
537 {
538 continue;
539 }
540
541 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
542 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
543 {
Jamie Madilld4442552018-02-27 22:03:47 -0500544 const FramebufferAttachment &secondAttachment = mColorAttachments[secondAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400545 if (!secondAttachment.isAttached())
546 {
547 continue;
548 }
549
550 if (firstAttachment == secondAttachment)
551 {
552 return false;
553 }
554 }
555 }
556
557 return true;
558}
559
Jamie Madill9c335862017-07-18 11:51:38 -0400560bool FramebufferState::hasDepth() const
561{
562 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
563}
564
565bool FramebufferState::hasStencil() const
566{
567 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
568}
569
Martin Radev5c00d0d2017-08-07 10:06:59 +0300570GLsizei FramebufferState::getNumViews() const
571{
572 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
573 if (attachment == nullptr)
574 {
575 return FramebufferAttachment::kDefaultNumViews;
576 }
577 return attachment->getNumViews();
578}
579
580const std::vector<Offset> *FramebufferState::getViewportOffsets() const
581{
582 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
583 if (attachment == nullptr)
584 {
585 return nullptr;
586 }
587 return &attachment->getMultiviewViewportOffsets();
588}
589
590GLenum FramebufferState::getMultiviewLayout() const
591{
592 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
593 if (attachment == nullptr)
594 {
595 return GL_NONE;
596 }
597 return attachment->getMultiviewLayout();
598}
599
Martin Radev4e619f52017-08-09 11:50:06 +0300600int FramebufferState::getBaseViewIndex() const
601{
602 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
603 if (attachment == nullptr)
604 {
605 return GL_NONE;
606 }
607 return attachment->getBaseViewIndex();
608}
609
Jamie Madill05b35b22017-10-03 09:01:44 -0400610Box FramebufferState::getDimensions() const
611{
612 ASSERT(attachmentsHaveSameDimensions());
613 ASSERT(getFirstNonNullAttachment() != nullptr);
614 Extents extents = getFirstNonNullAttachment()->getSize();
615 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
616}
617
Jamie Madill7aea7e02016-05-10 10:39:45 -0400618Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill2274b652018-05-31 10:56:08 -0400619 : mState(caps, id),
Jamie Madill362876b2016-06-16 14:46:59 -0400620 mImpl(factory->createFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400621 mCachedStatus(),
622 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
623 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624{
Corentin Wallez37c39792015-08-20 14:19:46 -0400625 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400626 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
627
Jamie Madill1e5499d2017-04-05 11:22:16 -0400628 for (uint32_t colorIndex = 0;
629 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400630 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400631 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400632 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400633}
634
Geoff Langbf7b95d2018-05-01 16:48:21 -0400635Framebuffer::Framebuffer(const Context *context, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400636 : mState(),
Geoff Langbf7b95d2018-05-01 16:48:21 -0400637 mImpl(surface->getImplementation()->createDefaultFramebuffer(context, mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400638 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
639 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
640 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400641{
Geoff Langda88add2014-12-01 10:22:01 -0500642 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400643 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500644
Geoff Langbf7b95d2018-05-01 16:48:21 -0400645 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400646 FramebufferAttachment::kDefaultNumViews,
Martin Radev5dae57b2017-07-14 16:15:55 +0300647 FramebufferAttachment::kDefaultBaseViewIndex,
648 FramebufferAttachment::kDefaultMultiviewLayout,
649 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500650
651 if (surface->getConfig()->depthSize > 0)
652 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400653 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400654 FramebufferAttachment::kDefaultNumViews,
Jamie Madilld4442552018-02-27 22:03:47 -0500655 FramebufferAttachment::kDefaultBaseViewIndex,
656 FramebufferAttachment::kDefaultMultiviewLayout,
657 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500658 }
659
660 if (surface->getConfig()->stencilSize > 0)
661 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400662 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400663 FramebufferAttachment::kDefaultNumViews,
664 FramebufferAttachment::kDefaultBaseViewIndex,
665 FramebufferAttachment::kDefaultMultiviewLayout,
666 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500667 }
Brandon Jones76746f92017-11-22 11:44:41 -0800668 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000669}
670
Corentin Wallezccab69d2017-01-27 16:57:15 -0500671Framebuffer::Framebuffer(rx::GLImplFactory *factory)
672 : mState(),
673 mImpl(factory->createFramebuffer(mState)),
Corentin Wallezccab69d2017-01-27 16:57:15 -0500674 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
675 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
676 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
677{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400678 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Brandon Jones76746f92017-11-22 11:44:41 -0800679 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500680}
681
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000682Framebuffer::~Framebuffer()
683{
Geoff Langda88add2014-12-01 10:22:01 -0500684 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000685}
686
Jamie Madill4928b7c2017-06-20 12:57:39 -0400687void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500688{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400689 for (auto &attachment : mState.mColorAttachments)
690 {
691 attachment.detach(context);
692 }
693 mState.mDepthAttachment.detach(context);
694 mState.mStencilAttachment.detach(context);
695 mState.mWebGLDepthAttachment.detach(context);
696 mState.mWebGLStencilAttachment.detach(context);
697 mState.mWebGLDepthStencilAttachment.detach(context);
698
Jamie Madillc564c072017-06-01 12:45:42 -0400699 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500700}
701
Geoff Lang70d0f492015-12-10 17:45:46 -0500702void Framebuffer::setLabel(const std::string &label)
703{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400704 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500705}
706
707const std::string &Framebuffer::getLabel() const
708{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400709 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500710}
711
Jamie Madill8693bdb2017-09-02 15:32:14 -0400712bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000713{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400714 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000715}
716
Jamie Madill8693bdb2017-09-02 15:32:14 -0400717bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000718{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400719 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500720}
Jamie Madille261b442014-06-25 12:42:21 -0400721
Jamie Madill8693bdb2017-09-02 15:32:14 -0400722bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500723{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400724 bool found = false;
725
Jamie Madill362876b2016-06-16 14:46:59 -0400726 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500727 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400728 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
729 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
730 {
731 found = true;
732 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000733 }
734
Jamie Madilla02315b2017-02-23 14:14:47 -0500735 if (context->isWebGL1())
736 {
737 const std::array<FramebufferAttachment *, 3> attachments = {
738 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
739 &mState.mWebGLStencilAttachment}};
740 for (FramebufferAttachment *attachment : attachments)
741 {
742 if (attachment->isAttached() && attachment->type() == resourceType &&
743 attachment->id() == resourceId)
744 {
745 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400746 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500747 }
748 }
749 }
750 else
751 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400752 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
753 DIRTY_BIT_DEPTH_ATTACHMENT))
754 {
755 found = true;
756 }
757 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
758 DIRTY_BIT_STENCIL_ATTACHMENT))
759 {
760 found = true;
761 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500762 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400763
764 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400765}
766
Jamie Madill8693bdb2017-09-02 15:32:14 -0400767bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400768 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400769 GLenum matchType,
770 GLuint matchId,
771 size_t dirtyBit)
772{
773 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
774 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400775 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400776 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -0400777 mState.mResourceNeedsInit.set(dirtyBit, false);
Jamie Madill8693bdb2017-09-02 15:32:14 -0400778 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400779 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400780
781 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000782}
783
Corentin Wallez37c39792015-08-20 14:19:46 -0400784const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400786 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000787}
788
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400789const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400790{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400791 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400792}
793
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400794const FramebufferAttachment *Framebuffer::getStencilbuffer() const
795{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400796 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400797}
798
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400799const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
800{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400801 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400802}
803
804const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000805{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400806 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000807}
808
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500809const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
810{
811 return mState.getStencilOrDepthStencilAttachment();
812}
813
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400814const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000815{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400816 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000817}
818
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000819GLenum Framebuffer::getReadColorbufferType() const
820{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400821 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400822 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000823}
824
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400825const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000826{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400827 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000828}
829
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400830const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
831{
832 return mState.getFirstNonNullAttachment();
833}
834
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800835const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
836 GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000837{
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800838 return mState.getAttachment(context, attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400839}
840
Geoff Langa15472a2015-08-11 11:48:03 -0400841size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000842{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400843 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400844}
845
846GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
847{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400848 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
849 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000850}
851
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500852const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
853{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400854 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500855}
856
Geoff Lang164d54e2014-12-01 10:55:33 -0500857void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000858{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400859 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500860
861 ASSERT(count <= drawStates.size());
862 std::copy(buffers, buffers + count, drawStates.begin());
863 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500864 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500865
866 mState.mEnabledDrawBuffers.reset();
Brandon Jones76746f92017-11-22 11:44:41 -0800867 mState.mDrawBufferTypeMask.reset();
868
Jamie Madilla4595b82017-01-11 17:36:34 -0500869 for (size_t index = 0; index < count; ++index)
870 {
Brandon Jones76746f92017-11-22 11:44:41 -0800871 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
872
Jamie Madilla4595b82017-01-11 17:36:34 -0500873 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
874 {
875 mState.mEnabledDrawBuffers.set(index);
876 }
877 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500878}
879
Geoff Langa15472a2015-08-11 11:48:03 -0400880const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
881{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400882 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400883}
884
Geoff Lange0cff192017-05-30 13:04:56 -0400885GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
886{
887 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
888 if (attachment == nullptr)
889 {
890 return GL_NONE;
891 }
892
893 GLenum componentType = attachment->getFormat().info->componentType;
894 switch (componentType)
895 {
896 case GL_INT:
897 case GL_UNSIGNED_INT:
898 return componentType;
899
900 default:
901 return GL_FLOAT;
902 }
903}
904
Brandon Jonesc405ae72017-12-06 14:15:03 -0800905ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
Brandon Jones76746f92017-11-22 11:44:41 -0800906{
907 return mState.mDrawBufferTypeMask;
908}
909
910DrawBufferMask Framebuffer::getDrawBufferMask() const
911{
912 return mState.mEnabledDrawBuffers;
913}
914
Geoff Langa15472a2015-08-11 11:48:03 -0400915bool Framebuffer::hasEnabledDrawBuffer() const
916{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400917 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400918 {
919 if (getDrawBuffer(drawbufferIdx) != nullptr)
920 {
921 return true;
922 }
923 }
924
925 return false;
926}
927
Geoff Lang9dd95802014-12-01 11:12:59 -0500928GLenum Framebuffer::getReadBufferState() const
929{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400930 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500931}
932
933void Framebuffer::setReadBuffer(GLenum buffer)
934{
Jamie Madillb885e572015-02-03 16:16:04 -0500935 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
936 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400937 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
938 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500939 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000940}
941
Corentin Wallez37c39792015-08-20 14:19:46 -0400942size_t Framebuffer::getNumColorBuffers() const
943{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400944 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400945}
946
Jamie Madill0df8fe42015-11-24 16:10:24 -0500947bool Framebuffer::hasDepth() const
948{
Jamie Madill9c335862017-07-18 11:51:38 -0400949 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500950}
951
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000952bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000953{
Jamie Madill9c335862017-07-18 11:51:38 -0400954 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000955}
956
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000957bool Framebuffer::usingExtendedDrawBuffers() const
958{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400959 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000960 {
Geoff Langa15472a2015-08-11 11:48:03 -0400961 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000962 {
963 return true;
964 }
965 }
966
967 return false;
968}
969
Geoff Lang9aded172017-04-05 11:07:56 -0400970void Framebuffer::invalidateCompletenessCache()
971{
Jamie Madill2274b652018-05-31 10:56:08 -0400972 if (mState.mId != 0)
Geoff Lang9aded172017-04-05 11:07:56 -0400973 {
974 mCachedStatus.reset();
975 }
976}
977
Jamie Madill427064d2018-04-13 16:20:34 -0400978GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000979{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500980 // The default framebuffer is always complete except when it is surfaceless in which
981 // case it is always unsupported. We return early because the default framebuffer may
982 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Jamie Madill2274b652018-05-31 10:56:08 -0400983 if (mState.mId == 0)
Geoff Lang528ce3c2014-12-01 10:44:07 -0500984 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500985 ASSERT(mCachedStatus.valid());
986 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
987 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
Jamie Madill427064d2018-04-13 16:20:34 -0400988 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500989 }
990
Jamie Madill362876b2016-06-16 14:46:59 -0400991 if (hasAnyDirtyBit() || !mCachedStatus.valid())
992 {
Jamie Madille98b1b52018-03-08 09:47:23 -0500993 mCachedStatus = checkStatusWithGLFrontEnd(context);
994
995 if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
996 {
Jamie Madill427064d2018-04-13 16:20:34 -0400997 Error err = syncState(context);
998 if (err.isError())
999 {
1000 context->handleError(err);
1001 return GetDefaultReturnValue<EntryPoint::CheckFramebufferStatus, GLenum>();
1002 }
Jamie Madille98b1b52018-03-08 09:47:23 -05001003 if (!mImpl->checkStatus(context))
1004 {
1005 mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
1006 }
1007 }
Jamie Madill362876b2016-06-16 14:46:59 -04001008 }
1009
Jamie Madill427064d2018-04-13 16:20:34 -04001010 return mCachedStatus.value();
Jamie Madill362876b2016-06-16 14:46:59 -04001011}
1012
Jamie Madille98b1b52018-03-08 09:47:23 -05001013GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -04001014{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001015 const ContextState &state = context->getContextState();
1016
Jamie Madill2274b652018-05-31 10:56:08 -04001017 ASSERT(mState.mId != 0);
Jamie Madill362876b2016-06-16 14:46:59 -04001018
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001019 bool hasAttachments = false;
1020 Optional<unsigned int> colorbufferSize;
1021 Optional<int> samples;
Geoff Lang92019432017-11-20 13:09:34 -05001022 Optional<bool> fixedSampleLocations;
JiangYizhou461d9a32017-01-04 16:37:26 +08001023 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001024
Martin Radev9bc9a322017-07-21 14:28:17 +03001025 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
1026
Jamie Madill48ef11b2016-04-27 15:21:52 -04001027 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001028 {
Jamie Madill2d06b732015-04-20 12:53:28 -04001029 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001030 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001031 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001032 {
1033 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1034 }
daniel@transgaming.com01868132010-08-24 19:21:17 +00001035
Geoff Lang677bb6f2017-04-05 12:40:40 -04001036 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001037 if (format.depthBits > 0 || format.stencilBits > 0)
1038 {
1039 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1040 }
1041
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001042 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
1043 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001044 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001045 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001046 }
1047
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001048 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
1049 // in GLES 3.0, there is no such restriction
1050 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001051 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001052 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001053 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001054 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +00001055 {
1056 return GL_FRAMEBUFFER_UNSUPPORTED;
1057 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001058 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001059 else
1060 {
1061 colorbufferSize = format.pixelBytes;
1062 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001063 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001064
Martin Radev9bc9a322017-07-21 14:28:17 +03001065 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
1066 {
1067 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1068 }
1069
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001070 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1071 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001072 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001073 }
1074
Jamie Madill48ef11b2016-04-27 15:21:52 -04001075 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001076 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001077 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001078 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001080 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001081 }
1082
Geoff Lang677bb6f2017-04-05 12:40:40 -04001083 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001084 if (format.depthBits == 0)
1085 {
1086 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001087 }
1088
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001089 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1090 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001091 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001092 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001093 }
Sami Väisänena797e062016-05-12 15:23:40 +03001094
Martin Radev9bc9a322017-07-21 14:28:17 +03001095 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1096 {
1097 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1098 }
1099
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001100 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1101 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001102 }
1103
Jamie Madill48ef11b2016-04-27 15:21:52 -04001104 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001105 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001106 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001107 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001108 {
1109 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1110 }
1111
Geoff Lang677bb6f2017-04-05 12:40:40 -04001112 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001113 if (format.stencilBits == 0)
1114 {
1115 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001116 }
1117
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001118 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1119 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001120 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001121 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001122 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001123
Martin Radev9bc9a322017-07-21 14:28:17 +03001124 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1125 {
1126 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1127 }
1128
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001129 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1130 hasAttachments = true;
1131 }
1132
1133 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1134 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1135 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1136 {
1137 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001138 }
1139
Jamie Madilla02315b2017-02-23 14:14:47 -05001140 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1141 if (state.isWebGL1())
1142 {
1143 if (!mState.mWebGLDepthStencilConsistent)
1144 {
1145 return GL_FRAMEBUFFER_UNSUPPORTED;
1146 }
1147
1148 if (mState.mWebGLDepthStencilAttachment.isAttached())
1149 {
1150 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1151 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1152 {
1153 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1154 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001155
1156 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1157 &mState.mWebGLDepthStencilAttachment))
1158 {
1159 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1160 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001161 }
1162 else if (mState.mStencilAttachment.isAttached() &&
1163 mState.mStencilAttachment.getDepthSize() > 0)
1164 {
1165 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1166 }
1167 else if (mState.mDepthAttachment.isAttached() &&
1168 mState.mDepthAttachment.getStencilSize() > 0)
1169 {
1170 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1171 }
1172 }
1173
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001174 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1175 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1176 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001177 GLint defaultWidth = mState.getDefaultWidth();
1178 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001179 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001180 {
1181 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001182 }
1183
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001184 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001185 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001186 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1187 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001188 {
1189 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1190 }
1191
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001192 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1193 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001194 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1195 {
1196 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1197 }
1198
Kenneth Russellce8602a2017-10-03 18:23:08 -07001199 // The WebGL conformance tests implicitly define that all framebuffer
1200 // attachments must be unique. For example, the same level of a texture can
1201 // not be attached to two different color attachments.
1202 if (state.getExtensions().webglCompatibility)
1203 {
1204 if (!mState.colorAttachmentsAreUniqueImages())
1205 {
1206 return GL_FRAMEBUFFER_UNSUPPORTED;
1207 }
1208 }
1209
Jamie Madillcc86d642015-11-24 13:00:07 -05001210 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001212
Jamie Madill4928b7c2017-06-20 12:57:39 -04001213Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001214{
Jamie Madill05b35b22017-10-03 09:01:44 -04001215 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1216 // can be no-ops, so we should probably do that to ensure consistency.
1217 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1218
Jamie Madill4928b7c2017-06-20 12:57:39 -04001219 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001220}
1221
Jamie Madill4928b7c2017-06-20 12:57:39 -04001222Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001223{
Jamie Madill05b35b22017-10-03 09:01:44 -04001224 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1225 // can be no-ops, so we should probably do that to ensure consistency.
1226 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1227
Jamie Madill4928b7c2017-06-20 12:57:39 -04001228 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001229}
1230
Jamie Madill05b35b22017-10-03 09:01:44 -04001231bool Framebuffer::partialClearNeedsInit(const Context *context,
1232 bool color,
1233 bool depth,
1234 bool stencil)
1235{
1236 const auto &glState = context->getGLState();
1237
1238 if (!glState.isRobustResourceInitEnabled())
1239 {
1240 return false;
1241 }
1242
1243 // Scissors can affect clearing.
1244 // TODO(jmadill): Check for complete scissor overlap.
1245 if (glState.isScissorTestEnabled())
1246 {
1247 return true;
1248 }
1249
1250 // If colors masked, we must clear before we clear. Do a simple check.
1251 // TODO(jmadill): Filter out unused color channels from the test.
1252 if (color)
1253 {
1254 const auto &blend = glState.getBlendState();
1255 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1256 blend.colorMaskAlpha))
1257 {
1258 return true;
1259 }
1260 }
1261
1262 const auto &depthStencil = glState.getDepthStencilState();
1263 ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
1264 if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
1265 {
1266 return true;
1267 }
1268
1269 return false;
1270}
1271
Jamie Madill4928b7c2017-06-20 12:57:39 -04001272Error Framebuffer::invalidateSub(const Context *context,
1273 size_t count,
1274 const GLenum *attachments,
Jamie Madilld4442552018-02-27 22:03:47 -05001275 const Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001276{
Jamie Madill05b35b22017-10-03 09:01:44 -04001277 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1278 // can be no-ops, so we should probably do that to ensure consistency.
1279 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1280
Jamie Madill4928b7c2017-06-20 12:57:39 -04001281 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001282}
1283
Jamie Madilld4442552018-02-27 22:03:47 -05001284Error Framebuffer::clear(const Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001285{
Jamie Madill05b35b22017-10-03 09:01:44 -04001286 const auto &glState = context->getGLState();
1287 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001288 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001289 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001290 }
1291
Jamie Madill05b35b22017-10-03 09:01:44 -04001292 ANGLE_TRY(mImpl->clear(context, mask));
1293
Jamie Madill05b35b22017-10-03 09:01:44 -04001294 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001295}
1296
Jamie Madilld4442552018-02-27 22:03:47 -05001297Error Framebuffer::clearBufferfv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001298 GLenum buffer,
1299 GLint drawbuffer,
1300 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001301{
Jamie Madill05b35b22017-10-03 09:01:44 -04001302 if (context->getGLState().isRasterizerDiscardEnabled() ||
1303 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001304 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001305 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001306 }
1307
Jamie Madill05b35b22017-10-03 09:01:44 -04001308 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1309
Jamie Madill05b35b22017-10-03 09:01:44 -04001310 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001311}
1312
Jamie Madilld4442552018-02-27 22:03:47 -05001313Error Framebuffer::clearBufferuiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001314 GLenum buffer,
1315 GLint drawbuffer,
1316 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001317{
Jamie Madill05b35b22017-10-03 09:01:44 -04001318 if (context->getGLState().isRasterizerDiscardEnabled() ||
1319 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001320 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001321 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001322 }
1323
Jamie Madill05b35b22017-10-03 09:01:44 -04001324 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1325
Jamie Madill05b35b22017-10-03 09:01:44 -04001326 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001327}
1328
Jamie Madilld4442552018-02-27 22:03:47 -05001329Error Framebuffer::clearBufferiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001330 GLenum buffer,
1331 GLint drawbuffer,
1332 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001333{
Jamie Madill05b35b22017-10-03 09:01:44 -04001334 if (context->getGLState().isRasterizerDiscardEnabled() ||
1335 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001336 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001337 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001338 }
1339
Jamie Madill05b35b22017-10-03 09:01:44 -04001340 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1341
Jamie Madill05b35b22017-10-03 09:01:44 -04001342 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001343}
1344
Jamie Madilld4442552018-02-27 22:03:47 -05001345Error Framebuffer::clearBufferfi(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001346 GLenum buffer,
1347 GLint drawbuffer,
1348 GLfloat depth,
1349 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001350{
Jamie Madill05b35b22017-10-03 09:01:44 -04001351 if (context->getGLState().isRasterizerDiscardEnabled() ||
1352 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001353 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001354 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001355 }
1356
Jamie Madill05b35b22017-10-03 09:01:44 -04001357 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1358
Jamie Madill05b35b22017-10-03 09:01:44 -04001359 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001360}
1361
Jamie Madill690c8eb2018-03-12 15:20:03 -04001362Error Framebuffer::getImplementationColorReadFormat(const Context *context, GLenum *formatOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001363{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001364 ANGLE_TRY(syncState(context));
1365 *formatOut = mImpl->getImplementationColorReadFormat(context);
1366 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001367}
1368
Jamie Madill690c8eb2018-03-12 15:20:03 -04001369Error Framebuffer::getImplementationColorReadType(const Context *context, GLenum *typeOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001370{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001371 ANGLE_TRY(syncState(context));
1372 *typeOut = mImpl->getImplementationColorReadType(context);
1373 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001374}
1375
Jamie Madilld4442552018-02-27 22:03:47 -05001376Error Framebuffer::readPixels(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001377 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001378 GLenum format,
1379 GLenum type,
Jamie Madill05b35b22017-10-03 09:01:44 -04001380 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001381{
Jamie Madill05b35b22017-10-03 09:01:44 -04001382 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001383 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001384
Jamie Madilld4442552018-02-27 22:03:47 -05001385 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001386 if (unpackBuffer)
1387 {
Jamie Madill09463932018-04-04 05:26:59 -04001388 unpackBuffer->onPixelPack(context);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001389 }
1390
Jamie Madill362876b2016-06-16 14:46:59 -04001391 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001392}
1393
Jamie Madilld4442552018-02-27 22:03:47 -05001394Error Framebuffer::blit(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001395 const Rectangle &sourceArea,
1396 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001397 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001398 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001399{
He Yunchao6be602d2016-12-22 14:33:07 +08001400 GLbitfield blitMask = mask;
1401
1402 // Note that blitting is called against draw framebuffer.
1403 // See the code in gl::Context::blitFramebuffer.
1404 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1405 {
1406 blitMask &= ~GL_COLOR_BUFFER_BIT;
1407 }
1408
1409 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1410 {
1411 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1412 }
1413
1414 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1415 {
1416 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1417 }
1418
1419 if (!blitMask)
1420 {
1421 return NoError();
1422 }
1423
Jamie Madill05b35b22017-10-03 09:01:44 -04001424 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1425 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1426
1427 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1428 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1429
He Yunchao6be602d2016-12-22 14:33:07 +08001430 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001431}
1432
Jamie Madill427064d2018-04-13 16:20:34 -04001433int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001434{
Jamie Madill427064d2018-04-13 16:20:34 -04001435 return (isComplete(context) ? getCachedSamples(context) : 0);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001436}
1437
Jamie Madill9c335862017-07-18 11:51:38 -04001438int Framebuffer::getCachedSamples(const Context *context)
1439{
Jamie Madill5b772312018-03-08 20:28:32 -05001440 ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
1441
Jamie Madill9c335862017-07-18 11:51:38 -04001442 // For a complete framebuffer, all attachments must have the same sample count.
1443 // In this case return the first nonzero sample size.
1444 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1445 if (firstNonNullAttachment)
1446 {
1447 ASSERT(firstNonNullAttachment->isAttached());
1448 return firstNonNullAttachment->getSamples();
1449 }
1450
1451 // No attachments found.
1452 return 0;
1453}
1454
Geoff Lang13455072018-05-09 11:24:43 -04001455Error Framebuffer::getSamplePosition(const Context *context, size_t index, GLfloat *xy) const
Corentin Wallezccab69d2017-01-27 16:57:15 -05001456{
Geoff Lang13455072018-05-09 11:24:43 -04001457 ANGLE_TRY(mImpl->getSamplePosition(context, index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001458 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001459}
1460
Jamie Madille261b442014-06-25 12:42:21 -04001461bool Framebuffer::hasValidDepthStencil() const
1462{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001463 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001464}
1465
Jamie Madilla02315b2017-02-23 14:14:47 -05001466void Framebuffer::setAttachment(const Context *context,
1467 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001468 GLenum binding,
1469 const ImageIndex &textureIndex,
1470 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001471{
Martin Radev5dae57b2017-07-14 16:15:55 +03001472 setAttachment(context, type, binding, textureIndex, resource,
1473 FramebufferAttachment::kDefaultNumViews,
1474 FramebufferAttachment::kDefaultBaseViewIndex,
1475 FramebufferAttachment::kDefaultMultiviewLayout,
1476 FramebufferAttachment::kDefaultViewportOffsets);
1477}
1478
1479void Framebuffer::setAttachment(const Context *context,
1480 GLenum type,
1481 GLenum binding,
1482 const ImageIndex &textureIndex,
1483 FramebufferAttachmentObject *resource,
1484 GLsizei numViews,
1485 GLuint baseViewIndex,
1486 GLenum multiviewLayout,
1487 const GLint *viewportOffsets)
1488{
Jamie Madilla02315b2017-02-23 14:14:47 -05001489 // Context may be null in unit tests.
1490 if (!context || !context->isWebGL1())
1491 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001492 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1493 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001494 return;
1495 }
1496
1497 switch (binding)
1498 {
1499 case GL_DEPTH_STENCIL:
1500 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001501 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001502 resource, numViews, baseViewIndex,
1503 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001504 break;
1505 case GL_DEPTH:
1506 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001507 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1508 numViews, baseViewIndex, multiviewLayout,
1509 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001510 break;
1511 case GL_STENCIL:
1512 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001513 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1514 numViews, baseViewIndex, multiviewLayout,
1515 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001516 break;
1517 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001518 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1519 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001520 return;
1521 }
1522
Martin Radev5dae57b2017-07-14 16:15:55 +03001523 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1524 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001525}
1526
Martin Radev82ef7742017-08-08 17:44:58 +03001527void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1528 GLenum type,
1529 GLenum binding,
1530 const ImageIndex &textureIndex,
1531 FramebufferAttachmentObject *resource,
1532 GLsizei numViews,
1533 GLint baseViewIndex)
1534{
1535 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1536 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1537 FramebufferAttachment::kDefaultViewportOffsets);
1538}
1539
Martin Radev5dae57b2017-07-14 16:15:55 +03001540void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1541 GLenum type,
1542 GLenum binding,
1543 const ImageIndex &textureIndex,
1544 FramebufferAttachmentObject *resource,
1545 GLsizei numViews,
1546 const GLint *viewportOffsets)
1547{
1548 setAttachment(context, type, binding, textureIndex, resource, numViews,
1549 FramebufferAttachment::kDefaultBaseViewIndex,
1550 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1551}
1552
1553void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1554 GLsizei numViews,
1555 GLuint baseViewIndex,
1556 GLenum multiviewLayout,
1557 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001558{
1559 int count = 0;
1560
1561 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1562 &mState.mWebGLDepthAttachment,
1563 &mState.mWebGLStencilAttachment}};
1564 for (FramebufferAttachment *attachment : attachments)
1565 {
1566 if (attachment->isAttached())
1567 {
1568 count++;
1569 }
1570 }
1571
1572 mState.mWebGLDepthStencilConsistent = (count <= 1);
1573 if (!mState.mWebGLDepthStencilConsistent)
1574 {
1575 // Inconsistent.
1576 return;
1577 }
1578
Geoff Lange466c552017-03-17 15:24:12 -04001579 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1580 if (attachment.type() == GL_TEXTURE)
1581 {
1582 return attachment.getTextureImageIndex();
1583 }
1584 else
1585 {
Jamie Madillcc129372018-04-12 09:13:18 -04001586 return ImageIndex();
Geoff Lange466c552017-03-17 15:24:12 -04001587 }
1588 };
1589
Jamie Madilla02315b2017-02-23 14:14:47 -05001590 if (mState.mWebGLDepthAttachment.isAttached())
1591 {
1592 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001593 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001594 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1595 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madillcc129372018-04-12 09:13:18 -04001596 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1597 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001598 }
1599 else if (mState.mWebGLStencilAttachment.isAttached())
1600 {
1601 const auto &stencil = mState.mWebGLStencilAttachment;
Jamie Madillcc129372018-04-12 09:13:18 -04001602 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1603 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001604 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001605 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1606 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001607 }
1608 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1609 {
1610 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001611 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001612 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001613 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1614 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001615 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001616 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001617 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1618 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001619 }
1620 else
1621 {
Jamie Madillcc129372018-04-12 09:13:18 -04001622 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1623 baseViewIndex, multiviewLayout, viewportOffsets);
1624 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1625 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001626 }
1627}
1628
Jamie Madill4928b7c2017-06-20 12:57:39 -04001629void Framebuffer::setAttachmentImpl(const Context *context,
1630 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001631 GLenum binding,
1632 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001633 FramebufferAttachmentObject *resource,
1634 GLsizei numViews,
1635 GLuint baseViewIndex,
1636 GLenum multiviewLayout,
1637 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001638{
Jamie Madilla02315b2017-02-23 14:14:47 -05001639 switch (binding)
1640 {
Jamie Madillb8126692017-04-05 11:22:17 -04001641 case GL_DEPTH_STENCIL:
1642 case GL_DEPTH_STENCIL_ATTACHMENT:
1643 {
1644 // ensure this is a legitimate depth+stencil format
1645 FramebufferAttachmentObject *attachmentObj = resource;
1646 if (resource)
1647 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001648 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001649 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1650 {
1651 // Attaching nullptr detaches the current attachment.
1652 attachmentObj = nullptr;
1653 }
1654 }
1655
Jamie Madill4928b7c2017-06-20 12:57:39 -04001656 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001657 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001658 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1659 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001660 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001661 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001662 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1663 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001664 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001665 }
1666
Jamie Madilla02315b2017-02-23 14:14:47 -05001667 case GL_DEPTH:
1668 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001669 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001670 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1671 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001672 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001673
Jamie Madilla02315b2017-02-23 14:14:47 -05001674 case GL_STENCIL:
1675 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001676 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001677 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1678 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001679 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001680
Jamie Madilla02315b2017-02-23 14:14:47 -05001681 case GL_BACK:
Geoff Lang8170eab2017-09-21 13:59:04 -04001682 updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1683 &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1684 resource, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001685 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001686
Jamie Madilla02315b2017-02-23 14:14:47 -05001687 default:
1688 {
1689 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1690 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001691 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001692 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001693 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001694 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1695 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001696
Corentin Walleze7557742017-06-01 13:09:57 -04001697 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1698 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001699 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1700 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Brandon Jones76746f92017-11-22 11:44:41 -08001701 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -04001702 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001703 break;
Geoff Langab75a052014-10-15 12:56:37 -04001704 }
Jamie Madill42975642017-10-12 12:31:51 -04001705
1706 mAttachedTextures.reset();
Geoff Langab75a052014-10-15 12:56:37 -04001707}
1708
Jamie Madill4928b7c2017-06-20 12:57:39 -04001709void Framebuffer::updateAttachment(const Context *context,
1710 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001711 size_t dirtyBit,
Jamie Madilld4442552018-02-27 22:03:47 -05001712 angle::ObserverBinding *onDirtyBinding,
Jamie Madillb8126692017-04-05 11:22:17 -04001713 GLenum type,
1714 GLenum binding,
1715 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001716 FramebufferAttachmentObject *resource,
1717 GLsizei numViews,
1718 GLuint baseViewIndex,
1719 GLenum multiviewLayout,
1720 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001721{
Martin Radev5dae57b2017-07-14 16:15:55 +03001722 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1723 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001724 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001725 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madill888081d2018-02-27 00:24:46 -05001726 onDirtyBinding->bind(resource ? resource->getSubject() : nullptr);
Jamie Madille98b1b52018-03-08 09:47:23 -05001727
1728 invalidateCompletenessCache();
Jamie Madillb8126692017-04-05 11:22:17 -04001729}
1730
Jamie Madilla02315b2017-02-23 14:14:47 -05001731void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001732{
Jamie Madillcc129372018-04-12 09:13:18 -04001733 setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001734}
1735
Jamie Madill19fa1c62018-03-08 09:47:21 -05001736Error Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001737{
1738 if (mDirtyBits.any())
1739 {
Jamie Madill888081d2018-02-27 00:24:46 -05001740 mDirtyBitsGuard = mDirtyBits;
Jamie Madill19fa1c62018-03-08 09:47:21 -05001741 ANGLE_TRY(mImpl->syncState(context, mDirtyBits));
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001742 mDirtyBits.reset();
Jamie Madill888081d2018-02-27 00:24:46 -05001743 mDirtyBitsGuard.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001744 }
Jamie Madill19fa1c62018-03-08 09:47:21 -05001745 return NoError();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001746}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001747
Jamie Madilld4442552018-02-27 22:03:47 -05001748void Framebuffer::onSubjectStateChange(const Context *context,
1749 angle::SubjectIndex index,
1750 angle::SubjectMessage message)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001751{
Jamie Madill888081d2018-02-27 00:24:46 -05001752 if (message == angle::SubjectMessage::DEPENDENT_DIRTY_BITS)
1753 {
1754 ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
1755 mDirtyBits.set(index);
1756 context->getGLState().setFramebufferDirty(this);
1757 return;
1758 }
1759
Geoff Lang8170eab2017-09-21 13:59:04 -04001760 // Only reset the cached status if this is not the default framebuffer. The default framebuffer
1761 // will still use this channel to mark itself dirty.
Jamie Madill2274b652018-05-31 10:56:08 -04001762 if (mState.mId != 0)
Geoff Lang8170eab2017-09-21 13:59:04 -04001763 {
1764 // TOOD(jmadill): Make this only update individual attachments to do less work.
1765 mCachedStatus.reset();
1766 }
Jamie Madill05b35b22017-10-03 09:01:44 -04001767
Jamie Madilld4442552018-02-27 22:03:47 -05001768 FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
1769
Jamie Madill05b35b22017-10-03 09:01:44 -04001770 // Mark the appropriate init flag.
Jamie Madilld4442552018-02-27 22:03:47 -05001771 mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
1772}
1773
1774FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
1775{
1776 switch (index)
1777 {
1778 case DIRTY_BIT_DEPTH_ATTACHMENT:
1779 return &mState.mDepthAttachment;
1780 case DIRTY_BIT_STENCIL_ATTACHMENT:
1781 return &mState.mStencilAttachment;
1782 default:
1783 size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
1784 ASSERT(colorIndex < mState.mColorAttachments.size());
1785 return &mState.mColorAttachments[colorIndex];
1786 }
Jamie Madill51f40ec2016-06-15 14:06:00 -04001787}
1788
Jamie Madill427064d2018-04-13 16:20:34 -04001789bool Framebuffer::isComplete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001790{
Jamie Madill427064d2018-04-13 16:20:34 -04001791 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001792}
1793
Jamie Madilla4595b82017-01-11 17:36:34 -05001794bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1795{
1796 const Program *program = state.getProgram();
1797
1798 // TODO(jmadill): Default framebuffer feedback loops.
Jamie Madill2274b652018-05-31 10:56:08 -04001799 if (mState.mId == 0)
Jamie Madilla4595b82017-01-11 17:36:34 -05001800 {
1801 return false;
1802 }
1803
1804 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001805 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001806 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001807 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1808 ASSERT(attachment.isAttached());
1809 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001810 {
1811 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001812 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001813 {
1814 return true;
1815 }
1816 }
1817 }
1818
Jamie Madill1d37bc52017-02-02 19:59:58 -05001819 // Validate depth-stencil feedback loop.
1820 const auto &dsState = state.getDepthStencilState();
1821
1822 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1823 const FramebufferAttachment *depth = getDepthbuffer();
1824 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1825 {
1826 if (program->samplesFromTexture(state, depth->id()))
1827 {
1828 return true;
1829 }
1830 }
1831
Jamie Madill1d37bc52017-02-02 19:59:58 -05001832 const FramebufferAttachment *stencil = getStencilbuffer();
Ken Russellb9f92502018-01-27 19:00:26 -08001833 if (dsState.stencilTest && stencil)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001834 {
Ken Russellb9f92502018-01-27 19:00:26 -08001835 GLuint stencilSize = stencil->getStencilSize();
1836 ASSERT(stencilSize <= 8);
1837 GLuint maxStencilValue = (1 << stencilSize) - 1;
1838 // We assume the front and back masks are the same for WebGL.
1839 ASSERT((dsState.stencilBackWritemask & maxStencilValue) ==
1840 (dsState.stencilWritemask & maxStencilValue));
1841 if (stencil->type() == GL_TEXTURE && dsState.stencilWritemask != 0)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001842 {
Ken Russellb9f92502018-01-27 19:00:26 -08001843 // Skip the feedback loop check if depth/stencil point to the same resource.
1844 if (!depth || *stencil != *depth)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001845 {
Ken Russellb9f92502018-01-27 19:00:26 -08001846 if (program->samplesFromTexture(state, stencil->id()))
1847 {
1848 return true;
1849 }
Jamie Madill1d37bc52017-02-02 19:59:58 -05001850 }
1851 }
1852 }
1853
Jamie Madilla4595b82017-01-11 17:36:34 -05001854 return false;
1855}
1856
Jamie Madillfd3dd432017-02-02 19:59:59 -05001857bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1858 GLint copyTextureLevel,
1859 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001860{
Jamie Madill2274b652018-05-31 10:56:08 -04001861 if (mState.mId == 0)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001862 {
1863 // It seems impossible to form a texture copying feedback loop with the default FBO.
1864 return false;
1865 }
1866
1867 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1868 ASSERT(readAttachment);
1869
1870 if (readAttachment->isTextureWithId(copyTextureID))
1871 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001872 const auto &imageIndex = readAttachment->getTextureImageIndex();
Jamie Madillcc129372018-04-12 09:13:18 -04001873 if (imageIndex.getLevelIndex() == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001874 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001875 // Check 3D/Array texture layers.
Jamie Madillcc129372018-04-12 09:13:18 -04001876 return !imageIndex.hasLayer() || copyTextureLayer == ImageIndex::kEntireLevel ||
1877 imageIndex.getLayerIndex() == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001878 }
1879 }
1880 return false;
1881}
1882
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001883GLint Framebuffer::getDefaultWidth() const
1884{
1885 return mState.getDefaultWidth();
1886}
1887
1888GLint Framebuffer::getDefaultHeight() const
1889{
1890 return mState.getDefaultHeight();
1891}
1892
1893GLint Framebuffer::getDefaultSamples() const
1894{
1895 return mState.getDefaultSamples();
1896}
1897
Geoff Lang92019432017-11-20 13:09:34 -05001898bool Framebuffer::getDefaultFixedSampleLocations() const
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001899{
1900 return mState.getDefaultFixedSampleLocations();
1901}
1902
Jiawei Shaob1e91382018-05-17 14:33:55 +08001903GLint Framebuffer::getDefaultLayers() const
1904{
1905 return mState.getDefaultLayers();
1906}
1907
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001908void Framebuffer::setDefaultWidth(GLint defaultWidth)
1909{
1910 mState.mDefaultWidth = defaultWidth;
1911 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
Jamie Madille98b1b52018-03-08 09:47:23 -05001912 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001913}
1914
1915void Framebuffer::setDefaultHeight(GLint defaultHeight)
1916{
1917 mState.mDefaultHeight = defaultHeight;
1918 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
Jamie Madille98b1b52018-03-08 09:47:23 -05001919 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001920}
1921
1922void Framebuffer::setDefaultSamples(GLint defaultSamples)
1923{
1924 mState.mDefaultSamples = defaultSamples;
1925 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
Jamie Madille98b1b52018-03-08 09:47:23 -05001926 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001927}
1928
Geoff Lang92019432017-11-20 13:09:34 -05001929void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001930{
1931 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1932 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
Jamie Madille98b1b52018-03-08 09:47:23 -05001933 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001934}
1935
Jiawei Shaob1e91382018-05-17 14:33:55 +08001936void Framebuffer::setDefaultLayers(GLint defaultLayers)
1937{
1938 mState.mDefaultLayers = defaultLayers;
1939 mDirtyBits.set(DIRTY_BIT_DEFAULT_LAYERS);
1940}
1941
Martin Radev14a26ae2017-07-24 15:56:29 +03001942GLsizei Framebuffer::getNumViews() const
1943{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001944 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03001945}
1946
Martin Radev4e619f52017-08-09 11:50:06 +03001947GLint Framebuffer::getBaseViewIndex() const
1948{
1949 return mState.getBaseViewIndex();
1950}
1951
Martin Radev878c8b12017-07-28 09:51:04 +03001952const std::vector<Offset> *Framebuffer::getViewportOffsets() const
1953{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001954 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03001955}
1956
1957GLenum Framebuffer::getMultiviewLayout() const
1958{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001959 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03001960}
1961
Geoff Langd4fff502017-09-22 11:28:28 -04001962Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask)
1963{
1964 const auto &glState = context->getGLState();
1965 if (!context->isRobustResourceInitEnabled() || glState.isRasterizerDiscardEnabled())
1966 {
1967 return NoError();
1968 }
1969
Geoff Langa36483f2018-03-09 16:11:21 -05001970 const BlendState &blend = glState.getBlendState();
1971 const DepthStencilState &depthStencil = glState.getDepthStencilState();
Geoff Langd4fff502017-09-22 11:28:28 -04001972
1973 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
1974 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
1975 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
1976
1977 if (!color && !depth && !stencil)
1978 {
1979 return NoError();
1980 }
1981
1982 if (partialClearNeedsInit(context, color, depth, stencil))
1983 {
1984 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1985 }
1986
1987 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
1988 // still be marked initialized. This simplifies design, allowing this method to be called before
1989 // the clear.
1990 markDrawAttachmentsInitialized(color, depth, stencil);
1991
1992 return NoError();
1993}
1994
1995Error Framebuffer::ensureClearBufferAttachmentsInitialized(const Context *context,
1996 GLenum buffer,
1997 GLint drawbuffer)
1998{
1999 if (!context->isRobustResourceInitEnabled() ||
2000 context->getGLState().isRasterizerDiscardEnabled() ||
2001 IsClearBufferMaskedOut(context, buffer))
2002 {
2003 return NoError();
2004 }
2005
2006 if (partialBufferClearNeedsInit(context, buffer))
2007 {
2008 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
2009 }
2010
2011 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2012 // still be marked initialized. This simplifies design, allowing this method to be called before
2013 // the clear.
2014 markBufferInitialized(buffer, drawbuffer);
2015
2016 return NoError();
2017}
2018
Jamie Madill05b35b22017-10-03 09:01:44 -04002019Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
2020{
2021 if (!context->isRobustResourceInitEnabled())
2022 {
2023 return NoError();
2024 }
2025
2026 // Note: we don't actually filter by the draw attachment enum. Just init everything.
2027 for (size_t bit : mState.mResourceNeedsInit)
2028 {
2029 switch (bit)
2030 {
2031 case DIRTY_BIT_DEPTH_ATTACHMENT:
2032 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2033 break;
2034 case DIRTY_BIT_STENCIL_ATTACHMENT:
2035 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2036 break;
2037 default:
2038 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2039 break;
2040 }
2041 }
2042
2043 mState.mResourceNeedsInit.reset();
2044 return NoError();
2045}
2046
2047Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
2048{
2049 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2050 {
2051 return NoError();
2052 }
2053
2054 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
2055 {
2056 size_t readIndex = mState.getReadIndex();
2057 if (mState.mResourceNeedsInit[readIndex])
2058 {
2059 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2060 mState.mResourceNeedsInit.reset(readIndex);
2061 }
2062 }
2063
2064 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
2065 {
2066 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2067 {
2068 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2069 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2070 }
2071 }
2072
2073 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
2074 {
2075 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2076 {
2077 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2078 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2079 }
2080 }
2081
2082 return NoError();
2083}
2084
2085void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2086{
2087 // Mark attachments as initialized.
2088 if (color)
2089 {
2090 for (auto colorIndex : mState.mEnabledDrawBuffers)
2091 {
2092 auto &colorAttachment = mState.mColorAttachments[colorIndex];
2093 ASSERT(colorAttachment.isAttached());
2094 colorAttachment.setInitState(InitState::Initialized);
2095 mState.mResourceNeedsInit.reset(colorIndex);
2096 }
2097 }
2098
2099 if (depth && mState.mDepthAttachment.isAttached())
2100 {
2101 mState.mDepthAttachment.setInitState(InitState::Initialized);
2102 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2103 }
2104
2105 if (stencil && mState.mStencilAttachment.isAttached())
2106 {
2107 mState.mStencilAttachment.setInitState(InitState::Initialized);
2108 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2109 }
2110}
2111
2112void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2113{
2114 switch (bufferType)
2115 {
2116 case GL_COLOR:
2117 {
2118 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2119 if (mState.mColorAttachments[bufferIndex].isAttached())
2120 {
2121 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2122 mState.mResourceNeedsInit.reset(bufferIndex);
2123 }
2124 break;
2125 }
2126 case GL_DEPTH:
2127 {
2128 if (mState.mDepthAttachment.isAttached())
2129 {
2130 mState.mDepthAttachment.setInitState(InitState::Initialized);
2131 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2132 }
2133 break;
2134 }
2135 case GL_STENCIL:
2136 {
2137 if (mState.mStencilAttachment.isAttached())
2138 {
2139 mState.mStencilAttachment.setInitState(InitState::Initialized);
2140 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2141 }
2142 break;
2143 }
2144 case GL_DEPTH_STENCIL:
2145 {
2146 if (mState.mDepthAttachment.isAttached())
2147 {
2148 mState.mDepthAttachment.setInitState(InitState::Initialized);
2149 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2150 }
2151 if (mState.mStencilAttachment.isAttached())
2152 {
2153 mState.mStencilAttachment.setInitState(InitState::Initialized);
2154 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2155 }
2156 break;
2157 }
2158 default:
2159 UNREACHABLE();
2160 break;
2161 }
2162}
2163
2164Box Framebuffer::getDimensions() const
2165{
2166 return mState.getDimensions();
2167}
2168
2169Error Framebuffer::ensureBufferInitialized(const Context *context,
2170 GLenum bufferType,
2171 GLint bufferIndex)
2172{
2173 ASSERT(context->isRobustResourceInitEnabled());
2174
2175 if (mState.mResourceNeedsInit.none())
2176 {
2177 return NoError();
2178 }
2179
2180 switch (bufferType)
2181 {
2182 case GL_COLOR:
2183 {
2184 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2185 if (mState.mResourceNeedsInit[bufferIndex])
2186 {
2187 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2188 mState.mResourceNeedsInit.reset(bufferIndex);
2189 }
2190 break;
2191 }
2192 case GL_DEPTH:
2193 {
2194 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2195 {
2196 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2197 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2198 }
2199 break;
2200 }
2201 case GL_STENCIL:
2202 {
2203 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2204 {
2205 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2206 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2207 }
2208 break;
2209 }
2210 case GL_DEPTH_STENCIL:
2211 {
2212 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2213 {
2214 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2215 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2216 }
2217 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2218 {
2219 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2220 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2221 }
2222 break;
2223 }
2224 default:
2225 UNREACHABLE();
2226 break;
2227 }
2228
2229 return NoError();
2230}
2231
2232bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2233{
2234 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2235 {
2236 return false;
2237 }
2238
2239 switch (bufferType)
2240 {
2241 case GL_COLOR:
2242 return partialClearNeedsInit(context, true, false, false);
2243 case GL_DEPTH:
2244 return partialClearNeedsInit(context, false, true, false);
2245 case GL_STENCIL:
2246 return partialClearNeedsInit(context, false, false, true);
2247 case GL_DEPTH_STENCIL:
2248 return partialClearNeedsInit(context, false, true, true);
2249 default:
2250 UNREACHABLE();
2251 return false;
2252 }
2253}
2254
Jamie Madill42975642017-10-12 12:31:51 -04002255bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2256{
2257 if (!mAttachedTextures.valid())
2258 {
2259 std::set<const FramebufferAttachmentObject *> attachedTextures;
2260
2261 for (const auto &colorAttachment : mState.mColorAttachments)
2262 {
2263 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2264 {
2265 attachedTextures.insert(colorAttachment.getResource());
2266 }
2267 }
2268
2269 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2270 {
2271 attachedTextures.insert(mState.mDepthAttachment.getResource());
2272 }
2273
2274 if (mState.mStencilAttachment.isAttached() &&
2275 mState.mStencilAttachment.type() == GL_TEXTURE)
2276 {
2277 attachedTextures.insert(mState.mStencilAttachment.getResource());
2278 }
2279
2280 mAttachedTextures = std::move(attachedTextures);
2281 }
2282
2283 return (mAttachedTextures.value().count(texture) > 0);
2284}
2285
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002286} // namespace gl