blob: 48249f3c6aa6cc89fc0a1c3419b2ec8392288a0c [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
Jamie Madill6f755b22018-10-09 12:48:54 -0400218angle::Result InitAttachment(const Context *context, FramebufferAttachment *attachment)
Jamie Madill05b35b22017-10-03 09:01:44 -0400219{
220 ASSERT(attachment->isAttached());
221 if (attachment->initState() == InitState::MayNeedInit)
222 {
223 ANGLE_TRY(attachment->initializeContents(context));
224 }
Jamie Madill6f755b22018-10-09 12:48:54 -0400225 return angle::Result::Continue();
Jamie Madill05b35b22017-10-03 09:01:44 -0400226}
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 +0300590const std::vector<Offset> *FramebufferState::getViewportOffsets() const
591{
592 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
593 if (attachment == nullptr)
594 {
595 return nullptr;
596 }
597 return &attachment->getMultiviewViewportOffsets();
598}
599
600GLenum FramebufferState::getMultiviewLayout() const
601{
602 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
603 if (attachment == nullptr)
604 {
605 return GL_NONE;
606 }
607 return attachment->getMultiviewLayout();
608}
609
Martin Radev4e619f52017-08-09 11:50:06 +0300610int FramebufferState::getBaseViewIndex() const
611{
612 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
613 if (attachment == nullptr)
614 {
615 return GL_NONE;
616 }
617 return attachment->getBaseViewIndex();
618}
619
Jamie Madill05b35b22017-10-03 09:01:44 -0400620Box FramebufferState::getDimensions() const
621{
622 ASSERT(attachmentsHaveSameDimensions());
623 ASSERT(getFirstNonNullAttachment() != nullptr);
624 Extents extents = getFirstNonNullAttachment()->getSize();
625 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
626}
627
Jamie Madill7aea7e02016-05-10 10:39:45 -0400628Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill2274b652018-05-31 10:56:08 -0400629 : mState(caps, id),
Jamie Madill362876b2016-06-16 14:46:59 -0400630 mImpl(factory->createFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400631 mCachedStatus(),
632 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
633 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634{
Corentin Wallez37c39792015-08-20 14:19:46 -0400635 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400636 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
637
Jamie Madill1e5499d2017-04-05 11:22:16 -0400638 for (uint32_t colorIndex = 0;
639 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400640 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400641 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400642 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400643}
644
Geoff Langbf7b95d2018-05-01 16:48:21 -0400645Framebuffer::Framebuffer(const Context *context, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400646 : mState(),
Geoff Langbf7b95d2018-05-01 16:48:21 -0400647 mImpl(surface->getImplementation()->createDefaultFramebuffer(context, mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400648 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
649 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
650 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400651{
Geoff Langda88add2014-12-01 10:22:01 -0500652 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400653 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500654
Geoff Langbf7b95d2018-05-01 16:48:21 -0400655 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400656 FramebufferAttachment::kDefaultNumViews,
Martin Radev5dae57b2017-07-14 16:15:55 +0300657 FramebufferAttachment::kDefaultBaseViewIndex,
658 FramebufferAttachment::kDefaultMultiviewLayout,
659 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500660
661 if (surface->getConfig()->depthSize > 0)
662 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400663 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400664 FramebufferAttachment::kDefaultNumViews,
Jamie Madilld4442552018-02-27 22:03:47 -0500665 FramebufferAttachment::kDefaultBaseViewIndex,
666 FramebufferAttachment::kDefaultMultiviewLayout,
667 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500668 }
669
670 if (surface->getConfig()->stencilSize > 0)
671 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400672 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400673 FramebufferAttachment::kDefaultNumViews,
674 FramebufferAttachment::kDefaultBaseViewIndex,
675 FramebufferAttachment::kDefaultMultiviewLayout,
676 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500677 }
Brandon Jones76746f92017-11-22 11:44:41 -0800678 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679}
680
Corentin Wallezccab69d2017-01-27 16:57:15 -0500681Framebuffer::Framebuffer(rx::GLImplFactory *factory)
682 : mState(),
683 mImpl(factory->createFramebuffer(mState)),
Corentin Wallezccab69d2017-01-27 16:57:15 -0500684 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
685 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
686 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
687{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400688 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Brandon Jones76746f92017-11-22 11:44:41 -0800689 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500690}
691
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000692Framebuffer::~Framebuffer()
693{
Geoff Langda88add2014-12-01 10:22:01 -0500694 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000695}
696
Jamie Madill4928b7c2017-06-20 12:57:39 -0400697void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500698{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400699 for (auto &attachment : mState.mColorAttachments)
700 {
701 attachment.detach(context);
702 }
703 mState.mDepthAttachment.detach(context);
704 mState.mStencilAttachment.detach(context);
705 mState.mWebGLDepthAttachment.detach(context);
706 mState.mWebGLStencilAttachment.detach(context);
707 mState.mWebGLDepthStencilAttachment.detach(context);
708
Jamie Madillc564c072017-06-01 12:45:42 -0400709 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500710}
711
Geoff Lang70d0f492015-12-10 17:45:46 -0500712void Framebuffer::setLabel(const std::string &label)
713{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400714 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500715}
716
717const std::string &Framebuffer::getLabel() const
718{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400719 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500720}
721
Jamie Madill8693bdb2017-09-02 15:32:14 -0400722bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000723{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400724 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000725}
726
Jamie Madill8693bdb2017-09-02 15:32:14 -0400727bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000728{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400729 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500730}
Jamie Madille261b442014-06-25 12:42:21 -0400731
Jamie Madill8693bdb2017-09-02 15:32:14 -0400732bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500733{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400734 bool found = false;
735
Jamie Madill362876b2016-06-16 14:46:59 -0400736 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500737 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400738 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
Olli Etuaho4ebd8f32018-09-20 11:12:46 +0300739 resourceId))
Jamie Madill8693bdb2017-09-02 15:32:14 -0400740 {
741 found = true;
742 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743 }
744
Jamie Madilla02315b2017-02-23 14:14:47 -0500745 if (context->isWebGL1())
746 {
747 const std::array<FramebufferAttachment *, 3> attachments = {
748 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
749 &mState.mWebGLStencilAttachment}};
750 for (FramebufferAttachment *attachment : attachments)
751 {
Olli Etuaho4ebd8f32018-09-20 11:12:46 +0300752 if (detachMatchingAttachment(context, attachment, resourceType, resourceId))
Jamie Madilla02315b2017-02-23 14:14:47 -0500753 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400754 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500755 }
756 }
757 }
758 else
759 {
Olli Etuaho4ebd8f32018-09-20 11:12:46 +0300760 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId))
Jamie Madill8693bdb2017-09-02 15:32:14 -0400761 {
762 found = true;
763 }
Olli Etuaho4ebd8f32018-09-20 11:12:46 +0300764 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId))
Jamie Madill8693bdb2017-09-02 15:32:14 -0400765 {
766 found = true;
767 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500768 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400769
770 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400771}
772
Jamie Madill8693bdb2017-09-02 15:32:14 -0400773bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400774 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400775 GLenum matchType,
Olli Etuaho4ebd8f32018-09-20 11:12:46 +0300776 GLuint matchId)
Jamie Madill362876b2016-06-16 14:46:59 -0400777{
778 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
779 {
Olli Etuaho4ebd8f32018-09-20 11:12:46 +0300780 // We go through resetAttachment to make sure that all the required bookkeeping will be done
781 // such as updating enabled draw buffer state.
782 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400783 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400784 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400785
786 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000787}
788
Corentin Wallez37c39792015-08-20 14:19:46 -0400789const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000790{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400791 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000792}
793
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400794const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400795{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400796 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400797}
798
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400799const FramebufferAttachment *Framebuffer::getStencilbuffer() const
800{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400801 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400802}
803
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400804const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
805{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400806 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400807}
808
809const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000810{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400811 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000812}
813
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500814const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
815{
816 return mState.getStencilOrDepthStencilAttachment();
817}
818
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400819const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000820{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400821 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000822}
823
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000824GLenum Framebuffer::getReadColorbufferType() const
825{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400826 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400827 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000828}
829
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400830const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000831{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400832 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000833}
834
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400835const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
836{
837 return mState.getFirstNonNullAttachment();
838}
839
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800840const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
841 GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000842{
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800843 return mState.getAttachment(context, attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400844}
845
Geoff Langa15472a2015-08-11 11:48:03 -0400846size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000847{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400848 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400849}
850
851GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
852{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400853 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
854 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000855}
856
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500857const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
858{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400859 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500860}
861
Geoff Lang164d54e2014-12-01 10:55:33 -0500862void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000863{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400864 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500865
866 ASSERT(count <= drawStates.size());
867 std::copy(buffers, buffers + count, drawStates.begin());
868 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500869 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500870
871 mState.mEnabledDrawBuffers.reset();
Brandon Jones76746f92017-11-22 11:44:41 -0800872 mState.mDrawBufferTypeMask.reset();
873
Jamie Madilla4595b82017-01-11 17:36:34 -0500874 for (size_t index = 0; index < count; ++index)
875 {
Brandon Jones76746f92017-11-22 11:44:41 -0800876 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
877
Jamie Madilla4595b82017-01-11 17:36:34 -0500878 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
879 {
880 mState.mEnabledDrawBuffers.set(index);
881 }
882 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500883}
884
Geoff Langa15472a2015-08-11 11:48:03 -0400885const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
886{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400887 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400888}
889
Geoff Lange0cff192017-05-30 13:04:56 -0400890GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
891{
892 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
893 if (attachment == nullptr)
894 {
895 return GL_NONE;
896 }
897
898 GLenum componentType = attachment->getFormat().info->componentType;
899 switch (componentType)
900 {
901 case GL_INT:
902 case GL_UNSIGNED_INT:
903 return componentType;
904
905 default:
906 return GL_FLOAT;
907 }
908}
909
Brandon Jonesc405ae72017-12-06 14:15:03 -0800910ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
Brandon Jones76746f92017-11-22 11:44:41 -0800911{
912 return mState.mDrawBufferTypeMask;
913}
914
915DrawBufferMask Framebuffer::getDrawBufferMask() const
916{
917 return mState.mEnabledDrawBuffers;
918}
919
Geoff Langa15472a2015-08-11 11:48:03 -0400920bool Framebuffer::hasEnabledDrawBuffer() const
921{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400922 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400923 {
924 if (getDrawBuffer(drawbufferIdx) != nullptr)
925 {
926 return true;
927 }
928 }
929
930 return false;
931}
932
Geoff Lang9dd95802014-12-01 11:12:59 -0500933GLenum Framebuffer::getReadBufferState() const
934{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400935 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500936}
937
938void Framebuffer::setReadBuffer(GLenum buffer)
939{
Jamie Madillb885e572015-02-03 16:16:04 -0500940 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
941 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400942 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
943 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500944 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000945}
946
Corentin Wallez37c39792015-08-20 14:19:46 -0400947size_t Framebuffer::getNumColorBuffers() const
948{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400949 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400950}
951
Jamie Madill0df8fe42015-11-24 16:10:24 -0500952bool Framebuffer::hasDepth() const
953{
Jamie Madill9c335862017-07-18 11:51:38 -0400954 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500955}
956
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000957bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000958{
Jamie Madill9c335862017-07-18 11:51:38 -0400959 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000960}
961
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000962bool Framebuffer::usingExtendedDrawBuffers() const
963{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400964 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000965 {
Geoff Langa15472a2015-08-11 11:48:03 -0400966 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000967 {
968 return true;
969 }
970 }
971
972 return false;
973}
974
Jamie Madillb983a4b2018-08-01 11:34:51 -0400975void Framebuffer::invalidateCompletenessCache(const Context *context)
Geoff Lang9aded172017-04-05 11:07:56 -0400976{
Jamie Madill2274b652018-05-31 10:56:08 -0400977 if (mState.mId != 0)
Geoff Lang9aded172017-04-05 11:07:56 -0400978 {
979 mCachedStatus.reset();
Jamie Madilld84b6732018-09-06 15:54:35 -0400980 onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
Geoff Lang9aded172017-04-05 11:07:56 -0400981 }
982}
983
Jamie Madillcc73f242018-08-01 11:34:48 -0400984GLenum Framebuffer::checkStatusImpl(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000985{
Jamie Madillcc73f242018-08-01 11:34:48 -0400986 ASSERT(!isDefault());
987 ASSERT(hasAnyDirtyBit() || !mCachedStatus.valid());
Geoff Lang528ce3c2014-12-01 10:44:07 -0500988
Jamie Madillcc73f242018-08-01 11:34:48 -0400989 mCachedStatus = checkStatusWithGLFrontEnd(context);
Jamie Madille98b1b52018-03-08 09:47:23 -0500990
Jamie Madillcc73f242018-08-01 11:34:48 -0400991 if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
992 {
993 Error err = syncState(context);
994 if (err.isError())
Jamie Madille98b1b52018-03-08 09:47:23 -0500995 {
Jamie Madillcc73f242018-08-01 11:34:48 -0400996 // TODO(jmadill): Remove when refactor complete. http://anglebug.com/2491
997 const_cast<Context *>(context)->handleError(err);
998 return GetDefaultReturnValue<EntryPoint::CheckFramebufferStatus, GLenum>();
999 }
1000 if (!mImpl->checkStatus(context))
1001 {
1002 mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
Jamie Madille98b1b52018-03-08 09:47:23 -05001003 }
Jamie Madill362876b2016-06-16 14:46:59 -04001004 }
1005
Jamie Madill427064d2018-04-13 16:20:34 -04001006 return mCachedStatus.value();
Jamie Madill362876b2016-06-16 14:46:59 -04001007}
1008
Jamie Madille98b1b52018-03-08 09:47:23 -05001009GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -04001010{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001011 const ContextState &state = context->getContextState();
1012
Jamie Madill2274b652018-05-31 10:56:08 -04001013 ASSERT(mState.mId != 0);
Jamie Madill362876b2016-06-16 14:46:59 -04001014
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001015 bool hasAttachments = false;
1016 Optional<unsigned int> colorbufferSize;
1017 Optional<int> samples;
Geoff Lang92019432017-11-20 13:09:34 -05001018 Optional<bool> fixedSampleLocations;
JiangYizhou461d9a32017-01-04 16:37:26 +08001019 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001020
Martin Radev9bc9a322017-07-21 14:28:17 +03001021 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
1022
Jiawei Shaoa8802472018-05-28 11:17:47 +08001023 Optional<bool> isLayered;
1024 Optional<TextureType> colorAttachmentsTextureType;
1025
Jamie Madill48ef11b2016-04-27 15:21:52 -04001026 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001027 {
Jamie Madill2d06b732015-04-20 12:53:28 -04001028 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001030 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001031 {
1032 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1033 }
daniel@transgaming.com01868132010-08-24 19:21:17 +00001034
Geoff Lang677bb6f2017-04-05 12:40:40 -04001035 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001036 if (format.depthBits > 0 || format.stencilBits > 0)
1037 {
1038 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1039 }
1040
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001041 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
1042 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001043 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001044 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001045 }
1046
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001047 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
1048 // in GLES 3.0, there is no such restriction
1049 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001050 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001051 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001052 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001053 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +00001054 {
1055 return GL_FRAMEBUFFER_UNSUPPORTED;
1056 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001057 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001058 else
1059 {
1060 colorbufferSize = format.pixelBytes;
1061 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001062 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001063
Martin Radev9bc9a322017-07-21 14:28:17 +03001064 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
1065 {
1066 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1067 }
1068
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001069 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001070
1071 if (!hasAttachments)
1072 {
1073 isLayered = colorAttachment.isLayered();
1074 if (isLayered.value())
1075 {
1076 colorAttachmentsTextureType = colorAttachment.getTextureImageIndex().getType();
1077 }
1078 hasAttachments = true;
1079 }
1080 else
1081 {
1082 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1083 // If any framebuffer attachment is layered, all populated attachments
1084 // must be layered. Additionally, all populated color attachments must
1085 // be from textures of the same target. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1086 ASSERT(isLayered.valid());
1087 if (isLayered.value() != colorAttachment.isLayered())
1088 {
1089 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1090 }
1091 else if (isLayered.value())
1092 {
1093 ASSERT(colorAttachmentsTextureType.valid());
1094 if (colorAttachmentsTextureType.value() !=
1095 colorAttachment.getTextureImageIndex().getType())
1096 {
1097 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1098 }
1099 }
1100 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001101 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001102 }
1103
Jamie Madill48ef11b2016-04-27 15:21:52 -04001104 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001105 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001106 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001107 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001108 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001109 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001110 }
1111
Geoff Lang677bb6f2017-04-05 12:40:40 -04001112 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001113 if (format.depthBits == 0)
1114 {
1115 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001116 }
1117
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001118 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1119 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001120 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001121 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001122 }
Sami Väisänena797e062016-05-12 15:23:40 +03001123
Martin Radev9bc9a322017-07-21 14:28:17 +03001124 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1125 {
1126 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1127 }
1128
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001129 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001130
1131 if (!hasAttachments)
1132 {
1133 isLayered = depthAttachment.isLayered();
1134 hasAttachments = true;
1135 }
1136 else
1137 {
1138 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1139 // If any framebuffer attachment is layered, all populated attachments
1140 // must be layered. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1141 ASSERT(isLayered.valid());
1142 if (isLayered.value() != depthAttachment.isLayered())
1143 {
1144 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1145 }
1146 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001147 }
1148
Jamie Madill48ef11b2016-04-27 15:21:52 -04001149 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001150 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001151 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001152 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001153 {
1154 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1155 }
1156
Geoff Lang677bb6f2017-04-05 12:40:40 -04001157 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001158 if (format.stencilBits == 0)
1159 {
1160 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001161 }
1162
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001163 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1164 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001165 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001166 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001167 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001168
Martin Radev9bc9a322017-07-21 14:28:17 +03001169 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1170 {
1171 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1172 }
1173
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001174 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001175
1176 if (!hasAttachments)
1177 {
1178 hasAttachments = true;
1179 }
1180 else
1181 {
1182 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1183 // If any framebuffer attachment is layered, all populated attachments
1184 // must be layered.
1185 // {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1186 ASSERT(isLayered.valid());
1187 if (isLayered.value() != stencilAttachment.isLayered())
1188 {
1189 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1190 }
1191 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001192 }
1193
1194 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1195 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1196 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1197 {
1198 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001199 }
1200
Jamie Madilla02315b2017-02-23 14:14:47 -05001201 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1202 if (state.isWebGL1())
1203 {
1204 if (!mState.mWebGLDepthStencilConsistent)
1205 {
1206 return GL_FRAMEBUFFER_UNSUPPORTED;
1207 }
1208
1209 if (mState.mWebGLDepthStencilAttachment.isAttached())
1210 {
1211 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1212 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1213 {
1214 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1215 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001216
1217 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1218 &mState.mWebGLDepthStencilAttachment))
1219 {
1220 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1221 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001222 }
1223 else if (mState.mStencilAttachment.isAttached() &&
1224 mState.mStencilAttachment.getDepthSize() > 0)
1225 {
1226 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1227 }
1228 else if (mState.mDepthAttachment.isAttached() &&
1229 mState.mDepthAttachment.getStencilSize() > 0)
1230 {
1231 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1232 }
1233 }
1234
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001235 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1236 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1237 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001238 GLint defaultWidth = mState.getDefaultWidth();
1239 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001240 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001241 {
1242 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001243 }
1244
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001245 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001246 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001247 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1248 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001249 {
1250 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1251 }
1252
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001253 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1254 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001255 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1256 {
1257 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1258 }
1259
Kenneth Russellce8602a2017-10-03 18:23:08 -07001260 // The WebGL conformance tests implicitly define that all framebuffer
1261 // attachments must be unique. For example, the same level of a texture can
1262 // not be attached to two different color attachments.
1263 if (state.getExtensions().webglCompatibility)
1264 {
1265 if (!mState.colorAttachmentsAreUniqueImages())
1266 {
1267 return GL_FRAMEBUFFER_UNSUPPORTED;
1268 }
1269 }
1270
Jamie Madillcc86d642015-11-24 13:00:07 -05001271 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001272}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001273
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001274angle::Result Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001275{
Jamie Madill05b35b22017-10-03 09:01:44 -04001276 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1277 // can be no-ops, so we should probably do that to ensure consistency.
1278 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1279
Jamie Madill4928b7c2017-06-20 12:57:39 -04001280 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001281}
1282
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001283angle::Result Framebuffer::invalidate(const Context *context,
1284 size_t count,
1285 const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001286{
Jamie Madill05b35b22017-10-03 09:01:44 -04001287 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1288 // can be no-ops, so we should probably do that to ensure consistency.
1289 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1290
Jamie Madill4928b7c2017-06-20 12:57:39 -04001291 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001292}
1293
Jamie Madill05b35b22017-10-03 09:01:44 -04001294bool Framebuffer::partialClearNeedsInit(const Context *context,
1295 bool color,
1296 bool depth,
1297 bool stencil)
1298{
1299 const auto &glState = context->getGLState();
1300
1301 if (!glState.isRobustResourceInitEnabled())
1302 {
1303 return false;
1304 }
1305
1306 // Scissors can affect clearing.
1307 // TODO(jmadill): Check for complete scissor overlap.
1308 if (glState.isScissorTestEnabled())
1309 {
1310 return true;
1311 }
1312
1313 // If colors masked, we must clear before we clear. Do a simple check.
1314 // TODO(jmadill): Filter out unused color channels from the test.
1315 if (color)
1316 {
1317 const auto &blend = glState.getBlendState();
1318 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1319 blend.colorMaskAlpha))
1320 {
1321 return true;
1322 }
1323 }
1324
1325 const auto &depthStencil = glState.getDepthStencilState();
Yuly Novikov21edf3d2018-07-23 16:44:16 -04001326 if (stencil && (depthStencil.stencilMask != depthStencil.stencilWritemask ||
1327 depthStencil.stencilBackMask != depthStencil.stencilBackWritemask))
Jamie Madill05b35b22017-10-03 09:01:44 -04001328 {
1329 return true;
1330 }
1331
1332 return false;
1333}
1334
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001335angle::Result Framebuffer::invalidateSub(const Context *context,
1336 size_t count,
1337 const GLenum *attachments,
1338 const Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001339{
Jamie Madill05b35b22017-10-03 09:01:44 -04001340 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1341 // can be no-ops, so we should probably do that to ensure consistency.
1342 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1343
Jamie Madill4928b7c2017-06-20 12:57:39 -04001344 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001345}
1346
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001347angle::Result Framebuffer::clear(const Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001348{
Jamie Madill05b35b22017-10-03 09:01:44 -04001349 const auto &glState = context->getGLState();
1350 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001351 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001352 return angle::Result::Continue();
Jamie Madill984ef412015-11-24 16:10:21 -05001353 }
1354
Jamie Madill05b35b22017-10-03 09:01:44 -04001355 ANGLE_TRY(mImpl->clear(context, mask));
1356
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001357 return angle::Result::Continue();
Geoff Langb04dc822014-12-01 12:02:02 -05001358}
1359
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001360angle::Result Framebuffer::clearBufferfv(const Context *context,
1361 GLenum buffer,
1362 GLint drawbuffer,
1363 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001364{
Jamie Madill05b35b22017-10-03 09:01:44 -04001365 if (context->getGLState().isRasterizerDiscardEnabled() ||
1366 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001367 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001368 return angle::Result::Continue();
Jamie Madill984ef412015-11-24 16:10:21 -05001369 }
1370
Jamie Madill05b35b22017-10-03 09:01:44 -04001371 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1372
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001373 return angle::Result::Continue();
Geoff Langb04dc822014-12-01 12:02:02 -05001374}
1375
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001376angle::Result Framebuffer::clearBufferuiv(const Context *context,
1377 GLenum buffer,
1378 GLint drawbuffer,
1379 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001380{
Jamie Madill05b35b22017-10-03 09:01:44 -04001381 if (context->getGLState().isRasterizerDiscardEnabled() ||
1382 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001383 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001384 return angle::Result::Continue();
Jamie Madill984ef412015-11-24 16:10:21 -05001385 }
1386
Jamie Madill05b35b22017-10-03 09:01:44 -04001387 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1388
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001389 return angle::Result::Continue();
Geoff Langb04dc822014-12-01 12:02:02 -05001390}
1391
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001392angle::Result Framebuffer::clearBufferiv(const Context *context,
1393 GLenum buffer,
1394 GLint drawbuffer,
1395 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001396{
Jamie Madill05b35b22017-10-03 09:01:44 -04001397 if (context->getGLState().isRasterizerDiscardEnabled() ||
1398 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001399 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001400 return angle::Result::Continue();
Jamie Madill984ef412015-11-24 16:10:21 -05001401 }
1402
Jamie Madill05b35b22017-10-03 09:01:44 -04001403 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1404
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001405 return angle::Result::Continue();
Geoff Langb04dc822014-12-01 12:02:02 -05001406}
1407
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001408angle::Result Framebuffer::clearBufferfi(const Context *context,
1409 GLenum buffer,
1410 GLint drawbuffer,
1411 GLfloat depth,
1412 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001413{
Jamie Madill05b35b22017-10-03 09:01:44 -04001414 if (context->getGLState().isRasterizerDiscardEnabled() ||
1415 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001416 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001417 return angle::Result::Continue();
Jamie Madill984ef412015-11-24 16:10:21 -05001418 }
1419
Jamie Madill05b35b22017-10-03 09:01:44 -04001420 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1421
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001422 return angle::Result::Continue();
Geoff Langb04dc822014-12-01 12:02:02 -05001423}
1424
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001425angle::Result Framebuffer::getImplementationColorReadFormat(const Context *context,
1426 GLenum *formatOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001427{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001428 ANGLE_TRY(syncState(context));
1429 *formatOut = mImpl->getImplementationColorReadFormat(context);
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001430 return angle::Result::Continue();
Geoff Langbce529e2014-12-01 12:48:41 -05001431}
1432
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001433angle::Result Framebuffer::getImplementationColorReadType(const Context *context, GLenum *typeOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001434{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001435 ANGLE_TRY(syncState(context));
1436 *typeOut = mImpl->getImplementationColorReadType(context);
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001437 return angle::Result::Continue();
Geoff Langbce529e2014-12-01 12:48:41 -05001438}
1439
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001440angle::Result Framebuffer::readPixels(const Context *context,
1441 const Rectangle &area,
1442 GLenum format,
1443 GLenum type,
1444 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001445{
Jamie Madill05b35b22017-10-03 09:01:44 -04001446 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001447 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001448
Jamie Madilld4442552018-02-27 22:03:47 -05001449 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001450 if (unpackBuffer)
1451 {
Jamie Madill09463932018-04-04 05:26:59 -04001452 unpackBuffer->onPixelPack(context);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001453 }
1454
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001455 return angle::Result::Continue();
Geoff Langbce529e2014-12-01 12:48:41 -05001456}
1457
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001458angle::Result Framebuffer::blit(const Context *context,
1459 const Rectangle &sourceArea,
1460 const Rectangle &destArea,
1461 GLbitfield mask,
1462 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001463{
He Yunchao6be602d2016-12-22 14:33:07 +08001464 GLbitfield blitMask = mask;
1465
1466 // Note that blitting is called against draw framebuffer.
1467 // See the code in gl::Context::blitFramebuffer.
1468 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1469 {
1470 blitMask &= ~GL_COLOR_BUFFER_BIT;
1471 }
1472
1473 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1474 {
1475 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1476 }
1477
1478 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1479 {
1480 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1481 }
1482
1483 if (!blitMask)
1484 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001485 return angle::Result::Continue();
He Yunchao6be602d2016-12-22 14:33:07 +08001486 }
1487
Jamie Madill05b35b22017-10-03 09:01:44 -04001488 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1489 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1490
1491 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1492 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1493
He Yunchao6be602d2016-12-22 14:33:07 +08001494 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001495}
1496
Luc Ferronbf6dc372018-06-28 15:24:19 -04001497bool Framebuffer::isDefault() const
1498{
1499 return id() == 0;
1500}
1501
Jamie Madill427064d2018-04-13 16:20:34 -04001502int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001503{
Jamie Madill427064d2018-04-13 16:20:34 -04001504 return (isComplete(context) ? getCachedSamples(context) : 0);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001505}
1506
Jamie Madill9c335862017-07-18 11:51:38 -04001507int Framebuffer::getCachedSamples(const Context *context)
1508{
Jamie Madill5b772312018-03-08 20:28:32 -05001509 ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
1510
Jamie Madill9c335862017-07-18 11:51:38 -04001511 // For a complete framebuffer, all attachments must have the same sample count.
1512 // In this case return the first nonzero sample size.
1513 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1514 if (firstNonNullAttachment)
1515 {
1516 ASSERT(firstNonNullAttachment->isAttached());
1517 return firstNonNullAttachment->getSamples();
1518 }
1519
1520 // No attachments found.
1521 return 0;
1522}
1523
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001524angle::Result Framebuffer::getSamplePosition(const Context *context,
1525 size_t index,
1526 GLfloat *xy) const
Corentin Wallezccab69d2017-01-27 16:57:15 -05001527{
Geoff Lang13455072018-05-09 11:24:43 -04001528 ANGLE_TRY(mImpl->getSamplePosition(context, index, xy));
Jamie Madill64b7c4f2018-10-19 11:38:04 -04001529 return angle::Result::Continue();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001530}
1531
Jamie Madille261b442014-06-25 12:42:21 -04001532bool Framebuffer::hasValidDepthStencil() const
1533{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001534 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001535}
1536
Jamie Madilla02315b2017-02-23 14:14:47 -05001537void Framebuffer::setAttachment(const Context *context,
1538 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001539 GLenum binding,
1540 const ImageIndex &textureIndex,
1541 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001542{
Martin Radev5dae57b2017-07-14 16:15:55 +03001543 setAttachment(context, type, binding, textureIndex, resource,
1544 FramebufferAttachment::kDefaultNumViews,
1545 FramebufferAttachment::kDefaultBaseViewIndex,
1546 FramebufferAttachment::kDefaultMultiviewLayout,
1547 FramebufferAttachment::kDefaultViewportOffsets);
1548}
1549
1550void Framebuffer::setAttachment(const Context *context,
1551 GLenum type,
1552 GLenum binding,
1553 const ImageIndex &textureIndex,
1554 FramebufferAttachmentObject *resource,
1555 GLsizei numViews,
1556 GLuint baseViewIndex,
1557 GLenum multiviewLayout,
1558 const GLint *viewportOffsets)
1559{
Jamie Madilla02315b2017-02-23 14:14:47 -05001560 // Context may be null in unit tests.
1561 if (!context || !context->isWebGL1())
1562 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001563 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1564 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001565 return;
1566 }
1567
1568 switch (binding)
1569 {
1570 case GL_DEPTH_STENCIL:
1571 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001572 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001573 resource, numViews, baseViewIndex,
1574 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001575 break;
1576 case GL_DEPTH:
1577 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001578 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1579 numViews, baseViewIndex, multiviewLayout,
1580 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001581 break;
1582 case GL_STENCIL:
1583 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001584 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1585 numViews, baseViewIndex, multiviewLayout,
1586 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001587 break;
1588 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001589 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1590 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001591 return;
1592 }
1593
Martin Radev5dae57b2017-07-14 16:15:55 +03001594 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1595 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001596}
1597
Martin Radev82ef7742017-08-08 17:44:58 +03001598void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1599 GLenum type,
1600 GLenum binding,
1601 const ImageIndex &textureIndex,
1602 FramebufferAttachmentObject *resource,
1603 GLsizei numViews,
1604 GLint baseViewIndex)
1605{
1606 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1607 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1608 FramebufferAttachment::kDefaultViewportOffsets);
1609}
1610
Martin Radev5dae57b2017-07-14 16:15:55 +03001611void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1612 GLenum type,
1613 GLenum binding,
1614 const ImageIndex &textureIndex,
1615 FramebufferAttachmentObject *resource,
1616 GLsizei numViews,
1617 const GLint *viewportOffsets)
1618{
1619 setAttachment(context, type, binding, textureIndex, resource, numViews,
1620 FramebufferAttachment::kDefaultBaseViewIndex,
1621 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1622}
1623
1624void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1625 GLsizei numViews,
1626 GLuint baseViewIndex,
1627 GLenum multiviewLayout,
1628 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001629{
1630 int count = 0;
1631
1632 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1633 &mState.mWebGLDepthAttachment,
1634 &mState.mWebGLStencilAttachment}};
1635 for (FramebufferAttachment *attachment : attachments)
1636 {
1637 if (attachment->isAttached())
1638 {
1639 count++;
1640 }
1641 }
1642
1643 mState.mWebGLDepthStencilConsistent = (count <= 1);
1644 if (!mState.mWebGLDepthStencilConsistent)
1645 {
1646 // Inconsistent.
1647 return;
1648 }
1649
Geoff Lange466c552017-03-17 15:24:12 -04001650 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1651 if (attachment.type() == GL_TEXTURE)
1652 {
1653 return attachment.getTextureImageIndex();
1654 }
1655 else
1656 {
Jamie Madillcc129372018-04-12 09:13:18 -04001657 return ImageIndex();
Geoff Lange466c552017-03-17 15:24:12 -04001658 }
1659 };
1660
Jamie Madilla02315b2017-02-23 14:14:47 -05001661 if (mState.mWebGLDepthAttachment.isAttached())
1662 {
1663 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001664 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001665 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1666 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madillcc129372018-04-12 09:13:18 -04001667 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1668 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001669 }
1670 else if (mState.mWebGLStencilAttachment.isAttached())
1671 {
1672 const auto &stencil = mState.mWebGLStencilAttachment;
Jamie Madillcc129372018-04-12 09:13:18 -04001673 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1674 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001675 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001676 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1677 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001678 }
1679 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1680 {
1681 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001682 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001683 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001684 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1685 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001686 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001687 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001688 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1689 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001690 }
1691 else
1692 {
Jamie Madillcc129372018-04-12 09:13:18 -04001693 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1694 baseViewIndex, multiviewLayout, viewportOffsets);
1695 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1696 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001697 }
1698}
1699
Jamie Madill4928b7c2017-06-20 12:57:39 -04001700void Framebuffer::setAttachmentImpl(const Context *context,
1701 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001702 GLenum binding,
1703 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001704 FramebufferAttachmentObject *resource,
1705 GLsizei numViews,
1706 GLuint baseViewIndex,
1707 GLenum multiviewLayout,
1708 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001709{
Jamie Madilla02315b2017-02-23 14:14:47 -05001710 switch (binding)
1711 {
Jamie Madillb8126692017-04-05 11:22:17 -04001712 case GL_DEPTH_STENCIL:
1713 case GL_DEPTH_STENCIL_ATTACHMENT:
1714 {
1715 // ensure this is a legitimate depth+stencil format
1716 FramebufferAttachmentObject *attachmentObj = resource;
1717 if (resource)
1718 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001719 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001720 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1721 {
1722 // Attaching nullptr detaches the current attachment.
1723 attachmentObj = nullptr;
1724 }
1725 }
1726
Jamie Madill4928b7c2017-06-20 12:57:39 -04001727 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001728 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001729 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1730 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001731 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001732 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001733 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1734 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001735 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001736 }
1737
Jamie Madilla02315b2017-02-23 14:14:47 -05001738 case GL_DEPTH:
1739 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001740 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001741 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1742 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001743 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001744
Jamie Madilla02315b2017-02-23 14:14:47 -05001745 case GL_STENCIL:
1746 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001747 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001748 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1749 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001750 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001751
Jamie Madilla02315b2017-02-23 14:14:47 -05001752 case GL_BACK:
Geoff Lang8170eab2017-09-21 13:59:04 -04001753 updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1754 &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1755 resource, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001756 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001757
Jamie Madilla02315b2017-02-23 14:14:47 -05001758 default:
1759 {
1760 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1761 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001762 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001763 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001764 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001765 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1766 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001767
Corentin Walleze7557742017-06-01 13:09:57 -04001768 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1769 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001770 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1771 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Brandon Jones76746f92017-11-22 11:44:41 -08001772 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -04001773 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001774 break;
Geoff Langab75a052014-10-15 12:56:37 -04001775 }
1776}
1777
Jamie Madill4928b7c2017-06-20 12:57:39 -04001778void Framebuffer::updateAttachment(const Context *context,
1779 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001780 size_t dirtyBit,
Jamie Madilld4442552018-02-27 22:03:47 -05001781 angle::ObserverBinding *onDirtyBinding,
Jamie Madillb8126692017-04-05 11:22:17 -04001782 GLenum type,
1783 GLenum binding,
1784 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001785 FramebufferAttachmentObject *resource,
1786 GLsizei numViews,
1787 GLuint baseViewIndex,
1788 GLenum multiviewLayout,
1789 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001790{
Martin Radev5dae57b2017-07-14 16:15:55 +03001791 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1792 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001793 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001794 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madill888081d2018-02-27 00:24:46 -05001795 onDirtyBinding->bind(resource ? resource->getSubject() : nullptr);
Jamie Madille98b1b52018-03-08 09:47:23 -05001796
Jamie Madillb983a4b2018-08-01 11:34:51 -04001797 invalidateCompletenessCache(context);
Jamie Madillb8126692017-04-05 11:22:17 -04001798}
1799
Jamie Madilla02315b2017-02-23 14:14:47 -05001800void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001801{
Jamie Madillcc129372018-04-12 09:13:18 -04001802 setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001803}
1804
Jamie Madill6f755b22018-10-09 12:48:54 -04001805angle::Result Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001806{
1807 if (mDirtyBits.any())
1808 {
Jamie Madill888081d2018-02-27 00:24:46 -05001809 mDirtyBitsGuard = mDirtyBits;
Jamie Madill19fa1c62018-03-08 09:47:21 -05001810 ANGLE_TRY(mImpl->syncState(context, mDirtyBits));
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001811 mDirtyBits.reset();
Jamie Madill888081d2018-02-27 00:24:46 -05001812 mDirtyBitsGuard.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001813 }
Jamie Madill6f755b22018-10-09 12:48:54 -04001814 return angle::Result::Continue();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001815}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001816
Jamie Madilld4442552018-02-27 22:03:47 -05001817void Framebuffer::onSubjectStateChange(const Context *context,
1818 angle::SubjectIndex index,
1819 angle::SubjectMessage message)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001820{
Jamie Madillf668a4b2018-09-23 17:01:20 -04001821 if (message != angle::SubjectMessage::STORAGE_CHANGED)
1822 {
1823 // This can be triggered by the GL back-end TextureGL class.
1824 ASSERT(message == angle::SubjectMessage::DEPENDENT_DIRTY_BITS);
1825 return;
1826 }
Jamie Madill55e57f92018-09-18 11:32:43 -04001827
1828 ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
1829 mDirtyBits.set(index);
1830 onStateChange(context, angle::SubjectMessage::STORAGE_CHANGED);
Jamie Madill888081d2018-02-27 00:24:46 -05001831
Jamie Madillb983a4b2018-08-01 11:34:51 -04001832 invalidateCompletenessCache(context);
Jamie Madill05b35b22017-10-03 09:01:44 -04001833
Jamie Madilld4442552018-02-27 22:03:47 -05001834 FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
1835
Jamie Madill05b35b22017-10-03 09:01:44 -04001836 // Mark the appropriate init flag.
Jamie Madilld4442552018-02-27 22:03:47 -05001837 mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
1838}
1839
1840FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
1841{
1842 switch (index)
1843 {
1844 case DIRTY_BIT_DEPTH_ATTACHMENT:
1845 return &mState.mDepthAttachment;
1846 case DIRTY_BIT_STENCIL_ATTACHMENT:
1847 return &mState.mStencilAttachment;
1848 default:
1849 size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
1850 ASSERT(colorIndex < mState.mColorAttachments.size());
1851 return &mState.mColorAttachments[colorIndex];
1852 }
Jamie Madill51f40ec2016-06-15 14:06:00 -04001853}
1854
Jamie Madilla4595b82017-01-11 17:36:34 -05001855bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1856{
Jamie Madill785e8a02018-10-04 17:42:00 -04001857 const Program *program = state.getProgram();
Jamie Madilla4595b82017-01-11 17:36:34 -05001858
1859 // TODO(jmadill): Default framebuffer feedback loops.
Jamie Madill2274b652018-05-31 10:56:08 -04001860 if (mState.mId == 0)
Jamie Madilla4595b82017-01-11 17:36:34 -05001861 {
1862 return false;
1863 }
1864
1865 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001866 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001867 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001868 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1869 ASSERT(attachment.isAttached());
1870 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001871 {
1872 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001873 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001874 {
1875 return true;
1876 }
1877 }
1878 }
1879
Jamie Madill38fe6842018-09-19 07:20:00 -04001880 // Validate depth-stencil feedback loop. This is independent of Depth/Stencil state.
Jamie Madill1d37bc52017-02-02 19:59:58 -05001881 const FramebufferAttachment *depth = getDepthbuffer();
Jamie Madill38fe6842018-09-19 07:20:00 -04001882 if (depth && depth->type() == GL_TEXTURE)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001883 {
1884 if (program->samplesFromTexture(state, depth->id()))
1885 {
1886 return true;
1887 }
1888 }
1889
Jamie Madill1d37bc52017-02-02 19:59:58 -05001890 const FramebufferAttachment *stencil = getStencilbuffer();
Jamie Madill38fe6842018-09-19 07:20:00 -04001891 if (stencil && stencil->type() == GL_TEXTURE)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001892 {
Jamie Madill38fe6842018-09-19 07:20:00 -04001893 // Skip the feedback loop check if depth/stencil point to the same resource.
1894 if (!depth || *stencil != *depth)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001895 {
Jamie Madill38fe6842018-09-19 07:20:00 -04001896 if (program->samplesFromTexture(state, stencil->id()))
Jamie Madill1d37bc52017-02-02 19:59:58 -05001897 {
Jamie Madill38fe6842018-09-19 07:20:00 -04001898 return true;
Jamie Madill1d37bc52017-02-02 19:59:58 -05001899 }
1900 }
1901 }
1902
Jamie Madilla4595b82017-01-11 17:36:34 -05001903 return false;
1904}
1905
Jamie Madillfd3dd432017-02-02 19:59:59 -05001906bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1907 GLint copyTextureLevel,
1908 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001909{
Jamie Madill2274b652018-05-31 10:56:08 -04001910 if (mState.mId == 0)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001911 {
1912 // It seems impossible to form a texture copying feedback loop with the default FBO.
1913 return false;
1914 }
1915
1916 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1917 ASSERT(readAttachment);
1918
1919 if (readAttachment->isTextureWithId(copyTextureID))
1920 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001921 const auto &imageIndex = readAttachment->getTextureImageIndex();
Jamie Madillcc129372018-04-12 09:13:18 -04001922 if (imageIndex.getLevelIndex() == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001923 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001924 // Check 3D/Array texture layers.
Jamie Madillcc129372018-04-12 09:13:18 -04001925 return !imageIndex.hasLayer() || copyTextureLayer == ImageIndex::kEntireLevel ||
1926 imageIndex.getLayerIndex() == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001927 }
1928 }
1929 return false;
1930}
1931
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001932GLint Framebuffer::getDefaultWidth() const
1933{
1934 return mState.getDefaultWidth();
1935}
1936
1937GLint Framebuffer::getDefaultHeight() const
1938{
1939 return mState.getDefaultHeight();
1940}
1941
1942GLint Framebuffer::getDefaultSamples() const
1943{
1944 return mState.getDefaultSamples();
1945}
1946
Geoff Lang92019432017-11-20 13:09:34 -05001947bool Framebuffer::getDefaultFixedSampleLocations() const
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001948{
1949 return mState.getDefaultFixedSampleLocations();
1950}
1951
Jiawei Shaob1e91382018-05-17 14:33:55 +08001952GLint Framebuffer::getDefaultLayers() const
1953{
1954 return mState.getDefaultLayers();
1955}
1956
Jamie Madillb983a4b2018-08-01 11:34:51 -04001957void Framebuffer::setDefaultWidth(const Context *context, GLint defaultWidth)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001958{
1959 mState.mDefaultWidth = defaultWidth;
1960 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
Jamie Madillb983a4b2018-08-01 11:34:51 -04001961 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001962}
1963
Jamie Madillb983a4b2018-08-01 11:34:51 -04001964void Framebuffer::setDefaultHeight(const Context *context, GLint defaultHeight)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001965{
1966 mState.mDefaultHeight = defaultHeight;
1967 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
Jamie Madillb983a4b2018-08-01 11:34:51 -04001968 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001969}
1970
Jamie Madillb983a4b2018-08-01 11:34:51 -04001971void Framebuffer::setDefaultSamples(const Context *context, GLint defaultSamples)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001972{
1973 mState.mDefaultSamples = defaultSamples;
1974 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
Jamie Madillb983a4b2018-08-01 11:34:51 -04001975 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001976}
1977
Jamie Madillb983a4b2018-08-01 11:34:51 -04001978void Framebuffer::setDefaultFixedSampleLocations(const Context *context,
1979 bool defaultFixedSampleLocations)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001980{
1981 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1982 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
Jamie Madillb983a4b2018-08-01 11:34:51 -04001983 invalidateCompletenessCache(context);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001984}
1985
Jiawei Shaob1e91382018-05-17 14:33:55 +08001986void Framebuffer::setDefaultLayers(GLint defaultLayers)
1987{
1988 mState.mDefaultLayers = defaultLayers;
1989 mDirtyBits.set(DIRTY_BIT_DEFAULT_LAYERS);
1990}
1991
Martin Radev14a26ae2017-07-24 15:56:29 +03001992GLsizei Framebuffer::getNumViews() const
1993{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001994 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03001995}
1996
Martin Radev4e619f52017-08-09 11:50:06 +03001997GLint Framebuffer::getBaseViewIndex() const
1998{
1999 return mState.getBaseViewIndex();
2000}
2001
Martin Radev878c8b12017-07-28 09:51:04 +03002002const std::vector<Offset> *Framebuffer::getViewportOffsets() const
2003{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002004 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03002005}
2006
2007GLenum Framebuffer::getMultiviewLayout() const
2008{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002009 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03002010}
2011
Olli Etuaho8acb1b62018-07-30 16:20:54 +03002012bool Framebuffer::readDisallowedByMultiview() const
2013{
2014 return (mState.getMultiviewLayout() != GL_NONE && mState.getNumViews() > 1) ||
2015 mState.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
2016}
2017
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002018angle::Result Framebuffer::ensureClearAttachmentsInitialized(const Context *context,
2019 GLbitfield mask)
Geoff Langd4fff502017-09-22 11:28:28 -04002020{
2021 const auto &glState = context->getGLState();
2022 if (!context->isRobustResourceInitEnabled() || glState.isRasterizerDiscardEnabled())
2023 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002024 return angle::Result::Continue();
Geoff Langd4fff502017-09-22 11:28:28 -04002025 }
2026
Geoff Langa36483f2018-03-09 16:11:21 -05002027 const BlendState &blend = glState.getBlendState();
2028 const DepthStencilState &depthStencil = glState.getDepthStencilState();
Geoff Langd4fff502017-09-22 11:28:28 -04002029
2030 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
2031 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
2032 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
2033
2034 if (!color && !depth && !stencil)
2035 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002036 return angle::Result::Continue();
Geoff Langd4fff502017-09-22 11:28:28 -04002037 }
2038
2039 if (partialClearNeedsInit(context, color, depth, stencil))
2040 {
2041 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
2042 }
2043
2044 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2045 // still be marked initialized. This simplifies design, allowing this method to be called before
2046 // the clear.
2047 markDrawAttachmentsInitialized(color, depth, stencil);
2048
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002049 return angle::Result::Continue();
Geoff Langd4fff502017-09-22 11:28:28 -04002050}
2051
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002052angle::Result Framebuffer::ensureClearBufferAttachmentsInitialized(const Context *context,
2053 GLenum buffer,
2054 GLint drawbuffer)
Geoff Langd4fff502017-09-22 11:28:28 -04002055{
2056 if (!context->isRobustResourceInitEnabled() ||
2057 context->getGLState().isRasterizerDiscardEnabled() ||
2058 IsClearBufferMaskedOut(context, buffer))
2059 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002060 return angle::Result::Continue();
Geoff Langd4fff502017-09-22 11:28:28 -04002061 }
2062
2063 if (partialBufferClearNeedsInit(context, buffer))
2064 {
2065 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
2066 }
2067
2068 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2069 // still be marked initialized. This simplifies design, allowing this method to be called before
2070 // the clear.
2071 markBufferInitialized(buffer, drawbuffer);
2072
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002073 return angle::Result::Continue();
Geoff Langd4fff502017-09-22 11:28:28 -04002074}
2075
Jamie Madill6f755b22018-10-09 12:48:54 -04002076angle::Result Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
Jamie Madill05b35b22017-10-03 09:01:44 -04002077{
2078 if (!context->isRobustResourceInitEnabled())
2079 {
Jamie Madill6f755b22018-10-09 12:48:54 -04002080 return angle::Result::Continue();
Jamie Madill05b35b22017-10-03 09:01:44 -04002081 }
2082
2083 // Note: we don't actually filter by the draw attachment enum. Just init everything.
2084 for (size_t bit : mState.mResourceNeedsInit)
2085 {
2086 switch (bit)
2087 {
2088 case DIRTY_BIT_DEPTH_ATTACHMENT:
2089 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2090 break;
2091 case DIRTY_BIT_STENCIL_ATTACHMENT:
2092 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2093 break;
2094 default:
2095 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2096 break;
2097 }
2098 }
2099
2100 mState.mResourceNeedsInit.reset();
Jamie Madill6f755b22018-10-09 12:48:54 -04002101 return angle::Result::Continue();
Jamie Madill05b35b22017-10-03 09:01:44 -04002102}
2103
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002104angle::Result Framebuffer::ensureReadAttachmentInitialized(const Context *context,
2105 GLbitfield blitMask)
Jamie Madill05b35b22017-10-03 09:01:44 -04002106{
2107 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2108 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002109 return angle::Result::Continue();
Jamie Madill05b35b22017-10-03 09:01:44 -04002110 }
2111
2112 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
2113 {
2114 size_t readIndex = mState.getReadIndex();
2115 if (mState.mResourceNeedsInit[readIndex])
2116 {
2117 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2118 mState.mResourceNeedsInit.reset(readIndex);
2119 }
2120 }
2121
2122 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
2123 {
2124 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2125 {
2126 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2127 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2128 }
2129 }
2130
2131 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
2132 {
2133 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2134 {
2135 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2136 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2137 }
2138 }
2139
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002140 return angle::Result::Continue();
Jamie Madill05b35b22017-10-03 09:01:44 -04002141}
2142
2143void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2144{
2145 // Mark attachments as initialized.
2146 if (color)
2147 {
2148 for (auto colorIndex : mState.mEnabledDrawBuffers)
2149 {
2150 auto &colorAttachment = mState.mColorAttachments[colorIndex];
2151 ASSERT(colorAttachment.isAttached());
2152 colorAttachment.setInitState(InitState::Initialized);
2153 mState.mResourceNeedsInit.reset(colorIndex);
2154 }
2155 }
2156
2157 if (depth && mState.mDepthAttachment.isAttached())
2158 {
2159 mState.mDepthAttachment.setInitState(InitState::Initialized);
2160 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2161 }
2162
2163 if (stencil && mState.mStencilAttachment.isAttached())
2164 {
2165 mState.mStencilAttachment.setInitState(InitState::Initialized);
2166 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2167 }
2168}
2169
2170void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2171{
2172 switch (bufferType)
2173 {
2174 case GL_COLOR:
2175 {
2176 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2177 if (mState.mColorAttachments[bufferIndex].isAttached())
2178 {
2179 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2180 mState.mResourceNeedsInit.reset(bufferIndex);
2181 }
2182 break;
2183 }
2184 case GL_DEPTH:
2185 {
2186 if (mState.mDepthAttachment.isAttached())
2187 {
2188 mState.mDepthAttachment.setInitState(InitState::Initialized);
2189 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2190 }
2191 break;
2192 }
2193 case GL_STENCIL:
2194 {
2195 if (mState.mStencilAttachment.isAttached())
2196 {
2197 mState.mStencilAttachment.setInitState(InitState::Initialized);
2198 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2199 }
2200 break;
2201 }
2202 case GL_DEPTH_STENCIL:
2203 {
2204 if (mState.mDepthAttachment.isAttached())
2205 {
2206 mState.mDepthAttachment.setInitState(InitState::Initialized);
2207 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2208 }
2209 if (mState.mStencilAttachment.isAttached())
2210 {
2211 mState.mStencilAttachment.setInitState(InitState::Initialized);
2212 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2213 }
2214 break;
2215 }
2216 default:
2217 UNREACHABLE();
2218 break;
2219 }
2220}
2221
2222Box Framebuffer::getDimensions() const
2223{
2224 return mState.getDimensions();
2225}
2226
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002227angle::Result Framebuffer::ensureBufferInitialized(const Context *context,
2228 GLenum bufferType,
2229 GLint bufferIndex)
Jamie Madill05b35b22017-10-03 09:01:44 -04002230{
2231 ASSERT(context->isRobustResourceInitEnabled());
2232
2233 if (mState.mResourceNeedsInit.none())
2234 {
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002235 return angle::Result::Continue();
Jamie Madill05b35b22017-10-03 09:01:44 -04002236 }
2237
2238 switch (bufferType)
2239 {
2240 case GL_COLOR:
2241 {
2242 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2243 if (mState.mResourceNeedsInit[bufferIndex])
2244 {
2245 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2246 mState.mResourceNeedsInit.reset(bufferIndex);
2247 }
2248 break;
2249 }
2250 case GL_DEPTH:
2251 {
2252 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2253 {
2254 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2255 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2256 }
2257 break;
2258 }
2259 case GL_STENCIL:
2260 {
2261 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2262 {
2263 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2264 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2265 }
2266 break;
2267 }
2268 case GL_DEPTH_STENCIL:
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 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2276 {
2277 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2278 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2279 }
2280 break;
2281 }
2282 default:
2283 UNREACHABLE();
2284 break;
2285 }
2286
Jamie Madill64b7c4f2018-10-19 11:38:04 -04002287 return angle::Result::Continue();
Jamie Madill05b35b22017-10-03 09:01:44 -04002288}
2289
2290bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2291{
2292 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2293 {
2294 return false;
2295 }
2296
2297 switch (bufferType)
2298 {
2299 case GL_COLOR:
2300 return partialClearNeedsInit(context, true, false, false);
2301 case GL_DEPTH:
2302 return partialClearNeedsInit(context, false, true, false);
2303 case GL_STENCIL:
2304 return partialClearNeedsInit(context, false, false, true);
2305 case GL_DEPTH_STENCIL:
2306 return partialClearNeedsInit(context, false, true, true);
2307 default:
2308 UNREACHABLE();
2309 return false;
2310 }
2311}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002312} // namespace gl