blob: d3efec47c02081a3376f31530cb5d9c19c43b8a7 [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"
22#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040023#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050024#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040025#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050026#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040027#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040028
Jamie Madill362876b2016-06-16 14:46:59 -040029using namespace angle;
30
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000031namespace gl
32{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000033
Jamie Madilld1405e52015-03-05 15:41:39 -050034namespace
35{
Jamie Madill362876b2016-06-16 14:46:59 -040036
Jamie Madill1e5499d2017-04-05 11:22:16 -040037void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmentObject *resource)
Jamie Madilld1405e52015-03-05 15:41:39 -050038{
Jamie Madill362876b2016-06-16 14:46:59 -040039 binding->bind(resource ? resource->getDirtyChannel() : nullptr);
Jamie Madilld1405e52015-03-05 15:41:39 -050040}
Jamie Madill362876b2016-06-16 14:46:59 -040041
Martin Radev9bc9a322017-07-21 14:28:17 +030042bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment,
43 const FramebufferAttachment *secondAttachment)
44{
45 ASSERT(firstAttachment && secondAttachment);
46 ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached());
47
48 if (firstAttachment->getNumViews() != secondAttachment->getNumViews())
49 {
50 return false;
51 }
52 if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex())
53 {
54 return false;
55 }
56 if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
57 {
58 return false;
59 }
60 if (firstAttachment->getMultiviewViewportOffsets() !=
61 secondAttachment->getMultiviewViewportOffsets())
62 {
63 return false;
64 }
65 return true;
66}
67
Geoff Lang9f10b772017-05-16 15:51:03 -040068bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
69{
70 ASSERT(attachment.isAttached());
71
72 const Extents &size = attachment.getSize();
73 if (size.width == 0 || size.height == 0)
74 {
75 return false;
76 }
77
78 const InternalFormat &format = *attachment.getFormat().info;
79 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
80 {
81 return false;
82 }
83
84 if (attachment.type() == GL_TEXTURE)
85 {
86 if (attachment.layer() >= size.depth)
87 {
88 return false;
89 }
90
91 // ES3 specifies that cube map texture attachments must be cube complete.
92 // This language is missing from the ES2 spec, but we enforce it here because some
93 // desktop OpenGL drivers also enforce this validation.
94 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
95 const Texture *texture = attachment.getTexture();
96 ASSERT(texture);
97 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
98 !texture->getTextureState().isCubeComplete())
99 {
100 return false;
101 }
Geoff Lang857c09d2017-05-16 15:55:04 -0400102
103 if (!texture->getImmutableFormat())
104 {
105 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
106
107 // From the ES 3.0 spec, pg 213:
108 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
109 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
110 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
111 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
112 // the effective maximum texture level defined in the Mipmapping discussion of
113 // section 3.8.10.4.
114 if (attachmentMipLevel < texture->getBaseLevel() ||
115 attachmentMipLevel > texture->getMipmapMaxLevel())
116 {
117 return false;
118 }
119
120 // Form the ES 3.0 spec, pg 213/214:
121 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
122 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
123 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
124 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
125 // a cubemap texture, the texture must also be cube complete.
126 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
127 {
128 return false;
129 }
130 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400131 }
132
133 return true;
134};
135
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400136bool CheckAttachmentSampleCompleteness(const Context *context,
137 const FramebufferAttachment &attachment,
138 bool colorAttachment,
139 Optional<int> *samples,
140 Optional<GLboolean> *fixedSampleLocations)
141{
142 ASSERT(attachment.isAttached());
143
144 if (attachment.type() == GL_TEXTURE)
145 {
146 const Texture *texture = attachment.getTexture();
147 ASSERT(texture);
148
149 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
150
151 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
152 // the same for all attached textures.
153 GLboolean fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type,
154 attachmentImageIndex.mipIndex);
155 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
156 {
157 return false;
158 }
159 else
160 {
161 *fixedSampleLocations = fixedSampleloc;
162 }
163 }
164
165 if (samples->valid())
166 {
167 if (attachment.getSamples() != samples->value())
168 {
169 if (colorAttachment)
170 {
171 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
172 // all color attachments have the same number of samples for the FBO to be complete.
173 return false;
174 }
175 else
176 {
177 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
178 // when its depth or stencil samples are a multiple of the number of color samples.
179 if (!context->getExtensions().framebufferMixedSamples)
180 {
181 return false;
182 }
183
184 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
185 {
186 return false;
187 }
188 }
189 }
190 }
191 else
192 {
193 *samples = attachment.getSamples();
194 }
195
196 return true;
197}
198
Jamie Madill362876b2016-06-16 14:46:59 -0400199} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500200
Jamie Madill6f60d052017-02-22 15:20:11 -0500201// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400202FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500203 : mLabel(),
204 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400205 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500206 mReadBufferState(GL_BACK),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800207 mDefaultWidth(0),
208 mDefaultHeight(0),
209 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500210 mDefaultFixedSampleLocations(GL_FALSE),
211 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400212{
Geoff Langd90d3882017-03-21 10:49:54 -0400213 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500214 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400215}
216
Jamie Madill48ef11b2016-04-27 15:21:52 -0400217FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -0500218 : mLabel(),
219 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -0500220 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800221 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
222 mDefaultWidth(0),
223 mDefaultHeight(0),
224 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500225 mDefaultFixedSampleLocations(GL_FALSE),
226 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500227{
Geoff Langa15472a2015-08-11 11:48:03 -0400228 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500229 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
230}
231
Jamie Madill48ef11b2016-04-27 15:21:52 -0400232FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500233{
Jamie Madilld1405e52015-03-05 15:41:39 -0500234}
235
Jamie Madill48ef11b2016-04-27 15:21:52 -0400236const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500237{
238 return mLabel;
239}
240
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400241const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
242{
243 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
244 {
245 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
246 }
247
248 switch (attachment)
249 {
250 case GL_COLOR:
251 case GL_BACK:
252 return getColorAttachment(0);
253 case GL_DEPTH:
254 case GL_DEPTH_ATTACHMENT:
255 return getDepthAttachment();
256 case GL_STENCIL:
257 case GL_STENCIL_ATTACHMENT:
258 return getStencilAttachment();
259 case GL_DEPTH_STENCIL:
260 case GL_DEPTH_STENCIL_ATTACHMENT:
261 return getDepthStencilAttachment();
262 default:
263 UNREACHABLE();
264 return nullptr;
265 }
266}
267
Jamie Madill48ef11b2016-04-27 15:21:52 -0400268const FramebufferAttachment *FramebufferState::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500269{
Antoine Labour2ec65dc2016-11-30 16:28:58 -0800270 if (mReadBufferState == GL_NONE)
271 {
272 return nullptr;
273 }
Jamie Madill231c7f52017-04-26 13:45:37 -0400274 ASSERT(mReadBufferState == GL_BACK ||
275 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
276 size_t readIndex = (mReadBufferState == GL_BACK
277 ? 0
278 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500279 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400280 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500281}
282
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500283const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
284{
285 auto *colorAttachment = getFirstColorAttachment();
286 if (colorAttachment)
287 {
288 return colorAttachment;
289 }
290 return getDepthOrStencilAttachment();
291}
292
Jamie Madill48ef11b2016-04-27 15:21:52 -0400293const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500294{
Jamie Madill2d06b732015-04-20 12:53:28 -0400295 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500296 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400297 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500298 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400299 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500300 }
301 }
302
303 return nullptr;
304}
305
Jamie Madill48ef11b2016-04-27 15:21:52 -0400306const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500307{
Jamie Madill2d06b732015-04-20 12:53:28 -0400308 if (mDepthAttachment.isAttached())
309 {
310 return &mDepthAttachment;
311 }
312 if (mStencilAttachment.isAttached())
313 {
314 return &mStencilAttachment;
315 }
316 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500317}
318
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500319const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
320{
321 if (mStencilAttachment.isAttached())
322 {
323 return &mStencilAttachment;
324 }
325 return getDepthStencilAttachment();
326}
327
Jamie Madill48ef11b2016-04-27 15:21:52 -0400328const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400329{
330 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400331 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
332 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400333}
334
Jamie Madill48ef11b2016-04-27 15:21:52 -0400335const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400336{
Jamie Madill2d06b732015-04-20 12:53:28 -0400337 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400338}
339
Jamie Madill48ef11b2016-04-27 15:21:52 -0400340const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400341{
Jamie Madill2d06b732015-04-20 12:53:28 -0400342 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400343}
344
Jamie Madill48ef11b2016-04-27 15:21:52 -0400345const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400346{
347 // A valid depth-stencil attachment has the same resource bound to both the
348 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400349 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500350 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400351 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400352 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400353 }
354
355 return nullptr;
356}
357
Jamie Madill48ef11b2016-04-27 15:21:52 -0400358bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500359{
360 Optional<Extents> attachmentSize;
361
Jamie Madill231c7f52017-04-26 13:45:37 -0400362 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500363 if (!attachment.isAttached())
364 {
365 return false;
366 }
367
368 if (!attachmentSize.valid())
369 {
370 attachmentSize = attachment.getSize();
371 return false;
372 }
373
374 return (attachment.getSize() != attachmentSize.value());
375 };
376
377 for (const auto &attachment : mColorAttachments)
378 {
379 if (hasMismatchedSize(attachment))
380 {
381 return false;
382 }
383 }
384
385 if (hasMismatchedSize(mDepthAttachment))
386 {
387 return false;
388 }
389
390 return !hasMismatchedSize(mStencilAttachment);
391}
392
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400393const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
394{
395 ASSERT(drawBufferIdx < mDrawBufferStates.size());
396 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
397 {
398 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
399 // must be COLOR_ATTACHMENTi or NONE"
400 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
401 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
402 return getAttachment(mDrawBufferStates[drawBufferIdx]);
403 }
404 else
405 {
406 return nullptr;
407 }
408}
409
410size_t FramebufferState::getDrawBufferCount() const
411{
412 return mDrawBufferStates.size();
413}
414
Geoff Langb21e20d2016-07-19 15:35:41 -0400415bool FramebufferState::colorAttachmentsAreUniqueImages() const
416{
417 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
418 firstAttachmentIdx++)
419 {
420 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
421 if (!firstAttachment.isAttached())
422 {
423 continue;
424 }
425
426 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
427 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
428 {
429 const gl::FramebufferAttachment &secondAttachment =
430 mColorAttachments[secondAttachmentIdx];
431 if (!secondAttachment.isAttached())
432 {
433 continue;
434 }
435
436 if (firstAttachment == secondAttachment)
437 {
438 return false;
439 }
440 }
441 }
442
443 return true;
444}
445
Jamie Madill9c335862017-07-18 11:51:38 -0400446bool FramebufferState::hasDepth() const
447{
448 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
449}
450
451bool FramebufferState::hasStencil() const
452{
453 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
454}
455
Jamie Madill7aea7e02016-05-10 10:39:45 -0400456Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400457 : mState(caps),
458 mImpl(factory->createFramebuffer(mState)),
459 mId(id),
460 mCachedStatus(),
461 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
462 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463{
Corentin Wallez37c39792015-08-20 14:19:46 -0400464 ASSERT(mId != 0);
465 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400466 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
467
Jamie Madill1e5499d2017-04-05 11:22:16 -0400468 for (uint32_t colorIndex = 0;
469 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400470 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400471 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400472 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400473}
474
Jamie Madill4928b7c2017-06-20 12:57:39 -0400475Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400476 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500477 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400478 mId(0),
479 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
480 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
481 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400482{
Geoff Langda88add2014-12-01 10:22:01 -0500483 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400484 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500485
Jamie Madill4928b7c2017-06-20 12:57:39 -0400486 const Context *proxyContext = display->getProxyContext();
487
488 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +0300489 surface, FramebufferAttachment::kDefaultNumViews,
490 FramebufferAttachment::kDefaultBaseViewIndex,
491 FramebufferAttachment::kDefaultMultiviewLayout,
492 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500493
494 if (surface->getConfig()->depthSize > 0)
495 {
Martin Radev5dae57b2017-07-14 16:15:55 +0300496 setAttachmentImpl(
497 proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface,
498 FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex,
499 FramebufferAttachment::kDefaultMultiviewLayout,
500 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500501 }
502
503 if (surface->getConfig()->stencilSize > 0)
504 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400505 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL,
Martin Radev5dae57b2017-07-14 16:15:55 +0300506 gl::ImageIndex::MakeInvalid(), surface,
507 FramebufferAttachment::kDefaultNumViews,
508 FramebufferAttachment::kDefaultBaseViewIndex,
509 FramebufferAttachment::kDefaultMultiviewLayout,
510 FramebufferAttachment::kDefaultViewportOffsets);
Jamie Madill6f60d052017-02-22 15:20:11 -0500511 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000512}
513
Corentin Wallezccab69d2017-01-27 16:57:15 -0500514Framebuffer::Framebuffer(rx::GLImplFactory *factory)
515 : mState(),
516 mImpl(factory->createFramebuffer(mState)),
517 mId(0),
518 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
519 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
520 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
521{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400522 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500523}
524
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000525Framebuffer::~Framebuffer()
526{
Geoff Langda88add2014-12-01 10:22:01 -0500527 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000528}
529
Jamie Madill4928b7c2017-06-20 12:57:39 -0400530void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500531{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400532 for (auto &attachment : mState.mColorAttachments)
533 {
534 attachment.detach(context);
535 }
536 mState.mDepthAttachment.detach(context);
537 mState.mStencilAttachment.detach(context);
538 mState.mWebGLDepthAttachment.detach(context);
539 mState.mWebGLStencilAttachment.detach(context);
540 mState.mWebGLDepthStencilAttachment.detach(context);
541
Jamie Madillc564c072017-06-01 12:45:42 -0400542 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500543}
544
545void Framebuffer::destroyDefault(const egl::Display *display)
546{
Jamie Madillc564c072017-06-01 12:45:42 -0400547 mImpl->destroyDefault(display);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500548}
549
Geoff Lang70d0f492015-12-10 17:45:46 -0500550void Framebuffer::setLabel(const std::string &label)
551{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400552 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500553}
554
555const std::string &Framebuffer::getLabel() const
556{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400557 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500558}
559
Jamie Madilla02315b2017-02-23 14:14:47 -0500560void Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000561{
Jamie Madilla02315b2017-02-23 14:14:47 -0500562 detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000563}
564
Jamie Madilla02315b2017-02-23 14:14:47 -0500565void Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000566{
Jamie Madilla02315b2017-02-23 14:14:47 -0500567 detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500568}
Jamie Madille261b442014-06-25 12:42:21 -0400569
Jamie Madilla02315b2017-02-23 14:14:47 -0500570void Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500571{
Jamie Madill362876b2016-06-16 14:46:59 -0400572 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500573 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400574 detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
575 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576 }
577
Jamie Madilla02315b2017-02-23 14:14:47 -0500578 if (context->isWebGL1())
579 {
580 const std::array<FramebufferAttachment *, 3> attachments = {
581 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
582 &mState.mWebGLStencilAttachment}};
583 for (FramebufferAttachment *attachment : attachments)
584 {
585 if (attachment->isAttached() && attachment->type() == resourceType &&
586 attachment->id() == resourceId)
587 {
588 resetAttachment(context, attachment->getBinding());
589 }
590 }
591 }
592 else
593 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400594 detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
Jamie Madilla02315b2017-02-23 14:14:47 -0500595 DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400596 detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
Jamie Madilla02315b2017-02-23 14:14:47 -0500597 DIRTY_BIT_STENCIL_ATTACHMENT);
598 }
Jamie Madill362876b2016-06-16 14:46:59 -0400599}
600
Jamie Madill4928b7c2017-06-20 12:57:39 -0400601void Framebuffer::detachMatchingAttachment(const Context *context,
602 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400603 GLenum matchType,
604 GLuint matchId,
605 size_t dirtyBit)
606{
607 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
608 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400609 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400610 mDirtyBits.set(dirtyBit);
611 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612}
613
Corentin Wallez37c39792015-08-20 14:19:46 -0400614const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000615{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400616 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000617}
618
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400619const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400620{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400621 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400622}
623
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400624const FramebufferAttachment *Framebuffer::getStencilbuffer() const
625{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400626 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400627}
628
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400629const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
630{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400631 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400632}
633
634const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000635{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400636 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000637}
638
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500639const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
640{
641 return mState.getStencilOrDepthStencilAttachment();
642}
643
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400644const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000645{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400646 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000647}
648
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000649GLenum Framebuffer::getReadColorbufferType() const
650{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400651 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400652 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000653}
654
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400655const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000656{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400657 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000658}
659
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400660const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
661{
662 return mState.getFirstNonNullAttachment();
663}
664
Jamie Madill2d06b732015-04-20 12:53:28 -0400665const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000666{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400667 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400668}
669
Geoff Langa15472a2015-08-11 11:48:03 -0400670size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000671{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400672 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400673}
674
675GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
676{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400677 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
678 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000679}
680
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500681const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
682{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400683 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500684}
685
Geoff Lang164d54e2014-12-01 10:55:33 -0500686void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000687{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400688 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500689
690 ASSERT(count <= drawStates.size());
691 std::copy(buffers, buffers + count, drawStates.begin());
692 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500693 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500694
695 mState.mEnabledDrawBuffers.reset();
696 for (size_t index = 0; index < count; ++index)
697 {
698 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
699 {
700 mState.mEnabledDrawBuffers.set(index);
701 }
702 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500703}
704
Geoff Langa15472a2015-08-11 11:48:03 -0400705const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
706{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400707 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400708}
709
Geoff Lange0cff192017-05-30 13:04:56 -0400710GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
711{
712 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
713 if (attachment == nullptr)
714 {
715 return GL_NONE;
716 }
717
718 GLenum componentType = attachment->getFormat().info->componentType;
719 switch (componentType)
720 {
721 case GL_INT:
722 case GL_UNSIGNED_INT:
723 return componentType;
724
725 default:
726 return GL_FLOAT;
727 }
728}
729
Geoff Langa15472a2015-08-11 11:48:03 -0400730bool Framebuffer::hasEnabledDrawBuffer() const
731{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400732 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400733 {
734 if (getDrawBuffer(drawbufferIdx) != nullptr)
735 {
736 return true;
737 }
738 }
739
740 return false;
741}
742
Geoff Lang9dd95802014-12-01 11:12:59 -0500743GLenum Framebuffer::getReadBufferState() const
744{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400745 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500746}
747
748void Framebuffer::setReadBuffer(GLenum buffer)
749{
Jamie Madillb885e572015-02-03 16:16:04 -0500750 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
751 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400752 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
753 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500754 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000755}
756
Corentin Wallez37c39792015-08-20 14:19:46 -0400757size_t Framebuffer::getNumColorBuffers() const
758{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400759 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400760}
761
Jamie Madill0df8fe42015-11-24 16:10:24 -0500762bool Framebuffer::hasDepth() const
763{
Jamie Madill9c335862017-07-18 11:51:38 -0400764 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500765}
766
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000767bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000768{
Jamie Madill9c335862017-07-18 11:51:38 -0400769 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000770}
771
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000772bool Framebuffer::usingExtendedDrawBuffers() const
773{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400774 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000775 {
Geoff Langa15472a2015-08-11 11:48:03 -0400776 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000777 {
778 return true;
779 }
780 }
781
782 return false;
783}
784
Geoff Lang9aded172017-04-05 11:07:56 -0400785void Framebuffer::invalidateCompletenessCache()
786{
787 if (mId != 0)
788 {
789 mCachedStatus.reset();
790 }
791}
792
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400793GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000794{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500795 // The default framebuffer is always complete except when it is surfaceless in which
796 // case it is always unsupported. We return early because the default framebuffer may
797 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500798 if (mId == 0)
799 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500800 ASSERT(mCachedStatus.valid());
801 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
802 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
803 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500804 }
805
Jamie Madill362876b2016-06-16 14:46:59 -0400806 if (hasAnyDirtyBit() || !mCachedStatus.valid())
807 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400808 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400809 }
810
811 return mCachedStatus.value();
812}
813
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400814GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400815{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400816 const ContextState &state = context->getContextState();
817
Jamie Madill362876b2016-06-16 14:46:59 -0400818 ASSERT(mId != 0);
819
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400820 bool hasAttachments = false;
821 Optional<unsigned int> colorbufferSize;
822 Optional<int> samples;
JiangYizhou461d9a32017-01-04 16:37:26 +0800823 Optional<GLboolean> fixedSampleLocations;
824 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000825
Martin Radev9bc9a322017-07-21 14:28:17 +0300826 const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
827
Jamie Madill48ef11b2016-04-27 15:21:52 -0400828 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000829 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400830 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000831 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400832 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000833 {
834 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
835 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000836
Geoff Lang677bb6f2017-04-05 12:40:40 -0400837 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400838 if (format.depthBits > 0 || format.stencilBits > 0)
839 {
840 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
841 }
842
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400843 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
844 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000845 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400846 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000847 }
848
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400849 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
850 // in GLES 3.0, there is no such restriction
851 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000852 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400853 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000854 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400855 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000856 {
857 return GL_FRAMEBUFFER_UNSUPPORTED;
858 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000859 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400860 else
861 {
862 colorbufferSize = format.pixelBytes;
863 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000864 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400865
Martin Radev9bc9a322017-07-21 14:28:17 +0300866 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
867 {
868 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
869 }
870
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400871 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
872 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000873 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000874 }
875
Jamie Madill48ef11b2016-04-27 15:21:52 -0400876 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400877 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000878 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400879 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000880 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000881 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000882 }
883
Geoff Lang677bb6f2017-04-05 12:40:40 -0400884 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400885 if (format.depthBits == 0)
886 {
887 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000888 }
889
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400890 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
891 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000892 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400893 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000894 }
Sami Väisänena797e062016-05-12 15:23:40 +0300895
Martin Radev9bc9a322017-07-21 14:28:17 +0300896 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
897 {
898 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
899 }
900
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400901 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
902 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000903 }
904
Jamie Madill48ef11b2016-04-27 15:21:52 -0400905 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400906 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000907 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400908 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000909 {
910 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
911 }
912
Geoff Lang677bb6f2017-04-05 12:40:40 -0400913 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400914 if (format.stencilBits == 0)
915 {
916 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000917 }
918
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400919 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
920 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000921 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400922 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000923 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400924
Martin Radev9bc9a322017-07-21 14:28:17 +0300925 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
926 {
927 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
928 }
929
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400930 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
931 hasAttachments = true;
932 }
933
934 // Starting from ES 3.0 stencil and depth, if present, should be the same image
935 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
936 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
937 {
938 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000939 }
940
Jamie Madilla02315b2017-02-23 14:14:47 -0500941 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
942 if (state.isWebGL1())
943 {
944 if (!mState.mWebGLDepthStencilConsistent)
945 {
946 return GL_FRAMEBUFFER_UNSUPPORTED;
947 }
948
949 if (mState.mWebGLDepthStencilAttachment.isAttached())
950 {
951 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
952 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
953 {
954 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
955 }
Martin Radev9bc9a322017-07-21 14:28:17 +0300956
957 if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
958 &mState.mWebGLDepthStencilAttachment))
959 {
960 return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
961 }
Jamie Madilla02315b2017-02-23 14:14:47 -0500962 }
963 else if (mState.mStencilAttachment.isAttached() &&
964 mState.mStencilAttachment.getDepthSize() > 0)
965 {
966 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
967 }
968 else if (mState.mDepthAttachment.isAttached() &&
969 mState.mDepthAttachment.getStencilSize() > 0)
970 {
971 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
972 }
973 }
974
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400975 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
976 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
977 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +0800978 GLint defaultWidth = mState.getDefaultWidth();
979 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400980 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000981 {
982 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000983 }
984
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400985 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -0500986 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400987 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
988 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500989 {
990 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
991 }
992
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400993 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
994 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +0800995 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
996 {
997 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
998 }
999
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001000 syncState(context);
Jamie Madillcc86d642015-11-24 13:00:07 -05001001 if (!mImpl->checkStatus())
1002 {
1003 return GL_FRAMEBUFFER_UNSUPPORTED;
1004 }
1005
1006 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001008
Jamie Madill4928b7c2017-06-20 12:57:39 -04001009Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -07001010{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001011 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -07001012}
1013
Jamie Madill4928b7c2017-06-20 12:57:39 -04001014Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001015{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001016 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -04001017}
1018
Jamie Madill4928b7c2017-06-20 12:57:39 -04001019Error Framebuffer::invalidateSub(const Context *context,
1020 size_t count,
1021 const GLenum *attachments,
1022 const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -04001023{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001024 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -04001025}
1026
Jamie Madillc564c072017-06-01 12:45:42 -04001027Error Framebuffer::clear(const gl::Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -05001028{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001029 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001030 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001031 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001032 }
1033
Jamie Madill8415b5f2016-04-26 13:41:39 -04001034 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -05001035}
1036
Jamie Madillc564c072017-06-01 12:45:42 -04001037Error Framebuffer::clearBufferfv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001038 GLenum buffer,
1039 GLint drawbuffer,
1040 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001041{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001042 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001043 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001044 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001045 }
1046
Jamie Madill8415b5f2016-04-26 13:41:39 -04001047 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -05001048}
1049
Jamie Madillc564c072017-06-01 12:45:42 -04001050Error Framebuffer::clearBufferuiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001051 GLenum buffer,
1052 GLint drawbuffer,
1053 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001054{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001055 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001056 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001057 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001058 }
1059
Jamie Madill8415b5f2016-04-26 13:41:39 -04001060 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -05001061}
1062
Jamie Madillc564c072017-06-01 12:45:42 -04001063Error Framebuffer::clearBufferiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001064 GLenum buffer,
1065 GLint drawbuffer,
1066 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001067{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001068 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001069 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001070 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001071 }
1072
Jamie Madill8415b5f2016-04-26 13:41:39 -04001073 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -05001074}
1075
Jamie Madillc564c072017-06-01 12:45:42 -04001076Error Framebuffer::clearBufferfi(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001077 GLenum buffer,
1078 GLint drawbuffer,
1079 GLfloat depth,
1080 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001081{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001082 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001083 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001084 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001085 }
1086
Jamie Madill8415b5f2016-04-26 13:41:39 -04001087 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -05001088}
1089
Jamie Madill4928b7c2017-06-20 12:57:39 -04001090GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001091{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001092 return mImpl->getImplementationColorReadFormat(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001093}
1094
Jamie Madill4928b7c2017-06-20 12:57:39 -04001095GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001096{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001097 return mImpl->getImplementationColorReadType(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001098}
1099
Jamie Madillc564c072017-06-01 12:45:42 -04001100Error Framebuffer::readPixels(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001101 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001102 GLenum format,
1103 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04001104 void *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -05001105{
Jamie Madill362876b2016-06-16 14:46:59 -04001106 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001107
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001108 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -04001109 if (unpackBuffer)
1110 {
1111 unpackBuffer->onPixelUnpack();
1112 }
1113
Jamie Madill362876b2016-06-16 14:46:59 -04001114 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001115}
1116
Jamie Madillc564c072017-06-01 12:45:42 -04001117Error Framebuffer::blit(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001118 const Rectangle &sourceArea,
1119 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001120 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001121 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001122{
He Yunchao6be602d2016-12-22 14:33:07 +08001123 GLbitfield blitMask = mask;
1124
1125 // Note that blitting is called against draw framebuffer.
1126 // See the code in gl::Context::blitFramebuffer.
1127 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1128 {
1129 blitMask &= ~GL_COLOR_BUFFER_BIT;
1130 }
1131
1132 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1133 {
1134 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1135 }
1136
1137 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1138 {
1139 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1140 }
1141
1142 if (!blitMask)
1143 {
1144 return NoError();
1145 }
1146
1147 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001148}
1149
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001150int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001151{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001152 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001153 {
Jamie Madill9c335862017-07-18 11:51:38 -04001154 return getCachedSamples(context);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001155 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001156
1157 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001158}
1159
Jamie Madill9c335862017-07-18 11:51:38 -04001160int Framebuffer::getCachedSamples(const Context *context)
1161{
1162 // For a complete framebuffer, all attachments must have the same sample count.
1163 // In this case return the first nonzero sample size.
1164 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1165 if (firstNonNullAttachment)
1166 {
1167 ASSERT(firstNonNullAttachment->isAttached());
1168 return firstNonNullAttachment->getSamples();
1169 }
1170
1171 // No attachments found.
1172 return 0;
1173}
1174
Corentin Wallezccab69d2017-01-27 16:57:15 -05001175Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1176{
1177 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001178 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001179}
1180
Jamie Madille261b442014-06-25 12:42:21 -04001181bool Framebuffer::hasValidDepthStencil() const
1182{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001183 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001184}
1185
Jamie Madilla02315b2017-02-23 14:14:47 -05001186void Framebuffer::setAttachment(const Context *context,
1187 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001188 GLenum binding,
1189 const ImageIndex &textureIndex,
1190 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001191{
Martin Radev5dae57b2017-07-14 16:15:55 +03001192 setAttachment(context, type, binding, textureIndex, resource,
1193 FramebufferAttachment::kDefaultNumViews,
1194 FramebufferAttachment::kDefaultBaseViewIndex,
1195 FramebufferAttachment::kDefaultMultiviewLayout,
1196 FramebufferAttachment::kDefaultViewportOffsets);
1197}
1198
1199void Framebuffer::setAttachment(const Context *context,
1200 GLenum type,
1201 GLenum binding,
1202 const ImageIndex &textureIndex,
1203 FramebufferAttachmentObject *resource,
1204 GLsizei numViews,
1205 GLuint baseViewIndex,
1206 GLenum multiviewLayout,
1207 const GLint *viewportOffsets)
1208{
Jamie Madilla02315b2017-02-23 14:14:47 -05001209 // Context may be null in unit tests.
1210 if (!context || !context->isWebGL1())
1211 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001212 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1213 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001214 return;
1215 }
1216
1217 switch (binding)
1218 {
1219 case GL_DEPTH_STENCIL:
1220 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001221 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001222 resource, numViews, baseViewIndex,
1223 multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001224 break;
1225 case GL_DEPTH:
1226 case GL_DEPTH_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001227 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
1228 numViews, baseViewIndex, multiviewLayout,
1229 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001230 break;
1231 case GL_STENCIL:
1232 case GL_STENCIL_ATTACHMENT:
Martin Radev5dae57b2017-07-14 16:15:55 +03001233 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
1234 numViews, baseViewIndex, multiviewLayout,
1235 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001236 break;
1237 default:
Martin Radev5dae57b2017-07-14 16:15:55 +03001238 setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
1239 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001240 return;
1241 }
1242
Martin Radev5dae57b2017-07-14 16:15:55 +03001243 commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
1244 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001245}
1246
Martin Radev5dae57b2017-07-14 16:15:55 +03001247void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
1248 GLenum type,
1249 GLenum binding,
1250 const ImageIndex &textureIndex,
1251 FramebufferAttachmentObject *resource,
1252 GLsizei numViews,
1253 const GLint *viewportOffsets)
1254{
1255 setAttachment(context, type, binding, textureIndex, resource, numViews,
1256 FramebufferAttachment::kDefaultBaseViewIndex,
1257 GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
1258}
1259
1260void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
1261 GLsizei numViews,
1262 GLuint baseViewIndex,
1263 GLenum multiviewLayout,
1264 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001265{
1266 int count = 0;
1267
1268 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1269 &mState.mWebGLDepthAttachment,
1270 &mState.mWebGLStencilAttachment}};
1271 for (FramebufferAttachment *attachment : attachments)
1272 {
1273 if (attachment->isAttached())
1274 {
1275 count++;
1276 }
1277 }
1278
1279 mState.mWebGLDepthStencilConsistent = (count <= 1);
1280 if (!mState.mWebGLDepthStencilConsistent)
1281 {
1282 // Inconsistent.
1283 return;
1284 }
1285
Geoff Lange466c552017-03-17 15:24:12 -04001286 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1287 if (attachment.type() == GL_TEXTURE)
1288 {
1289 return attachment.getTextureImageIndex();
1290 }
1291 else
1292 {
1293 return ImageIndex::MakeInvalid();
1294 }
1295 };
1296
Jamie Madilla02315b2017-02-23 14:14:47 -05001297 if (mState.mWebGLDepthAttachment.isAttached())
1298 {
1299 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001300 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001301 getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
1302 baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001303 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001304 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001305 }
1306 else if (mState.mWebGLStencilAttachment.isAttached())
1307 {
1308 const auto &stencil = mState.mWebGLStencilAttachment;
Martin Radev5dae57b2017-07-14 16:15:55 +03001309 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1310 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001311 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001312 getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
1313 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001314 }
1315 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1316 {
1317 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001318 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001319 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001320 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1321 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001322 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001323 getImageIndexIfTextureAttachment(depthStencil),
Martin Radev5dae57b2017-07-14 16:15:55 +03001324 depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
1325 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001326 }
1327 else
1328 {
Martin Radev5dae57b2017-07-14 16:15:55 +03001329 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr,
1330 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001331 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
Martin Radev5dae57b2017-07-14 16:15:55 +03001332 nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001333 }
1334}
1335
Jamie Madill4928b7c2017-06-20 12:57:39 -04001336void Framebuffer::setAttachmentImpl(const Context *context,
1337 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001338 GLenum binding,
1339 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001340 FramebufferAttachmentObject *resource,
1341 GLsizei numViews,
1342 GLuint baseViewIndex,
1343 GLenum multiviewLayout,
1344 const GLint *viewportOffsets)
Jamie Madilla02315b2017-02-23 14:14:47 -05001345{
Jamie Madilla02315b2017-02-23 14:14:47 -05001346 switch (binding)
1347 {
Jamie Madillb8126692017-04-05 11:22:17 -04001348 case GL_DEPTH_STENCIL:
1349 case GL_DEPTH_STENCIL_ATTACHMENT:
1350 {
1351 // ensure this is a legitimate depth+stencil format
1352 FramebufferAttachmentObject *attachmentObj = resource;
1353 if (resource)
1354 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001355 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001356 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1357 {
1358 // Attaching nullptr detaches the current attachment.
1359 attachmentObj = nullptr;
1360 }
1361 }
1362
Jamie Madill4928b7c2017-06-20 12:57:39 -04001363 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001364 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001365 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1366 viewportOffsets);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001367 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001368 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001369 attachmentObj, numViews, baseViewIndex, multiviewLayout,
1370 viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001371 return;
1372 }
1373
Jamie Madilla02315b2017-02-23 14:14:47 -05001374 case GL_DEPTH:
1375 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001376 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001377 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
1378 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madill2d06b732015-04-20 12:53:28 -04001379 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001380
Jamie Madilla02315b2017-02-23 14:14:47 -05001381 case GL_STENCIL:
1382 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001383 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Martin Radev5dae57b2017-07-14 16:15:55 +03001384 &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
1385 numViews, baseViewIndex, multiviewLayout, viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001386 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001387
Jamie Madilla02315b2017-02-23 14:14:47 -05001388 case GL_BACK:
Martin Radev5dae57b2017-07-14 16:15:55 +03001389 mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource,
1390 numViews, baseViewIndex, multiviewLayout,
1391 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001392 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1393 // No need for a resource binding for the default FBO, it's always complete.
1394 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001395
Jamie Madilla02315b2017-02-23 14:14:47 -05001396 default:
1397 {
1398 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1399 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001400 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001401 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001402 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
Martin Radev5dae57b2017-07-14 16:15:55 +03001403 textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
1404 viewportOffsets);
Jamie Madilla02315b2017-02-23 14:14:47 -05001405
Corentin Walleze7557742017-06-01 13:09:57 -04001406 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1407 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001408 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1409 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001410 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001411 break;
Geoff Langab75a052014-10-15 12:56:37 -04001412 }
1413}
1414
Jamie Madill4928b7c2017-06-20 12:57:39 -04001415void Framebuffer::updateAttachment(const Context *context,
1416 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001417 size_t dirtyBit,
1418 OnAttachmentDirtyBinding *onDirtyBinding,
1419 GLenum type,
1420 GLenum binding,
1421 const ImageIndex &textureIndex,
Martin Radev5dae57b2017-07-14 16:15:55 +03001422 FramebufferAttachmentObject *resource,
1423 GLsizei numViews,
1424 GLuint baseViewIndex,
1425 GLenum multiviewLayout,
1426 const GLint *viewportOffsets)
Jamie Madillb8126692017-04-05 11:22:17 -04001427{
Martin Radev5dae57b2017-07-14 16:15:55 +03001428 attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
1429 multiviewLayout, viewportOffsets);
Jamie Madillb8126692017-04-05 11:22:17 -04001430 mDirtyBits.set(dirtyBit);
1431 BindResourceChannel(onDirtyBinding, resource);
1432}
1433
Jamie Madilla02315b2017-02-23 14:14:47 -05001434void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001435{
Jamie Madilla02315b2017-02-23 14:14:47 -05001436 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001437}
1438
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001439void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001440{
1441 if (mDirtyBits.any())
1442 {
Jamie Madillc564c072017-06-01 12:45:42 -04001443 mImpl->syncState(context, mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001444 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001445 if (mId != 0)
1446 {
1447 mCachedStatus.reset();
1448 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001449 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001450}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001451
Jamie Madill1e5499d2017-04-05 11:22:16 -04001452void Framebuffer::signal(uint32_t token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001453{
Jamie Madill362876b2016-06-16 14:46:59 -04001454 // TOOD(jmadill): Make this only update individual attachments to do less work.
1455 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001456}
1457
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001458bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001459{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001460 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1461}
1462
1463bool Framebuffer::cachedComplete() const
1464{
1465 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001466}
1467
Jamie Madilla4595b82017-01-11 17:36:34 -05001468bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1469{
1470 const Program *program = state.getProgram();
1471
1472 // TODO(jmadill): Default framebuffer feedback loops.
1473 if (mId == 0)
1474 {
1475 return false;
1476 }
1477
1478 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001479 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001480 {
Jamie Madill5aca1932017-07-21 12:22:01 -04001481 const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex];
1482 ASSERT(attachment.isAttached());
1483 if (attachment.type() == GL_TEXTURE)
Jamie Madilla4595b82017-01-11 17:36:34 -05001484 {
1485 // Validate the feedback loop.
Jamie Madill5aca1932017-07-21 12:22:01 -04001486 if (program->samplesFromTexture(state, attachment.id()))
Jamie Madilla4595b82017-01-11 17:36:34 -05001487 {
1488 return true;
1489 }
1490 }
1491 }
1492
Jamie Madill1d37bc52017-02-02 19:59:58 -05001493 // Validate depth-stencil feedback loop.
1494 const auto &dsState = state.getDepthStencilState();
1495
1496 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1497 const FramebufferAttachment *depth = getDepthbuffer();
1498 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1499 {
1500 if (program->samplesFromTexture(state, depth->id()))
1501 {
1502 return true;
1503 }
1504 }
1505
1506 // Note: we assume the front and back masks are the same for WebGL.
1507 const FramebufferAttachment *stencil = getStencilbuffer();
1508 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1509 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1510 dsState.stencilWritemask != 0)
1511 {
1512 // Skip the feedback loop check if depth/stencil point to the same resource.
1513 if (!depth || *stencil != *depth)
1514 {
1515 if (program->samplesFromTexture(state, stencil->id()))
1516 {
1517 return true;
1518 }
1519 }
1520 }
1521
Jamie Madilla4595b82017-01-11 17:36:34 -05001522 return false;
1523}
1524
Jamie Madillfd3dd432017-02-02 19:59:59 -05001525bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1526 GLint copyTextureLevel,
1527 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001528{
1529 if (mId == 0)
1530 {
1531 // It seems impossible to form a texture copying feedback loop with the default FBO.
1532 return false;
1533 }
1534
1535 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1536 ASSERT(readAttachment);
1537
1538 if (readAttachment->isTextureWithId(copyTextureID))
1539 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001540 const auto &imageIndex = readAttachment->getTextureImageIndex();
1541 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001542 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001543 // Check 3D/Array texture layers.
1544 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1545 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1546 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001547 }
1548 }
1549 return false;
1550}
1551
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001552GLint Framebuffer::getDefaultWidth() const
1553{
1554 return mState.getDefaultWidth();
1555}
1556
1557GLint Framebuffer::getDefaultHeight() const
1558{
1559 return mState.getDefaultHeight();
1560}
1561
1562GLint Framebuffer::getDefaultSamples() const
1563{
1564 return mState.getDefaultSamples();
1565}
1566
1567GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1568{
1569 return mState.getDefaultFixedSampleLocations();
1570}
1571
1572void Framebuffer::setDefaultWidth(GLint defaultWidth)
1573{
1574 mState.mDefaultWidth = defaultWidth;
1575 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1576}
1577
1578void Framebuffer::setDefaultHeight(GLint defaultHeight)
1579{
1580 mState.mDefaultHeight = defaultHeight;
1581 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1582}
1583
1584void Framebuffer::setDefaultSamples(GLint defaultSamples)
1585{
1586 mState.mDefaultSamples = defaultSamples;
1587 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1588}
1589
1590void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1591{
1592 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1593 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1594}
1595
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001596// TODO(jmadill): Remove this kludge.
1597GLenum Framebuffer::checkStatus(const ValidationContext *context)
1598{
1599 return checkStatus(static_cast<const Context *>(context));
1600}
1601
1602int Framebuffer::getSamples(const ValidationContext *context)
1603{
1604 return getSamples(static_cast<const Context *>(context));
1605}
1606
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001607} // namespace gl