blob: 4bb4837a530a4664dc98cf5c63373006d816c910 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Framebuffer.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040011
Jamie Madillcc86d642015-11-24 13:00:07 -050012#include "common/Optional.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040013#include "common/bitset_utils.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040014#include "common/utilities.h"
15#include "libANGLE/Config.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Context.h"
Jamie Madill6c1f6712017-02-14 19:08:04 -050017#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050018#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040019#include "libANGLE/Renderbuffer.h"
20#include "libANGLE/Surface.h"
21#include "libANGLE/Texture.h"
Brandon Jones76746f92017-11-22 11:44:41 -080022#include "libANGLE/angletypes.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040023#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040024#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050025#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040026#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050027#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040028#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040029
Jamie Madill362876b2016-06-16 14:46:59 -040030using namespace angle;
31
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000032namespace gl
33{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000034
Jamie Madilld1405e52015-03-05 15:41:39 -050035namespace
36{
Jamie Madill362876b2016-06-16 14:46:59 -040037
Martin Radev9bc9a322017-07-21 14:28:17 +030038bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
39 const FramebufferAttachment *secondAttachment)
40{
41 ASSERT(firstAttachment && secondAttachment);
42 ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
43
44 if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
45 {
46 return false;
47 }
48 if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
49 {
50 return false;
51 }
52 if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
53 {
54 return false;
55 }
56 if (firstAttachment->getMultiviewViewportOffsets() !=
57 secondAttachment->getMultiviewViewportOffsets())
58 {
59 return false;
60 }
61 return true;
62}
63
Geoff Lang9f10b772017-05-16 15:51:03 -040064bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
65{
66 ASSERT(attachment.isAttached());
67
68 const Extents &size = attachment.getSize();
69 if (size.width == 0 || size.height == 0)
70 {
71 return false;
72 }
73
74 const InternalFormat &format = *attachment.getFormat().info;
75 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
76 {
77 return false;
78 }
79
80 if (attachment.type() == GL_TEXTURE)
81 {
82 if (attachment.layer() >= size.depth)
83 {
84 return false;
85 }
86
87 // ES3 specifies that cube map texture attachments must be cube complete.
88 // This language is missing from the ES2 spec, but we enforce it here because some
89 // desktop OpenGL drivers also enforce this validation.
90 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
91 const Texture *texture = attachment.getTexture();
92 ASSERT(texture);
Corentin Wallez99d492c2018-02-27 15:17:10 -050093 if (texture->getType() == TextureType::CubeMap &&
Geoff Lang9f10b772017-05-16 15:51:03 -040094 !texture->getTextureState().isCubeComplete())
95 {
96 return false;
97 }
Geoff Lang857c09d2017-05-16 15:55:04 -040098
99 if (!texture->getImmutableFormat())
100 {
101 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
102
103 // From the ES 3.0 spec, pg 213:
104 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
105 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
106 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
107 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
108 // the effective maximum texture level defined in the Mipmapping discussion of
109 // section 3.8.10.4.
110 if (attachmentMipLevel < texture->getBaseLevel() ||
111 attachmentMipLevel > texture->getMipmapMaxLevel())
112 {
113 return false;
114 }
115
116 // Form the ES 3.0 spec, pg 213/214:
117 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
118 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
119 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
120 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
121 // a cubemap texture, the texture must also be cube complete.
122 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
123 {
124 return false;
125 }
126 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400127 }
128
129 return true;
130};
131
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400132bool CheckAttachmentSampleCompleteness(const Context *context,
133 const FramebufferAttachment &attachment,
134 bool colorAttachment,
135 Optional<int> *samples,
Geoff Lang92019432017-11-20 13:09:34 -0500136 Optional<bool> *fixedSampleLocations)
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400137{
138 ASSERT(attachment.isAttached());
139
140 if (attachment.type() == GL_TEXTURE)
141 {
142 const Texture *texture = attachment.getTexture();
143 ASSERT(texture);
144
145 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
146
147 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
148 // the same for all attached textures.
Jamie Madillcc129372018-04-12 09:13:18 -0400149 bool fixedSampleloc = texture->getFixedSampleLocations(
150 attachmentImageIndex.getTarget(), attachmentImageIndex.getLevelIndex());
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400151 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
152 {
153 return false;
154 }
155 else
156 {
157 *fixedSampleLocations = fixedSampleloc;
158 }
159 }
160
161 if (samples->valid())
162 {
163 if (attachment.getSamples() != samples->value())
164 {
165 if (colorAttachment)
166 {
167 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
168 // all color attachments have the same number of samples for the FBO to be complete.
169 return false;
170 }
171 else
172 {
173 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
174 // when its depth or stencil samples are a multiple of the number of color samples.
175 if (!context->getExtensions().framebufferMixedSamples)
176 {
177 return false;
178 }
179
180 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
181 {
182 return false;
183 }
184 }
185 }
186 }
187 else
188 {
189 *samples = attachment.getSamples();
190 }
191
192 return true;
193}
194
Jamie Madill05b35b22017-10-03 09:01:44 -0400195// Needed to index into the attachment arrays/bitsets.
Jamie Madill682efdc2017-10-03 14:10:29 -0400196static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500197 Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX,
Jamie Madill05b35b22017-10-03 09:01:44 -0400198 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400199static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500200 Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400201 "Framebuffer Dirty bit mismatch");
Jamie Madill682efdc2017-10-03 14:10:29 -0400202static_assert(static_cast<size_t>(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) ==
Jamie Madilld4442552018-02-27 22:03:47 -0500203 Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madill05b35b22017-10-03 09:01:44 -0400204 "Framebuffer Dirty bit mismatch");
205
206Error InitAttachment(const Context *context, FramebufferAttachment *attachment)
207{
208 ASSERT(attachment->isAttached());
209 if (attachment->initState() == InitState::MayNeedInit)
210 {
211 ANGLE_TRY(attachment->initializeContents(context));
212 }
213 return NoError();
214}
215
216bool IsColorMaskedOut(const BlendState &blend)
217{
218 return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue &&
219 !blend.colorMaskAlpha);
220}
221
222bool IsDepthMaskedOut(const DepthStencilState &depthStencil)
223{
224 return !depthStencil.depthMask;
225}
226
227bool IsStencilMaskedOut(const DepthStencilState &depthStencil)
228{
229 return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0);
230}
231
232bool IsClearBufferMaskedOut(const Context *context, GLenum buffer)
233{
234 switch (buffer)
235 {
236 case GL_COLOR:
237 return IsColorMaskedOut(context->getGLState().getBlendState());
238 case GL_DEPTH:
239 return IsDepthMaskedOut(context->getGLState().getDepthStencilState());
240 case GL_STENCIL:
241 return IsStencilMaskedOut(context->getGLState().getDepthStencilState());
242 case GL_DEPTH_STENCIL:
243 return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) &&
244 IsStencilMaskedOut(context->getGLState().getDepthStencilState());
245 default:
246 UNREACHABLE();
247 return true;
248 }
249}
250
Jamie Madill362876b2016-06-16 14:46:59 -0400251} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500252
Jamie Madill6f60d052017-02-22 15:20:11 -0500253// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400254FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500255 : mLabel(),
256 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400257 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500258 mReadBufferState(GL_BACK),
Brandon Jones76746f92017-11-22 11:44:41 -0800259 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800260 mDefaultWidth(0),
261 mDefaultHeight(0),
262 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500263 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800264 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500265 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400266{
Geoff Langd90d3882017-03-21 10:49:54 -0400267 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500268 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400269}
270
Jamie Madill48ef11b2016-04-27 15:21:52 -0400271FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -0500272 : mLabel(),
273 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -0500274 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800275 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
Brandon Jones76746f92017-11-22 11:44:41 -0800276 mDrawBufferTypeMask(),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800277 mDefaultWidth(0),
278 mDefaultHeight(0),
279 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500280 mDefaultFixedSampleLocations(GL_FALSE),
Jiawei Shaob1e91382018-05-17 14:33:55 +0800281 mDefaultLayers(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500282 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500283{
Geoff Langa15472a2015-08-11 11:48:03 -0400284 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500285 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
286}
287
Jamie Madill48ef11b2016-04-27 15:21:52 -0400288FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500289{
Jamie Madilld1405e52015-03-05 15:41:39 -0500290}
291
Jamie Madill48ef11b2016-04-27 15:21:52 -0400292const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500293{
294 return mLabel;
295}
296
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800297const FramebufferAttachment *FramebufferState::getAttachment(const Context *context,
298 GLenum attachment) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400299{
300 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
301 {
302 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
303 }
304
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800305 // WebGL1 allows a developer to query for attachment parameters even when "inconsistant" (i.e.
306 // multiple conflicting attachment points) and requires us to return the framebuffer attachment
307 // associated with WebGL.
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400308 switch (attachment)
309 {
310 case GL_COLOR:
311 case GL_BACK:
312 return getColorAttachment(0);
313 case GL_DEPTH:
314 case GL_DEPTH_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800315 if (context->isWebGL1())
316 {
317 return getWebGLDepthAttachment();
318 }
319 else
320 {
321 return getDepthAttachment();
322 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400323 case GL_STENCIL:
324 case GL_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800325 if (context->isWebGL1())
326 {
327 return getWebGLStencilAttachment();
328 }
329 else
330 {
331 return getStencilAttachment();
332 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400333 case GL_DEPTH_STENCIL:
334 case GL_DEPTH_STENCIL_ATTACHMENT:
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800335 if (context->isWebGL1())
336 {
337 return getWebGLDepthStencilAttachment();
338 }
339 else
340 {
341 return getDepthStencilAttachment();
342 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400343 default:
344 UNREACHABLE();
345 return nullptr;
346 }
347}
348
Jamie Madill05b35b22017-10-03 09:01:44 -0400349size_t FramebufferState::getReadIndex() const
Jamie Madill7147f012015-03-05 15:41:40 -0500350{
Jamie Madill231c7f52017-04-26 13:45:37 -0400351 ASSERT(mReadBufferState == GL_BACK ||
352 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
353 size_t readIndex = (mReadBufferState == GL_BACK
354 ? 0
355 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500356 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill05b35b22017-10-03 09:01:44 -0400357 return readIndex;
358}
359
360const FramebufferAttachment *FramebufferState::getReadAttachment() const
361{
362 if (mReadBufferState == GL_NONE)
363 {
364 return nullptr;
365 }
366 size_t readIndex = getReadIndex();
Jamie Madill2d06b732015-04-20 12:53:28 -0400367 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500368}
369
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500370const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
371{
372 auto *colorAttachment = getFirstColorAttachment();
373 if (colorAttachment)
374 {
375 return colorAttachment;
376 }
377 return getDepthOrStencilAttachment();
378}
379
Jamie Madill48ef11b2016-04-27 15:21:52 -0400380const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500381{
Jamie Madill2d06b732015-04-20 12:53:28 -0400382 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500383 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400384 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500385 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400386 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500387 }
388 }
389
390 return nullptr;
391}
392
Jamie Madill48ef11b2016-04-27 15:21:52 -0400393const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500394{
Jamie Madill2d06b732015-04-20 12:53:28 -0400395 if (mDepthAttachment.isAttached())
396 {
397 return &mDepthAttachment;
398 }
399 if (mStencilAttachment.isAttached())
400 {
401 return &mStencilAttachment;
402 }
403 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500404}
405
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500406const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
407{
408 if (mStencilAttachment.isAttached())
409 {
410 return &mStencilAttachment;
411 }
412 return getDepthStencilAttachment();
413}
414
Jamie Madill48ef11b2016-04-27 15:21:52 -0400415const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400416{
417 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400418 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
419 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400420}
421
Jamie Madill48ef11b2016-04-27 15:21:52 -0400422const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400423{
Jamie Madill2d06b732015-04-20 12:53:28 -0400424 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400425}
426
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800427const FramebufferAttachment *FramebufferState::getWebGLDepthAttachment() const
428{
429 return mWebGLDepthAttachment.isAttached() ? &mWebGLDepthAttachment : nullptr;
430}
431
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800432const FramebufferAttachment *FramebufferState::getWebGLDepthStencilAttachment() const
433{
434 return mWebGLDepthStencilAttachment.isAttached() ? &mWebGLDepthStencilAttachment : nullptr;
435}
436
Jamie Madill48ef11b2016-04-27 15:21:52 -0400437const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400438{
Jamie Madill2d06b732015-04-20 12:53:28 -0400439 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400440}
441
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -0800442const FramebufferAttachment *FramebufferState::getWebGLStencilAttachment() const
443{
444 return mWebGLStencilAttachment.isAttached() ? &mWebGLStencilAttachment : nullptr;
445}
446
Jamie Madill48ef11b2016-04-27 15:21:52 -0400447const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400448{
449 // A valid depth-stencil attachment has the same resource bound to both the
450 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400451 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500452 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400453 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400454 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400455 }
456
457 return nullptr;
458}
459
Jamie Madill48ef11b2016-04-27 15:21:52 -0400460bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500461{
462 Optional<Extents> attachmentSize;
463
Jamie Madill231c7f52017-04-26 13:45:37 -0400464 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500465 if (!attachment.isAttached())
466 {
467 return false;
468 }
469
470 if (!attachmentSize.valid())
471 {
472 attachmentSize = attachment.getSize();
473 return false;
474 }
475
Jeff Gilbert8f8edd62017-10-31 14:26:30 -0700476 const auto &prevSize = attachmentSize.value();
477 const auto &curSize = attachment.getSize();
478 return (curSize.width != prevSize.width || curSize.height != prevSize.height);
Jamie Madillcc86d642015-11-24 13:00:07 -0500479 };
480
481 for (const auto &attachment : mColorAttachments)
482 {
483 if (hasMismatchedSize(attachment))
484 {
485 return false;
486 }
487 }
488
489 if (hasMismatchedSize(mDepthAttachment))
490 {
491 return false;
492 }
493
494 return !hasMismatchedSize(mStencilAttachment);
495}
496
Jamie Madilld4442552018-02-27 22:03:47 -0500497const FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400498{
499 ASSERT(drawBufferIdx < mDrawBufferStates.size());
500 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
501 {
502 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
503 // must be COLOR_ATTACHMENTi or NONE"
504 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
505 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800506
507 if (mDrawBufferStates[drawBufferIdx] == GL_BACK)
508 {
509 return getColorAttachment(0);
510 }
511 else
512 {
513 return getColorAttachment(mDrawBufferStates[drawBufferIdx] - GL_COLOR_ATTACHMENT0);
514 }
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400515 }
516 else
517 {
518 return nullptr;
519 }
520}
521
522size_t FramebufferState::getDrawBufferCount() const
523{
524 return mDrawBufferStates.size();
525}
526
Geoff Langb21e20d2016-07-19 15:35:41 -0400527bool FramebufferState::colorAttachmentsAreUniqueImages() const
528{
529 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
530 firstAttachmentIdx++)
531 {
Jamie Madilld4442552018-02-27 22:03:47 -0500532 const FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400533 if (!firstAttachment.isAttached())
534 {
535 continue;
536 }
537
538 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
539 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
540 {
Jamie Madilld4442552018-02-27 22:03:47 -0500541 const FramebufferAttachment &secondAttachment = mColorAttachments[secondAttachmentIdx];
Geoff Langb21e20d2016-07-19 15:35:41 -0400542 if (!secondAttachment.isAttached())
543 {
544 continue;
545 }
546
547 if (firstAttachment == secondAttachment)
548 {
549 return false;
550 }
551 }
552 }
553
554 return true;
555}
556
Jamie Madill9c335862017-07-18 11:51:38 -0400557bool FramebufferState::hasDepth() const
558{
559 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
560}
561
562bool FramebufferState::hasStencil() const
563{
564 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
565}
566
Martin Radev5c00d0d2017-08-07 10:06:59 +0300567GLsizei FramebufferState::getNumViews() const
568{
569 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
570 if (attachment == nullptr)
571 {
572 return FramebufferAttachment::kDefaultNumViews;
573 }
574 return attachment->getNumViews();
575}
576
577const std::vector<Offset> *FramebufferState::getViewportOffsets() const
578{
579 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
580 if (attachment == nullptr)
581 {
582 return nullptr;
583 }
584 return &attachment->getMultiviewViewportOffsets();
585}
586
587GLenum FramebufferState::getMultiviewLayout() const
588{
589 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
590 if (attachment == nullptr)
591 {
592 return GL_NONE;
593 }
594 return attachment->getMultiviewLayout();
595}
596
Martin Radev4e619f52017-08-09 11:50:06 +0300597int FramebufferState::getBaseViewIndex() const
598{
599 const FramebufferAttachment *attachment = getFirstNonNullAttachment();
600 if (attachment == nullptr)
601 {
602 return GL_NONE;
603 }
604 return attachment->getBaseViewIndex();
605}
606
Jamie Madill05b35b22017-10-03 09:01:44 -0400607Box FramebufferState::getDimensions() const
608{
609 ASSERT(attachmentsHaveSameDimensions());
610 ASSERT(getFirstNonNullAttachment() != nullptr);
611 Extents extents = getFirstNonNullAttachment()->getSize();
612 return Box(0, 0, 0, extents.width, extents.height, extents.depth);
613}
614
Jamie Madill7aea7e02016-05-10 10:39:45 -0400615Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400616 : mState(caps),
617 mImpl(factory->createFramebuffer(mState)),
618 mId(id),
619 mCachedStatus(),
620 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
621 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000622{
Corentin Wallez37c39792015-08-20 14:19:46 -0400623 ASSERT(mId != 0);
624 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400625 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
626
Jamie Madill1e5499d2017-04-05 11:22:16 -0400627 for (uint32_t colorIndex = 0;
628 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400629 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400630 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400631 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400632}
633
Jamie Madill4928b7c2017-06-20 12:57:39 -0400634Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400635 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500636 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400637 mId(0),
638 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
639 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
640 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400641{
Geoff Langda88add2014-12-01 10:22:01 -0500642 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400643 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500644
Jamie Madill4928b7c2017-06-20 12:57:39 -0400645 const Context *proxyContext = display->getProxyContext();
646
Jamie Madillcc129372018-04-12 09:13:18 -0400647 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
648 FramebufferAttachment::kDefaultNumViews,
Martin Radev5dae57b2017-07-14 16:15:55 +0300649 FramebufferAttachment::kDefaultBaseViewIndex,
650 FramebufferAttachment::kDefaultMultiviewLayout,
651 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500652
653 if (surface->getConfig()->depthSize > 0)
654 {
Jamie Madillcc129372018-04-12 09:13:18 -0400655 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
656 FramebufferAttachment::kDefaultNumViews,
Jamie Madilld4442552018-02-27 22:03:47 -0500657 FramebufferAttachment::kDefaultBaseViewIndex,
658 FramebufferAttachment::kDefaultMultiviewLayout,
659 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500660 }
661
662 if (surface->getConfig()->stencilSize > 0)
663 {
Jamie Madillcc129372018-04-12 09:13:18 -0400664 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
665 FramebufferAttachment::kDefaultNumViews,
666 FramebufferAttachment::kDefaultBaseViewIndex,
667 FramebufferAttachment::kDefaultMultiviewLayout,
668 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500669 }
Brandon Jones76746f92017-11-22 11:44:41 -0800670 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000671}
672
Corentin Wallezccab69d2017-01-27 16:57:15 -0500673Framebuffer::Framebuffer(rx::GLImplFactory *factory)
674 : mState(),
675 mImpl(factory->createFramebuffer(mState)),
676 mId(0),
677 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
678 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
679 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
680{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400681 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Brandon Jones76746f92017-11-22 11:44:41 -0800682 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500683}
684
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000685Framebuffer::~Framebuffer()
686{
Geoff Langda88add2014-12-01 10:22:01 -0500687 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000688}
689
Jamie Madill4928b7c2017-06-20 12:57:39 -0400690void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500691{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400692 for (auto &attachment : mState.mColorAttachments)
693 {
694 attachment.detach(context);
695 }
696 mState.mDepthAttachment.detach(context);
697 mState.mStencilAttachment.detach(context);
698 mState.mWebGLDepthAttachment.detach(context);
699 mState.mWebGLStencilAttachment.detach(context);
700 mState.mWebGLDepthStencilAttachment.detach(context);
701
Jamie Madillc564c072017-06-01 12:45:42 -0400702 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500703}
704
Geoff Lang70d0f492015-12-10 17:45:46 -0500705void Framebuffer::setLabel(const std::string &label)
706{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400707 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500708}
709
710const std::string &Framebuffer::getLabel() const
711{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400712 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500713}
714
Jamie Madill8693bdb2017-09-02 15:32:14 -0400715bool Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000716{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400717 return detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000718}
719
Jamie Madill8693bdb2017-09-02 15:32:14 -0400720bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000721{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400722 return detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500723}
Jamie Madille261b442014-06-25 12:42:21 -0400724
Jamie Madill8693bdb2017-09-02 15:32:14 -0400725bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500726{
Jamie Madill8693bdb2017-09-02 15:32:14 -0400727 bool found = false;
728
Jamie Madill362876b2016-06-16 14:46:59 -0400729 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500730 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400731 if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
732 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex))
733 {
734 found = true;
735 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000736 }
737
Jamie Madilla02315b2017-02-23 14:14:47 -0500738 if (context->isWebGL1())
739 {
740 const std::array<FramebufferAttachment *, 3> attachments = {
741 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
742 &mState.mWebGLStencilAttachment}};
743 for (FramebufferAttachment *attachment : attachments)
744 {
745 if (attachment->isAttached() && attachment->type() == resourceType &&
746 attachment->id() == resourceId)
747 {
748 resetAttachment(context, attachment->getBinding());
Jamie Madill8693bdb2017-09-02 15:32:14 -0400749 found = true;
Jamie Madilla02315b2017-02-23 14:14:47 -0500750 }
751 }
752 }
753 else
754 {
Jamie Madill8693bdb2017-09-02 15:32:14 -0400755 if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
756 DIRTY_BIT_DEPTH_ATTACHMENT))
757 {
758 found = true;
759 }
760 if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
761 DIRTY_BIT_STENCIL_ATTACHMENT))
762 {
763 found = true;
764 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500765 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400766
767 return found;
Jamie Madill362876b2016-06-16 14:46:59 -0400768}
769
Jamie Madill8693bdb2017-09-02 15:32:14 -0400770bool Framebuffer::detachMatchingAttachment(const Context *context,
Jamie Madill4928b7c2017-06-20 12:57:39 -0400771 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400772 GLenum matchType,
773 GLuint matchId,
774 size_t dirtyBit)
775{
776 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
777 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400778 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400779 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -0400780 mState.mResourceNeedsInit.set(dirtyBit, false);
Jamie Madill8693bdb2017-09-02 15:32:14 -0400781 return true;
Jamie Madill362876b2016-06-16 14:46:59 -0400782 }
Jamie Madill8693bdb2017-09-02 15:32:14 -0400783
784 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785}
786
Corentin Wallez37c39792015-08-20 14:19:46 -0400787const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000788{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400789 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000790}
791
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400792const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400793{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400794 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400795}
796
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400797const FramebufferAttachment *Framebuffer::getStencilbuffer() const
798{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400799 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400800}
801
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400802const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
803{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400804 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400805}
806
807const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000808{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400809 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000810}
811
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500812const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
813{
814 return mState.getStencilOrDepthStencilAttachment();
815}
816
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400817const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000818{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400819 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000820}
821
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000822GLenum Framebuffer::getReadColorbufferType() const
823{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400824 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400825 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000826}
827
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400828const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000829{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400830 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000831}
832
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400833const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
834{
835 return mState.getFirstNonNullAttachment();
836}
837
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800838const FramebufferAttachment *Framebuffer::getAttachment(const Context *context,
839 GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000840{
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -0800841 return mState.getAttachment(context, attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400842}
843
Geoff Langa15472a2015-08-11 11:48:03 -0400844size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000845{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400846 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400847}
848
849GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
850{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400851 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
852 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000853}
854
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500855const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
856{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400857 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500858}
859
Geoff Lang164d54e2014-12-01 10:55:33 -0500860void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000861{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400862 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500863
864 ASSERT(count <= drawStates.size());
865 std::copy(buffers, buffers + count, drawStates.begin());
866 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500867 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500868
869 mState.mEnabledDrawBuffers.reset();
Brandon Jones76746f92017-11-22 11:44:41 -0800870 mState.mDrawBufferTypeMask.reset();
871
Jamie Madilla4595b82017-01-11 17:36:34 -0500872 for (size_t index = 0; index < count; ++index)
873 {
Brandon Jones76746f92017-11-22 11:44:41 -0800874 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
875
Jamie Madilla4595b82017-01-11 17:36:34 -0500876 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
877 {
878 mState.mEnabledDrawBuffers.set(index);
879 }
880 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500881}
882
Geoff Langa15472a2015-08-11 11:48:03 -0400883const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
884{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400885 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400886}
887
Geoff Lange0cff192017-05-30 13:04:56 -0400888GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
889{
890 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
891 if (attachment == nullptr)
892 {
893 return GL_NONE;
894 }
895
896 GLenum componentType = attachment->getFormat().info->componentType;
897 switch (componentType)
898 {
899 case GL_INT:
900 case GL_UNSIGNED_INT:
901 return componentType;
902
903 default:
904 return GL_FLOAT;
905 }
906}
907
Brandon Jonesc405ae72017-12-06 14:15:03 -0800908ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
Brandon Jones76746f92017-11-22 11:44:41 -0800909{
910 return mState.mDrawBufferTypeMask;
911}
912
913DrawBufferMask Framebuffer::getDrawBufferMask() const
914{
915 return mState.mEnabledDrawBuffers;
916}
917
Geoff Langa15472a2015-08-11 11:48:03 -0400918bool Framebuffer::hasEnabledDrawBuffer() const
919{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400920 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400921 {
922 if (getDrawBuffer(drawbufferIdx) != nullptr)
923 {
924 return true;
925 }
926 }
927
928 return false;
929}
930
Geoff Lang9dd95802014-12-01 11:12:59 -0500931GLenum Framebuffer::getReadBufferState() const
932{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400933 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500934}
935
936void Framebuffer::setReadBuffer(GLenum buffer)
937{
Jamie Madillb885e572015-02-03 16:16:04 -0500938 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
939 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400940 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
941 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500942 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000943}
944
Corentin Wallez37c39792015-08-20 14:19:46 -0400945size_t Framebuffer::getNumColorBuffers() const
946{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400947 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400948}
949
Jamie Madill0df8fe42015-11-24 16:10:24 -0500950bool Framebuffer::hasDepth() const
951{
Jamie Madill9c335862017-07-18 11:51:38 -0400952 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500953}
954
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000955bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000956{
Jamie Madill9c335862017-07-18 11:51:38 -0400957 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000958}
959
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000960bool Framebuffer::usingExtendedDrawBuffers() const
961{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400962 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000963 {
Geoff Langa15472a2015-08-11 11:48:03 -0400964 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000965 {
966 return true;
967 }
968 }
969
970 return false;
971}
972
Geoff Lang9aded172017-04-05 11:07:56 -0400973void Framebuffer::invalidateCompletenessCache()
974{
975 if (mId != 0)
976 {
977 mCachedStatus.reset();
978 }
979}
980
Jamie Madill427064d2018-04-13 16:20:34 -0400981GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000982{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500983 // The default framebuffer is always complete except when it is surfaceless in which
984 // case it is always unsupported. We return early because the default framebuffer may
985 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500986 if (mId == 0)
987 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500988 ASSERT(mCachedStatus.valid());
989 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
990 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
Jamie Madill427064d2018-04-13 16:20:34 -0400991 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500992 }
993
Jamie Madill362876b2016-06-16 14:46:59 -0400994 if (hasAnyDirtyBit() || !mCachedStatus.valid())
995 {
Jamie Madille98b1b52018-03-08 09:47:23 -0500996 mCachedStatus = checkStatusWithGLFrontEnd(context);
997
998 if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
999 {
Jamie Madill427064d2018-04-13 16:20:34 -04001000 Error err = syncState(context);
1001 if (err.isError())
1002 {
1003 context->handleError(err);
1004 return GetDefaultReturnValue<EntryPoint::CheckFramebufferStatus, GLenum>();
1005 }
Jamie Madille98b1b52018-03-08 09:47:23 -05001006 if (!mImpl->checkStatus(context))
1007 {
1008 mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
1009 }
1010 }
Jamie Madill362876b2016-06-16 14:46:59 -04001011 }
1012
Jamie Madill427064d2018-04-13 16:20:34 -04001013 return mCachedStatus.value();
Jamie Madill362876b2016-06-16 14:46:59 -04001014}
1015
Jamie Madille98b1b52018-03-08 09:47:23 -05001016GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -04001017{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001018 const ContextState &state = context->getContextState();
1019
Jamie Madill362876b2016-06-16 14:46:59 -04001020 ASSERT(mId != 0);
1021
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001022 bool hasAttachments = false;
1023 Optional<unsigned int> colorbufferSize;
1024 Optional<int> samples;
Geoff Lang92019432017-11-20 13:09:34 -05001025 Optional<bool> fixedSampleLocations;
JiangYizhou461d9a32017-01-04 16:37:26 +08001026 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001027
Martin Radev9bc9a322017-07-21 14:28:17 +03001028 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
1029
Jamie Madill48ef11b2016-04-27 15:21:52 -04001030 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031 {
Jamie Madill2d06b732015-04-20 12:53:28 -04001032 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001033 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001034 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001035 {
1036 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1037 }
daniel@transgaming.com01868132010-08-24 19:21:17 +00001038
Geoff Lang677bb6f2017-04-05 12:40:40 -04001039 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001040 if (format.depthBits > 0 || format.stencilBits > 0)
1041 {
1042 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1043 }
1044
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001045 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
1046 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001047 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001048 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001049 }
1050
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001051 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
1052 // in GLES 3.0, there is no such restriction
1053 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001054 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001055 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001056 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001057 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +00001058 {
1059 return GL_FRAMEBUFFER_UNSUPPORTED;
1060 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001061 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001062 else
1063 {
1064 colorbufferSize = format.pixelBytes;
1065 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001066 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001067
Martin Radev9bc9a322017-07-21 14:28:17 +03001068 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
1069 {
1070 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1071 }
1072
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001073 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
1074 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001075 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001076 }
1077
Jamie Madill48ef11b2016-04-27 15:21:52 -04001078 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001079 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001080 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001081 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001083 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001084 }
1085
Geoff Lang677bb6f2017-04-05 12:40:40 -04001086 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001087 if (format.depthBits == 0)
1088 {
1089 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001090 }
1091
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001092 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
1093 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001094 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001095 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001096 }
Sami Väisänena797e062016-05-12 15:23:40 +03001097
Martin Radev9bc9a322017-07-21 14:28:17 +03001098 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
1099 {
1100 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1101 }
1102
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001103 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
1104 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001105 }
1106
Jamie Madill48ef11b2016-04-27 15:21:52 -04001107 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -04001108 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001109 {
Geoff Lang9f10b772017-05-16 15:51:03 -04001110 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001111 {
1112 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1113 }
1114
Geoff Lang677bb6f2017-04-05 12:40:40 -04001115 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -04001116 if (format.stencilBits == 0)
1117 {
1118 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001119 }
1120
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001121 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
1122 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001123 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001124 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001125 }
Corentin Wallez086d59a2016-04-29 09:06:49 -04001126
Martin Radev9bc9a322017-07-21 14:28:17 +03001127 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
1128 {
1129 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1130 }
1131
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001132 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
1133 hasAttachments = true;
1134 }
1135
1136 // Starting from ES 3.0 stencil and depth, if present, should be the same image
1137 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
1138 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
1139 {
1140 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001141 }
1142
Jamie Madilla02315b2017-02-23 14:14:47 -05001143 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
1144 if (state.isWebGL1())
1145 {
1146 if (!mState.mWebGLDepthStencilConsistent)
1147 {
1148 return GL_FRAMEBUFFER_UNSUPPORTED;
1149 }
1150
1151 if (mState.mWebGLDepthStencilAttachment.isAttached())
1152 {
1153 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
1154 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
1155 {
1156 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1157 }
Martin Radev9bc9a322017-07-21 14:28:17 +03001158
1159 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
1160 &mState.mWebGLDepthStencilAttachment))
1161 {
1162 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
1163 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001164 }
1165 else if (mState.mStencilAttachment.isAttached() &&
1166 mState.mStencilAttachment.getDepthSize() > 0)
1167 {
1168 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1169 }
1170 else if (mState.mDepthAttachment.isAttached() &&
1171 mState.mDepthAttachment.getStencilSize() > 0)
1172 {
1173 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1174 }
1175 }
1176
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001177 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
1178 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
1179 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +08001180 GLint defaultWidth = mState.getDefaultWidth();
1181 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001182 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +00001183 {
1184 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +00001185 }
1186
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001187 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -05001188 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -04001189 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
1190 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -05001191 {
1192 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
1193 }
1194
Geoff Langa1b9d5a2017-05-18 11:22:27 -04001195 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
1196 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +08001197 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
1198 {
1199 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1200 }
1201
Kenneth Russellce8602a2017-10-03 18:23:08 -07001202 // The WebGL conformance tests implicitly define that all framebuffer
1203 // attachments must be unique. For example, the same level of a texture can
1204 // not be attached to two different color attachments.
1205 if (state.getExtensions().webglCompatibility)
1206 {
1207 if (!mState.colorAttachmentsAreUniqueImages())
1208 {
1209 return GL_FRAMEBUFFER_UNSUPPORTED;
1210 }
1211 }
1212
Jamie Madillcc86d642015-11-24 13:00:07 -05001213 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001214}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001215
Jamie Madill4928b7c2017-06-20 12:57:39 -04001216Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001217{
Jamie Madill05b35b22017-10-03 09:01:44 -04001218 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1219 // can be no-ops, so we should probably do that to ensure consistency.
1220 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1221
Jamie Madill4928b7c2017-06-20 12:57:39 -04001222 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001223}
1224
Jamie Madill4928b7c2017-06-20 12:57:39 -04001225Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001226{
Jamie Madill05b35b22017-10-03 09:01:44 -04001227 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1228 // can be no-ops, so we should probably do that to ensure consistency.
1229 // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL.
1230
Jamie Madill4928b7c2017-06-20 12:57:39 -04001231 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001232}
1233
Jamie Madill05b35b22017-10-03 09:01:44 -04001234bool Framebuffer::partialClearNeedsInit(const Context *context,
1235 bool color,
1236 bool depth,
1237 bool stencil)
1238{
1239 const auto &glState = context->getGLState();
1240
1241 if (!glState.isRobustResourceInitEnabled())
1242 {
1243 return false;
1244 }
1245
1246 // Scissors can affect clearing.
1247 // TODO(jmadill): Check for complete scissor overlap.
1248 if (glState.isScissorTestEnabled())
1249 {
1250 return true;
1251 }
1252
1253 // If colors masked, we must clear before we clear. Do a simple check.
1254 // TODO(jmadill): Filter out unused color channels from the test.
1255 if (color)
1256 {
1257 const auto &blend = glState.getBlendState();
1258 if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue &&
1259 blend.colorMaskAlpha))
1260 {
1261 return true;
1262 }
1263 }
1264
1265 const auto &depthStencil = glState.getDepthStencilState();
1266 ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask);
1267 if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask)
1268 {
1269 return true;
1270 }
1271
1272 return false;
1273}
1274
Jamie Madill4928b7c2017-06-20 12:57:39 -04001275Error Framebuffer::invalidateSub(const Context *context,
1276 size_t count,
1277 const GLenum *attachments,
Jamie Madilld4442552018-02-27 22:03:47 -05001278 const Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001279{
Jamie Madill05b35b22017-10-03 09:01:44 -04001280 // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations
1281 // can be no-ops, so we should probably do that to ensure consistency.
1282 // TODO(jmadill): Make a invalidate no-op in WebGL 2.0.
1283
Jamie Madill4928b7c2017-06-20 12:57:39 -04001284 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001285}
1286
Jamie Madilld4442552018-02-27 22:03:47 -05001287Error Framebuffer::clear(const Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001288{
Jamie Madill05b35b22017-10-03 09:01:44 -04001289 const auto &glState = context->getGLState();
1290 if (glState.isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001291 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001292 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001293 }
1294
Jamie Madill05b35b22017-10-03 09:01:44 -04001295 ANGLE_TRY(mImpl->clear(context, mask));
1296
Jamie Madill05b35b22017-10-03 09:01:44 -04001297 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001298}
1299
Jamie Madilld4442552018-02-27 22:03:47 -05001300Error Framebuffer::clearBufferfv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001301 GLenum buffer,
1302 GLint drawbuffer,
1303 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001304{
Jamie Madill05b35b22017-10-03 09:01:44 -04001305 if (context->getGLState().isRasterizerDiscardEnabled() ||
1306 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001307 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001308 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001309 }
1310
Jamie Madill05b35b22017-10-03 09:01:44 -04001311 ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
1312
Jamie Madill05b35b22017-10-03 09:01:44 -04001313 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001314}
1315
Jamie Madilld4442552018-02-27 22:03:47 -05001316Error Framebuffer::clearBufferuiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001317 GLenum buffer,
1318 GLint drawbuffer,
1319 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001320{
Jamie Madill05b35b22017-10-03 09:01:44 -04001321 if (context->getGLState().isRasterizerDiscardEnabled() ||
1322 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001323 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001324 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001325 }
1326
Jamie Madill05b35b22017-10-03 09:01:44 -04001327 ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
1328
Jamie Madill05b35b22017-10-03 09:01:44 -04001329 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001330}
1331
Jamie Madilld4442552018-02-27 22:03:47 -05001332Error Framebuffer::clearBufferiv(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001333 GLenum buffer,
1334 GLint drawbuffer,
1335 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001336{
Jamie Madill05b35b22017-10-03 09:01:44 -04001337 if (context->getGLState().isRasterizerDiscardEnabled() ||
1338 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001339 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001340 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001341 }
1342
Jamie Madill05b35b22017-10-03 09:01:44 -04001343 ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
1344
Jamie Madill05b35b22017-10-03 09:01:44 -04001345 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001346}
1347
Jamie Madilld4442552018-02-27 22:03:47 -05001348Error Framebuffer::clearBufferfi(const Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001349 GLenum buffer,
1350 GLint drawbuffer,
1351 GLfloat depth,
1352 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001353{
Jamie Madill05b35b22017-10-03 09:01:44 -04001354 if (context->getGLState().isRasterizerDiscardEnabled() ||
1355 IsClearBufferMaskedOut(context, buffer))
Jamie Madill984ef412015-11-24 16:10:21 -05001356 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001357 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001358 }
1359
Jamie Madill05b35b22017-10-03 09:01:44 -04001360 ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil));
1361
Jamie Madill05b35b22017-10-03 09:01:44 -04001362 return NoError();
Geoff Langb04dc822014-12-01 12:02:02 -05001363}
1364
Jamie Madill690c8eb2018-03-12 15:20:03 -04001365Error Framebuffer::getImplementationColorReadFormat(const Context *context, GLenum *formatOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001366{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001367 ANGLE_TRY(syncState(context));
1368 *formatOut = mImpl->getImplementationColorReadFormat(context);
1369 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001370}
1371
Jamie Madill690c8eb2018-03-12 15:20:03 -04001372Error Framebuffer::getImplementationColorReadType(const Context *context, GLenum *typeOut)
Geoff Langbce529e2014-12-01 12:48:41 -05001373{
Jamie Madill690c8eb2018-03-12 15:20:03 -04001374 ANGLE_TRY(syncState(context));
1375 *typeOut = mImpl->getImplementationColorReadType(context);
1376 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001377}
1378
Jamie Madilld4442552018-02-27 22:03:47 -05001379Error Framebuffer::readPixels(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001380 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001381 GLenum format,
1382 GLenum type,
Jamie Madill05b35b22017-10-03 09:01:44 -04001383 void *pixels)
Geoff Langbce529e2014-12-01 12:48:41 -05001384{
Jamie Madill05b35b22017-10-03 09:01:44 -04001385 ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
Jamie Madill362876b2016-06-16 14:46:59 -04001386 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001387
Jamie Madilld4442552018-02-27 22:03:47 -05001388 Buffer *unpackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001389 if (unpackBuffer)
1390 {
Jamie Madill09463932018-04-04 05:26:59 -04001391 unpackBuffer->onPixelPack(context);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001392 }
1393
Jamie Madill362876b2016-06-16 14:46:59 -04001394 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001395}
1396
Jamie Madilld4442552018-02-27 22:03:47 -05001397Error Framebuffer::blit(const Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001398 const Rectangle &sourceArea,
1399 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001400 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001401 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001402{
He Yunchao6be602d2016-12-22 14:33:07 +08001403 GLbitfield blitMask = mask;
1404
1405 // Note that blitting is called against draw framebuffer.
1406 // See the code in gl::Context::blitFramebuffer.
1407 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1408 {
1409 blitMask &= ~GL_COLOR_BUFFER_BIT;
1410 }
1411
1412 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1413 {
1414 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1415 }
1416
1417 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1418 {
1419 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1420 }
1421
1422 if (!blitMask)
1423 {
1424 return NoError();
1425 }
1426
Jamie Madill05b35b22017-10-03 09:01:44 -04001427 auto *sourceFBO = context->getGLState().getReadFramebuffer();
1428 ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask));
1429
1430 // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask.
1431 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1432
He Yunchao6be602d2016-12-22 14:33:07 +08001433 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001434}
1435
Jamie Madill427064d2018-04-13 16:20:34 -04001436int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001437{
Jamie Madill427064d2018-04-13 16:20:34 -04001438 return (isComplete(context) ? getCachedSamples(context) : 0);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001439}
1440
Jamie Madill9c335862017-07-18 11:51:38 -04001441int Framebuffer::getCachedSamples(const Context *context)
1442{
Jamie Madill5b772312018-03-08 20:28:32 -05001443 ASSERT(mCachedStatus.valid() && mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE);
1444
Jamie Madill9c335862017-07-18 11:51:38 -04001445 // For a complete framebuffer, all attachments must have the same sample count.
1446 // In this case return the first nonzero sample size.
1447 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1448 if (firstNonNullAttachment)
1449 {
1450 ASSERT(firstNonNullAttachment->isAttached());
1451 return firstNonNullAttachment->getSamples();
1452 }
1453
1454 // No attachments found.
1455 return 0;
1456}
1457
Geoff Lang13455072018-05-09 11:24:43 -04001458Error Framebuffer::getSamplePosition(const Context *context, size_t index, GLfloat *xy) const
Corentin Wallezccab69d2017-01-27 16:57:15 -05001459{
Geoff Lang13455072018-05-09 11:24:43 -04001460 ANGLE_TRY(mImpl->getSamplePosition(context, index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001461 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001462}
1463
Jamie Madille261b442014-06-25 12:42:21 -04001464bool Framebuffer::hasValidDepthStencil() const
1465{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001466 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001467}
1468
Jamie Madilla02315b2017-02-23 14:14:47 -05001469void Framebuffer::setAttachment(const Context *context,
1470 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001471 GLenum binding,
1472 const ImageIndex &textureIndex,
1473 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001474{
Martin Radev5dae57b2017-07-14 16:15:55 +03001475 setAttachment(context, type, binding, textureIndex, resource,
1476 FramebufferAttachment::kDefaultNumViews,
1477 FramebufferAttachment::kDefaultBaseViewIndex,
1478 FramebufferAttachment::kDefaultMultiviewLayout,
1479 FramebufferAttachment::kDefaultViewportOffsets);
1480}
1481
1482void Framebuffer::setAttachment(const Context *context,
1483 GLenum type,
1484 GLenum binding,
1485 const ImageIndex &textureIndex,
1486 FramebufferAttachmentObject *resource,
1487 GLsizei numViews,
1488 GLuint baseViewIndex,
1489 GLenum multiviewLayout,
1490 const GLint *viewportOffsets)
1491{
Jamie Madilla02315b2017-02-23 14:14:47 -05001492 // Context may be null in unit tests.
1493 if (!context || !context->isWebGL1())
1494 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001495 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1496 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001497 return;
1498 }
1499
1500 switch (binding)
1501 {
1502 case GL_DEPTH_STENCIL:
1503 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001504 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001505 resource, numViews, baseViewIndex,
1506 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001507 break;
1508 case GL_DEPTH:
1509 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001510 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1511 numViews, baseViewIndex, multiviewLayout,
1512 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001513 break;
1514 case GL_STENCIL:
1515 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001516 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1517 numViews, baseViewIndex, multiviewLayout,
1518 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001519 break;
1520 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001521 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1522 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001523 return;
1524 }
1525
Martin Radev5dae57b2017-07-14 16:15:55 +03001526 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1527 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001528}
1529
Martin Radev82ef7742017-08-08 17:44:58 +03001530void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
1531 GLenum type,
1532 GLenum binding,
1533 const ImageIndex &textureIndex,
1534 FramebufferAttachmentObject *resource,
1535 GLsizei numViews,
1536 GLint baseViewIndex)
1537{
1538 setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1539 GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
1540 FramebufferAttachment::kDefaultViewportOffsets);
1541}
1542
Martin Radev5dae57b2017-07-14 16:15:55 +03001543void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1544 GLenum type,
1545 GLenum binding,
1546 const ImageIndex &textureIndex,
1547 FramebufferAttachmentObject *resource,
1548 GLsizei numViews,
1549 const GLint *viewportOffsets)
1550{
1551 setAttachment(context, type, binding, textureIndex, resource, numViews,
1552 FramebufferAttachment::kDefaultBaseViewIndex,
1553 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1554}
1555
1556void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1557 GLsizei numViews,
1558 GLuint baseViewIndex,
1559 GLenum multiviewLayout,
1560 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001561{
1562 int count = 0;
1563
1564 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1565 &mState.mWebGLDepthAttachment,
1566 &mState.mWebGLStencilAttachment}};
1567 for (FramebufferAttachment *attachment : attachments)
1568 {
1569 if (attachment->isAttached())
1570 {
1571 count++;
1572 }
1573 }
1574
1575 mState.mWebGLDepthStencilConsistent = (count <= 1);
1576 if (!mState.mWebGLDepthStencilConsistent)
1577 {
1578 // Inconsistent.
1579 return;
1580 }
1581
Geoff Lange466c552017-03-17 15:24:12 -04001582 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1583 if (attachment.type() == GL_TEXTURE)
1584 {
1585 return attachment.getTextureImageIndex();
1586 }
1587 else
1588 {
Jamie Madillcc129372018-04-12 09:13:18 -04001589 return ImageIndex();
Geoff Lange466c552017-03-17 15:24:12 -04001590 }
1591 };
1592
Jamie Madilla02315b2017-02-23 14:14:47 -05001593 if (mState.mWebGLDepthAttachment.isAttached())
1594 {
1595 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001596 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001597 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1598 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madillcc129372018-04-12 09:13:18 -04001599 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1600 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001601 }
1602 else if (mState.mWebGLStencilAttachment.isAttached())
1603 {
1604 const auto &stencil = mState.mWebGLStencilAttachment;
Jamie Madillcc129372018-04-12 09:13:18 -04001605 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1606 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001607 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001608 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1609 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001610 }
1611 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1612 {
1613 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001614 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001615 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001616 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1617 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001618 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001619 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001620 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1621 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001622 }
1623 else
1624 {
Jamie Madillcc129372018-04-12 09:13:18 -04001625 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
1626 baseViewIndex, multiviewLayout, viewportOffsets);
1627 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
1628 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001629 }
1630}
1631
Jamie Madill4928b7c2017-06-20 12:57:39 -04001632void Framebuffer::setAttachmentImpl(const Context *context,
1633 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001634 GLenum binding,
1635 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001636 FramebufferAttachmentObject *resource,
1637 GLsizei numViews,
1638 GLuint baseViewIndex,
1639 GLenum multiviewLayout,
1640 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001641{
Jamie Madilla02315b2017-02-23 14:14:47 -05001642 switch (binding)
1643 {
Jamie Madillb8126692017-04-05 11:22:17 -04001644 case GL_DEPTH_STENCIL:
1645 case GL_DEPTH_STENCIL_ATTACHMENT:
1646 {
1647 // ensure this is a legitimate depth+stencil format
1648 FramebufferAttachmentObject *attachmentObj = resource;
1649 if (resource)
1650 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001651 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001652 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1653 {
1654 // Attaching nullptr detaches the current attachment.
1655 attachmentObj = nullptr;
1656 }
1657 }
1658
Jamie Madill4928b7c2017-06-20 12:57:39 -04001659 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001660 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001661 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1662 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001663 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001664 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001665 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1666 viewportOffsets);
Jamie Madill42975642017-10-12 12:31:51 -04001667 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001668 }
1669
Jamie Madilla02315b2017-02-23 14:14:47 -05001670 case GL_DEPTH:
1671 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001672 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001673 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1674 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001675 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001676
Jamie Madilla02315b2017-02-23 14:14:47 -05001677 case GL_STENCIL:
1678 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001679 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001680 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1681 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001682 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001683
Jamie Madilla02315b2017-02-23 14:14:47 -05001684 case GL_BACK:
Geoff Lang8170eab2017-09-21 13:59:04 -04001685 updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
1686 &mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
1687 resource, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001688 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001689
Jamie Madilla02315b2017-02-23 14:14:47 -05001690 default:
1691 {
1692 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1693 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001694 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001695 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001696 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001697 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1698 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001699
Corentin Walleze7557742017-06-01 13:09:57 -04001700 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1701 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001702 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1703 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Brandon Jones76746f92017-11-22 11:44:41 -08001704 mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -04001705 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001706 break;
Geoff Langab75a052014-10-15 12:56:37 -04001707 }
Jamie Madill42975642017-10-12 12:31:51 -04001708
1709 mAttachedTextures.reset();
Geoff Langab75a052014-10-15 12:56:37 -04001710}
1711
Jamie Madill4928b7c2017-06-20 12:57:39 -04001712void Framebuffer::updateAttachment(const Context *context,
1713 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001714 size_t dirtyBit,
Jamie Madilld4442552018-02-27 22:03:47 -05001715 angle::ObserverBinding *onDirtyBinding,
Jamie Madillb8126692017-04-05 11:22:17 -04001716 GLenum type,
1717 GLenum binding,
1718 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001719 FramebufferAttachmentObject *resource,
1720 GLsizei numViews,
1721 GLuint baseViewIndex,
1722 GLenum multiviewLayout,
1723 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001724{
Martin Radev5dae57b2017-07-14 16:15:55 +03001725 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1726 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001727 mDirtyBits.set(dirtyBit);
Jamie Madill05b35b22017-10-03 09:01:44 -04001728 mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
Jamie Madill888081d2018-02-27 00:24:46 -05001729 onDirtyBinding->bind(resource ? resource->getSubject() : nullptr);
Jamie Madille98b1b52018-03-08 09:47:23 -05001730
1731 invalidateCompletenessCache();
Jamie Madillb8126692017-04-05 11:22:17 -04001732}
1733
Jamie Madilla02315b2017-02-23 14:14:47 -05001734void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001735{
Jamie Madillcc129372018-04-12 09:13:18 -04001736 setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001737}
1738
Jamie Madill19fa1c62018-03-08 09:47:21 -05001739Error Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001740{
1741 if (mDirtyBits.any())
1742 {
Jamie Madill888081d2018-02-27 00:24:46 -05001743 mDirtyBitsGuard = mDirtyBits;
Jamie Madill19fa1c62018-03-08 09:47:21 -05001744 ANGLE_TRY(mImpl->syncState(context, mDirtyBits));
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001745 mDirtyBits.reset();
Jamie Madill888081d2018-02-27 00:24:46 -05001746 mDirtyBitsGuard.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001747 }
Jamie Madill19fa1c62018-03-08 09:47:21 -05001748 return NoError();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001749}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001750
Jamie Madilld4442552018-02-27 22:03:47 -05001751void Framebuffer::onSubjectStateChange(const Context *context,
1752 angle::SubjectIndex index,
1753 angle::SubjectMessage message)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001754{
Jamie Madill888081d2018-02-27 00:24:46 -05001755 if (message == angle::SubjectMessage::DEPENDENT_DIRTY_BITS)
1756 {
1757 ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
1758 mDirtyBits.set(index);
1759 context->getGLState().setFramebufferDirty(this);
1760 return;
1761 }
1762
Geoff Lang8170eab2017-09-21 13:59:04 -04001763 // Only reset the cached status if this is not the default framebuffer. The default framebuffer
1764 // will still use this channel to mark itself dirty.
1765 if (mId != 0)
1766 {
1767 // TOOD(jmadill): Make this only update individual attachments to do less work.
1768 mCachedStatus.reset();
1769 }
Jamie Madill05b35b22017-10-03 09:01:44 -04001770
Jamie Madilld4442552018-02-27 22:03:47 -05001771 FramebufferAttachment *attachment = getAttachmentFromSubjectIndex(index);
1772
Jamie Madill05b35b22017-10-03 09:01:44 -04001773 // Mark the appropriate init flag.
Jamie Madilld4442552018-02-27 22:03:47 -05001774 mState.mResourceNeedsInit.set(index, attachment->initState() == InitState::MayNeedInit);
1775}
1776
1777FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::SubjectIndex index)
1778{
1779 switch (index)
1780 {
1781 case DIRTY_BIT_DEPTH_ATTACHMENT:
1782 return &mState.mDepthAttachment;
1783 case DIRTY_BIT_STENCIL_ATTACHMENT:
1784 return &mState.mStencilAttachment;
1785 default:
1786 size_t colorIndex = (index - DIRTY_BIT_COLOR_ATTACHMENT_0);
1787 ASSERT(colorIndex < mState.mColorAttachments.size());
1788 return &mState.mColorAttachments[colorIndex];
1789 }
Jamie Madill51f40ec2016-06-15 14:06:00 -04001790}
1791
Jamie Madill427064d2018-04-13 16:20:34 -04001792bool Framebuffer::isComplete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001793{
Jamie Madill427064d2018-04-13 16:20:34 -04001794 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001795}
1796
Jamie Madilla4595b82017-01-11 17:36:34 -05001797bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1798{
1799 const Program *program = state.getProgram();
1800
1801 // TODO(jmadill): Default framebuffer feedback loops.
1802 if (mId == 0)
1803 {
1804 return false;
1805 }
1806
1807 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001808 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001809 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001810 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1811 ASSERT(attachment.isAttached());
1812 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001813 {
1814 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001815 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001816 {
1817 return true;
1818 }
1819 }
1820 }
1821
Jamie Madill1d37bc52017-02-02 19:59:58 -05001822 // Validate depth-stencil feedback loop.
1823 const auto &dsState = state.getDepthStencilState();
1824
1825 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1826 const FramebufferAttachment *depth = getDepthbuffer();
1827 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1828 {
1829 if (program->samplesFromTexture(state, depth->id()))
1830 {
1831 return true;
1832 }
1833 }
1834
Jamie Madill1d37bc52017-02-02 19:59:58 -05001835 const FramebufferAttachment *stencil = getStencilbuffer();
Ken Russellb9f92502018-01-27 19:00:26 -08001836 if (dsState.stencilTest && stencil)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001837 {
Ken Russellb9f92502018-01-27 19:00:26 -08001838 GLuint stencilSize = stencil->getStencilSize();
1839 ASSERT(stencilSize <= 8);
1840 GLuint maxStencilValue = (1 << stencilSize) - 1;
1841 // We assume the front and back masks are the same for WebGL.
1842 ASSERT((dsState.stencilBackWritemask & maxStencilValue) ==
1843 (dsState.stencilWritemask & maxStencilValue));
1844 if (stencil->type() == GL_TEXTURE && dsState.stencilWritemask != 0)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001845 {
Ken Russellb9f92502018-01-27 19:00:26 -08001846 // Skip the feedback loop check if depth/stencil point to the same resource.
1847 if (!depth || *stencil != *depth)
Jamie Madill1d37bc52017-02-02 19:59:58 -05001848 {
Ken Russellb9f92502018-01-27 19:00:26 -08001849 if (program->samplesFromTexture(state, stencil->id()))
1850 {
1851 return true;
1852 }
Jamie Madill1d37bc52017-02-02 19:59:58 -05001853 }
1854 }
1855 }
1856
Jamie Madilla4595b82017-01-11 17:36:34 -05001857 return false;
1858}
1859
Jamie Madillfd3dd432017-02-02 19:59:59 -05001860bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1861 GLint copyTextureLevel,
1862 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001863{
1864 if (mId == 0)
1865 {
1866 // It seems impossible to form a texture copying feedback loop with the default FBO.
1867 return false;
1868 }
1869
1870 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1871 ASSERT(readAttachment);
1872
1873 if (readAttachment->isTextureWithId(copyTextureID))
1874 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001875 const auto &imageIndex = readAttachment->getTextureImageIndex();
Jamie Madillcc129372018-04-12 09:13:18 -04001876 if (imageIndex.getLevelIndex() == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001877 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001878 // Check 3D/Array texture layers.
Jamie Madillcc129372018-04-12 09:13:18 -04001879 return !imageIndex.hasLayer() || copyTextureLayer == ImageIndex::kEntireLevel ||
1880 imageIndex.getLayerIndex() == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001881 }
1882 }
1883 return false;
1884}
1885
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001886GLint Framebuffer::getDefaultWidth() const
1887{
1888 return mState.getDefaultWidth();
1889}
1890
1891GLint Framebuffer::getDefaultHeight() const
1892{
1893 return mState.getDefaultHeight();
1894}
1895
1896GLint Framebuffer::getDefaultSamples() const
1897{
1898 return mState.getDefaultSamples();
1899}
1900
Geoff Lang92019432017-11-20 13:09:34 -05001901bool Framebuffer::getDefaultFixedSampleLocations() const
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001902{
1903 return mState.getDefaultFixedSampleLocations();
1904}
1905
Jiawei Shaob1e91382018-05-17 14:33:55 +08001906GLint Framebuffer::getDefaultLayers() const
1907{
1908 return mState.getDefaultLayers();
1909}
1910
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001911void Framebuffer::setDefaultWidth(GLint defaultWidth)
1912{
1913 mState.mDefaultWidth = defaultWidth;
1914 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
Jamie Madille98b1b52018-03-08 09:47:23 -05001915 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001916}
1917
1918void Framebuffer::setDefaultHeight(GLint defaultHeight)
1919{
1920 mState.mDefaultHeight = defaultHeight;
1921 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
Jamie Madille98b1b52018-03-08 09:47:23 -05001922 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001923}
1924
1925void Framebuffer::setDefaultSamples(GLint defaultSamples)
1926{
1927 mState.mDefaultSamples = defaultSamples;
1928 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
Jamie Madille98b1b52018-03-08 09:47:23 -05001929 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001930}
1931
Geoff Lang92019432017-11-20 13:09:34 -05001932void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations)
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001933{
1934 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1935 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
Jamie Madille98b1b52018-03-08 09:47:23 -05001936 invalidateCompletenessCache();
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001937}
1938
Jiawei Shaob1e91382018-05-17 14:33:55 +08001939void Framebuffer::setDefaultLayers(GLint defaultLayers)
1940{
1941 mState.mDefaultLayers = defaultLayers;
1942 mDirtyBits.set(DIRTY_BIT_DEFAULT_LAYERS);
1943}
1944
Martin Radev14a26ae2017-07-24 15:56:29 +03001945GLsizei Framebuffer::getNumViews() const
1946{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001947 return mState.getNumViews();
Martin Radev14a26ae2017-07-24 15:56:29 +03001948}
1949
Martin Radev4e619f52017-08-09 11:50:06 +03001950GLint Framebuffer::getBaseViewIndex() const
1951{
1952 return mState.getBaseViewIndex();
1953}
1954
Martin Radev878c8b12017-07-28 09:51:04 +03001955const std::vector<Offset> *Framebuffer::getViewportOffsets() const
1956{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001957 return mState.getViewportOffsets();
Martin Radev878c8b12017-07-28 09:51:04 +03001958}
1959
1960GLenum Framebuffer::getMultiviewLayout() const
1961{
Martin Radev5c00d0d2017-08-07 10:06:59 +03001962 return mState.getMultiviewLayout();
Martin Radev878c8b12017-07-28 09:51:04 +03001963}
1964
Geoff Langd4fff502017-09-22 11:28:28 -04001965Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask)
1966{
1967 const auto &glState = context->getGLState();
1968 if (!context->isRobustResourceInitEnabled() || glState.isRasterizerDiscardEnabled())
1969 {
1970 return NoError();
1971 }
1972
Geoff Langa36483f2018-03-09 16:11:21 -05001973 const BlendState &blend = glState.getBlendState();
1974 const DepthStencilState &depthStencil = glState.getDepthStencilState();
Geoff Langd4fff502017-09-22 11:28:28 -04001975
1976 bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend);
1977 bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil);
1978 bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil);
1979
1980 if (!color && !depth && !stencil)
1981 {
1982 return NoError();
1983 }
1984
1985 if (partialClearNeedsInit(context, color, depth, stencil))
1986 {
1987 ANGLE_TRY(ensureDrawAttachmentsInitialized(context));
1988 }
1989
1990 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
1991 // still be marked initialized. This simplifies design, allowing this method to be called before
1992 // the clear.
1993 markDrawAttachmentsInitialized(color, depth, stencil);
1994
1995 return NoError();
1996}
1997
1998Error Framebuffer::ensureClearBufferAttachmentsInitialized(const Context *context,
1999 GLenum buffer,
2000 GLint drawbuffer)
2001{
2002 if (!context->isRobustResourceInitEnabled() ||
2003 context->getGLState().isRasterizerDiscardEnabled() ||
2004 IsClearBufferMaskedOut(context, buffer))
2005 {
2006 return NoError();
2007 }
2008
2009 if (partialBufferClearNeedsInit(context, buffer))
2010 {
2011 ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer));
2012 }
2013
2014 // If the impl encounters an error during a a full (non-partial) clear, the attachments will
2015 // still be marked initialized. This simplifies design, allowing this method to be called before
2016 // the clear.
2017 markBufferInitialized(buffer, drawbuffer);
2018
2019 return NoError();
2020}
2021
Jamie Madill05b35b22017-10-03 09:01:44 -04002022Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context)
2023{
2024 if (!context->isRobustResourceInitEnabled())
2025 {
2026 return NoError();
2027 }
2028
2029 // Note: we don't actually filter by the draw attachment enum. Just init everything.
2030 for (size_t bit : mState.mResourceNeedsInit)
2031 {
2032 switch (bit)
2033 {
2034 case DIRTY_BIT_DEPTH_ATTACHMENT:
2035 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2036 break;
2037 case DIRTY_BIT_STENCIL_ATTACHMENT:
2038 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2039 break;
2040 default:
2041 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit]));
2042 break;
2043 }
2044 }
2045
2046 mState.mResourceNeedsInit.reset();
2047 return NoError();
2048}
2049
2050Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask)
2051{
2052 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2053 {
2054 return NoError();
2055 }
2056
2057 if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE)
2058 {
2059 size_t readIndex = mState.getReadIndex();
2060 if (mState.mResourceNeedsInit[readIndex])
2061 {
2062 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex]));
2063 mState.mResourceNeedsInit.reset(readIndex);
2064 }
2065 }
2066
2067 if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth())
2068 {
2069 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2070 {
2071 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2072 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2073 }
2074 }
2075
2076 if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil())
2077 {
2078 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2079 {
2080 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2081 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2082 }
2083 }
2084
2085 return NoError();
2086}
2087
2088void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil)
2089{
2090 // Mark attachments as initialized.
2091 if (color)
2092 {
2093 for (auto colorIndex : mState.mEnabledDrawBuffers)
2094 {
2095 auto &colorAttachment = mState.mColorAttachments[colorIndex];
2096 ASSERT(colorAttachment.isAttached());
2097 colorAttachment.setInitState(InitState::Initialized);
2098 mState.mResourceNeedsInit.reset(colorIndex);
2099 }
2100 }
2101
2102 if (depth && mState.mDepthAttachment.isAttached())
2103 {
2104 mState.mDepthAttachment.setInitState(InitState::Initialized);
2105 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2106 }
2107
2108 if (stencil && mState.mStencilAttachment.isAttached())
2109 {
2110 mState.mStencilAttachment.setInitState(InitState::Initialized);
2111 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2112 }
2113}
2114
2115void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex)
2116{
2117 switch (bufferType)
2118 {
2119 case GL_COLOR:
2120 {
2121 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2122 if (mState.mColorAttachments[bufferIndex].isAttached())
2123 {
2124 mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized);
2125 mState.mResourceNeedsInit.reset(bufferIndex);
2126 }
2127 break;
2128 }
2129 case GL_DEPTH:
2130 {
2131 if (mState.mDepthAttachment.isAttached())
2132 {
2133 mState.mDepthAttachment.setInitState(InitState::Initialized);
2134 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2135 }
2136 break;
2137 }
2138 case GL_STENCIL:
2139 {
2140 if (mState.mStencilAttachment.isAttached())
2141 {
2142 mState.mStencilAttachment.setInitState(InitState::Initialized);
2143 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2144 }
2145 break;
2146 }
2147 case GL_DEPTH_STENCIL:
2148 {
2149 if (mState.mDepthAttachment.isAttached())
2150 {
2151 mState.mDepthAttachment.setInitState(InitState::Initialized);
2152 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2153 }
2154 if (mState.mStencilAttachment.isAttached())
2155 {
2156 mState.mStencilAttachment.setInitState(InitState::Initialized);
2157 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2158 }
2159 break;
2160 }
2161 default:
2162 UNREACHABLE();
2163 break;
2164 }
2165}
2166
2167Box Framebuffer::getDimensions() const
2168{
2169 return mState.getDimensions();
2170}
2171
2172Error Framebuffer::ensureBufferInitialized(const Context *context,
2173 GLenum bufferType,
2174 GLint bufferIndex)
2175{
2176 ASSERT(context->isRobustResourceInitEnabled());
2177
2178 if (mState.mResourceNeedsInit.none())
2179 {
2180 return NoError();
2181 }
2182
2183 switch (bufferType)
2184 {
2185 case GL_COLOR:
2186 {
2187 ASSERT(bufferIndex < static_cast<GLint>(mState.mColorAttachments.size()));
2188 if (mState.mResourceNeedsInit[bufferIndex])
2189 {
2190 ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex]));
2191 mState.mResourceNeedsInit.reset(bufferIndex);
2192 }
2193 break;
2194 }
2195 case GL_DEPTH:
2196 {
2197 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2198 {
2199 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2200 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2201 }
2202 break;
2203 }
2204 case GL_STENCIL:
2205 {
2206 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2207 {
2208 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2209 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2210 }
2211 break;
2212 }
2213 case GL_DEPTH_STENCIL:
2214 {
2215 if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT])
2216 {
2217 ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment));
2218 mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT);
2219 }
2220 if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT])
2221 {
2222 ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment));
2223 mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT);
2224 }
2225 break;
2226 }
2227 default:
2228 UNREACHABLE();
2229 break;
2230 }
2231
2232 return NoError();
2233}
2234
2235bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType)
2236{
2237 if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())
2238 {
2239 return false;
2240 }
2241
2242 switch (bufferType)
2243 {
2244 case GL_COLOR:
2245 return partialClearNeedsInit(context, true, false, false);
2246 case GL_DEPTH:
2247 return partialClearNeedsInit(context, false, true, false);
2248 case GL_STENCIL:
2249 return partialClearNeedsInit(context, false, false, true);
2250 case GL_DEPTH_STENCIL:
2251 return partialClearNeedsInit(context, false, true, true);
2252 default:
2253 UNREACHABLE();
2254 return false;
2255 }
2256}
2257
Jamie Madill42975642017-10-12 12:31:51 -04002258bool Framebuffer::hasTextureAttachment(const Texture *texture) const
2259{
2260 if (!mAttachedTextures.valid())
2261 {
2262 std::set<const FramebufferAttachmentObject *> attachedTextures;
2263
2264 for (const auto &colorAttachment : mState.mColorAttachments)
2265 {
2266 if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
2267 {
2268 attachedTextures.insert(colorAttachment.getResource());
2269 }
2270 }
2271
2272 if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
2273 {
2274 attachedTextures.insert(mState.mDepthAttachment.getResource());
2275 }
2276
2277 if (mState.mStencilAttachment.isAttached() &&
2278 mState.mStencilAttachment.type() == GL_TEXTURE)
2279 {
2280 attachedTextures.insert(mState.mStencilAttachment.getResource());
2281 }
2282
2283 mAttachedTextures = std::move(attachedTextures);
2284 }
2285
2286 return (mAttachedTextures.value().count(texture) > 0);
2287}
2288
Jamie Madill60ec6ea2016-01-22 15:27:19 -05002289} // namespace gl