blob: 7ab7671ca5f05bc939506a0919ea0ad88654311b [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
Yuly Novikov2eb54072018-08-22 16:41:26 -040074 if (!attachment.isRenderable(context))
Geoff Lang9f10b772017-05-16 15:51:03 -040075 {
76 return false;
77 }
78
79 if (attachment.type() == GL_TEXTURE)
80 {
Jiawei Shaoa8802472018-05-28 11:17:47 +080081 // [EXT_geometry_shader] Section 9.4.1, "Framebuffer Completeness"
82 // If <image> is a three-dimensional texture or a two-dimensional array texture and the
83 // attachment is not layered, the selected layer is less than the depth or layer count,
84 // respectively, of the texture.
85 if (!attachment.isLayered())
Geoff Lang9f10b772017-05-16 15:51:03 -040086 {
Jiawei Shaoa8802472018-05-28 11:17:47 +080087 if (attachment.layer() >= size.depth)
88 {
89 return false;
90 }
91 }
92 // If <image> is a three-dimensional texture or a two-dimensional array texture and the
93 // attachment is layered, the depth or layer count, respectively, of the texture is less
94 // than or equal to the value of MAX_FRAMEBUFFER_LAYERS_EXT.
95 else
96 {
97 if (static_cast<GLuint>(size.depth) >= context->getCaps().maxFramebufferLayers)
98 {
99 return false;
100 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400101 }
102
103 // ES3 specifies that cube map texture attachments must be cube complete.
104 // This language is missing from the ES2 spec, but we enforce it here because some
105 // desktop OpenGL drivers also enforce this validation.
106 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
107 const Texture *texture = attachment.getTexture();
108 ASSERT(texture);
Corentin Wallez99d492c2018-02-27 15:17:10 -0500109 if (texture->getType() == TextureType::CubeMap &&
Geoff Lang9f10b772017-05-16 15:51:03 -0400110 !texture->getTextureState().isCubeComplete())
111 {
112 return false;
113 }
Geoff Lang857c09d2017-05-16 15:55:04 -0400114
115 if (!texture->getImmutableFormat())
116 {
117 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
118
119 // From the ES 3.0 spec, pg 213:
120 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
121 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
122 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
123 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
124 // the effective maximum texture level defined in the Mipmapping discussion of
125 // section 3.8.10.4.
126 if (attachmentMipLevel < texture->getBaseLevel() ||
127 attachmentMipLevel > texture->getMipmapMaxLevel())
128 {
129 return false;
130 }
131
132 // Form the ES 3.0 spec, pg 213/214:
133 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
134 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
135 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
136 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
137 // a cubemap texture, the texture must also be cube complete.
138 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
139 {
140 return false;
141 }
142 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400143 }
144
145 return true;
146};
147
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400148bool CheckAttachmentSampleCompleteness(const Context *context,
149 const FramebufferAttachment &attachment,
150 bool colorAttachment,
151 Optional<int> *samples,
Geoff Lang92019432017-11-20 13:09:34 -0500152 Optional<bool> *fixedSampleLocations)
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400153{
154 ASSERT(attachment.isAttached());
155
156 if (attachment.type() == GL_TEXTURE)
157 {
158 const Texture *texture = attachment.getTexture();
159 ASSERT(texture);
160
161 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
Jiawei Shaoa8802472018-05-28 11:17:47 +0800162 bool fixedSampleloc = texture->getAttachmentFixedSampleLocations(attachmentImageIndex);
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400163 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
164 {
165 return false;
166 }
167 else
168 {
169 *fixedSampleLocations = fixedSampleloc;
170 }
171 }
172
173 if (samples->valid())
174 {
175 if (attachment.getSamples() != samples->value())
176 {
177 if (colorAttachment)
178 {
179 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
180 // all color attachments have the same number of samples for the FBO to be complete.
181 return false;
182 }
183 else
184 {
185 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
186 // when its depth or stencil samples are a multiple of the number of color samples.
187 if (!context->getExtensions().framebufferMixedSamples)
188 {
189 return false;
190 }
191
192 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
193 {
194 return false;
195 }
196 }
197 }
198 }
199 else
200 {
201 *samples = attachment.getSamples();
202 }
203
204 return true;
205}
206
Jamie Madill05b35b22017-10-03 09:01:44 -0400207// Needed to index into the attachment arrays/bitsets.
Jamie Madill682efdc2017-10-03 14:10:29 -0400208static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500209 Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
Jamie Madill05b35b22017-10-03 09:01:44 -0400210 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400211static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500212 Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400213 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400214static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500215 Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400216 "Framebuffer Dirty bit mismatch");
217
218Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
219{
220 ASSERT(attachment->isAttached());
221 if (attachment->initState() == InitState::MayNeedInit)
222 {
223 ANGLE_TRY(attachment->initializeContents(context));
224 }
225 return NoError();
226}
227
228bool IsColorMaskedOut(const BlendState &blend)
229{
230 return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
231 !blend.colorMaskAlpha);
232}
233
234bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
235{
236 return !depthStencil.depthMask;
237}
238
239bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
240{
241 return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
242}
243
244bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
245{
246 switch (buffer)
247 {
248 case GL_COLOR:
249 return IsColorMaskedOut(context->getGLState().getBlendState());
250 case GL_DEPTH:
251 return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
252 case GL_STENCIL:
253 return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
254 case GL_DEPTH_STENCIL:
255 return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
256 IsStencilMaskedOut(context->getGLState().getDepthStencilState());
257 default:
258 UNREACHABLE();
259 return true;
260 }
261}
262
Jamie Madill362876b2016-06-16 14:46:59 -0400263} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500264
Jamie Madill6f60d052017-02-22 15:20:11 -0500265// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400266FramebufferState::FramebufferState()
Jamie Madill2274b652018-05-31 10:56:08 -0400267 : mId(0),
268 mLabel(),
Geoff Lang70d0f492015-12-10 17:45:46 -0500269 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400270 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500271 mReadBufferState(GL_BACK),
Brandon Jones76746f92017-11-22 11:44:41 -0800272 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800273 mDefaultWidth(0),
274 mDefaultHeight(0),
275 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500276 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800277 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500278 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400279{
Geoff Langd90d3882017-03-21 10:49:54 -0400280 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500281 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400282}
283
Jamie Madill2274b652018-05-31 10:56:08 -0400284FramebufferState::FramebufferState(const Caps &caps, GLuint id)
285 : mId(id),
286 mLabel(),
Geoff Lang70d0f492015-12-10 17:45:46 -0500287 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -0500288 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800289 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
Brandon Jones76746f92017-11-22 11:44:41 -0800290 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800291 mDefaultWidth(0),
292 mDefaultHeight(0),
293 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500294 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800295 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500296 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500297{
Jamie Madill2274b652018-05-31 10:56:08 -0400298 ASSERT(mId != 0);
Geoff Langa15472a2015-08-11 11:48:03 -0400299 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500300 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
301}
302
Jamie Madill48ef11b2016-04-27 15:21:52 -0400303FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500304{
Jamie Madilld1405e52015-03-05 15:41:39 -0500305}
306
Jamie Madill48ef11b2016-04-27 15:21:52 -0400307const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500308{
309 return mLabel;
310}
311
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800312const FramebufferAttachment *FramebufferState::getAttachment(const Context *context,
313 GLenum attachment) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400314{
315 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
316 {
317 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
318 }
319
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800320 // WebGL1 allows a developer to query for attachment parameters even when "inconsistant" (i.e.
321 // multiple conflicting attachment points) and requires us to return the framebuffer attachment
322 // associated with WebGL.
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400323 switch (attachment)
324 {
325 case GL_COLOR:
326 case GL_BACK:
327 return getColorAttachment(0);
328 case GL_DEPTH:
329 case GL_DEPTH_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800330 if (context->isWebGL1())
331 {
332 return getWebGLDepthAttachment();
333 }
334 else
335 {
336 return getDepthAttachment();
337 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400338 case GL_STENCIL:
339 case GL_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800340 if (context->isWebGL1())
341 {
342 return getWebGLStencilAttachment();
343 }
344 else
345 {
346 return getStencilAttachment();
347 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400348 case GL_DEPTH_STENCIL:
349 case GL_DEPTH_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800350 if (context->isWebGL1())
351 {
352 return getWebGLDepthStencilAttachment();
353 }
354 else
355 {
356 return getDepthStencilAttachment();
357 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400358 default:
359 UNREACHABLE();
360 return nullptr;
361 }
362}
363
Jamie Madill05b35b22017-10-03 09:01:44 -0400364size_t FramebufferState::getReadIndex() const
Jamie Madill7147f012015-03-05 15:41:40 -0500365{
Jamie Madill231c7f52017-04-26 13:45:37 -0400366 ASSERT(mReadBufferState == GL_BACK ||
367 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
368 size_t readIndex = (mReadBufferState == GL_BACK
369 ? 0
370 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500371 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill05b35b22017-10-03 09:01:44 -0400372 return readIndex;
373}
374
375const FramebufferAttachment *FramebufferState::getReadAttachment() const
376{
377 if (mReadBufferState == GL_NONE)
378 {
379 return nullptr;
380 }
381 size_t readIndex = getReadIndex();
Jamie Madill2d06b732015-04-20 12:53:28 -0400382 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500383}
384
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500385const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
386{
387 auto *colorAttachment = getFirstColorAttachment();
388 if (colorAttachment)
389 {
390 return colorAttachment;
391 }
392 return getDepthOrStencilAttachment();
393}
394
Jamie Madill48ef11b2016-04-27 15:21:52 -0400395const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500396{
Jamie Madill2d06b732015-04-20 12:53:28 -0400397 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500398 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400399 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500400 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400401 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500402 }
403 }
404
405 return nullptr;
406}
407
Jamie Madill48ef11b2016-04-27 15:21:52 -0400408const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500409{
Jamie Madill2d06b732015-04-20 12:53:28 -0400410 if (mDepthAttachment.isAttached())
411 {
412 return &mDepthAttachment;
413 }
414 if (mStencilAttachment.isAttached())
415 {
416 return &mStencilAttachment;
417 }
418 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500419}
420
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500421const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
422{
423 if (mStencilAttachment.isAttached())
424 {
425 return &mStencilAttachment;
426 }
427 return getDepthStencilAttachment();
428}
429
Jamie Madill48ef11b2016-04-27 15:21:52 -0400430const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400431{
432 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400433 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
434 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400435}
436
Jamie Madill48ef11b2016-04-27 15:21:52 -0400437const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400438{
Jamie Madill2d06b732015-04-20 12:53:28 -0400439 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400440}
441
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800442const FramebufferAttachment *FramebufferState::getWebGLDepthAttachment() const
443{
444 return mWebGLDepthAttachment.isAttached() ? &mWebGLDepthAttachment : nullptr;
445}
446
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800447const FramebufferAttachment *FramebufferState::getWebGLDepthStencilAttachment() const
448{
449 return mWebGLDepthStencilAttachment.isAttached() ? &mWebGLDepthStencilAttachment : nullptr;
450}
451
Jamie Madill48ef11b2016-04-27 15:21:52 -0400452const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400453{
Jamie Madill2d06b732015-04-20 12:53:28 -0400454 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400455}
456
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800457const FramebufferAttachment *FramebufferState::getWebGLStencilAttachment() const
458{
459 return mWebGLStencilAttachment.isAttached() ? &mWebGLStencilAttachment : nullptr;
460}
461
Jamie Madill48ef11b2016-04-27 15:21:52 -0400462const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400463{
464 // A valid depth-stencil attachment has the same resource bound to both the
465 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400466 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500467 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400468 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400469 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400470 }
471
472 return nullptr;
473}
474
Jamie Madill48ef11b2016-04-27 15:21:52 -0400475bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500476{
477 Optional<Extents> attachmentSize;
478
Jamie Madill231c7f52017-04-26 13:45:37 -0400479 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500480 if (!attachment.isAttached())
481 {
482 return false;
483 }
484
485 if (!attachmentSize.valid())
486 {
487 attachmentSize = attachment.getSize();
488 return false;
489 }
490
Jeff Gilbert8f8edd62017-10-31 14:26:30 -0700491 const auto &prevSize = attachmentSize.value();
492 const auto &curSize = attachment.getSize();
493 return (curSize.width != prevSize.width || curSize.height != prevSize.height);
Jamie Madillcc86d642015-11-24 13:00:07 -0500494 };
495
496 for (const auto &attachment : mColorAttachments)
497 {
498 if (hasMismatchedSize(attachment))
499 {
500 return false;
501 }
502 }
503
504 if (hasMismatchedSize(mDepthAttachment))
505 {
506 return false;
507 }
508
509 return !hasMismatchedSize(mStencilAttachment);
510}
511
Luc Ferron5bdf8bd2018-06-20 09:51:37 -0400512bool FramebufferState::hasSeparateDepthAndStencilAttachments() const
513{
514 // if we have both a depth and stencil buffer, they must refer to the same object
515 // since we only support packed_depth_stencil and not separate depth and stencil
516 return (getDepthAttachment() != nullptr && getStencilAttachment() != nullptr &&
517 getDepthStencilAttachment() == nullptr);
518}
519
Jamie Madilld4442552018-02-27 22:03:47 -0500520const FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400521{
522 ASSERT(drawBufferIdx < mDrawBufferStates.size());
523 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
524 {
525 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
526 // must be COLOR_ATTACHMENTi or NONE"
527 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
528 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800529
530 if (mDrawBufferStates[drawBufferIdx] == GL_BACK)
531 {
532 return getColorAttachment(0);
533 }
534 else
535 {
536 return getColorAttachment(mDrawBufferStates[drawBufferIdx] - GL_COLOR_ATTACHMENT0);
537 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400538 }
539 else
540 {
541 return nullptr;
542 }
543}
544
545size_t FramebufferState::getDrawBufferCount() const
546{
547 return mDrawBufferStates.size();
548}
549
Geoff Langb21e20d2016-07-19 15:35:41 -0400550bool FramebufferState::colorAttachmentsAreUniqueImages() const
551{
552 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
553 firstAttachmentIdx++)
554 {
Jamie Madilld4442552018-02-27 22:03:47 -0500555 const FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400556 if (!firstAttachment.isAttached())
557 {
558 continue;
559 }
560
561 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
562 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
563 {
Jamie Madilld4442552018-02-27 22:03:47 -0500564 const FramebufferAttachment &secondAttachment = mColorAttachments[secondAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400565 if (!secondAttachment.isAttached())
566 {
567 continue;
568 }
569
570 if (firstAttachment == secondAttachment)
571 {
572 return false;
573 }
574 }
575 }
576
577 return true;
578}
579
Jamie Madill9c335862017-07-18 11:51:38 -0400580bool FramebufferState::hasDepth() const
581{
582 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
583}
584
585bool FramebufferState::hasStencil() const
586{
587 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
588}
589
Martin Radev5c00d0d2017-08-07 10:06:59 +0300590GLsizei FramebufferState::getNumViews() const
591{
592 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
593 if (attachment == nullptr)
594 {
595 return FramebufferAttachment::kDefaultNumViews;
596 }
597 return attachment->getNumViews();
598}
599
600const std::vector<Offset> *FramebufferState::getViewportOffsets() const
601{
602 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
603 if (attachment == nullptr)
604 {
605 return nullptr;
606 }
607 return &attachment->getMultiviewViewportOffsets();
608}
609
610GLenum FramebufferState::getMultiviewLayout() const
611{
612 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
613 if (attachment == nullptr)
614 {
615 return GL_NONE;
616 }
617 return attachment->getMultiviewLayout();
618}
619
Martin Radev4e619f52017-08-09 11:50:06 +0300620int FramebufferState::getBaseViewIndex() const
621{
622 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
623 if (attachment == nullptr)
624 {
625 return GL_NONE;
626 }
627 return attachment->getBaseViewIndex();
628}
629
Jamie Madill05b35b22017-10-03 09:01:44 -0400630Box FramebufferState::getDimensions() const
631{
632 ASSERT(attachmentsHaveSameDimensions());
633 ASSERT(getFirstNonNullAttachment() != nullptr);
634 Extents extents = getFirstNonNullAttachment()->getSize();
635 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
636}
637
Jamie Madill7aea7e02016-05-10 10:39:45 -0400638Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill2274b652018-05-31 10:56:08 -0400639 : mState(caps, id),
Jamie Madill362876b2016-06-16 14:46:59 -0400640 mImpl(factory->createFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400641 mCachedStatus(),
642 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
643 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644{
Corentin Wallez37c39792015-08-20 14:19:46 -0400645 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400646 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
647
Jamie Madill1e5499d2017-04-05 11:22:16 -0400648 for (uint32_t colorIndex = 0;
649 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400650 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400651 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400652 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400653}
654
Geoff Langbf7b95d2018-05-01 16:48:21 -0400655Framebuffer::Framebuffer(const Context *context, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400656 : mState(),
Geoff Langbf7b95d2018-05-01 16:48:21 -0400657 mImpl(surface->getImplementation()->createDefaultFramebuffer(context, mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400658 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
659 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
660 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400661{
Geoff Langda88add2014-12-01 10:22:01 -0500662 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400663 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500664
Geoff Langbf7b95d2018-05-01 16:48:21 -0400665 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400666 FramebufferAttachment::kDefaultNumViews,
Martin Radev5dae57b2017-07-14 16:15:55 +0300667 FramebufferAttachment::kDefaultBaseViewIndex,
668 FramebufferAttachment::kDefaultMultiviewLayout,
669 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500670
671 if (surface->getConfig()->depthSize > 0)
672 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400673 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400674 FramebufferAttachment::kDefaultNumViews,
Jamie Madilld4442552018-02-27 22:03:47 -0500675 FramebufferAttachment::kDefaultBaseViewIndex,
676 FramebufferAttachment::kDefaultMultiviewLayout,
677 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500678 }
679
680 if (surface->getConfig()->stencilSize > 0)
681 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400682 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400683 FramebufferAttachment::kDefaultNumViews,
684 FramebufferAttachment::kDefaultBaseViewIndex,
685 FramebufferAttachment::kDefaultMultiviewLayout,
686 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500687 }
Brandon Jones76746f92017-11-22 11:44:41 -0800688 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000689}
690
Corentin Wallezccab69d2017-01-27 16:57:15 -0500691Framebuffer::Framebuffer(rx::GLImplFactory *factory)
692 : mState(),
693 mImpl(factory->createFramebuffer(mState)),
Corentin Wallezccab69d2017-01-27 16:57:15 -0500694 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
695 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
696 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
697{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400698 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Brandon Jones76746f92017-11-22 11:44:41 -0800699 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500700}
701
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000702Framebuffer::~Framebuffer()
703{
Geoff Langda88add2014-12-01 10:22:01 -0500704 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000705}
706
Jamie Madill4928b7c2017-06-20 12:57:39 -0400707void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500708{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400709 for (auto &attachment : mState.mColorAttachments)
710 {
711 attachment.detach(context);
712 }
713 mState.mDepthAttachment.detach(context);
714 mState.mStencilAttachment.detach(context);
715 mState.mWebGLDepthAttachment.detach(context);
716 mState.mWebGLStencilAttachment.detach(context);
717 mState.mWebGLDepthStencilAttachment.detach(context);
718
Jamie Madillc564c072017-06-01 12:45:42 -0400719 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500720}
721
Geoff Lang70d0f492015-12-10 17:45:46 -0500722void Framebuffer::setLabel(const std::string &label)
723{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400724 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500725}
726
727const std::string &Framebuffer::getLabel() const
728{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400729 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500730}
731
Jamie Madill8693bdb2017-09-02 15:32:14 -0400732bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000733{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400734 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000735}
736
Jamie Madill8693bdb2017-09-02 15:32:14 -0400737bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000738{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400739 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500740}
Jamie Madille261b442014-06-25 12:42:21 -0400741
Jamie Madill8693bdb2017-09-02 15:32:14 -0400742bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500743{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400744 bool found = false;
745
Jamie Madill362876b2016-06-16 14:46:59 -0400746 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500747 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400748 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
749 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
750 {
751 found = true;
752 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000753 }
754
Jamie Madilla02315b2017-02-23 14:14:47 -0500755 if (context->isWebGL1())
756 {
757 const std::array<FramebufferAttachment *, 3> attachments = {
758 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
759 &mState.mWebGLStencilAttachment}};
760 for (FramebufferAttachment *attachment : attachments)
761 {
762 if (attachment->isAttached() && attachment->type() == resourceType &&
763 attachment->id() == resourceId)
764 {
765 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400766 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500767 }
768 }
769 }
770 else
771 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400772 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
773 DIRTY_BIT_DEPTH_ATTACHMENT))
774 {
775 found = true;
776 }
777 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
778 DIRTY_BIT_STENCIL_ATTACHMENT))
779 {
780 found = true;
781 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500782 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400783
784 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400785}
786
Jamie Madill8693bdb2017-09-02 15:32:14 -0400787bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400788 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400789 GLenum matchType,
790 GLuint matchId,
791 size_t dirtyBit)
792{
793 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
794 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400795 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400796 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -0400797 mState.mResourceNeedsInit.set(dirtyBit, false);
Jamie Madill8693bdb2017-09-02 15:32:14 -0400798 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400799 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400800
801 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000802}
803
Corentin Wallez37c39792015-08-20 14:19:46 -0400804const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000805{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400806 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000807}
808
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400809const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400810{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400811 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400812}
813
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400814const FramebufferAttachment *Framebuffer::getStencilbuffer() const
815{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400816 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400817}
818
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400819const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
820{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400821 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400822}
823
824const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000825{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400826 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000827}
828
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500829const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
830{
831 return mState.getStencilOrDepthStencilAttachment();
832}
833
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400834const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000835{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400836 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000837}
838
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000839GLenum Framebuffer::getReadColorbufferType() const
840{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400841 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400842 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000843}
844
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400845const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000846{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400847 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000848}
849
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400850const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
851{
852 return mState.getFirstNonNullAttachment();
853}
854
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800855const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
856 GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000857{
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800858 return mState.getAttachment(context, attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400859}
860
Geoff Langa15472a2015-08-11 11:48:03 -0400861size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000862{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400863 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400864}
865
866GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
867{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400868 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
869 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000870}
871
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500872const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
873{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400874 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500875}
876
Geoff Lang164d54e2014-12-01 10:55:33 -0500877void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000878{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400879 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500880
881 ASSERT(count <= drawStates.size());
882 std::copy(buffers, buffers + count, drawStates.begin());
883 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500884 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500885
886 mState.mEnabledDrawBuffers.reset();
Brandon Jones76746f92017-11-22 11:44:41 -0800887 mState.mDrawBufferTypeMask.reset();
888
Jamie Madilla4595b82017-01-11 17:36:34 -0500889 for (size_t index = 0; index < count; ++index)
890 {
Brandon Jones76746f92017-11-22 11:44:41 -0800891 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
892
Jamie Madilla4595b82017-01-11 17:36:34 -0500893 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
894 {
895 mState.mEnabledDrawBuffers.set(index);
896 }
897 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500898}
899
Geoff Langa15472a2015-08-11 11:48:03 -0400900const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
901{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400902 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400903}
904
Geoff Lange0cff192017-05-30 13:04:56 -0400905GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
906{
907 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
908 if (attachment == nullptr)
909 {
910 return GL_NONE;
911 }
912
913 GLenum componentType = attachment->getFormat().info->componentType;
914 switch (componentType)
915 {
916 case GL_INT:
917 case GL_UNSIGNED_INT:
918 return componentType;
919
920 default:
921 return GL_FLOAT;
922 }
923}
924
Brandon Jonesc405ae72017-12-06 14:15:03 -0800925ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
Brandon Jones76746f92017-11-22 11:44:41 -0800926{
927 return mState.mDrawBufferTypeMask;
928}
929
930DrawBufferMask Framebuffer::getDrawBufferMask() const
931{
932 return mState.mEnabledDrawBuffers;
933}
934
Geoff Langa15472a2015-08-11 11:48:03 -0400935bool Framebuffer::hasEnabledDrawBuffer() const
936{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400937 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400938 {
939 if (getDrawBuffer(drawbufferIdx) != nullptr)
940 {
941 return true;
942 }
943 }
944
945 return false;
946}
947
Geoff Lang9dd95802014-12-01 11:12:59 -0500948GLenum Framebuffer::getReadBufferState() const
949{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400950 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500951}
952
953void Framebuffer::setReadBuffer(GLenum buffer)
954{
Jamie Madillb885e572015-02-03 16:16:04 -0500955 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
956 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400957 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
958 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500959 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000960}
961
Corentin Wallez37c39792015-08-20 14:19:46 -0400962size_t Framebuffer::getNumColorBuffers() const
963{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400964 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400965}
966
Jamie Madill0df8fe42015-11-24 16:10:24 -0500967bool Framebuffer::hasDepth() const
968{
Jamie Madill9c335862017-07-18 11:51:38 -0400969 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500970}
971
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000972bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000973{
Jamie Madill9c335862017-07-18 11:51:38 -0400974 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000975}
976
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000977bool Framebuffer::usingExtendedDrawBuffers() const
978{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400979 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000980 {
Geoff Langa15472a2015-08-11 11:48:03 -0400981 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000982 {
983 return true;
984 }
985 }
986
987 return false;
988}
989
Jamie Madillb983a4b2018-08-01 11:34:51 -0400990void Framebuffer::invalidateCompletenessCache(const Context *context)
Geoff Lang9aded172017-04-05 11:07:56 -0400991{
Jamie Madill2274b652018-05-31 10:56:08 -0400992 if (mState.mId != 0)
Geoff Lang9aded172017-04-05 11:07:56 -0400993 {
994 mCachedStatus.reset();
995 }
996}
997
Jamie Madillcc73f242018-08-01 11:34:48 -0400998GLenum Framebuffer::checkStatusImpl(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999{
Jamie Madillcc73f242018-08-01 11:34:48 -04001000 ASSERT(!isDefault());
1001 ASSERT(hasAnyDirtyBit() || !mCachedStatus.valid());
Geoff Lang528ce3c2014-12-01 10:44:07 -05001002
Jamie Madillcc73f242018-08-01 11:34:48 -04001003 mCachedStatus = checkStatusWithGLFrontEnd(context);
Jamie Madille98b1b52018-03-08 09:47:23 -05001004
Jamie Madillcc73f242018-08-01 11:34:48 -04001005 if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
1006 {
1007 Error err = syncState(context);
1008 if (err.isError())
Jamie Madille98b1b52018-03-08 09:47:23 -05001009 {
Jamie Madillcc73f242018-08-01 11:34:48 -04001010 // TODO(jmadill): Remove when refactor complete. http://anglebug.com/2491
1011 const_cast<Context *>(context)->handleError(err);
1012 return GetDefaultReturnValue<EntryPoint::CheckFramebufferStatus, GLenum>();
1013 }
1014 if (!mImpl->checkStatus(context))
1015 {
1016 mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
Jamie Madille98b1b52018-03-08 09:47:23 -05001017 }
Jamie Madill362876b2016-06-16 14:46:59 -04001018 }
1019
Jamie Madill427064d2018-04-13 16:20:34 -04001020 return mCachedStatus.value();
Jamie Madill362876b2016-06-16 14:46:59 -04001021}
1022
Jamie Madille98b1b52018-03-08 09:47:23 -05001023GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -04001024{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001025 const ContextState &state = context->getContextState();
1026
Jamie Madill2274b652018-05-31 10:56:08 -04001027 ASSERT(mState.mId != 0);
Jamie Madill362876b2016-06-16 14:46:59 -04001028
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001029 bool hasAttachments = false;
1030 Optional<unsigned int> colorbufferSize;
1031 Optional<int> samples;
Geoff Lang92019432017-11-20 13:09:34 -05001032 Optional<bool> fixedSampleLocations;
JiangYizhou461d9a32017-01-04 16:37:26 +08001033 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001034
Martin Radev9bc9a322017-07-21 14:28:17 +03001035 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
1036
Jiawei Shaoa8802472018-05-28 11:17:47 +08001037 Optional<bool> isLayered;
1038 Optional<TextureType> colorAttachmentsTextureType;
1039
Jamie Madill48ef11b2016-04-27 15:21:52 -04001040 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001041 {
Jamie Madill2d06b732015-04-20 12:53:28 -04001042 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001044 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001045 {
1046 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1047 }
daniel@transgaming.com01868132010-08-24 19:21:17 +00001048
Geoff Lang677bb6f2017-04-05 12:40:40 -04001049 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001050 if (format.depthBits > 0 || format.stencilBits > 0)
1051 {
1052 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1053 }
1054
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001055 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
1056 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001057 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001058 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001059 }
1060
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001061 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
1062 // in GLES 3.0, there is no such restriction
1063 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001064 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001065 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001066 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001067 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +00001068 {
1069 return GL_FRAMEBUFFER_UNSUPPORTED;
1070 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001071 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001072 else
1073 {
1074 colorbufferSize = format.pixelBytes;
1075 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001076 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001077
Martin Radev9bc9a322017-07-21 14:28:17 +03001078 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
1079 {
1080 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1081 }
1082
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001083 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001084
1085 if (!hasAttachments)
1086 {
1087 isLayered = colorAttachment.isLayered();
1088 if (isLayered.value())
1089 {
1090 colorAttachmentsTextureType = colorAttachment.getTextureImageIndex().getType();
1091 }
1092 hasAttachments = true;
1093 }
1094 else
1095 {
1096 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1097 // If any framebuffer attachment is layered, all populated attachments
1098 // must be layered. Additionally, all populated color attachments must
1099 // be from textures of the same target. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1100 ASSERT(isLayered.valid());
1101 if (isLayered.value() != colorAttachment.isLayered())
1102 {
1103 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1104 }
1105 else if (isLayered.value())
1106 {
1107 ASSERT(colorAttachmentsTextureType.valid());
1108 if (colorAttachmentsTextureType.value() !=
1109 colorAttachment.getTextureImageIndex().getType())
1110 {
1111 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1112 }
1113 }
1114 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001115 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001116 }
1117
Jamie Madill48ef11b2016-04-27 15:21:52 -04001118 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001119 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001120 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001121 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001122 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001123 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001124 }
1125
Geoff Lang677bb6f2017-04-05 12:40:40 -04001126 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001127 if (format.depthBits == 0)
1128 {
1129 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001130 }
1131
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001132 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1133 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001134 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001135 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001136 }
Sami Väisänena797e062016-05-12 15:23:40 +03001137
Martin Radev9bc9a322017-07-21 14:28:17 +03001138 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1139 {
1140 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1141 }
1142
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001143 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001144
1145 if (!hasAttachments)
1146 {
1147 isLayered = depthAttachment.isLayered();
1148 hasAttachments = true;
1149 }
1150 else
1151 {
1152 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1153 // If any framebuffer attachment is layered, all populated attachments
1154 // must be layered. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1155 ASSERT(isLayered.valid());
1156 if (isLayered.value() != depthAttachment.isLayered())
1157 {
1158 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1159 }
1160 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001161 }
1162
Jamie Madill48ef11b2016-04-27 15:21:52 -04001163 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001164 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001165 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001166 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001167 {
1168 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1169 }
1170
Geoff Lang677bb6f2017-04-05 12:40:40 -04001171 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001172 if (format.stencilBits == 0)
1173 {
1174 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001175 }
1176
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001177 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1178 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001179 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001180 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001181 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001182
Martin Radev9bc9a322017-07-21 14:28:17 +03001183 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1184 {
1185 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1186 }
1187
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001188 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001189
1190 if (!hasAttachments)
1191 {
1192 hasAttachments = true;
1193 }
1194 else
1195 {
1196 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1197 // If any framebuffer attachment is layered, all populated attachments
1198 // must be layered.
1199 // {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1200 ASSERT(isLayered.valid());
1201 if (isLayered.value() != stencilAttachment.isLayered())
1202 {
1203 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1204 }
1205 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001206 }
1207
1208 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1209 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1210 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1211 {
1212 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001213 }
1214
Jamie Madilla02315b2017-02-23 14:14:47 -05001215 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1216 if (state.isWebGL1())
1217 {
1218 if (!mState.mWebGLDepthStencilConsistent)
1219 {
1220 return GL_FRAMEBUFFER_UNSUPPORTED;
1221 }
1222
1223 if (mState.mWebGLDepthStencilAttachment.isAttached())
1224 {
1225 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1226 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1227 {
1228 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1229 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001230
1231 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1232 &mState.mWebGLDepthStencilAttachment))
1233 {
1234 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1235 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001236 }
1237 else if (mState.mStencilAttachment.isAttached() &&
1238 mState.mStencilAttachment.getDepthSize() > 0)
1239 {
1240 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1241 }
1242 else if (mState.mDepthAttachment.isAttached() &&
1243 mState.mDepthAttachment.getStencilSize() > 0)
1244 {
1245 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1246 }
1247 }
1248
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001249 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1250 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1251 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001252 GLint defaultWidth = mState.getDefaultWidth();
1253 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001254 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001255 {
1256 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001257 }
1258
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001259 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001260 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001261 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1262 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001263 {
1264 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1265 }
1266
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001267 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1268 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001269 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1270 {
1271 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1272 }
1273
Kenneth Russellce8602a2017-10-03 18:23:08 -07001274 // The WebGL conformance tests implicitly define that all framebuffer
1275 // attachments must be unique. For example, the same level of a texture can
1276 // not be attached to two different color attachments.
1277 if (state.getExtensions().webglCompatibility)
1278 {
1279 if (!mState.colorAttachmentsAreUniqueImages())
1280 {
1281 return GL_FRAMEBUFFER_UNSUPPORTED;
1282 }
1283 }
1284
Jamie Madillcc86d642015-11-24 13:00:07 -05001285 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001286}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001287
Jamie Madill4928b7c2017-06-20 12:57:39 -04001288Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001289{
Jamie Madill05b35b22017-10-03 09:01:44 -04001290 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1291 // can be no-ops, so we should probably do that to ensure consistency.
1292 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1293
Jamie Madill4928b7c2017-06-20 12:57:39 -04001294 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001295}
1296
Jamie Madill4928b7c2017-06-20 12:57:39 -04001297Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001298{
Jamie Madill05b35b22017-10-03 09:01:44 -04001299 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1300 // can be no-ops, so we should probably do that to ensure consistency.
1301 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1302
Jamie Madill4928b7c2017-06-20 12:57:39 -04001303 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001304}
1305
Jamie Madill05b35b22017-10-03 09:01:44 -04001306bool Framebuffer::partialClearNeedsInit(const Context *context,
1307 bool color,
1308 bool depth,
1309 bool stencil)
1310{
1311 const auto &glState = context->getGLState();
1312
1313 if (!glState.isRobustResourceInitEnabled())
1314 {
1315 return false;
1316 }
1317
1318 // Scissors can affect clearing.
1319 // TODO(jmadill): Check for complete scissor overlap.
1320 if (glState.isScissorTestEnabled())
1321 {
1322 return true;
1323 }
1324
1325 // If colors masked, we must clear before we clear. Do a simple check.
1326 // TODO(jmadill): Filter out unused color channels from the test.
1327 if (color)
1328 {
1329 const auto &blend = glState.getBlendState();
1330 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1331 blend.colorMaskAlpha))
1332 {
1333 return true;
1334 }
1335 }
1336
1337 const auto &depthStencil = glState.getDepthStencilState();
Yuly Novikov21edf3d2018-07-23 16:44:16 -04001338 if (stencil && (depthStencil.stencilMask != depthStencil.stencilWritemask ||
1339 depthStencil.stencilBackMask != depthStencil.stencilBackWritemask))
Jamie Madill05b35b22017-10-03 09:01:44 -04001340 {
1341 return true;
1342 }
1343
1344 return false;
1345}
1346
Jamie Madill4928b7c2017-06-20 12:57:39 -04001347Error Framebuffer::invalidateSub(const Context *context,
1348 size_t count,
1349 const GLenum *attachments,
Jamie Madilld4442552018-02-27 22:03:47 -05001350 const Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001351{
Jamie Madill05b35b22017-10-03 09:01:44 -04001352 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1353 // can be no-ops, so we should probably do that to ensure consistency.
1354 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1355
Jamie Madill4928b7c2017-06-20 12:57:39 -04001356 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001357}
1358
Jamie Madilld4442552018-02-27 22:03:47 -05001359Error Framebuffer::clear(const Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001360{
Jamie Madill05b35b22017-10-03 09:01:44 -04001361 const auto &glState = context->getGLState();
1362 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001363 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001364 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001365 }
1366
Jamie Madill05b35b22017-10-03 09:01:44 -04001367 ANGLE_TRY(mImpl->clear(context, mask));
1368
Jamie Madill05b35b22017-10-03 09:01:44 -04001369 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001370}
1371
Jamie Madilld4442552018-02-27 22:03:47 -05001372Error Framebuffer::clearBufferfv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001373 GLenum buffer,
1374 GLint drawbuffer,
1375 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001376{
Jamie Madill05b35b22017-10-03 09:01:44 -04001377 if (context->getGLState().isRasterizerDiscardEnabled() ||
1378 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001379 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001380 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001381 }
1382
Jamie Madill05b35b22017-10-03 09:01:44 -04001383 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1384
Jamie Madill05b35b22017-10-03 09:01:44 -04001385 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001386}
1387
Jamie Madilld4442552018-02-27 22:03:47 -05001388Error Framebuffer::clearBufferuiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001389 GLenum buffer,
1390 GLint drawbuffer,
1391 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001392{
Jamie Madill05b35b22017-10-03 09:01:44 -04001393 if (context->getGLState().isRasterizerDiscardEnabled() ||
1394 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001395 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001396 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001397 }
1398
Jamie Madill05b35b22017-10-03 09:01:44 -04001399 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1400
Jamie Madill05b35b22017-10-03 09:01:44 -04001401 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001402}
1403
Jamie Madilld4442552018-02-27 22:03:47 -05001404Error Framebuffer::clearBufferiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001405 GLenum buffer,
1406 GLint drawbuffer,
1407 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001408{
Jamie Madill05b35b22017-10-03 09:01:44 -04001409 if (context->getGLState().isRasterizerDiscardEnabled() ||
1410 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001411 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001412 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001413 }
1414
Jamie Madill05b35b22017-10-03 09:01:44 -04001415 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1416
Jamie Madill05b35b22017-10-03 09:01:44 -04001417 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001418}
1419
Jamie Madilld4442552018-02-27 22:03:47 -05001420Error Framebuffer::clearBufferfi(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001421 GLenum buffer,
1422 GLint drawbuffer,
1423 GLfloat depth,
1424 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001425{
Jamie Madill05b35b22017-10-03 09:01:44 -04001426 if (context->getGLState().isRasterizerDiscardEnabled() ||
1427 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001428 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001429 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001430 }
1431
Jamie Madill05b35b22017-10-03 09:01:44 -04001432 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1433
Jamie Madill05b35b22017-10-03 09:01:44 -04001434 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001435}
1436
Jamie Madill690c8eb2018-03-12 15:20:03 -04001437Error Framebuffer::getImplementationColorReadFormat(const Context *context, GLenum *formatOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001438{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001439 ANGLE_TRY(syncState(context));
1440 *formatOut = mImpl->getImplementationColorReadFormat(context);
1441 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001442}
1443
Jamie Madill690c8eb2018-03-12 15:20:03 -04001444Error Framebuffer::getImplementationColorReadType(const Context *context, GLenum *typeOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001445{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001446 ANGLE_TRY(syncState(context));
1447 *typeOut = mImpl->getImplementationColorReadType(context);
1448 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001449}
1450
Jamie Madilld4442552018-02-27 22:03:47 -05001451Error Framebuffer::readPixels(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001452 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001453 GLenum format,
1454 GLenum type,
Jamie Madill05b35b22017-10-03 09:01:44 -04001455 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001456{
Jamie Madill05b35b22017-10-03 09:01:44 -04001457 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001458 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001459
Jamie Madilld4442552018-02-27 22:03:47 -05001460 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001461 if (unpackBuffer)
1462 {
Jamie Madill09463932018-04-04 05:26:59 -04001463 unpackBuffer->onPixelPack(context);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001464 }
1465
Jamie Madill362876b2016-06-16 14:46:59 -04001466 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001467}
1468
Jamie Madilld4442552018-02-27 22:03:47 -05001469Error Framebuffer::blit(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001470 const Rectangle &sourceArea,
1471 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001472 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001473 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001474{
He Yunchao6be602d2016-12-22 14:33:07 +08001475 GLbitfield blitMask = mask;
1476
1477 // Note that blitting is called against draw framebuffer.
1478 // See the code in gl::Context::blitFramebuffer.
1479 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1480 {
1481 blitMask &= ~GL_COLOR_BUFFER_BIT;
1482 }
1483
1484 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1485 {
1486 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1487 }
1488
1489 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1490 {
1491 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1492 }
1493
1494 if (!blitMask)
1495 {
1496 return NoError();
1497 }
1498
Jamie Madill05b35b22017-10-03 09:01:44 -04001499 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1500 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1501
1502 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1503 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1504
He Yunchao6be602d2016-12-22 14:33:07 +08001505 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001506}
1507
Luc Ferronbf6dc372018-06-28 15:24:19 -04001508bool Framebuffer::isDefault() const
1509{
1510 return id() == 0;
1511}
1512
Jamie Madill427064d2018-04-13 16:20:34 -04001513int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001514{
Jamie Madill427064d2018-04-13 16:20:34 -04001515 return (isComplete(context) ? getCachedSamples(context) : 0);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001516}
1517
Jamie Madill9c335862017-07-18 11:51:38 -04001518int Framebuffer::getCachedSamples(const Context *context)
1519{
Jamie Madill5b772312018-03-08 20:28:32 -05001520 ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
1521
Jamie Madill9c335862017-07-18 11:51:38 -04001522 // For a complete framebuffer, all attachments must have the same sample count.
1523 // In this case return the first nonzero sample size.
1524 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1525 if (firstNonNullAttachment)
1526 {
1527 ASSERT(firstNonNullAttachment->isAttached());
1528 return firstNonNullAttachment->getSamples();
1529 }
1530
1531 // No attachments found.
1532 return 0;
1533}
1534
Geoff Lang13455072018-05-09 11:24:43 -04001535Error Framebuffer::getSamplePosition(const Context *context, size_t index, GLfloat *xy) const
Corentin Wallezccab69d2017-01-27 16:57:15 -05001536{
Geoff Lang13455072018-05-09 11:24:43 -04001537 ANGLE_TRY(mImpl->getSamplePosition(context, index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001538 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001539}
1540
Jamie Madille261b442014-06-25 12:42:21 -04001541bool Framebuffer::hasValidDepthStencil() const
1542{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001543 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001544}
1545
Jamie Madilla02315b2017-02-23 14:14:47 -05001546void Framebuffer::setAttachment(const Context *context,
1547 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001548 GLenum binding,
1549 const ImageIndex &textureIndex,
1550 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001551{
Martin Radev5dae57b2017-07-14 16:15:55 +03001552 setAttachment(context, type, binding, textureIndex, resource,
1553 FramebufferAttachment::kDefaultNumViews,
1554 FramebufferAttachment::kDefaultBaseViewIndex,
1555 FramebufferAttachment::kDefaultMultiviewLayout,
1556 FramebufferAttachment::kDefaultViewportOffsets);
1557}
1558
1559void Framebuffer::setAttachment(const Context *context,
1560 GLenum type,
1561 GLenum binding,
1562 const ImageIndex &textureIndex,
1563 FramebufferAttachmentObject *resource,
1564 GLsizei numViews,
1565 GLuint baseViewIndex,
1566 GLenum multiviewLayout,
1567 const GLint *viewportOffsets)
1568{
Jamie Madilla02315b2017-02-23 14:14:47 -05001569 // Context may be null in unit tests.
1570 if (!context || !context->isWebGL1())
1571 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001572 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1573 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001574 return;
1575 }
1576
1577 switch (binding)
1578 {
1579 case GL_DEPTH_STENCIL:
1580 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001581 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001582 resource, numViews, baseViewIndex,
1583 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001584 break;
1585 case GL_DEPTH:
1586 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001587 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1588 numViews, baseViewIndex, multiviewLayout,
1589 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001590 break;
1591 case GL_STENCIL:
1592 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001593 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1594 numViews, baseViewIndex, multiviewLayout,
1595 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001596 break;
1597 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001598 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1599 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001600 return;
1601 }
1602
Martin Radev5dae57b2017-07-14 16:15:55 +03001603 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1604 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001605}
1606
Martin Radev82ef7742017-08-08 17:44:58 +03001607void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1608 GLenum type,
1609 GLenum binding,
1610 const ImageIndex &textureIndex,
1611 FramebufferAttachmentObject *resource,
1612 GLsizei numViews,
1613 GLint baseViewIndex)
1614{
1615 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1616 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1617 FramebufferAttachment::kDefaultViewportOffsets);
1618}
1619
Martin Radev5dae57b2017-07-14 16:15:55 +03001620void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1621 GLenum type,
1622 GLenum binding,
1623 const ImageIndex &textureIndex,
1624 FramebufferAttachmentObject *resource,
1625 GLsizei numViews,
1626 const GLint *viewportOffsets)
1627{
1628 setAttachment(context, type, binding, textureIndex, resource, numViews,
1629 FramebufferAttachment::kDefaultBaseViewIndex,
1630 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1631}
1632
1633void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1634 GLsizei numViews,
1635 GLuint baseViewIndex,
1636 GLenum multiviewLayout,
1637 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001638{
1639 int count = 0;
1640
1641 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1642 &mState.mWebGLDepthAttachment,
1643 &mState.mWebGLStencilAttachment}};
1644 for (FramebufferAttachment *attachment : attachments)
1645 {
1646 if (attachment->isAttached())
1647 {
1648 count++;
1649 }
1650 }
1651
1652 mState.mWebGLDepthStencilConsistent = (count <= 1);
1653 if (!mState.mWebGLDepthStencilConsistent)
1654 {
1655 // Inconsistent.
1656 return;
1657 }
1658
Geoff Lange466c552017-03-17 15:24:12 -04001659 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1660 if (attachment.type() == GL_TEXTURE)
1661 {
1662 return attachment.getTextureImageIndex();
1663 }
1664 else
1665 {
Jamie Madillcc129372018-04-12 09:13:18 -04001666 return ImageIndex();
Geoff Lange466c552017-03-17 15:24:12 -04001667 }
1668 };
1669
Jamie Madilla02315b2017-02-23 14:14:47 -05001670 if (mState.mWebGLDepthAttachment.isAttached())
1671 {
1672 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001673 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001674 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1675 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madillcc129372018-04-12 09:13:18 -04001676 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1677 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001678 }
1679 else if (mState.mWebGLStencilAttachment.isAttached())
1680 {
1681 const auto &stencil = mState.mWebGLStencilAttachment;
Jamie Madillcc129372018-04-12 09:13:18 -04001682 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1683 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001684 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001685 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1686 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001687 }
1688 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1689 {
1690 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001691 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001692 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001693 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1694 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001695 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001696 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001697 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1698 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001699 }
1700 else
1701 {
Jamie Madillcc129372018-04-12 09:13:18 -04001702 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1703 baseViewIndex, multiviewLayout, viewportOffsets);
1704 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1705 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001706 }
1707}
1708
Jamie Madill4928b7c2017-06-20 12:57:39 -04001709void Framebuffer::setAttachmentImpl(const Context *context,
1710 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001711 GLenum binding,
1712 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001713 FramebufferAttachmentObject *resource,
1714 GLsizei numViews,
1715 GLuint baseViewIndex,
1716 GLenum multiviewLayout,
1717 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001718{
Jamie Madilla02315b2017-02-23 14:14:47 -05001719 switch (binding)
1720 {
Jamie Madillb8126692017-04-05 11:22:17 -04001721 case GL_DEPTH_STENCIL:
1722 case GL_DEPTH_STENCIL_ATTACHMENT:
1723 {
1724 // ensure this is a legitimate depth+stencil format
1725 FramebufferAttachmentObject *attachmentObj = resource;
1726 if (resource)
1727 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001728 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001729 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1730 {
1731 // Attaching nullptr detaches the current attachment.
1732 attachmentObj = nullptr;
1733 }
1734 }
1735
Jamie Madill4928b7c2017-06-20 12:57:39 -04001736 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001737 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001738 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1739 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001740 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001741 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001742 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1743 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001744 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001745 }
1746
Jamie Madilla02315b2017-02-23 14:14:47 -05001747 case GL_DEPTH:
1748 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001749 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001750 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1751 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001752 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001753
Jamie Madilla02315b2017-02-23 14:14:47 -05001754 case GL_STENCIL:
1755 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001756 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001757 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1758 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001759 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001760
Jamie Madilla02315b2017-02-23 14:14:47 -05001761 case GL_BACK:
Geoff Lang8170eab2017-09-21 13:59:04 -04001762 updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1763 &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1764 resource, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001765 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001766
Jamie Madilla02315b2017-02-23 14:14:47 -05001767 default:
1768 {
1769 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1770 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001771 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001772 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001773 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001774 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1775 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001776
Corentin Walleze7557742017-06-01 13:09:57 -04001777 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1778 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001779 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1780 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Brandon Jones76746f92017-11-22 11:44:41 -08001781 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -04001782 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001783 break;
Geoff Langab75a052014-10-15 12:56:37 -04001784 }
Jamie Madill42975642017-10-12 12:31:51 -04001785
1786 mAttachedTextures.reset();
Geoff Langab75a052014-10-15 12:56:37 -04001787}
1788
Jamie Madill4928b7c2017-06-20 12:57:39 -04001789void Framebuffer::updateAttachment(const Context *context,
1790 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001791 size_t dirtyBit,
Jamie Madilld4442552018-02-27 22:03:47 -05001792 angle::ObserverBinding *onDirtyBinding,
Jamie Madillb8126692017-04-05 11:22:17 -04001793 GLenum type,
1794 GLenum binding,
1795 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001796 FramebufferAttachmentObject *resource,
1797 GLsizei numViews,
1798 GLuint baseViewIndex,
1799 GLenum multiviewLayout,
1800 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001801{
Martin Radev5dae57b2017-07-14 16:15:55 +03001802 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1803 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001804 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001805 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madill888081d2018-02-27 00:24:46 -05001806 onDirtyBinding->bind(resource ? resource->getSubject() : nullptr);
Jamie Madille98b1b52018-03-08 09:47:23 -05001807
Jamie Madillb983a4b2018-08-01 11:34:51 -04001808 invalidateCompletenessCache(context);
Jamie Madillb8126692017-04-05 11:22:17 -04001809}
1810
Jamie Madilla02315b2017-02-23 14:14:47 -05001811void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001812{
Jamie Madillcc129372018-04-12 09:13:18 -04001813 setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001814}
1815
Jamie Madill19fa1c62018-03-08 09:47:21 -05001816Error Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001817{
1818 if (mDirtyBits.any())
1819 {
Jamie Madill888081d2018-02-27 00:24:46 -05001820 mDirtyBitsGuard = mDirtyBits;
Jamie Madill19fa1c62018-03-08 09:47:21 -05001821 ANGLE_TRY(mImpl->syncState(context, mDirtyBits));
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001822 mDirtyBits.reset();
Jamie Madill888081d2018-02-27 00:24:46 -05001823 mDirtyBitsGuard.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001824 }
Jamie Madill19fa1c62018-03-08 09:47:21 -05001825 return NoError();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001826}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001827
Jamie Madilld4442552018-02-27 22:03:47 -05001828void Framebuffer::onSubjectStateChange(const Context *context,
1829 angle::SubjectIndex index,
1830 angle::SubjectMessage message)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001831{
Jamie Madill888081d2018-02-27 00:24:46 -05001832 if (message == angle::SubjectMessage::DEPENDENT_DIRTY_BITS)
1833 {
1834 ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
1835 mDirtyBits.set(index);
Jamie Madilla11819d2018-07-30 10:26:01 -04001836 onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
Jamie Madill888081d2018-02-27 00:24:46 -05001837 return;
1838 }
1839
Jamie Madillb983a4b2018-08-01 11:34:51 -04001840 invalidateCompletenessCache(context);
Jamie Madill05b35b22017-10-03 09:01:44 -04001841
Jamie Madilld4442552018-02-27 22:03:47 -05001842 FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
1843
Jamie Madill05b35b22017-10-03 09:01:44 -04001844 // Mark the appropriate init flag.
Jamie Madilld4442552018-02-27 22:03:47 -05001845 mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
1846}
1847
1848FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
1849{
1850 switch (index)
1851 {
1852 case DIRTY_BIT_DEPTH_ATTACHMENT:
1853 return &mState.mDepthAttachment;
1854 case DIRTY_BIT_STENCIL_ATTACHMENT:
1855 return &mState.mStencilAttachment;
1856 default:
1857 size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
1858 ASSERT(colorIndex < mState.mColorAttachments.size());
1859 return &mState.mColorAttachments[colorIndex];
1860 }
Jamie Madill51f40ec2016-06-15 14:06:00 -04001861}
1862
Jamie Madilla4595b82017-01-11 17:36:34 -05001863bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1864{
1865 const Program *program = state.getProgram();
1866
1867 // TODO(jmadill): Default framebuffer feedback loops.
Jamie Madill2274b652018-05-31 10:56:08 -04001868 if (mState.mId == 0)
Jamie Madilla4595b82017-01-11 17:36:34 -05001869 {
1870 return false;
1871 }
1872
1873 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001874 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001875 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001876 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1877 ASSERT(attachment.isAttached());
1878 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001879 {
1880 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001881 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001882 {
1883 return true;
1884 }
1885 }
1886 }
1887
Jamie Madill1d37bc52017-02-02 19:59:58 -05001888 // Validate depth-stencil feedback loop.
1889 const auto &dsState = state.getDepthStencilState();
1890
1891 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1892 const FramebufferAttachment *depth = getDepthbuffer();
1893 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1894 {
1895 if (program->samplesFromTexture(state, depth->id()))
1896 {
1897 return true;
1898 }
1899 }
1900
Jamie Madill1d37bc52017-02-02 19:59:58 -05001901 const FramebufferAttachment *stencil = getStencilbuffer();
Ken Russellb9f92502018-01-27 19:00:26 -08001902 if (dsState.stencilTest && stencil)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001903 {
Ken Russellb9f92502018-01-27 19:00:26 -08001904 GLuint stencilSize = stencil->getStencilSize();
1905 ASSERT(stencilSize <= 8);
1906 GLuint maxStencilValue = (1 << stencilSize) - 1;
1907 // We assume the front and back masks are the same for WebGL.
1908 ASSERT((dsState.stencilBackWritemask & maxStencilValue) ==
1909 (dsState.stencilWritemask & maxStencilValue));
1910 if (stencil->type() == GL_TEXTURE && dsState.stencilWritemask != 0)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001911 {
Ken Russellb9f92502018-01-27 19:00:26 -08001912 // Skip the feedback loop check if depth/stencil point to the same resource.
1913 if (!depth || *stencil != *depth)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001914 {
Ken Russellb9f92502018-01-27 19:00:26 -08001915 if (program->samplesFromTexture(state, stencil->id()))
1916 {
1917 return true;
1918 }
Jamie Madill1d37bc52017-02-02 19:59:58 -05001919 }
1920 }
1921 }
1922
Jamie Madilla4595b82017-01-11 17:36:34 -05001923 return false;
1924}
1925
Jamie Madillfd3dd432017-02-02 19:59:59 -05001926bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1927 GLint copyTextureLevel,
1928 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001929{
Jamie Madill2274b652018-05-31 10:56:08 -04001930 if (mState.mId == 0)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001931 {
1932 // It seems impossible to form a texture copying feedback loop with the default FBO.
1933 return false;
1934 }
1935
1936 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1937 ASSERT(readAttachment);
1938
1939 if (readAttachment->isTextureWithId(copyTextureID))
1940 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001941 const auto &imageIndex = readAttachment->getTextureImageIndex();
Jamie Madillcc129372018-04-12 09:13:18 -04001942 if (imageIndex.getLevelIndex() == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001943 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001944 // Check 3D/Array texture layers.
Jamie Madillcc129372018-04-12 09:13:18 -04001945 return !imageIndex.hasLayer() || copyTextureLayer == ImageIndex::kEntireLevel ||
1946 imageIndex.getLayerIndex() == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001947 }
1948 }
1949 return false;
1950}
1951
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001952GLint Framebuffer::getDefaultWidth() const
1953{
1954 return mState.getDefaultWidth();
1955}
1956
1957GLint Framebuffer::getDefaultHeight() const
1958{
1959 return mState.getDefaultHeight();
1960}
1961
1962GLint Framebuffer::getDefaultSamples() const
1963{
1964 return mState.getDefaultSamples();
1965}
1966
Geoff Lang92019432017-11-20 13:09:34 -05001967bool Framebuffer::getDefaultFixedSampleLocations() const
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001968{
1969 return mState.getDefaultFixedSampleLocations();
1970}
1971
Jiawei Shaob1e91382018-05-17 14:33:55 +08001972GLint Framebuffer::getDefaultLayers() const
1973{
1974 return mState.getDefaultLayers();
1975}
1976
Jamie Madillb983a4b2018-08-01 11:34:51 -04001977void Framebuffer::setDefaultWidth(const Context *context, GLint defaultWidth)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001978{
1979 mState.mDefaultWidth = defaultWidth;
1980 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
Jamie Madillb983a4b2018-08-01 11:34:51 -04001981 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001982}
1983
Jamie Madillb983a4b2018-08-01 11:34:51 -04001984void Framebuffer::setDefaultHeight(const Context *context, GLint defaultHeight)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001985{
1986 mState.mDefaultHeight = defaultHeight;
1987 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
Jamie Madillb983a4b2018-08-01 11:34:51 -04001988 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001989}
1990
Jamie Madillb983a4b2018-08-01 11:34:51 -04001991void Framebuffer::setDefaultSamples(const Context *context, GLint defaultSamples)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001992{
1993 mState.mDefaultSamples = defaultSamples;
1994 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
Jamie Madillb983a4b2018-08-01 11:34:51 -04001995 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001996}
1997
Jamie Madillb983a4b2018-08-01 11:34:51 -04001998void Framebuffer::setDefaultFixedSampleLocations(const Context *context,
1999 bool defaultFixedSampleLocations)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08002000{
2001 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
2002 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
Jamie Madillb983a4b2018-08-01 11:34:51 -04002003 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08002004}
2005
Jiawei Shaob1e91382018-05-17 14:33:55 +08002006void Framebuffer::setDefaultLayers(GLint defaultLayers)
2007{
2008 mState.mDefaultLayers = defaultLayers;
2009 mDirtyBits.set(DIRTY_BIT_DEFAULT_LAYERS);
2010}
2011
Martin Radev14a26ae2017-07-24 15:56:29 +03002012GLsizei Framebuffer::getNumViews() const
2013{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002014 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03002015}
2016
Martin Radev4e619f52017-08-09 11:50:06 +03002017GLint Framebuffer::getBaseViewIndex() const
2018{
2019 return mState.getBaseViewIndex();
2020}
2021
Martin Radev878c8b12017-07-28 09:51:04 +03002022const std::vector<Offset> *Framebuffer::getViewportOffsets() const
2023{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002024 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03002025}
2026
2027GLenum Framebuffer::getMultiviewLayout() const
2028{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002029 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03002030}
2031
Olli Etuaho8acb1b62018-07-30 16:20:54 +03002032bool Framebuffer::readDisallowedByMultiview() const
2033{
2034 return (mState.getMultiviewLayout() != GL_NONE && mState.getNumViews() > 1) ||
2035 mState.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
2036}
2037
Geoff Langd4fff502017-09-22 11:28:28 -04002038Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask)
2039{
2040 const auto &glState = context->getGLState();
2041 if (!context->isRobustResourceInitEnabled() || glState.isRasterizerDiscardEnabled())
2042 {
2043 return NoError();
2044 }
2045
Geoff Langa36483f2018-03-09 16:11:21 -05002046 const BlendState &blend = glState.getBlendState();
2047 const DepthStencilState &depthStencil = glState.getDepthStencilState();
Geoff Langd4fff502017-09-22 11:28:28 -04002048
2049 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
2050 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
2051 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
2052
2053 if (!color && !depth && !stencil)
2054 {
2055 return NoError();
2056 }
2057
2058 if (partialClearNeedsInit(context, color, depth, stencil))
2059 {
2060 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
2061 }
2062
2063 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2064 // still be marked initialized. This simplifies design, allowing this method to be called before
2065 // the clear.
2066 markDrawAttachmentsInitialized(color, depth, stencil);
2067
2068 return NoError();
2069}
2070
2071Error Framebuffer::ensureClearBufferAttachmentsInitialized(const Context *context,
2072 GLenum buffer,
2073 GLint drawbuffer)
2074{
2075 if (!context->isRobustResourceInitEnabled() ||
2076 context->getGLState().isRasterizerDiscardEnabled() ||
2077 IsClearBufferMaskedOut(context, buffer))
2078 {
2079 return NoError();
2080 }
2081
2082 if (partialBufferClearNeedsInit(context, buffer))
2083 {
2084 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
2085 }
2086
2087 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2088 // still be marked initialized. This simplifies design, allowing this method to be called before
2089 // the clear.
2090 markBufferInitialized(buffer, drawbuffer);
2091
2092 return NoError();
2093}
2094
Jamie Madill05b35b22017-10-03 09:01:44 -04002095Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
2096{
2097 if (!context->isRobustResourceInitEnabled())
2098 {
2099 return NoError();
2100 }
2101
2102 // Note: we don't actually filter by the draw attachment enum. Just init everything.
2103 for (size_t bit : mState.mResourceNeedsInit)
2104 {
2105 switch (bit)
2106 {
2107 case DIRTY_BIT_DEPTH_ATTACHMENT:
2108 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2109 break;
2110 case DIRTY_BIT_STENCIL_ATTACHMENT:
2111 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2112 break;
2113 default:
2114 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2115 break;
2116 }
2117 }
2118
2119 mState.mResourceNeedsInit.reset();
2120 return NoError();
2121}
2122
2123Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
2124{
2125 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2126 {
2127 return NoError();
2128 }
2129
2130 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
2131 {
2132 size_t readIndex = mState.getReadIndex();
2133 if (mState.mResourceNeedsInit[readIndex])
2134 {
2135 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2136 mState.mResourceNeedsInit.reset(readIndex);
2137 }
2138 }
2139
2140 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
2141 {
2142 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2143 {
2144 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2145 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2146 }
2147 }
2148
2149 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
2150 {
2151 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2152 {
2153 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2154 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2155 }
2156 }
2157
2158 return NoError();
2159}
2160
2161void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2162{
2163 // Mark attachments as initialized.
2164 if (color)
2165 {
2166 for (auto colorIndex : mState.mEnabledDrawBuffers)
2167 {
2168 auto &colorAttachment = mState.mColorAttachments[colorIndex];
2169 ASSERT(colorAttachment.isAttached());
2170 colorAttachment.setInitState(InitState::Initialized);
2171 mState.mResourceNeedsInit.reset(colorIndex);
2172 }
2173 }
2174
2175 if (depth && mState.mDepthAttachment.isAttached())
2176 {
2177 mState.mDepthAttachment.setInitState(InitState::Initialized);
2178 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2179 }
2180
2181 if (stencil && mState.mStencilAttachment.isAttached())
2182 {
2183 mState.mStencilAttachment.setInitState(InitState::Initialized);
2184 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2185 }
2186}
2187
2188void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2189{
2190 switch (bufferType)
2191 {
2192 case GL_COLOR:
2193 {
2194 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2195 if (mState.mColorAttachments[bufferIndex].isAttached())
2196 {
2197 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2198 mState.mResourceNeedsInit.reset(bufferIndex);
2199 }
2200 break;
2201 }
2202 case GL_DEPTH:
2203 {
2204 if (mState.mDepthAttachment.isAttached())
2205 {
2206 mState.mDepthAttachment.setInitState(InitState::Initialized);
2207 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2208 }
2209 break;
2210 }
2211 case GL_STENCIL:
2212 {
2213 if (mState.mStencilAttachment.isAttached())
2214 {
2215 mState.mStencilAttachment.setInitState(InitState::Initialized);
2216 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2217 }
2218 break;
2219 }
2220 case GL_DEPTH_STENCIL:
2221 {
2222 if (mState.mDepthAttachment.isAttached())
2223 {
2224 mState.mDepthAttachment.setInitState(InitState::Initialized);
2225 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2226 }
2227 if (mState.mStencilAttachment.isAttached())
2228 {
2229 mState.mStencilAttachment.setInitState(InitState::Initialized);
2230 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2231 }
2232 break;
2233 }
2234 default:
2235 UNREACHABLE();
2236 break;
2237 }
2238}
2239
2240Box Framebuffer::getDimensions() const
2241{
2242 return mState.getDimensions();
2243}
2244
2245Error Framebuffer::ensureBufferInitialized(const Context *context,
2246 GLenum bufferType,
2247 GLint bufferIndex)
2248{
2249 ASSERT(context->isRobustResourceInitEnabled());
2250
2251 if (mState.mResourceNeedsInit.none())
2252 {
2253 return NoError();
2254 }
2255
2256 switch (bufferType)
2257 {
2258 case GL_COLOR:
2259 {
2260 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2261 if (mState.mResourceNeedsInit[bufferIndex])
2262 {
2263 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2264 mState.mResourceNeedsInit.reset(bufferIndex);
2265 }
2266 break;
2267 }
2268 case GL_DEPTH:
2269 {
2270 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2271 {
2272 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2273 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2274 }
2275 break;
2276 }
2277 case GL_STENCIL:
2278 {
2279 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2280 {
2281 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2282 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2283 }
2284 break;
2285 }
2286 case GL_DEPTH_STENCIL:
2287 {
2288 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2289 {
2290 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2291 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2292 }
2293 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2294 {
2295 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2296 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2297 }
2298 break;
2299 }
2300 default:
2301 UNREACHABLE();
2302 break;
2303 }
2304
2305 return NoError();
2306}
2307
2308bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2309{
2310 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2311 {
2312 return false;
2313 }
2314
2315 switch (bufferType)
2316 {
2317 case GL_COLOR:
2318 return partialClearNeedsInit(context, true, false, false);
2319 case GL_DEPTH:
2320 return partialClearNeedsInit(context, false, true, false);
2321 case GL_STENCIL:
2322 return partialClearNeedsInit(context, false, false, true);
2323 case GL_DEPTH_STENCIL:
2324 return partialClearNeedsInit(context, false, true, true);
2325 default:
2326 UNREACHABLE();
2327 return false;
2328 }
2329}
2330
Jamie Madill42975642017-10-12 12:31:51 -04002331bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2332{
2333 if (!mAttachedTextures.valid())
2334 {
Geoff Langb8430dd2018-08-01 15:27:18 -04002335 FramebufferTextureAttachmentVector attachedTextures;
Jamie Madill42975642017-10-12 12:31:51 -04002336
2337 for (const auto &colorAttachment : mState.mColorAttachments)
2338 {
2339 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2340 {
Geoff Langb8430dd2018-08-01 15:27:18 -04002341 attachedTextures.push_back(colorAttachment.getResource());
Jamie Madill42975642017-10-12 12:31:51 -04002342 }
2343 }
2344
2345 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2346 {
Geoff Langb8430dd2018-08-01 15:27:18 -04002347 attachedTextures.push_back(mState.mDepthAttachment.getResource());
Jamie Madill42975642017-10-12 12:31:51 -04002348 }
2349
2350 if (mState.mStencilAttachment.isAttached() &&
2351 mState.mStencilAttachment.type() == GL_TEXTURE)
2352 {
Geoff Langb8430dd2018-08-01 15:27:18 -04002353 attachedTextures.push_back(mState.mStencilAttachment.getResource());
Jamie Madill42975642017-10-12 12:31:51 -04002354 }
2355
2356 mAttachedTextures = std::move(attachedTextures);
2357 }
2358
Geoff Langb8430dd2018-08-01 15:27:18 -04002359 return std::find(mAttachedTextures.value().begin(), mAttachedTextures.value().end(), texture) !=
2360 mAttachedTextures.value().end();
Jamie Madill42975642017-10-12 12:31:51 -04002361}
2362
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002363} // namespace gl