blob: 3e5859d7c320148e30f122e519901ef965670bd8 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Framebuffer.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040011
Jamie Madillcc86d642015-11-24 13:00:07 -050012#include "common/Optional.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040013#include "common/bitset_utils.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040014#include "common/utilities.h"
15#include "libANGLE/Config.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Context.h"
Jamie Madill6c1f6712017-02-14 19:08:04 -050017#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050018#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040019#include "libANGLE/Renderbuffer.h"
20#include "libANGLE/Surface.h"
21#include "libANGLE/Texture.h"
Brandon Jones76746f92017-11-22 11:44:41 -080022#include "libANGLE/angletypes.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040023#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040024#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050025#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040026#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050027#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040028#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040029
Jamie Madill362876b2016-06-16 14:46:59 -040030using namespace angle;
31
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000032namespace gl
33{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000034
Jamie Madilld1405e52015-03-05 15:41:39 -050035namespace
36{
Jamie Madill362876b2016-06-16 14:46:59 -040037
Martin Radev9bc9a322017-07-21 14:28:17 +030038bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
39 const FramebufferAttachment *secondAttachment)
40{
41 ASSERT(firstAttachment && secondAttachment);
42 ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
43
44 if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
45 {
46 return false;
47 }
48 if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
49 {
50 return false;
51 }
52 if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
53 {
54 return false;
55 }
56 if (firstAttachment->getMultiviewViewportOffsets() !=
57 secondAttachment->getMultiviewViewportOffsets())
58 {
59 return false;
60 }
61 return true;
62}
63
Geoff Lang9f10b772017-05-16 15:51:03 -040064bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
65{
66 ASSERT(attachment.isAttached());
67
68 const Extents &size = attachment.getSize();
69 if (size.width == 0 || size.height == 0)
70 {
71 return false;
72 }
73
74 const InternalFormat &format = *attachment.getFormat().info;
Yuly Novikovf15f8862018-06-04 18:59:41 -040075 if (attachment.type() == GL_RENDERBUFFER &&
76 !format.renderbufferSupport(context->getClientVersion(), context->getExtensions()))
77 {
78 return false;
79 }
80 if (attachment.type() == GL_TEXTURE &&
81 !format.textureAttachmentSupport(context->getClientVersion(), context->getExtensions()))
Geoff Lang9f10b772017-05-16 15:51:03 -040082 {
83 return false;
84 }
85
86 if (attachment.type() == GL_TEXTURE)
87 {
Jiawei Shaoa8802472018-05-28 11:17:47 +080088 // [EXT_geometry_shader] Section 9.4.1, "Framebuffer Completeness"
89 // If <image> is a three-dimensional texture or a two-dimensional array texture and the
90 // attachment is not layered, the selected layer is less than the depth or layer count,
91 // respectively, of the texture.
92 if (!attachment.isLayered())
Geoff Lang9f10b772017-05-16 15:51:03 -040093 {
Jiawei Shaoa8802472018-05-28 11:17:47 +080094 if (attachment.layer() >= size.depth)
95 {
96 return false;
97 }
98 }
99 // If <image> is a three-dimensional texture or a two-dimensional array texture and the
100 // attachment is layered, the depth or layer count, respectively, of the texture is less
101 // than or equal to the value of MAX_FRAMEBUFFER_LAYERS_EXT.
102 else
103 {
104 if (static_cast<GLuint>(size.depth) >= context->getCaps().maxFramebufferLayers)
105 {
106 return false;
107 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400108 }
109
110 // ES3 specifies that cube map texture attachments must be cube complete.
111 // This language is missing from the ES2 spec, but we enforce it here because some
112 // desktop OpenGL drivers also enforce this validation.
113 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
114 const Texture *texture = attachment.getTexture();
115 ASSERT(texture);
Corentin Wallez99d492c2018-02-27 15:17:10 -0500116 if (texture->getType() == TextureType::CubeMap &&
Geoff Lang9f10b772017-05-16 15:51:03 -0400117 !texture->getTextureState().isCubeComplete())
118 {
119 return false;
120 }
Geoff Lang857c09d2017-05-16 15:55:04 -0400121
122 if (!texture->getImmutableFormat())
123 {
124 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
125
126 // From the ES 3.0 spec, pg 213:
127 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
128 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
129 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
130 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
131 // the effective maximum texture level defined in the Mipmapping discussion of
132 // section 3.8.10.4.
133 if (attachmentMipLevel < texture->getBaseLevel() ||
134 attachmentMipLevel > texture->getMipmapMaxLevel())
135 {
136 return false;
137 }
138
139 // Form the ES 3.0 spec, pg 213/214:
140 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
141 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
142 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
143 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
144 // a cubemap texture, the texture must also be cube complete.
145 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
146 {
147 return false;
148 }
149 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400150 }
151
152 return true;
153};
154
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400155bool CheckAttachmentSampleCompleteness(const Context *context,
156 const FramebufferAttachment &attachment,
157 bool colorAttachment,
158 Optional<int> *samples,
Geoff Lang92019432017-11-20 13:09:34 -0500159 Optional<bool> *fixedSampleLocations)
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400160{
161 ASSERT(attachment.isAttached());
162
163 if (attachment.type() == GL_TEXTURE)
164 {
165 const Texture *texture = attachment.getTexture();
166 ASSERT(texture);
167
168 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
Jiawei Shaoa8802472018-05-28 11:17:47 +0800169 bool fixedSampleloc = texture->getAttachmentFixedSampleLocations(attachmentImageIndex);
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400170 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
171 {
172 return false;
173 }
174 else
175 {
176 *fixedSampleLocations = fixedSampleloc;
177 }
178 }
179
180 if (samples->valid())
181 {
182 if (attachment.getSamples() != samples->value())
183 {
184 if (colorAttachment)
185 {
186 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
187 // all color attachments have the same number of samples for the FBO to be complete.
188 return false;
189 }
190 else
191 {
192 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
193 // when its depth or stencil samples are a multiple of the number of color samples.
194 if (!context->getExtensions().framebufferMixedSamples)
195 {
196 return false;
197 }
198
199 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
200 {
201 return false;
202 }
203 }
204 }
205 }
206 else
207 {
208 *samples = attachment.getSamples();
209 }
210
211 return true;
212}
213
Jamie Madill05b35b22017-10-03 09:01:44 -0400214// Needed to index into the attachment arrays/bitsets.
Jamie Madill682efdc2017-10-03 14:10:29 -0400215static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500216 Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
Jamie Madill05b35b22017-10-03 09:01:44 -0400217 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400218static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500219 Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400220 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400221static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500222 Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400223 "Framebuffer Dirty bit mismatch");
224
225Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
226{
227 ASSERT(attachment->isAttached());
228 if (attachment->initState() == InitState::MayNeedInit)
229 {
230 ANGLE_TRY(attachment->initializeContents(context));
231 }
232 return NoError();
233}
234
235bool IsColorMaskedOut(const BlendState &blend)
236{
237 return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
238 !blend.colorMaskAlpha);
239}
240
241bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
242{
243 return !depthStencil.depthMask;
244}
245
246bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
247{
248 return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
249}
250
251bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
252{
253 switch (buffer)
254 {
255 case GL_COLOR:
256 return IsColorMaskedOut(context->getGLState().getBlendState());
257 case GL_DEPTH:
258 return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
259 case GL_STENCIL:
260 return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
261 case GL_DEPTH_STENCIL:
262 return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
263 IsStencilMaskedOut(context->getGLState().getDepthStencilState());
264 default:
265 UNREACHABLE();
266 return true;
267 }
268}
269
Jamie Madill362876b2016-06-16 14:46:59 -0400270} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500271
Jamie Madill6f60d052017-02-22 15:20:11 -0500272// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400273FramebufferState::FramebufferState()
Jamie Madill2274b652018-05-31 10:56:08 -0400274 : mId(0),
275 mLabel(),
Geoff Lang70d0f492015-12-10 17:45:46 -0500276 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400277 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500278 mReadBufferState(GL_BACK),
Brandon Jones76746f92017-11-22 11:44:41 -0800279 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800280 mDefaultWidth(0),
281 mDefaultHeight(0),
282 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500283 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800284 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500285 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400286{
Geoff Langd90d3882017-03-21 10:49:54 -0400287 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500288 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400289}
290
Jamie Madill2274b652018-05-31 10:56:08 -0400291FramebufferState::FramebufferState(const Caps &caps, GLuint id)
292 : mId(id),
293 mLabel(),
Geoff Lang70d0f492015-12-10 17:45:46 -0500294 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -0500295 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800296 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
Brandon Jones76746f92017-11-22 11:44:41 -0800297 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800298 mDefaultWidth(0),
299 mDefaultHeight(0),
300 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500301 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800302 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500303 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500304{
Jamie Madill2274b652018-05-31 10:56:08 -0400305 ASSERT(mId != 0);
Geoff Langa15472a2015-08-11 11:48:03 -0400306 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500307 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
308}
309
Jamie Madill48ef11b2016-04-27 15:21:52 -0400310FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500311{
Jamie Madilld1405e52015-03-05 15:41:39 -0500312}
313
Jamie Madill48ef11b2016-04-27 15:21:52 -0400314const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500315{
316 return mLabel;
317}
318
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800319const FramebufferAttachment *FramebufferState::getAttachment(const Context *context,
320 GLenum attachment) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400321{
322 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
323 {
324 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
325 }
326
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800327 // WebGL1 allows a developer to query for attachment parameters even when "inconsistant" (i.e.
328 // multiple conflicting attachment points) and requires us to return the framebuffer attachment
329 // associated with WebGL.
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400330 switch (attachment)
331 {
332 case GL_COLOR:
333 case GL_BACK:
334 return getColorAttachment(0);
335 case GL_DEPTH:
336 case GL_DEPTH_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800337 if (context->isWebGL1())
338 {
339 return getWebGLDepthAttachment();
340 }
341 else
342 {
343 return getDepthAttachment();
344 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400345 case GL_STENCIL:
346 case GL_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800347 if (context->isWebGL1())
348 {
349 return getWebGLStencilAttachment();
350 }
351 else
352 {
353 return getStencilAttachment();
354 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400355 case GL_DEPTH_STENCIL:
356 case GL_DEPTH_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800357 if (context->isWebGL1())
358 {
359 return getWebGLDepthStencilAttachment();
360 }
361 else
362 {
363 return getDepthStencilAttachment();
364 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400365 default:
366 UNREACHABLE();
367 return nullptr;
368 }
369}
370
Jamie Madill05b35b22017-10-03 09:01:44 -0400371size_t FramebufferState::getReadIndex() const
Jamie Madill7147f012015-03-05 15:41:40 -0500372{
Jamie Madill231c7f52017-04-26 13:45:37 -0400373 ASSERT(mReadBufferState == GL_BACK ||
374 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
375 size_t readIndex = (mReadBufferState == GL_BACK
376 ? 0
377 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500378 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill05b35b22017-10-03 09:01:44 -0400379 return readIndex;
380}
381
382const FramebufferAttachment *FramebufferState::getReadAttachment() const
383{
384 if (mReadBufferState == GL_NONE)
385 {
386 return nullptr;
387 }
388 size_t readIndex = getReadIndex();
Jamie Madill2d06b732015-04-20 12:53:28 -0400389 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500390}
391
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500392const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
393{
394 auto *colorAttachment = getFirstColorAttachment();
395 if (colorAttachment)
396 {
397 return colorAttachment;
398 }
399 return getDepthOrStencilAttachment();
400}
401
Jamie Madill48ef11b2016-04-27 15:21:52 -0400402const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500403{
Jamie Madill2d06b732015-04-20 12:53:28 -0400404 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500405 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400406 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500407 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400408 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500409 }
410 }
411
412 return nullptr;
413}
414
Jamie Madill48ef11b2016-04-27 15:21:52 -0400415const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500416{
Jamie Madill2d06b732015-04-20 12:53:28 -0400417 if (mDepthAttachment.isAttached())
418 {
419 return &mDepthAttachment;
420 }
421 if (mStencilAttachment.isAttached())
422 {
423 return &mStencilAttachment;
424 }
425 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500426}
427
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500428const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
429{
430 if (mStencilAttachment.isAttached())
431 {
432 return &mStencilAttachment;
433 }
434 return getDepthStencilAttachment();
435}
436
Jamie Madill48ef11b2016-04-27 15:21:52 -0400437const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400438{
439 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400440 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
441 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400442}
443
Jamie Madill48ef11b2016-04-27 15:21:52 -0400444const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400445{
Jamie Madill2d06b732015-04-20 12:53:28 -0400446 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400447}
448
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800449const FramebufferAttachment *FramebufferState::getWebGLDepthAttachment() const
450{
451 return mWebGLDepthAttachment.isAttached() ? &mWebGLDepthAttachment : nullptr;
452}
453
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800454const FramebufferAttachment *FramebufferState::getWebGLDepthStencilAttachment() const
455{
456 return mWebGLDepthStencilAttachment.isAttached() ? &mWebGLDepthStencilAttachment : nullptr;
457}
458
Jamie Madill48ef11b2016-04-27 15:21:52 -0400459const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400460{
Jamie Madill2d06b732015-04-20 12:53:28 -0400461 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400462}
463
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800464const FramebufferAttachment *FramebufferState::getWebGLStencilAttachment() const
465{
466 return mWebGLStencilAttachment.isAttached() ? &mWebGLStencilAttachment : nullptr;
467}
468
Jamie Madill48ef11b2016-04-27 15:21:52 -0400469const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400470{
471 // A valid depth-stencil attachment has the same resource bound to both the
472 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400473 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500474 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400475 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400476 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400477 }
478
479 return nullptr;
480}
481
Jamie Madill48ef11b2016-04-27 15:21:52 -0400482bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500483{
484 Optional<Extents> attachmentSize;
485
Jamie Madill231c7f52017-04-26 13:45:37 -0400486 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500487 if (!attachment.isAttached())
488 {
489 return false;
490 }
491
492 if (!attachmentSize.valid())
493 {
494 attachmentSize = attachment.getSize();
495 return false;
496 }
497
Jeff Gilbert8f8edd62017-10-31 14:26:30 -0700498 const auto &prevSize = attachmentSize.value();
499 const auto &curSize = attachment.getSize();
500 return (curSize.width != prevSize.width || curSize.height != prevSize.height);
Jamie Madillcc86d642015-11-24 13:00:07 -0500501 };
502
503 for (const auto &attachment : mColorAttachments)
504 {
505 if (hasMismatchedSize(attachment))
506 {
507 return false;
508 }
509 }
510
511 if (hasMismatchedSize(mDepthAttachment))
512 {
513 return false;
514 }
515
516 return !hasMismatchedSize(mStencilAttachment);
517}
518
Jamie Madilld4442552018-02-27 22:03:47 -0500519const FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400520{
521 ASSERT(drawBufferIdx < mDrawBufferStates.size());
522 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
523 {
524 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
525 // must be COLOR_ATTACHMENTi or NONE"
526 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
527 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800528
529 if (mDrawBufferStates[drawBufferIdx] == GL_BACK)
530 {
531 return getColorAttachment(0);
532 }
533 else
534 {
535 return getColorAttachment(mDrawBufferStates[drawBufferIdx] - GL_COLOR_ATTACHMENT0);
536 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400537 }
538 else
539 {
540 return nullptr;
541 }
542}
543
544size_t FramebufferState::getDrawBufferCount() const
545{
546 return mDrawBufferStates.size();
547}
548
Geoff Langb21e20d2016-07-19 15:35:41 -0400549bool FramebufferState::colorAttachmentsAreUniqueImages() const
550{
551 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
552 firstAttachmentIdx++)
553 {
Jamie Madilld4442552018-02-27 22:03:47 -0500554 const FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400555 if (!firstAttachment.isAttached())
556 {
557 continue;
558 }
559
560 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
561 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
562 {
Jamie Madilld4442552018-02-27 22:03:47 -0500563 const FramebufferAttachment &secondAttachment = mColorAttachments[secondAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400564 if (!secondAttachment.isAttached())
565 {
566 continue;
567 }
568
569 if (firstAttachment == secondAttachment)
570 {
571 return false;
572 }
573 }
574 }
575
576 return true;
577}
578
Jamie Madill9c335862017-07-18 11:51:38 -0400579bool FramebufferState::hasDepth() const
580{
581 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
582}
583
584bool FramebufferState::hasStencil() const
585{
586 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
587}
588
Martin Radev5c00d0d2017-08-07 10:06:59 +0300589GLsizei FramebufferState::getNumViews() const
590{
591 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
592 if (attachment == nullptr)
593 {
594 return FramebufferAttachment::kDefaultNumViews;
595 }
596 return attachment->getNumViews();
597}
598
599const std::vector<Offset> *FramebufferState::getViewportOffsets() const
600{
601 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
602 if (attachment == nullptr)
603 {
604 return nullptr;
605 }
606 return &attachment->getMultiviewViewportOffsets();
607}
608
609GLenum FramebufferState::getMultiviewLayout() const
610{
611 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
612 if (attachment == nullptr)
613 {
614 return GL_NONE;
615 }
616 return attachment->getMultiviewLayout();
617}
618
Martin Radev4e619f52017-08-09 11:50:06 +0300619int FramebufferState::getBaseViewIndex() const
620{
621 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
622 if (attachment == nullptr)
623 {
624 return GL_NONE;
625 }
626 return attachment->getBaseViewIndex();
627}
628
Jamie Madill05b35b22017-10-03 09:01:44 -0400629Box FramebufferState::getDimensions() const
630{
631 ASSERT(attachmentsHaveSameDimensions());
632 ASSERT(getFirstNonNullAttachment() != nullptr);
633 Extents extents = getFirstNonNullAttachment()->getSize();
634 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
635}
636
Jamie Madill7aea7e02016-05-10 10:39:45 -0400637Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill2274b652018-05-31 10:56:08 -0400638 : mState(caps, id),
Jamie Madill362876b2016-06-16 14:46:59 -0400639 mImpl(factory->createFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400640 mCachedStatus(),
641 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
642 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643{
Corentin Wallez37c39792015-08-20 14:19:46 -0400644 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400645 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
646
Jamie Madill1e5499d2017-04-05 11:22:16 -0400647 for (uint32_t colorIndex = 0;
648 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400649 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400650 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400651 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400652}
653
Geoff Langbf7b95d2018-05-01 16:48:21 -0400654Framebuffer::Framebuffer(const Context *context, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400655 : mState(),
Geoff Langbf7b95d2018-05-01 16:48:21 -0400656 mImpl(surface->getImplementation()->createDefaultFramebuffer(context, mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400657 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
658 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
659 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400660{
Geoff Langda88add2014-12-01 10:22:01 -0500661 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400662 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500663
Geoff Langbf7b95d2018-05-01 16:48:21 -0400664 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400665 FramebufferAttachment::kDefaultNumViews,
Martin Radev5dae57b2017-07-14 16:15:55 +0300666 FramebufferAttachment::kDefaultBaseViewIndex,
667 FramebufferAttachment::kDefaultMultiviewLayout,
668 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500669
670 if (surface->getConfig()->depthSize > 0)
671 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400672 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400673 FramebufferAttachment::kDefaultNumViews,
Jamie Madilld4442552018-02-27 22:03:47 -0500674 FramebufferAttachment::kDefaultBaseViewIndex,
675 FramebufferAttachment::kDefaultMultiviewLayout,
676 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500677 }
678
679 if (surface->getConfig()->stencilSize > 0)
680 {
Geoff Langbf7b95d2018-05-01 16:48:21 -0400681 setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
Jamie Madillcc129372018-04-12 09:13:18 -0400682 FramebufferAttachment::kDefaultNumViews,
683 FramebufferAttachment::kDefaultBaseViewIndex,
684 FramebufferAttachment::kDefaultMultiviewLayout,
685 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500686 }
Brandon Jones76746f92017-11-22 11:44:41 -0800687 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000688}
689
Corentin Wallezccab69d2017-01-27 16:57:15 -0500690Framebuffer::Framebuffer(rx::GLImplFactory *factory)
691 : mState(),
692 mImpl(factory->createFramebuffer(mState)),
Corentin Wallezccab69d2017-01-27 16:57:15 -0500693 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
694 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
695 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
696{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400697 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Brandon Jones76746f92017-11-22 11:44:41 -0800698 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500699}
700
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000701Framebuffer::~Framebuffer()
702{
Geoff Langda88add2014-12-01 10:22:01 -0500703 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000704}
705
Jamie Madill4928b7c2017-06-20 12:57:39 -0400706void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500707{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400708 for (auto &attachment : mState.mColorAttachments)
709 {
710 attachment.detach(context);
711 }
712 mState.mDepthAttachment.detach(context);
713 mState.mStencilAttachment.detach(context);
714 mState.mWebGLDepthAttachment.detach(context);
715 mState.mWebGLStencilAttachment.detach(context);
716 mState.mWebGLDepthStencilAttachment.detach(context);
717
Jamie Madillc564c072017-06-01 12:45:42 -0400718 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500719}
720
Geoff Lang70d0f492015-12-10 17:45:46 -0500721void Framebuffer::setLabel(const std::string &label)
722{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400723 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500724}
725
726const std::string &Framebuffer::getLabel() const
727{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400728 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500729}
730
Jamie Madill8693bdb2017-09-02 15:32:14 -0400731bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000732{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400733 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000734}
735
Jamie Madill8693bdb2017-09-02 15:32:14 -0400736bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000737{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400738 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500739}
Jamie Madille261b442014-06-25 12:42:21 -0400740
Jamie Madill8693bdb2017-09-02 15:32:14 -0400741bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500742{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400743 bool found = false;
744
Jamie Madill362876b2016-06-16 14:46:59 -0400745 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500746 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400747 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
748 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
749 {
750 found = true;
751 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000752 }
753
Jamie Madilla02315b2017-02-23 14:14:47 -0500754 if (context->isWebGL1())
755 {
756 const std::array<FramebufferAttachment *, 3> attachments = {
757 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
758 &mState.mWebGLStencilAttachment}};
759 for (FramebufferAttachment *attachment : attachments)
760 {
761 if (attachment->isAttached() && attachment->type() == resourceType &&
762 attachment->id() == resourceId)
763 {
764 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400765 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500766 }
767 }
768 }
769 else
770 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400771 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
772 DIRTY_BIT_DEPTH_ATTACHMENT))
773 {
774 found = true;
775 }
776 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
777 DIRTY_BIT_STENCIL_ATTACHMENT))
778 {
779 found = true;
780 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500781 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400782
783 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400784}
785
Jamie Madill8693bdb2017-09-02 15:32:14 -0400786bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400787 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400788 GLenum matchType,
789 GLuint matchId,
790 size_t dirtyBit)
791{
792 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
793 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400794 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400795 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -0400796 mState.mResourceNeedsInit.set(dirtyBit, false);
Jamie Madill8693bdb2017-09-02 15:32:14 -0400797 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400798 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400799
800 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000801}
802
Corentin Wallez37c39792015-08-20 14:19:46 -0400803const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400805 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806}
807
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400808const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400809{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400810 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400811}
812
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400813const FramebufferAttachment *Framebuffer::getStencilbuffer() const
814{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400815 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400816}
817
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400818const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
819{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400820 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400821}
822
823const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000824{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400825 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000826}
827
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500828const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
829{
830 return mState.getStencilOrDepthStencilAttachment();
831}
832
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400833const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000834{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400835 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000836}
837
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000838GLenum Framebuffer::getReadColorbufferType() const
839{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400840 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400841 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000842}
843
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400844const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000845{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400846 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000847}
848
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400849const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
850{
851 return mState.getFirstNonNullAttachment();
852}
853
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800854const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
855 GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000856{
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800857 return mState.getAttachment(context, attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400858}
859
Geoff Langa15472a2015-08-11 11:48:03 -0400860size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000861{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400862 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400863}
864
865GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
866{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400867 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
868 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000869}
870
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500871const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
872{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400873 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500874}
875
Geoff Lang164d54e2014-12-01 10:55:33 -0500876void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000877{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400878 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500879
880 ASSERT(count <= drawStates.size());
881 std::copy(buffers, buffers + count, drawStates.begin());
882 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500883 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500884
885 mState.mEnabledDrawBuffers.reset();
Brandon Jones76746f92017-11-22 11:44:41 -0800886 mState.mDrawBufferTypeMask.reset();
887
Jamie Madilla4595b82017-01-11 17:36:34 -0500888 for (size_t index = 0; index < count; ++index)
889 {
Brandon Jones76746f92017-11-22 11:44:41 -0800890 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
891
Jamie Madilla4595b82017-01-11 17:36:34 -0500892 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
893 {
894 mState.mEnabledDrawBuffers.set(index);
895 }
896 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500897}
898
Geoff Langa15472a2015-08-11 11:48:03 -0400899const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
900{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400901 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400902}
903
Geoff Lange0cff192017-05-30 13:04:56 -0400904GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
905{
906 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
907 if (attachment == nullptr)
908 {
909 return GL_NONE;
910 }
911
912 GLenum componentType = attachment->getFormat().info->componentType;
913 switch (componentType)
914 {
915 case GL_INT:
916 case GL_UNSIGNED_INT:
917 return componentType;
918
919 default:
920 return GL_FLOAT;
921 }
922}
923
Brandon Jonesc405ae72017-12-06 14:15:03 -0800924ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
Brandon Jones76746f92017-11-22 11:44:41 -0800925{
926 return mState.mDrawBufferTypeMask;
927}
928
929DrawBufferMask Framebuffer::getDrawBufferMask() const
930{
931 return mState.mEnabledDrawBuffers;
932}
933
Geoff Langa15472a2015-08-11 11:48:03 -0400934bool Framebuffer::hasEnabledDrawBuffer() const
935{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400936 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400937 {
938 if (getDrawBuffer(drawbufferIdx) != nullptr)
939 {
940 return true;
941 }
942 }
943
944 return false;
945}
946
Geoff Lang9dd95802014-12-01 11:12:59 -0500947GLenum Framebuffer::getReadBufferState() const
948{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400949 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500950}
951
952void Framebuffer::setReadBuffer(GLenum buffer)
953{
Jamie Madillb885e572015-02-03 16:16:04 -0500954 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
955 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400956 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
957 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500958 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000959}
960
Corentin Wallez37c39792015-08-20 14:19:46 -0400961size_t Framebuffer::getNumColorBuffers() const
962{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400963 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400964}
965
Jamie Madill0df8fe42015-11-24 16:10:24 -0500966bool Framebuffer::hasDepth() const
967{
Jamie Madill9c335862017-07-18 11:51:38 -0400968 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500969}
970
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000971bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000972{
Jamie Madill9c335862017-07-18 11:51:38 -0400973 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000974}
975
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000976bool Framebuffer::usingExtendedDrawBuffers() const
977{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400978 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000979 {
Geoff Langa15472a2015-08-11 11:48:03 -0400980 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000981 {
982 return true;
983 }
984 }
985
986 return false;
987}
988
Geoff Lang9aded172017-04-05 11:07:56 -0400989void Framebuffer::invalidateCompletenessCache()
990{
Jamie Madill2274b652018-05-31 10:56:08 -0400991 if (mState.mId != 0)
Geoff Lang9aded172017-04-05 11:07:56 -0400992 {
993 mCachedStatus.reset();
994 }
995}
996
Jamie Madill427064d2018-04-13 16:20:34 -0400997GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000998{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500999 // The default framebuffer is always complete except when it is surfaceless in which
1000 // case it is always unsupported. We return early because the default framebuffer may
1001 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Jamie Madill2274b652018-05-31 10:56:08 -04001002 if (mState.mId == 0)
Geoff Lang528ce3c2014-12-01 10:44:07 -05001003 {
Corentin Wallezccab69d2017-01-27 16:57:15 -05001004 ASSERT(mCachedStatus.valid());
1005 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
1006 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
Jamie Madill427064d2018-04-13 16:20:34 -04001007 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -05001008 }
1009
Jamie Madill362876b2016-06-16 14:46:59 -04001010 if (hasAnyDirtyBit() || !mCachedStatus.valid())
1011 {
Jamie Madille98b1b52018-03-08 09:47:23 -05001012 mCachedStatus = checkStatusWithGLFrontEnd(context);
1013
1014 if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
1015 {
Jamie Madill427064d2018-04-13 16:20:34 -04001016 Error err = syncState(context);
1017 if (err.isError())
1018 {
1019 context->handleError(err);
1020 return GetDefaultReturnValue<EntryPoint::CheckFramebufferStatus, GLenum>();
1021 }
Jamie Madille98b1b52018-03-08 09:47:23 -05001022 if (!mImpl->checkStatus(context))
1023 {
1024 mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
1025 }
1026 }
Jamie Madill362876b2016-06-16 14:46:59 -04001027 }
1028
Jamie Madill427064d2018-04-13 16:20:34 -04001029 return mCachedStatus.value();
Jamie Madill362876b2016-06-16 14:46:59 -04001030}
1031
Jamie Madille98b1b52018-03-08 09:47:23 -05001032GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -04001033{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001034 const ContextState &state = context->getContextState();
1035
Jamie Madill2274b652018-05-31 10:56:08 -04001036 ASSERT(mState.mId != 0);
Jamie Madill362876b2016-06-16 14:46:59 -04001037
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001038 bool hasAttachments = false;
1039 Optional<unsigned int> colorbufferSize;
1040 Optional<int> samples;
Geoff Lang92019432017-11-20 13:09:34 -05001041 Optional<bool> fixedSampleLocations;
JiangYizhou461d9a32017-01-04 16:37:26 +08001042 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043
Martin Radev9bc9a322017-07-21 14:28:17 +03001044 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
1045
Jiawei Shaoa8802472018-05-28 11:17:47 +08001046 Optional<bool> isLayered;
1047 Optional<TextureType> colorAttachmentsTextureType;
1048
Jamie Madill48ef11b2016-04-27 15:21:52 -04001049 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001050 {
Jamie Madill2d06b732015-04-20 12:53:28 -04001051 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001052 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001053 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001054 {
1055 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1056 }
daniel@transgaming.com01868132010-08-24 19:21:17 +00001057
Geoff Lang677bb6f2017-04-05 12:40:40 -04001058 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001059 if (format.depthBits > 0 || format.stencilBits > 0)
1060 {
1061 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1062 }
1063
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001064 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
1065 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001066 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001067 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001068 }
1069
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001070 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
1071 // in GLES 3.0, there is no such restriction
1072 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001073 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001074 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001075 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001076 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +00001077 {
1078 return GL_FRAMEBUFFER_UNSUPPORTED;
1079 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001080 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001081 else
1082 {
1083 colorbufferSize = format.pixelBytes;
1084 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001085 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001086
Martin Radev9bc9a322017-07-21 14:28:17 +03001087 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
1088 {
1089 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1090 }
1091
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001092 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001093
1094 if (!hasAttachments)
1095 {
1096 isLayered = colorAttachment.isLayered();
1097 if (isLayered.value())
1098 {
1099 colorAttachmentsTextureType = colorAttachment.getTextureImageIndex().getType();
1100 }
1101 hasAttachments = true;
1102 }
1103 else
1104 {
1105 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1106 // If any framebuffer attachment is layered, all populated attachments
1107 // must be layered. Additionally, all populated color attachments must
1108 // be from textures of the same target. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1109 ASSERT(isLayered.valid());
1110 if (isLayered.value() != colorAttachment.isLayered())
1111 {
1112 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1113 }
1114 else if (isLayered.value())
1115 {
1116 ASSERT(colorAttachmentsTextureType.valid());
1117 if (colorAttachmentsTextureType.value() !=
1118 colorAttachment.getTextureImageIndex().getType())
1119 {
1120 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1121 }
1122 }
1123 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001124 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001125 }
1126
Jamie Madill48ef11b2016-04-27 15:21:52 -04001127 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001128 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001129 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001130 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001131 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001132 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001133 }
1134
Geoff Lang677bb6f2017-04-05 12:40:40 -04001135 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001136 if (format.depthBits == 0)
1137 {
1138 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001139 }
1140
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001141 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1142 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001143 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001144 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001145 }
Sami Väisänena797e062016-05-12 15:23:40 +03001146
Martin Radev9bc9a322017-07-21 14:28:17 +03001147 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1148 {
1149 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1150 }
1151
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001152 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001153
1154 if (!hasAttachments)
1155 {
1156 isLayered = depthAttachment.isLayered();
1157 hasAttachments = true;
1158 }
1159 else
1160 {
1161 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1162 // If any framebuffer attachment is layered, all populated attachments
1163 // must be layered. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1164 ASSERT(isLayered.valid());
1165 if (isLayered.value() != depthAttachment.isLayered())
1166 {
1167 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1168 }
1169 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001170 }
1171
Jamie Madill48ef11b2016-04-27 15:21:52 -04001172 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001173 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001174 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001175 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001176 {
1177 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1178 }
1179
Geoff Lang677bb6f2017-04-05 12:40:40 -04001180 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001181 if (format.stencilBits == 0)
1182 {
1183 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001184 }
1185
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001186 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1187 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001188 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001189 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001190 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001191
Martin Radev9bc9a322017-07-21 14:28:17 +03001192 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1193 {
1194 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1195 }
1196
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001197 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
Jiawei Shaoa8802472018-05-28 11:17:47 +08001198
1199 if (!hasAttachments)
1200 {
1201 hasAttachments = true;
1202 }
1203 else
1204 {
1205 // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
1206 // If any framebuffer attachment is layered, all populated attachments
1207 // must be layered.
1208 // {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
1209 ASSERT(isLayered.valid());
1210 if (isLayered.value() != stencilAttachment.isLayered())
1211 {
1212 return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
1213 }
1214 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001215 }
1216
1217 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1218 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1219 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1220 {
1221 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001222 }
1223
Jamie Madilla02315b2017-02-23 14:14:47 -05001224 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1225 if (state.isWebGL1())
1226 {
1227 if (!mState.mWebGLDepthStencilConsistent)
1228 {
1229 return GL_FRAMEBUFFER_UNSUPPORTED;
1230 }
1231
1232 if (mState.mWebGLDepthStencilAttachment.isAttached())
1233 {
1234 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1235 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1236 {
1237 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1238 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001239
1240 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1241 &mState.mWebGLDepthStencilAttachment))
1242 {
1243 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1244 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001245 }
1246 else if (mState.mStencilAttachment.isAttached() &&
1247 mState.mStencilAttachment.getDepthSize() > 0)
1248 {
1249 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1250 }
1251 else if (mState.mDepthAttachment.isAttached() &&
1252 mState.mDepthAttachment.getStencilSize() > 0)
1253 {
1254 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1255 }
1256 }
1257
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001258 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1259 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1260 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001261 GLint defaultWidth = mState.getDefaultWidth();
1262 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001263 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001264 {
1265 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001266 }
1267
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001268 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001269 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001270 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1271 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001272 {
1273 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1274 }
1275
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001276 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1277 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001278 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1279 {
1280 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1281 }
1282
Kenneth Russellce8602a2017-10-03 18:23:08 -07001283 // The WebGL conformance tests implicitly define that all framebuffer
1284 // attachments must be unique. For example, the same level of a texture can
1285 // not be attached to two different color attachments.
1286 if (state.getExtensions().webglCompatibility)
1287 {
1288 if (!mState.colorAttachmentsAreUniqueImages())
1289 {
1290 return GL_FRAMEBUFFER_UNSUPPORTED;
1291 }
1292 }
1293
Jamie Madillcc86d642015-11-24 13:00:07 -05001294 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001295}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001296
Jamie Madill4928b7c2017-06-20 12:57:39 -04001297Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001298{
Jamie Madill05b35b22017-10-03 09:01:44 -04001299 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1300 // can be no-ops, so we should probably do that to ensure consistency.
1301 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1302
Jamie Madill4928b7c2017-06-20 12:57:39 -04001303 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001304}
1305
Jamie Madill4928b7c2017-06-20 12:57:39 -04001306Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001307{
Jamie Madill05b35b22017-10-03 09:01:44 -04001308 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1309 // can be no-ops, so we should probably do that to ensure consistency.
1310 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1311
Jamie Madill4928b7c2017-06-20 12:57:39 -04001312 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001313}
1314
Jamie Madill05b35b22017-10-03 09:01:44 -04001315bool Framebuffer::partialClearNeedsInit(const Context *context,
1316 bool color,
1317 bool depth,
1318 bool stencil)
1319{
1320 const auto &glState = context->getGLState();
1321
1322 if (!glState.isRobustResourceInitEnabled())
1323 {
1324 return false;
1325 }
1326
1327 // Scissors can affect clearing.
1328 // TODO(jmadill): Check for complete scissor overlap.
1329 if (glState.isScissorTestEnabled())
1330 {
1331 return true;
1332 }
1333
1334 // If colors masked, we must clear before we clear. Do a simple check.
1335 // TODO(jmadill): Filter out unused color channels from the test.
1336 if (color)
1337 {
1338 const auto &blend = glState.getBlendState();
1339 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1340 blend.colorMaskAlpha))
1341 {
1342 return true;
1343 }
1344 }
1345
1346 const auto &depthStencil = glState.getDepthStencilState();
1347 ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
1348 if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
1349 {
1350 return true;
1351 }
1352
1353 return false;
1354}
1355
Jamie Madill4928b7c2017-06-20 12:57:39 -04001356Error Framebuffer::invalidateSub(const Context *context,
1357 size_t count,
1358 const GLenum *attachments,
Jamie Madilld4442552018-02-27 22:03:47 -05001359 const Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001360{
Jamie Madill05b35b22017-10-03 09:01:44 -04001361 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1362 // can be no-ops, so we should probably do that to ensure consistency.
1363 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1364
Jamie Madill4928b7c2017-06-20 12:57:39 -04001365 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001366}
1367
Jamie Madilld4442552018-02-27 22:03:47 -05001368Error Framebuffer::clear(const Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001369{
Jamie Madill05b35b22017-10-03 09:01:44 -04001370 const auto &glState = context->getGLState();
1371 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001372 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001373 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001374 }
1375
Jamie Madill05b35b22017-10-03 09:01:44 -04001376 ANGLE_TRY(mImpl->clear(context, mask));
1377
Jamie Madill05b35b22017-10-03 09:01:44 -04001378 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001379}
1380
Jamie Madilld4442552018-02-27 22:03:47 -05001381Error Framebuffer::clearBufferfv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001382 GLenum buffer,
1383 GLint drawbuffer,
1384 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001385{
Jamie Madill05b35b22017-10-03 09:01:44 -04001386 if (context->getGLState().isRasterizerDiscardEnabled() ||
1387 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001388 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001389 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001390 }
1391
Jamie Madill05b35b22017-10-03 09:01:44 -04001392 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1393
Jamie Madill05b35b22017-10-03 09:01:44 -04001394 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001395}
1396
Jamie Madilld4442552018-02-27 22:03:47 -05001397Error Framebuffer::clearBufferuiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001398 GLenum buffer,
1399 GLint drawbuffer,
1400 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001401{
Jamie Madill05b35b22017-10-03 09:01:44 -04001402 if (context->getGLState().isRasterizerDiscardEnabled() ||
1403 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001404 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001405 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001406 }
1407
Jamie Madill05b35b22017-10-03 09:01:44 -04001408 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1409
Jamie Madill05b35b22017-10-03 09:01:44 -04001410 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001411}
1412
Jamie Madilld4442552018-02-27 22:03:47 -05001413Error Framebuffer::clearBufferiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001414 GLenum buffer,
1415 GLint drawbuffer,
1416 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001417{
Jamie Madill05b35b22017-10-03 09:01:44 -04001418 if (context->getGLState().isRasterizerDiscardEnabled() ||
1419 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001420 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001421 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001422 }
1423
Jamie Madill05b35b22017-10-03 09:01:44 -04001424 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1425
Jamie Madill05b35b22017-10-03 09:01:44 -04001426 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001427}
1428
Jamie Madilld4442552018-02-27 22:03:47 -05001429Error Framebuffer::clearBufferfi(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001430 GLenum buffer,
1431 GLint drawbuffer,
1432 GLfloat depth,
1433 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001434{
Jamie Madill05b35b22017-10-03 09:01:44 -04001435 if (context->getGLState().isRasterizerDiscardEnabled() ||
1436 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001437 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001438 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001439 }
1440
Jamie Madill05b35b22017-10-03 09:01:44 -04001441 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1442
Jamie Madill05b35b22017-10-03 09:01:44 -04001443 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001444}
1445
Jamie Madill690c8eb2018-03-12 15:20:03 -04001446Error Framebuffer::getImplementationColorReadFormat(const Context *context, GLenum *formatOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001447{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001448 ANGLE_TRY(syncState(context));
1449 *formatOut = mImpl->getImplementationColorReadFormat(context);
1450 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001451}
1452
Jamie Madill690c8eb2018-03-12 15:20:03 -04001453Error Framebuffer::getImplementationColorReadType(const Context *context, GLenum *typeOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001454{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001455 ANGLE_TRY(syncState(context));
1456 *typeOut = mImpl->getImplementationColorReadType(context);
1457 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001458}
1459
Jamie Madilld4442552018-02-27 22:03:47 -05001460Error Framebuffer::readPixels(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001461 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001462 GLenum format,
1463 GLenum type,
Jamie Madill05b35b22017-10-03 09:01:44 -04001464 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001465{
Jamie Madill05b35b22017-10-03 09:01:44 -04001466 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001467 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001468
Jamie Madilld4442552018-02-27 22:03:47 -05001469 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001470 if (unpackBuffer)
1471 {
Jamie Madill09463932018-04-04 05:26:59 -04001472 unpackBuffer->onPixelPack(context);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001473 }
1474
Jamie Madill362876b2016-06-16 14:46:59 -04001475 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001476}
1477
Jamie Madilld4442552018-02-27 22:03:47 -05001478Error Framebuffer::blit(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001479 const Rectangle &sourceArea,
1480 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001481 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001482 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001483{
He Yunchao6be602d2016-12-22 14:33:07 +08001484 GLbitfield blitMask = mask;
1485
1486 // Note that blitting is called against draw framebuffer.
1487 // See the code in gl::Context::blitFramebuffer.
1488 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1489 {
1490 blitMask &= ~GL_COLOR_BUFFER_BIT;
1491 }
1492
1493 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1494 {
1495 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1496 }
1497
1498 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1499 {
1500 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1501 }
1502
1503 if (!blitMask)
1504 {
1505 return NoError();
1506 }
1507
Jamie Madill05b35b22017-10-03 09:01:44 -04001508 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1509 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1510
1511 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1512 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1513
He Yunchao6be602d2016-12-22 14:33:07 +08001514 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001515}
1516
Jamie Madill427064d2018-04-13 16:20:34 -04001517int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001518{
Jamie Madill427064d2018-04-13 16:20:34 -04001519 return (isComplete(context) ? getCachedSamples(context) : 0);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001520}
1521
Jamie Madill9c335862017-07-18 11:51:38 -04001522int Framebuffer::getCachedSamples(const Context *context)
1523{
Jamie Madill5b772312018-03-08 20:28:32 -05001524 ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
1525
Jamie Madill9c335862017-07-18 11:51:38 -04001526 // For a complete framebuffer, all attachments must have the same sample count.
1527 // In this case return the first nonzero sample size.
1528 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1529 if (firstNonNullAttachment)
1530 {
1531 ASSERT(firstNonNullAttachment->isAttached());
1532 return firstNonNullAttachment->getSamples();
1533 }
1534
1535 // No attachments found.
1536 return 0;
1537}
1538
Geoff Lang13455072018-05-09 11:24:43 -04001539Error Framebuffer::getSamplePosition(const Context *context, size_t index, GLfloat *xy) const
Corentin Wallezccab69d2017-01-27 16:57:15 -05001540{
Geoff Lang13455072018-05-09 11:24:43 -04001541 ANGLE_TRY(mImpl->getSamplePosition(context, index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001542 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001543}
1544
Jamie Madille261b442014-06-25 12:42:21 -04001545bool Framebuffer::hasValidDepthStencil() const
1546{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001547 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001548}
1549
Jamie Madilla02315b2017-02-23 14:14:47 -05001550void Framebuffer::setAttachment(const Context *context,
1551 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001552 GLenum binding,
1553 const ImageIndex &textureIndex,
1554 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001555{
Martin Radev5dae57b2017-07-14 16:15:55 +03001556 setAttachment(context, type, binding, textureIndex, resource,
1557 FramebufferAttachment::kDefaultNumViews,
1558 FramebufferAttachment::kDefaultBaseViewIndex,
1559 FramebufferAttachment::kDefaultMultiviewLayout,
1560 FramebufferAttachment::kDefaultViewportOffsets);
1561}
1562
1563void Framebuffer::setAttachment(const Context *context,
1564 GLenum type,
1565 GLenum binding,
1566 const ImageIndex &textureIndex,
1567 FramebufferAttachmentObject *resource,
1568 GLsizei numViews,
1569 GLuint baseViewIndex,
1570 GLenum multiviewLayout,
1571 const GLint *viewportOffsets)
1572{
Jamie Madilla02315b2017-02-23 14:14:47 -05001573 // Context may be null in unit tests.
1574 if (!context || !context->isWebGL1())
1575 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001576 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1577 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001578 return;
1579 }
1580
1581 switch (binding)
1582 {
1583 case GL_DEPTH_STENCIL:
1584 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001585 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001586 resource, numViews, baseViewIndex,
1587 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001588 break;
1589 case GL_DEPTH:
1590 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001591 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1592 numViews, baseViewIndex, multiviewLayout,
1593 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001594 break;
1595 case GL_STENCIL:
1596 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001597 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1598 numViews, baseViewIndex, multiviewLayout,
1599 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001600 break;
1601 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001602 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1603 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001604 return;
1605 }
1606
Martin Radev5dae57b2017-07-14 16:15:55 +03001607 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1608 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001609}
1610
Martin Radev82ef7742017-08-08 17:44:58 +03001611void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1612 GLenum type,
1613 GLenum binding,
1614 const ImageIndex &textureIndex,
1615 FramebufferAttachmentObject *resource,
1616 GLsizei numViews,
1617 GLint baseViewIndex)
1618{
1619 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1620 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1621 FramebufferAttachment::kDefaultViewportOffsets);
1622}
1623
Martin Radev5dae57b2017-07-14 16:15:55 +03001624void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1625 GLenum type,
1626 GLenum binding,
1627 const ImageIndex &textureIndex,
1628 FramebufferAttachmentObject *resource,
1629 GLsizei numViews,
1630 const GLint *viewportOffsets)
1631{
1632 setAttachment(context, type, binding, textureIndex, resource, numViews,
1633 FramebufferAttachment::kDefaultBaseViewIndex,
1634 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1635}
1636
1637void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1638 GLsizei numViews,
1639 GLuint baseViewIndex,
1640 GLenum multiviewLayout,
1641 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001642{
1643 int count = 0;
1644
1645 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1646 &mState.mWebGLDepthAttachment,
1647 &mState.mWebGLStencilAttachment}};
1648 for (FramebufferAttachment *attachment : attachments)
1649 {
1650 if (attachment->isAttached())
1651 {
1652 count++;
1653 }
1654 }
1655
1656 mState.mWebGLDepthStencilConsistent = (count <= 1);
1657 if (!mState.mWebGLDepthStencilConsistent)
1658 {
1659 // Inconsistent.
1660 return;
1661 }
1662
Geoff Lange466c552017-03-17 15:24:12 -04001663 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1664 if (attachment.type() == GL_TEXTURE)
1665 {
1666 return attachment.getTextureImageIndex();
1667 }
1668 else
1669 {
Jamie Madillcc129372018-04-12 09:13:18 -04001670 return ImageIndex();
Geoff Lange466c552017-03-17 15:24:12 -04001671 }
1672 };
1673
Jamie Madilla02315b2017-02-23 14:14:47 -05001674 if (mState.mWebGLDepthAttachment.isAttached())
1675 {
1676 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001677 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001678 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1679 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madillcc129372018-04-12 09:13:18 -04001680 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1681 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001682 }
1683 else if (mState.mWebGLStencilAttachment.isAttached())
1684 {
1685 const auto &stencil = mState.mWebGLStencilAttachment;
Jamie Madillcc129372018-04-12 09:13:18 -04001686 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1687 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001688 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001689 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1690 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001691 }
1692 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1693 {
1694 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001695 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001696 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001697 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1698 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001699 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001700 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001701 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1702 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001703 }
1704 else
1705 {
Jamie Madillcc129372018-04-12 09:13:18 -04001706 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1707 baseViewIndex, multiviewLayout, viewportOffsets);
1708 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1709 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001710 }
1711}
1712
Jamie Madill4928b7c2017-06-20 12:57:39 -04001713void Framebuffer::setAttachmentImpl(const Context *context,
1714 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001715 GLenum binding,
1716 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001717 FramebufferAttachmentObject *resource,
1718 GLsizei numViews,
1719 GLuint baseViewIndex,
1720 GLenum multiviewLayout,
1721 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001722{
Jamie Madilla02315b2017-02-23 14:14:47 -05001723 switch (binding)
1724 {
Jamie Madillb8126692017-04-05 11:22:17 -04001725 case GL_DEPTH_STENCIL:
1726 case GL_DEPTH_STENCIL_ATTACHMENT:
1727 {
1728 // ensure this is a legitimate depth+stencil format
1729 FramebufferAttachmentObject *attachmentObj = resource;
1730 if (resource)
1731 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001732 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001733 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1734 {
1735 // Attaching nullptr detaches the current attachment.
1736 attachmentObj = nullptr;
1737 }
1738 }
1739
Jamie Madill4928b7c2017-06-20 12:57:39 -04001740 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001741 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001742 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1743 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001744 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001745 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001746 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1747 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001748 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001749 }
1750
Jamie Madilla02315b2017-02-23 14:14:47 -05001751 case GL_DEPTH:
1752 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001753 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001754 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1755 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001756 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001757
Jamie Madilla02315b2017-02-23 14:14:47 -05001758 case GL_STENCIL:
1759 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001760 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001761 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1762 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001763 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001764
Jamie Madilla02315b2017-02-23 14:14:47 -05001765 case GL_BACK:
Geoff Lang8170eab2017-09-21 13:59:04 -04001766 updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1767 &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1768 resource, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001769 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001770
Jamie Madilla02315b2017-02-23 14:14:47 -05001771 default:
1772 {
1773 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1774 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001775 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001776 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001777 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001778 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1779 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001780
Corentin Walleze7557742017-06-01 13:09:57 -04001781 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1782 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001783 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1784 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Brandon Jones76746f92017-11-22 11:44:41 -08001785 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -04001786 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001787 break;
Geoff Langab75a052014-10-15 12:56:37 -04001788 }
Jamie Madill42975642017-10-12 12:31:51 -04001789
1790 mAttachedTextures.reset();
Geoff Langab75a052014-10-15 12:56:37 -04001791}
1792
Jamie Madill4928b7c2017-06-20 12:57:39 -04001793void Framebuffer::updateAttachment(const Context *context,
1794 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001795 size_t dirtyBit,
Jamie Madilld4442552018-02-27 22:03:47 -05001796 angle::ObserverBinding *onDirtyBinding,
Jamie Madillb8126692017-04-05 11:22:17 -04001797 GLenum type,
1798 GLenum binding,
1799 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001800 FramebufferAttachmentObject *resource,
1801 GLsizei numViews,
1802 GLuint baseViewIndex,
1803 GLenum multiviewLayout,
1804 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001805{
Martin Radev5dae57b2017-07-14 16:15:55 +03001806 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1807 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001808 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001809 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madill888081d2018-02-27 00:24:46 -05001810 onDirtyBinding->bind(resource ? resource->getSubject() : nullptr);
Jamie Madille98b1b52018-03-08 09:47:23 -05001811
1812 invalidateCompletenessCache();
Jamie Madillb8126692017-04-05 11:22:17 -04001813}
1814
Jamie Madilla02315b2017-02-23 14:14:47 -05001815void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001816{
Jamie Madillcc129372018-04-12 09:13:18 -04001817 setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001818}
1819
Jamie Madill19fa1c62018-03-08 09:47:21 -05001820Error Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001821{
1822 if (mDirtyBits.any())
1823 {
Jamie Madill888081d2018-02-27 00:24:46 -05001824 mDirtyBitsGuard = mDirtyBits;
Jamie Madill19fa1c62018-03-08 09:47:21 -05001825 ANGLE_TRY(mImpl->syncState(context, mDirtyBits));
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001826 mDirtyBits.reset();
Jamie Madill888081d2018-02-27 00:24:46 -05001827 mDirtyBitsGuard.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001828 }
Jamie Madill19fa1c62018-03-08 09:47:21 -05001829 return NoError();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001830}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001831
Jamie Madilld4442552018-02-27 22:03:47 -05001832void Framebuffer::onSubjectStateChange(const Context *context,
1833 angle::SubjectIndex index,
1834 angle::SubjectMessage message)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001835{
Jamie Madill888081d2018-02-27 00:24:46 -05001836 if (message == angle::SubjectMessage::DEPENDENT_DIRTY_BITS)
1837 {
1838 ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
1839 mDirtyBits.set(index);
1840 context->getGLState().setFramebufferDirty(this);
1841 return;
1842 }
1843
Geoff Lang8170eab2017-09-21 13:59:04 -04001844 // Only reset the cached status if this is not the default framebuffer. The default framebuffer
1845 // will still use this channel to mark itself dirty.
Jamie Madill2274b652018-05-31 10:56:08 -04001846 if (mState.mId != 0)
Geoff Lang8170eab2017-09-21 13:59:04 -04001847 {
1848 // TOOD(jmadill): Make this only update individual attachments to do less work.
1849 mCachedStatus.reset();
1850 }
Jamie Madill05b35b22017-10-03 09:01:44 -04001851
Jamie Madilld4442552018-02-27 22:03:47 -05001852 FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
1853
Jamie Madill05b35b22017-10-03 09:01:44 -04001854 // Mark the appropriate init flag.
Jamie Madilld4442552018-02-27 22:03:47 -05001855 mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
1856}
1857
1858FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
1859{
1860 switch (index)
1861 {
1862 case DIRTY_BIT_DEPTH_ATTACHMENT:
1863 return &mState.mDepthAttachment;
1864 case DIRTY_BIT_STENCIL_ATTACHMENT:
1865 return &mState.mStencilAttachment;
1866 default:
1867 size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
1868 ASSERT(colorIndex < mState.mColorAttachments.size());
1869 return &mState.mColorAttachments[colorIndex];
1870 }
Jamie Madill51f40ec2016-06-15 14:06:00 -04001871}
1872
Jamie Madill427064d2018-04-13 16:20:34 -04001873bool Framebuffer::isComplete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001874{
Jamie Madill427064d2018-04-13 16:20:34 -04001875 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001876}
1877
Jamie Madilla4595b82017-01-11 17:36:34 -05001878bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1879{
1880 const Program *program = state.getProgram();
1881
1882 // TODO(jmadill): Default framebuffer feedback loops.
Jamie Madill2274b652018-05-31 10:56:08 -04001883 if (mState.mId == 0)
Jamie Madilla4595b82017-01-11 17:36:34 -05001884 {
1885 return false;
1886 }
1887
1888 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001889 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001890 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001891 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1892 ASSERT(attachment.isAttached());
1893 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001894 {
1895 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001896 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001897 {
1898 return true;
1899 }
1900 }
1901 }
1902
Jamie Madill1d37bc52017-02-02 19:59:58 -05001903 // Validate depth-stencil feedback loop.
1904 const auto &dsState = state.getDepthStencilState();
1905
1906 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1907 const FramebufferAttachment *depth = getDepthbuffer();
1908 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1909 {
1910 if (program->samplesFromTexture(state, depth->id()))
1911 {
1912 return true;
1913 }
1914 }
1915
Jamie Madill1d37bc52017-02-02 19:59:58 -05001916 const FramebufferAttachment *stencil = getStencilbuffer();
Ken Russellb9f92502018-01-27 19:00:26 -08001917 if (dsState.stencilTest && stencil)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001918 {
Ken Russellb9f92502018-01-27 19:00:26 -08001919 GLuint stencilSize = stencil->getStencilSize();
1920 ASSERT(stencilSize <= 8);
1921 GLuint maxStencilValue = (1 << stencilSize) - 1;
1922 // We assume the front and back masks are the same for WebGL.
1923 ASSERT((dsState.stencilBackWritemask & maxStencilValue) ==
1924 (dsState.stencilWritemask & maxStencilValue));
1925 if (stencil->type() == GL_TEXTURE && dsState.stencilWritemask != 0)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001926 {
Ken Russellb9f92502018-01-27 19:00:26 -08001927 // Skip the feedback loop check if depth/stencil point to the same resource.
1928 if (!depth || *stencil != *depth)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001929 {
Ken Russellb9f92502018-01-27 19:00:26 -08001930 if (program->samplesFromTexture(state, stencil->id()))
1931 {
1932 return true;
1933 }
Jamie Madill1d37bc52017-02-02 19:59:58 -05001934 }
1935 }
1936 }
1937
Jamie Madilla4595b82017-01-11 17:36:34 -05001938 return false;
1939}
1940
Jamie Madillfd3dd432017-02-02 19:59:59 -05001941bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1942 GLint copyTextureLevel,
1943 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001944{
Jamie Madill2274b652018-05-31 10:56:08 -04001945 if (mState.mId == 0)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001946 {
1947 // It seems impossible to form a texture copying feedback loop with the default FBO.
1948 return false;
1949 }
1950
1951 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1952 ASSERT(readAttachment);
1953
1954 if (readAttachment->isTextureWithId(copyTextureID))
1955 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001956 const auto &imageIndex = readAttachment->getTextureImageIndex();
Jamie Madillcc129372018-04-12 09:13:18 -04001957 if (imageIndex.getLevelIndex() == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001958 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001959 // Check 3D/Array texture layers.
Jamie Madillcc129372018-04-12 09:13:18 -04001960 return !imageIndex.hasLayer() || copyTextureLayer == ImageIndex::kEntireLevel ||
1961 imageIndex.getLayerIndex() == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001962 }
1963 }
1964 return false;
1965}
1966
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001967GLint Framebuffer::getDefaultWidth() const
1968{
1969 return mState.getDefaultWidth();
1970}
1971
1972GLint Framebuffer::getDefaultHeight() const
1973{
1974 return mState.getDefaultHeight();
1975}
1976
1977GLint Framebuffer::getDefaultSamples() const
1978{
1979 return mState.getDefaultSamples();
1980}
1981
Geoff Lang92019432017-11-20 13:09:34 -05001982bool Framebuffer::getDefaultFixedSampleLocations() const
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001983{
1984 return mState.getDefaultFixedSampleLocations();
1985}
1986
Jiawei Shaob1e91382018-05-17 14:33:55 +08001987GLint Framebuffer::getDefaultLayers() const
1988{
1989 return mState.getDefaultLayers();
1990}
1991
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001992void Framebuffer::setDefaultWidth(GLint defaultWidth)
1993{
1994 mState.mDefaultWidth = defaultWidth;
1995 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
Jamie Madille98b1b52018-03-08 09:47:23 -05001996 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001997}
1998
1999void Framebuffer::setDefaultHeight(GLint defaultHeight)
2000{
2001 mState.mDefaultHeight = defaultHeight;
2002 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
Jamie Madille98b1b52018-03-08 09:47:23 -05002003 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08002004}
2005
2006void Framebuffer::setDefaultSamples(GLint defaultSamples)
2007{
2008 mState.mDefaultSamples = defaultSamples;
2009 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
Jamie Madille98b1b52018-03-08 09:47:23 -05002010 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08002011}
2012
Geoff Lang92019432017-11-20 13:09:34 -05002013void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08002014{
2015 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
2016 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
Jamie Madille98b1b52018-03-08 09:47:23 -05002017 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08002018}
2019
Jiawei Shaob1e91382018-05-17 14:33:55 +08002020void Framebuffer::setDefaultLayers(GLint defaultLayers)
2021{
2022 mState.mDefaultLayers = defaultLayers;
2023 mDirtyBits.set(DIRTY_BIT_DEFAULT_LAYERS);
2024}
2025
Martin Radev14a26ae2017-07-24 15:56:29 +03002026GLsizei Framebuffer::getNumViews() const
2027{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002028 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03002029}
2030
Martin Radev4e619f52017-08-09 11:50:06 +03002031GLint Framebuffer::getBaseViewIndex() const
2032{
2033 return mState.getBaseViewIndex();
2034}
2035
Martin Radev878c8b12017-07-28 09:51:04 +03002036const std::vector<Offset> *Framebuffer::getViewportOffsets() const
2037{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002038 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03002039}
2040
2041GLenum Framebuffer::getMultiviewLayout() const
2042{
Martin Radev5c00d0d2017-08-07 10:06:59 +03002043 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03002044}
2045
Geoff Langd4fff502017-09-22 11:28:28 -04002046Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask)
2047{
2048 const auto &glState = context->getGLState();
2049 if (!context->isRobustResourceInitEnabled() || glState.isRasterizerDiscardEnabled())
2050 {
2051 return NoError();
2052 }
2053
Geoff Langa36483f2018-03-09 16:11:21 -05002054 const BlendState &blend = glState.getBlendState();
2055 const DepthStencilState &depthStencil = glState.getDepthStencilState();
Geoff Langd4fff502017-09-22 11:28:28 -04002056
2057 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
2058 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
2059 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
2060
2061 if (!color && !depth && !stencil)
2062 {
2063 return NoError();
2064 }
2065
2066 if (partialClearNeedsInit(context, color, depth, stencil))
2067 {
2068 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
2069 }
2070
2071 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2072 // still be marked initialized. This simplifies design, allowing this method to be called before
2073 // the clear.
2074 markDrawAttachmentsInitialized(color, depth, stencil);
2075
2076 return NoError();
2077}
2078
2079Error Framebuffer::ensureClearBufferAttachmentsInitialized(const Context *context,
2080 GLenum buffer,
2081 GLint drawbuffer)
2082{
2083 if (!context->isRobustResourceInitEnabled() ||
2084 context->getGLState().isRasterizerDiscardEnabled() ||
2085 IsClearBufferMaskedOut(context, buffer))
2086 {
2087 return NoError();
2088 }
2089
2090 if (partialBufferClearNeedsInit(context, buffer))
2091 {
2092 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
2093 }
2094
2095 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2096 // still be marked initialized. This simplifies design, allowing this method to be called before
2097 // the clear.
2098 markBufferInitialized(buffer, drawbuffer);
2099
2100 return NoError();
2101}
2102
Jamie Madill05b35b22017-10-03 09:01:44 -04002103Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
2104{
2105 if (!context->isRobustResourceInitEnabled())
2106 {
2107 return NoError();
2108 }
2109
2110 // Note: we don't actually filter by the draw attachment enum. Just init everything.
2111 for (size_t bit : mState.mResourceNeedsInit)
2112 {
2113 switch (bit)
2114 {
2115 case DIRTY_BIT_DEPTH_ATTACHMENT:
2116 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2117 break;
2118 case DIRTY_BIT_STENCIL_ATTACHMENT:
2119 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2120 break;
2121 default:
2122 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2123 break;
2124 }
2125 }
2126
2127 mState.mResourceNeedsInit.reset();
2128 return NoError();
2129}
2130
2131Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
2132{
2133 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2134 {
2135 return NoError();
2136 }
2137
2138 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
2139 {
2140 size_t readIndex = mState.getReadIndex();
2141 if (mState.mResourceNeedsInit[readIndex])
2142 {
2143 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2144 mState.mResourceNeedsInit.reset(readIndex);
2145 }
2146 }
2147
2148 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
2149 {
2150 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2151 {
2152 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2153 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2154 }
2155 }
2156
2157 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
2158 {
2159 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2160 {
2161 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2162 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2163 }
2164 }
2165
2166 return NoError();
2167}
2168
2169void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2170{
2171 // Mark attachments as initialized.
2172 if (color)
2173 {
2174 for (auto colorIndex : mState.mEnabledDrawBuffers)
2175 {
2176 auto &colorAttachment = mState.mColorAttachments[colorIndex];
2177 ASSERT(colorAttachment.isAttached());
2178 colorAttachment.setInitState(InitState::Initialized);
2179 mState.mResourceNeedsInit.reset(colorIndex);
2180 }
2181 }
2182
2183 if (depth && mState.mDepthAttachment.isAttached())
2184 {
2185 mState.mDepthAttachment.setInitState(InitState::Initialized);
2186 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2187 }
2188
2189 if (stencil && mState.mStencilAttachment.isAttached())
2190 {
2191 mState.mStencilAttachment.setInitState(InitState::Initialized);
2192 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2193 }
2194}
2195
2196void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2197{
2198 switch (bufferType)
2199 {
2200 case GL_COLOR:
2201 {
2202 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2203 if (mState.mColorAttachments[bufferIndex].isAttached())
2204 {
2205 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2206 mState.mResourceNeedsInit.reset(bufferIndex);
2207 }
2208 break;
2209 }
2210 case GL_DEPTH:
2211 {
2212 if (mState.mDepthAttachment.isAttached())
2213 {
2214 mState.mDepthAttachment.setInitState(InitState::Initialized);
2215 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2216 }
2217 break;
2218 }
2219 case GL_STENCIL:
2220 {
2221 if (mState.mStencilAttachment.isAttached())
2222 {
2223 mState.mStencilAttachment.setInitState(InitState::Initialized);
2224 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2225 }
2226 break;
2227 }
2228 case GL_DEPTH_STENCIL:
2229 {
2230 if (mState.mDepthAttachment.isAttached())
2231 {
2232 mState.mDepthAttachment.setInitState(InitState::Initialized);
2233 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2234 }
2235 if (mState.mStencilAttachment.isAttached())
2236 {
2237 mState.mStencilAttachment.setInitState(InitState::Initialized);
2238 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2239 }
2240 break;
2241 }
2242 default:
2243 UNREACHABLE();
2244 break;
2245 }
2246}
2247
2248Box Framebuffer::getDimensions() const
2249{
2250 return mState.getDimensions();
2251}
2252
2253Error Framebuffer::ensureBufferInitialized(const Context *context,
2254 GLenum bufferType,
2255 GLint bufferIndex)
2256{
2257 ASSERT(context->isRobustResourceInitEnabled());
2258
2259 if (mState.mResourceNeedsInit.none())
2260 {
2261 return NoError();
2262 }
2263
2264 switch (bufferType)
2265 {
2266 case GL_COLOR:
2267 {
2268 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2269 if (mState.mResourceNeedsInit[bufferIndex])
2270 {
2271 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2272 mState.mResourceNeedsInit.reset(bufferIndex);
2273 }
2274 break;
2275 }
2276 case GL_DEPTH:
2277 {
2278 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2279 {
2280 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2281 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2282 }
2283 break;
2284 }
2285 case GL_STENCIL:
2286 {
2287 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2288 {
2289 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2290 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2291 }
2292 break;
2293 }
2294 case GL_DEPTH_STENCIL:
2295 {
2296 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2297 {
2298 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2299 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2300 }
2301 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2302 {
2303 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2304 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2305 }
2306 break;
2307 }
2308 default:
2309 UNREACHABLE();
2310 break;
2311 }
2312
2313 return NoError();
2314}
2315
2316bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2317{
2318 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2319 {
2320 return false;
2321 }
2322
2323 switch (bufferType)
2324 {
2325 case GL_COLOR:
2326 return partialClearNeedsInit(context, true, false, false);
2327 case GL_DEPTH:
2328 return partialClearNeedsInit(context, false, true, false);
2329 case GL_STENCIL:
2330 return partialClearNeedsInit(context, false, false, true);
2331 case GL_DEPTH_STENCIL:
2332 return partialClearNeedsInit(context, false, true, true);
2333 default:
2334 UNREACHABLE();
2335 return false;
2336 }
2337}
2338
Jamie Madill42975642017-10-12 12:31:51 -04002339bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2340{
2341 if (!mAttachedTextures.valid())
2342 {
2343 std::set<const FramebufferAttachmentObject *> attachedTextures;
2344
2345 for (const auto &colorAttachment : mState.mColorAttachments)
2346 {
2347 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2348 {
2349 attachedTextures.insert(colorAttachment.getResource());
2350 }
2351 }
2352
2353 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2354 {
2355 attachedTextures.insert(mState.mDepthAttachment.getResource());
2356 }
2357
2358 if (mState.mStencilAttachment.isAttached() &&
2359 mState.mStencilAttachment.type() == GL_TEXTURE)
2360 {
2361 attachedTextures.insert(mState.mStencilAttachment.getResource());
2362 }
2363
2364 mAttachedTextures = std::move(attachedTextures);
2365 }
2366
2367 return (mAttachedTextures.value().count(texture) > 0);
2368}
2369
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002370} // namespace gl