blob: 45b2d47c78318092ad3ba3eba1d13888c7f234e8 [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
Geoff Lang9f10b772017-05-16 15:51:03 -040042bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment)
43{
44 ASSERT(attachment.isAttached());
45
46 const Extents &size = attachment.getSize();
47 if (size.width == 0 || size.height == 0)
48 {
49 return false;
50 }
51
52 const InternalFormat &format = *attachment.getFormat().info;
53 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
54 {
55 return false;
56 }
57
58 if (attachment.type() == GL_TEXTURE)
59 {
60 if (attachment.layer() >= size.depth)
61 {
62 return false;
63 }
64
65 // ES3 specifies that cube map texture attachments must be cube complete.
66 // This language is missing from the ES2 spec, but we enforce it here because some
67 // desktop OpenGL drivers also enforce this validation.
68 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
69 const Texture *texture = attachment.getTexture();
70 ASSERT(texture);
71 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
72 !texture->getTextureState().isCubeComplete())
73 {
74 return false;
75 }
Geoff Lang857c09d2017-05-16 15:55:04 -040076
77 if (!texture->getImmutableFormat())
78 {
79 GLuint attachmentMipLevel = static_cast<GLuint>(attachment.mipLevel());
80
81 // From the ES 3.0 spec, pg 213:
82 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
83 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture,
84 // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the
85 // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is
86 // the effective maximum texture level defined in the Mipmapping discussion of
87 // section 3.8.10.4.
88 if (attachmentMipLevel < texture->getBaseLevel() ||
89 attachmentMipLevel > texture->getMipmapMaxLevel())
90 {
91 return false;
92 }
93
94 // Form the ES 3.0 spec, pg 213/214:
95 // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of
96 // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and
97 // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the
98 // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names
99 // a cubemap texture, the texture must also be cube complete.
100 if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete())
101 {
102 return false;
103 }
104 }
Geoff Lang9f10b772017-05-16 15:51:03 -0400105 }
106
107 return true;
108};
109
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400110bool CheckAttachmentSampleCompleteness(const Context *context,
111 const FramebufferAttachment &attachment,
112 bool colorAttachment,
113 Optional<int> *samples,
114 Optional<GLboolean> *fixedSampleLocations)
115{
116 ASSERT(attachment.isAttached());
117
118 if (attachment.type() == GL_TEXTURE)
119 {
120 const Texture *texture = attachment.getTexture();
121 ASSERT(texture);
122
123 const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
124
125 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
126 // the same for all attached textures.
127 GLboolean fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type,
128 attachmentImageIndex.mipIndex);
129 if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
130 {
131 return false;
132 }
133 else
134 {
135 *fixedSampleLocations = fixedSampleloc;
136 }
137 }
138
139 if (samples->valid())
140 {
141 if (attachment.getSamples() != samples->value())
142 {
143 if (colorAttachment)
144 {
145 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
146 // all color attachments have the same number of samples for the FBO to be complete.
147 return false;
148 }
149 else
150 {
151 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
152 // when its depth or stencil samples are a multiple of the number of color samples.
153 if (!context->getExtensions().framebufferMixedSamples)
154 {
155 return false;
156 }
157
158 if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
159 {
160 return false;
161 }
162 }
163 }
164 }
165 else
166 {
167 *samples = attachment.getSamples();
168 }
169
170 return true;
171}
172
Jamie Madill362876b2016-06-16 14:46:59 -0400173} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -0500174
Jamie Madill6f60d052017-02-22 15:20:11 -0500175// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400176FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -0500177 : mLabel(),
178 mColorAttachments(1),
Corentin Walleze7557742017-06-01 13:09:57 -0400179 mDrawBufferStates(1, GL_BACK),
Jamie Madill6f60d052017-02-22 15:20:11 -0500180 mReadBufferState(GL_BACK),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800181 mDefaultWidth(0),
182 mDefaultHeight(0),
183 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500184 mDefaultFixedSampleLocations(GL_FALSE),
185 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -0400186{
Geoff Langd90d3882017-03-21 10:49:54 -0400187 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilla4595b82017-01-11 17:36:34 -0500188 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -0400189}
190
Jamie Madill48ef11b2016-04-27 15:21:52 -0400191FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -0500192 : mLabel(),
193 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -0500194 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800195 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
196 mDefaultWidth(0),
197 mDefaultHeight(0),
198 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -0500199 mDefaultFixedSampleLocations(GL_FALSE),
200 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -0500201{
Geoff Langa15472a2015-08-11 11:48:03 -0400202 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500203 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
Corentin Walleze7557742017-06-01 13:09:57 -0400204 mEnabledDrawBuffers.set(0);
Jamie Madilld1405e52015-03-05 15:41:39 -0500205}
206
Jamie Madill48ef11b2016-04-27 15:21:52 -0400207FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -0500208{
Jamie Madilld1405e52015-03-05 15:41:39 -0500209}
210
Jamie Madill48ef11b2016-04-27 15:21:52 -0400211const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -0500212{
213 return mLabel;
214}
215
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400216const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
217{
218 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
219 {
220 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
221 }
222
223 switch (attachment)
224 {
225 case GL_COLOR:
226 case GL_BACK:
227 return getColorAttachment(0);
228 case GL_DEPTH:
229 case GL_DEPTH_ATTACHMENT:
230 return getDepthAttachment();
231 case GL_STENCIL:
232 case GL_STENCIL_ATTACHMENT:
233 return getStencilAttachment();
234 case GL_DEPTH_STENCIL:
235 case GL_DEPTH_STENCIL_ATTACHMENT:
236 return getDepthStencilAttachment();
237 default:
238 UNREACHABLE();
239 return nullptr;
240 }
241}
242
Jamie Madill48ef11b2016-04-27 15:21:52 -0400243const FramebufferAttachment *FramebufferState::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500244{
Antoine Labour2ec65dc2016-11-30 16:28:58 -0800245 if (mReadBufferState == GL_NONE)
246 {
247 return nullptr;
248 }
Jamie Madill231c7f52017-04-26 13:45:37 -0400249 ASSERT(mReadBufferState == GL_BACK ||
250 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
251 size_t readIndex = (mReadBufferState == GL_BACK
252 ? 0
253 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500254 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400255 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500256}
257
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500258const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
259{
260 auto *colorAttachment = getFirstColorAttachment();
261 if (colorAttachment)
262 {
263 return colorAttachment;
264 }
265 return getDepthOrStencilAttachment();
266}
267
Jamie Madill48ef11b2016-04-27 15:21:52 -0400268const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500269{
Jamie Madill2d06b732015-04-20 12:53:28 -0400270 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500271 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400272 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500273 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400274 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500275 }
276 }
277
278 return nullptr;
279}
280
Jamie Madill48ef11b2016-04-27 15:21:52 -0400281const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500282{
Jamie Madill2d06b732015-04-20 12:53:28 -0400283 if (mDepthAttachment.isAttached())
284 {
285 return &mDepthAttachment;
286 }
287 if (mStencilAttachment.isAttached())
288 {
289 return &mStencilAttachment;
290 }
291 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500292}
293
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500294const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
295{
296 if (mStencilAttachment.isAttached())
297 {
298 return &mStencilAttachment;
299 }
300 return getDepthStencilAttachment();
301}
302
Jamie Madill48ef11b2016-04-27 15:21:52 -0400303const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400304{
305 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400306 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
307 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400308}
309
Jamie Madill48ef11b2016-04-27 15:21:52 -0400310const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400311{
Jamie Madill2d06b732015-04-20 12:53:28 -0400312 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400313}
314
Jamie Madill48ef11b2016-04-27 15:21:52 -0400315const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400316{
Jamie Madill2d06b732015-04-20 12:53:28 -0400317 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400318}
319
Jamie Madill48ef11b2016-04-27 15:21:52 -0400320const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400321{
322 // A valid depth-stencil attachment has the same resource bound to both the
323 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400324 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500325 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400326 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400327 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400328 }
329
330 return nullptr;
331}
332
Jamie Madill48ef11b2016-04-27 15:21:52 -0400333bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500334{
335 Optional<Extents> attachmentSize;
336
Jamie Madill231c7f52017-04-26 13:45:37 -0400337 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500338 if (!attachment.isAttached())
339 {
340 return false;
341 }
342
343 if (!attachmentSize.valid())
344 {
345 attachmentSize = attachment.getSize();
346 return false;
347 }
348
349 return (attachment.getSize() != attachmentSize.value());
350 };
351
352 for (const auto &attachment : mColorAttachments)
353 {
354 if (hasMismatchedSize(attachment))
355 {
356 return false;
357 }
358 }
359
360 if (hasMismatchedSize(mDepthAttachment))
361 {
362 return false;
363 }
364
365 return !hasMismatchedSize(mStencilAttachment);
366}
367
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400368const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
369{
370 ASSERT(drawBufferIdx < mDrawBufferStates.size());
371 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
372 {
373 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
374 // must be COLOR_ATTACHMENTi or NONE"
375 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
376 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
377 return getAttachment(mDrawBufferStates[drawBufferIdx]);
378 }
379 else
380 {
381 return nullptr;
382 }
383}
384
385size_t FramebufferState::getDrawBufferCount() const
386{
387 return mDrawBufferStates.size();
388}
389
Geoff Langb21e20d2016-07-19 15:35:41 -0400390bool FramebufferState::colorAttachmentsAreUniqueImages() const
391{
392 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
393 firstAttachmentIdx++)
394 {
395 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
396 if (!firstAttachment.isAttached())
397 {
398 continue;
399 }
400
401 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
402 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
403 {
404 const gl::FramebufferAttachment &secondAttachment =
405 mColorAttachments[secondAttachmentIdx];
406 if (!secondAttachment.isAttached())
407 {
408 continue;
409 }
410
411 if (firstAttachment == secondAttachment)
412 {
413 return false;
414 }
415 }
416 }
417
418 return true;
419}
420
Jamie Madill9c335862017-07-18 11:51:38 -0400421bool FramebufferState::hasDepth() const
422{
423 return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0);
424}
425
426bool FramebufferState::hasStencil() const
427{
428 return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
429}
430
Jamie Madill7aea7e02016-05-10 10:39:45 -0400431Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400432 : mState(caps),
433 mImpl(factory->createFramebuffer(mState)),
434 mId(id),
435 mCachedStatus(),
436 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
437 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438{
Corentin Wallez37c39792015-08-20 14:19:46 -0400439 ASSERT(mId != 0);
440 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400441 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
442
Jamie Madill1e5499d2017-04-05 11:22:16 -0400443 for (uint32_t colorIndex = 0;
444 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400445 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400446 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400447 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400448}
449
Jamie Madill4928b7c2017-06-20 12:57:39 -0400450Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400451 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500452 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400453 mId(0),
454 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
455 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
456 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400457{
Geoff Langda88add2014-12-01 10:22:01 -0500458 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400459 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500460
Jamie Madill4928b7c2017-06-20 12:57:39 -0400461 const Context *proxyContext = display->getProxyContext();
462
463 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(),
464 surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500465
466 if (surface->getConfig()->depthSize > 0)
467 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400468 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH,
469 gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500470 }
471
472 if (surface->getConfig()->stencilSize > 0)
473 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400474 setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL,
475 gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500476 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000477}
478
Corentin Wallezccab69d2017-01-27 16:57:15 -0500479Framebuffer::Framebuffer(rx::GLImplFactory *factory)
480 : mState(),
481 mImpl(factory->createFramebuffer(mState)),
482 mId(0),
483 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
484 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
485 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
486{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400487 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500488}
489
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000490Framebuffer::~Framebuffer()
491{
Geoff Langda88add2014-12-01 10:22:01 -0500492 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000493}
494
Jamie Madill4928b7c2017-06-20 12:57:39 -0400495void Framebuffer::onDestroy(const Context *context)
Jamie Madill6c1f6712017-02-14 19:08:04 -0500496{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400497 for (auto &attachment : mState.mColorAttachments)
498 {
499 attachment.detach(context);
500 }
501 mState.mDepthAttachment.detach(context);
502 mState.mStencilAttachment.detach(context);
503 mState.mWebGLDepthAttachment.detach(context);
504 mState.mWebGLStencilAttachment.detach(context);
505 mState.mWebGLDepthStencilAttachment.detach(context);
506
Jamie Madillc564c072017-06-01 12:45:42 -0400507 mImpl->destroy(context);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500508}
509
510void Framebuffer::destroyDefault(const egl::Display *display)
511{
Jamie Madillc564c072017-06-01 12:45:42 -0400512 mImpl->destroyDefault(display);
Jamie Madill6c1f6712017-02-14 19:08:04 -0500513}
514
Geoff Lang70d0f492015-12-10 17:45:46 -0500515void Framebuffer::setLabel(const std::string &label)
516{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400517 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500518}
519
520const std::string &Framebuffer::getLabel() const
521{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400522 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500523}
524
Jamie Madilla02315b2017-02-23 14:14:47 -0500525void Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000526{
Jamie Madilla02315b2017-02-23 14:14:47 -0500527 detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000528}
529
Jamie Madilla02315b2017-02-23 14:14:47 -0500530void Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531{
Jamie Madilla02315b2017-02-23 14:14:47 -0500532 detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500533}
Jamie Madille261b442014-06-25 12:42:21 -0400534
Jamie Madilla02315b2017-02-23 14:14:47 -0500535void Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500536{
Jamie Madill362876b2016-06-16 14:46:59 -0400537 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500538 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400539 detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType,
540 resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541 }
542
Jamie Madilla02315b2017-02-23 14:14:47 -0500543 if (context->isWebGL1())
544 {
545 const std::array<FramebufferAttachment *, 3> attachments = {
546 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
547 &mState.mWebGLStencilAttachment}};
548 for (FramebufferAttachment *attachment : attachments)
549 {
550 if (attachment->isAttached() && attachment->type() == resourceType &&
551 attachment->id() == resourceId)
552 {
553 resetAttachment(context, attachment->getBinding());
554 }
555 }
556 }
557 else
558 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400559 detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId,
Jamie Madilla02315b2017-02-23 14:14:47 -0500560 DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill4928b7c2017-06-20 12:57:39 -0400561 detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId,
Jamie Madilla02315b2017-02-23 14:14:47 -0500562 DIRTY_BIT_STENCIL_ATTACHMENT);
563 }
Jamie Madill362876b2016-06-16 14:46:59 -0400564}
565
Jamie Madill4928b7c2017-06-20 12:57:39 -0400566void Framebuffer::detachMatchingAttachment(const Context *context,
567 FramebufferAttachment *attachment,
Jamie Madill362876b2016-06-16 14:46:59 -0400568 GLenum matchType,
569 GLuint matchId,
570 size_t dirtyBit)
571{
572 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
573 {
Jamie Madill4928b7c2017-06-20 12:57:39 -0400574 attachment->detach(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400575 mDirtyBits.set(dirtyBit);
576 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000577}
578
Corentin Wallez37c39792015-08-20 14:19:46 -0400579const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000580{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400581 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000582}
583
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400584const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400585{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400586 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400587}
588
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400589const FramebufferAttachment *Framebuffer::getStencilbuffer() const
590{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400591 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400592}
593
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400594const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
595{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400596 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400597}
598
599const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000600{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400601 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000602}
603
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500604const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
605{
606 return mState.getStencilOrDepthStencilAttachment();
607}
608
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400609const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000610{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400611 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000612}
613
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000614GLenum Framebuffer::getReadColorbufferType() const
615{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400616 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400617 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000618}
619
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400620const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000621{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400622 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000623}
624
Jamie Madill6dd06ea2017-07-19 13:47:55 -0400625const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const
626{
627 return mState.getFirstNonNullAttachment();
628}
629
Jamie Madill2d06b732015-04-20 12:53:28 -0400630const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000631{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400632 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400633}
634
Geoff Langa15472a2015-08-11 11:48:03 -0400635size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000636{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400637 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400638}
639
640GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
641{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400642 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
643 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000644}
645
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500646const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
647{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400648 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500649}
650
Geoff Lang164d54e2014-12-01 10:55:33 -0500651void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000652{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400653 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500654
655 ASSERT(count <= drawStates.size());
656 std::copy(buffers, buffers + count, drawStates.begin());
657 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500658 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500659
660 mState.mEnabledDrawBuffers.reset();
661 for (size_t index = 0; index < count; ++index)
662 {
663 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
664 {
665 mState.mEnabledDrawBuffers.set(index);
666 }
667 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500668}
669
Geoff Langa15472a2015-08-11 11:48:03 -0400670const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
671{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400672 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400673}
674
Geoff Lange0cff192017-05-30 13:04:56 -0400675GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
676{
677 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
678 if (attachment == nullptr)
679 {
680 return GL_NONE;
681 }
682
683 GLenum componentType = attachment->getFormat().info->componentType;
684 switch (componentType)
685 {
686 case GL_INT:
687 case GL_UNSIGNED_INT:
688 return componentType;
689
690 default:
691 return GL_FLOAT;
692 }
693}
694
Geoff Langa15472a2015-08-11 11:48:03 -0400695bool Framebuffer::hasEnabledDrawBuffer() const
696{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400697 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400698 {
699 if (getDrawBuffer(drawbufferIdx) != nullptr)
700 {
701 return true;
702 }
703 }
704
705 return false;
706}
707
Geoff Lang9dd95802014-12-01 11:12:59 -0500708GLenum Framebuffer::getReadBufferState() const
709{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400710 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500711}
712
713void Framebuffer::setReadBuffer(GLenum buffer)
714{
Jamie Madillb885e572015-02-03 16:16:04 -0500715 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
716 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400717 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
718 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500719 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000720}
721
Corentin Wallez37c39792015-08-20 14:19:46 -0400722size_t Framebuffer::getNumColorBuffers() const
723{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400724 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400725}
726
Jamie Madill0df8fe42015-11-24 16:10:24 -0500727bool Framebuffer::hasDepth() const
728{
Jamie Madill9c335862017-07-18 11:51:38 -0400729 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500730}
731
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000732bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000733{
Jamie Madill9c335862017-07-18 11:51:38 -0400734 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000735}
736
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000737bool Framebuffer::usingExtendedDrawBuffers() const
738{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400739 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000740 {
Geoff Langa15472a2015-08-11 11:48:03 -0400741 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000742 {
743 return true;
744 }
745 }
746
747 return false;
748}
749
Geoff Lang9aded172017-04-05 11:07:56 -0400750void Framebuffer::invalidateCompletenessCache()
751{
752 if (mId != 0)
753 {
754 mCachedStatus.reset();
755 }
756}
757
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400758GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000759{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500760 // The default framebuffer is always complete except when it is surfaceless in which
761 // case it is always unsupported. We return early because the default framebuffer may
762 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500763 if (mId == 0)
764 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500765 ASSERT(mCachedStatus.valid());
766 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
767 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
768 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500769 }
770
Jamie Madill362876b2016-06-16 14:46:59 -0400771 if (hasAnyDirtyBit() || !mCachedStatus.valid())
772 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400773 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400774 }
775
776 return mCachedStatus.value();
777}
778
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400779GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400780{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400781 const ContextState &state = context->getContextState();
782
Jamie Madill362876b2016-06-16 14:46:59 -0400783 ASSERT(mId != 0);
784
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400785 bool hasAttachments = false;
786 Optional<unsigned int> colorbufferSize;
787 Optional<int> samples;
JiangYizhou461d9a32017-01-04 16:37:26 +0800788 Optional<GLboolean> fixedSampleLocations;
789 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000790
Jamie Madill48ef11b2016-04-27 15:21:52 -0400791 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000792 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400793 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000794 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400795 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000796 {
797 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
798 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000799
Geoff Lang677bb6f2017-04-05 12:40:40 -0400800 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400801 if (format.depthBits > 0 || format.stencilBits > 0)
802 {
803 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
804 }
805
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400806 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
807 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000808 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400809 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000810 }
811
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400812 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
813 // in GLES 3.0, there is no such restriction
814 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000815 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400816 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000817 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400818 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000819 {
820 return GL_FRAMEBUFFER_UNSUPPORTED;
821 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000822 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400823 else
824 {
825 colorbufferSize = format.pixelBytes;
826 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000827 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400828
829 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
830 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000831 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000832 }
833
Jamie Madill48ef11b2016-04-27 15:21:52 -0400834 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400835 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000836 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400837 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000838 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000839 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000840 }
841
Geoff Lang677bb6f2017-04-05 12:40:40 -0400842 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400843 if (format.depthBits == 0)
844 {
845 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000846 }
847
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400848 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
849 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000850 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400851 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000852 }
Sami Väisänena797e062016-05-12 15:23:40 +0300853
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400854 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
855 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000856 }
857
Jamie Madill48ef11b2016-04-27 15:21:52 -0400858 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400859 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000860 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400861 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000862 {
863 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
864 }
865
Geoff Lang677bb6f2017-04-05 12:40:40 -0400866 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400867 if (format.stencilBits == 0)
868 {
869 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000870 }
871
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400872 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
873 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000874 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400875 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000876 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400877
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400878 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
879 hasAttachments = true;
880 }
881
882 // Starting from ES 3.0 stencil and depth, if present, should be the same image
883 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
884 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
885 {
886 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000887 }
888
Jamie Madilla02315b2017-02-23 14:14:47 -0500889 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
890 if (state.isWebGL1())
891 {
892 if (!mState.mWebGLDepthStencilConsistent)
893 {
894 return GL_FRAMEBUFFER_UNSUPPORTED;
895 }
896
897 if (mState.mWebGLDepthStencilAttachment.isAttached())
898 {
899 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
900 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
901 {
902 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
903 }
904 }
905 else if (mState.mStencilAttachment.isAttached() &&
906 mState.mStencilAttachment.getDepthSize() > 0)
907 {
908 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
909 }
910 else if (mState.mDepthAttachment.isAttached() &&
911 mState.mDepthAttachment.getStencilSize() > 0)
912 {
913 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
914 }
915 }
916
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400917 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
918 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
919 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +0800920 GLint defaultWidth = mState.getDefaultWidth();
921 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400922 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000923 {
924 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000925 }
926
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400927 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -0500928 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400929 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
930 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500931 {
932 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
933 }
934
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400935 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
936 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +0800937 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
938 {
939 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
940 }
941
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400942 syncState(context);
Jamie Madillcc86d642015-11-24 13:00:07 -0500943 if (!mImpl->checkStatus())
944 {
945 return GL_FRAMEBUFFER_UNSUPPORTED;
946 }
947
948 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000949}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000950
Jamie Madill4928b7c2017-06-20 12:57:39 -0400951Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -0700952{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400953 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -0700954}
955
Jamie Madill4928b7c2017-06-20 12:57:39 -0400956Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400957{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400958 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400959}
960
Jamie Madill4928b7c2017-06-20 12:57:39 -0400961Error Framebuffer::invalidateSub(const Context *context,
962 size_t count,
963 const GLenum *attachments,
964 const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400965{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400966 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400967}
968
Jamie Madillc564c072017-06-01 12:45:42 -0400969Error Framebuffer::clear(const gl::Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500970{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700971 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500972 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500973 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500974 }
975
Jamie Madill8415b5f2016-04-26 13:41:39 -0400976 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500977}
978
Jamie Madillc564c072017-06-01 12:45:42 -0400979Error Framebuffer::clearBufferfv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400980 GLenum buffer,
981 GLint drawbuffer,
982 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500983{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700984 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500985 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500986 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500987 }
988
Jamie Madill8415b5f2016-04-26 13:41:39 -0400989 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500990}
991
Jamie Madillc564c072017-06-01 12:45:42 -0400992Error Framebuffer::clearBufferuiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400993 GLenum buffer,
994 GLint drawbuffer,
995 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500996{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700997 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500998 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500999 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001000 }
1001
Jamie Madill8415b5f2016-04-26 13:41:39 -04001002 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -05001003}
1004
Jamie Madillc564c072017-06-01 12:45:42 -04001005Error Framebuffer::clearBufferiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001006 GLenum buffer,
1007 GLint drawbuffer,
1008 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001009{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001010 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001011 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001012 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001013 }
1014
Jamie Madill8415b5f2016-04-26 13:41:39 -04001015 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -05001016}
1017
Jamie Madillc564c072017-06-01 12:45:42 -04001018Error Framebuffer::clearBufferfi(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001019 GLenum buffer,
1020 GLint drawbuffer,
1021 GLfloat depth,
1022 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001023{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001024 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001025 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001026 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001027 }
1028
Jamie Madill8415b5f2016-04-26 13:41:39 -04001029 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -05001030}
1031
Jamie Madill4928b7c2017-06-20 12:57:39 -04001032GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001033{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001034 return mImpl->getImplementationColorReadFormat(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001035}
1036
Jamie Madill4928b7c2017-06-20 12:57:39 -04001037GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001038{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001039 return mImpl->getImplementationColorReadType(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001040}
1041
Jamie Madillc564c072017-06-01 12:45:42 -04001042Error Framebuffer::readPixels(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001043 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001044 GLenum format,
1045 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04001046 void *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -05001047{
Jamie Madill362876b2016-06-16 14:46:59 -04001048 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001049
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001050 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -04001051 if (unpackBuffer)
1052 {
1053 unpackBuffer->onPixelUnpack();
1054 }
1055
Jamie Madill362876b2016-06-16 14:46:59 -04001056 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001057}
1058
Jamie Madillc564c072017-06-01 12:45:42 -04001059Error Framebuffer::blit(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001060 const Rectangle &sourceArea,
1061 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001062 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001063 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001064{
He Yunchao6be602d2016-12-22 14:33:07 +08001065 GLbitfield blitMask = mask;
1066
1067 // Note that blitting is called against draw framebuffer.
1068 // See the code in gl::Context::blitFramebuffer.
1069 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1070 {
1071 blitMask &= ~GL_COLOR_BUFFER_BIT;
1072 }
1073
1074 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1075 {
1076 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1077 }
1078
1079 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1080 {
1081 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1082 }
1083
1084 if (!blitMask)
1085 {
1086 return NoError();
1087 }
1088
1089 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001090}
1091
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001092int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001093{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001094 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001095 {
Jamie Madill9c335862017-07-18 11:51:38 -04001096 return getCachedSamples(context);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001097 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001098
1099 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001100}
1101
Jamie Madill9c335862017-07-18 11:51:38 -04001102int Framebuffer::getCachedSamples(const Context *context)
1103{
1104 // For a complete framebuffer, all attachments must have the same sample count.
1105 // In this case return the first nonzero sample size.
1106 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1107 if (firstNonNullAttachment)
1108 {
1109 ASSERT(firstNonNullAttachment->isAttached());
1110 return firstNonNullAttachment->getSamples();
1111 }
1112
1113 // No attachments found.
1114 return 0;
1115}
1116
Corentin Wallezccab69d2017-01-27 16:57:15 -05001117Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1118{
1119 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001120 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001121}
1122
Jamie Madille261b442014-06-25 12:42:21 -04001123bool Framebuffer::hasValidDepthStencil() const
1124{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001125 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001126}
1127
Jamie Madilla02315b2017-02-23 14:14:47 -05001128void Framebuffer::setAttachment(const Context *context,
1129 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001130 GLenum binding,
1131 const ImageIndex &textureIndex,
1132 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001133{
Jamie Madilla02315b2017-02-23 14:14:47 -05001134 // Context may be null in unit tests.
1135 if (!context || !context->isWebGL1())
1136 {
Jamie Madill4928b7c2017-06-20 12:57:39 -04001137 setAttachmentImpl(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001138 return;
1139 }
1140
1141 switch (binding)
1142 {
1143 case GL_DEPTH_STENCIL:
1144 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001145 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
1146 resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001147 break;
1148 case GL_DEPTH:
1149 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001150 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001151 break;
1152 case GL_STENCIL:
1153 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001154 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001155 break;
1156 default:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001157 setAttachmentImpl(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001158 return;
1159 }
1160
Jamie Madill4928b7c2017-06-20 12:57:39 -04001161 commitWebGL1DepthStencilIfConsistent(context);
Jamie Madilla02315b2017-02-23 14:14:47 -05001162}
1163
Jamie Madill4928b7c2017-06-20 12:57:39 -04001164void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context)
Jamie Madilla02315b2017-02-23 14:14:47 -05001165{
1166 int count = 0;
1167
1168 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1169 &mState.mWebGLDepthAttachment,
1170 &mState.mWebGLStencilAttachment}};
1171 for (FramebufferAttachment *attachment : attachments)
1172 {
1173 if (attachment->isAttached())
1174 {
1175 count++;
1176 }
1177 }
1178
1179 mState.mWebGLDepthStencilConsistent = (count <= 1);
1180 if (!mState.mWebGLDepthStencilConsistent)
1181 {
1182 // Inconsistent.
1183 return;
1184 }
1185
Geoff Lange466c552017-03-17 15:24:12 -04001186 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1187 if (attachment.type() == GL_TEXTURE)
1188 {
1189 return attachment.getTextureImageIndex();
1190 }
1191 else
1192 {
1193 return ImageIndex::MakeInvalid();
1194 }
1195 };
1196
Jamie Madilla02315b2017-02-23 14:14:47 -05001197 if (mState.mWebGLDepthAttachment.isAttached())
1198 {
1199 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001200 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001201 getImageIndexIfTextureAttachment(depth), depth.getResource());
Jamie Madill4928b7c2017-06-20 12:57:39 -04001202 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1203 nullptr);
Jamie Madilla02315b2017-02-23 14:14:47 -05001204 }
1205 else if (mState.mWebGLStencilAttachment.isAttached())
1206 {
1207 const auto &stencil = mState.mWebGLStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001208 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(),
1209 nullptr);
1210 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001211 getImageIndexIfTextureAttachment(stencil), stencil.getResource());
Jamie Madilla02315b2017-02-23 14:14:47 -05001212 }
1213 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1214 {
1215 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001216 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001217 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001218 depthStencil.getResource());
Jamie Madill4928b7c2017-06-20 12:57:39 -04001219 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001220 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001221 depthStencil.getResource());
1222 }
1223 else
1224 {
Jamie Madill4928b7c2017-06-20 12:57:39 -04001225 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(),
1226 nullptr);
1227 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1228 nullptr);
Jamie Madilla02315b2017-02-23 14:14:47 -05001229 }
1230}
1231
Jamie Madill4928b7c2017-06-20 12:57:39 -04001232void Framebuffer::setAttachmentImpl(const Context *context,
1233 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001234 GLenum binding,
1235 const ImageIndex &textureIndex,
1236 FramebufferAttachmentObject *resource)
1237{
Jamie Madilla02315b2017-02-23 14:14:47 -05001238 switch (binding)
1239 {
Jamie Madillb8126692017-04-05 11:22:17 -04001240 case GL_DEPTH_STENCIL:
1241 case GL_DEPTH_STENCIL_ATTACHMENT:
1242 {
1243 // ensure this is a legitimate depth+stencil format
1244 FramebufferAttachmentObject *attachmentObj = resource;
1245 if (resource)
1246 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001247 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001248 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1249 {
1250 // Attaching nullptr detaches the current attachment.
1251 attachmentObj = nullptr;
1252 }
1253 }
1254
Jamie Madill4928b7c2017-06-20 12:57:39 -04001255 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001256 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
1257 attachmentObj);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001258 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001259 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1260 attachmentObj);
1261 return;
1262 }
1263
Jamie Madilla02315b2017-02-23 14:14:47 -05001264 case GL_DEPTH:
1265 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001266 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001267 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource);
Jamie Madill2d06b732015-04-20 12:53:28 -04001268 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001269
Jamie Madilla02315b2017-02-23 14:14:47 -05001270 case GL_STENCIL:
1271 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001272 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001273 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1274 resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001275 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001276
Jamie Madilla02315b2017-02-23 14:14:47 -05001277 case GL_BACK:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001278 mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001279 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1280 // No need for a resource binding for the default FBO, it's always complete.
1281 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001282
Jamie Madilla02315b2017-02-23 14:14:47 -05001283 default:
1284 {
1285 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1286 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001287 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001288 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001289 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
1290 textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001291
Corentin Walleze7557742017-06-01 13:09:57 -04001292 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1293 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001294 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1295 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001296 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001297 break;
Geoff Langab75a052014-10-15 12:56:37 -04001298 }
1299}
1300
Jamie Madill4928b7c2017-06-20 12:57:39 -04001301void Framebuffer::updateAttachment(const Context *context,
1302 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001303 size_t dirtyBit,
1304 OnAttachmentDirtyBinding *onDirtyBinding,
1305 GLenum type,
1306 GLenum binding,
1307 const ImageIndex &textureIndex,
1308 FramebufferAttachmentObject *resource)
1309{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001310 attachment->attach(context, type, binding, textureIndex, resource);
Jamie Madillb8126692017-04-05 11:22:17 -04001311 mDirtyBits.set(dirtyBit);
1312 BindResourceChannel(onDirtyBinding, resource);
1313}
1314
Jamie Madilla02315b2017-02-23 14:14:47 -05001315void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001316{
Jamie Madilla02315b2017-02-23 14:14:47 -05001317 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001318}
1319
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001320void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001321{
1322 if (mDirtyBits.any())
1323 {
Jamie Madillc564c072017-06-01 12:45:42 -04001324 mImpl->syncState(context, mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001325 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001326 if (mId != 0)
1327 {
1328 mCachedStatus.reset();
1329 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001330 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001332
Jamie Madill1e5499d2017-04-05 11:22:16 -04001333void Framebuffer::signal(uint32_t token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001334{
Jamie Madill362876b2016-06-16 14:46:59 -04001335 // TOOD(jmadill): Make this only update individual attachments to do less work.
1336 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001337}
1338
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001339bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001340{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001341 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1342}
1343
1344bool Framebuffer::cachedComplete() const
1345{
1346 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001347}
1348
Jamie Madilla4595b82017-01-11 17:36:34 -05001349bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1350{
1351 const Program *program = state.getProgram();
1352
1353 // TODO(jmadill): Default framebuffer feedback loops.
1354 if (mId == 0)
1355 {
1356 return false;
1357 }
1358
1359 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001360 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001361 {
1362 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1363 if (attachment && attachment->type() == GL_TEXTURE)
1364 {
1365 // Validate the feedback loop.
1366 if (program->samplesFromTexture(state, attachment->id()))
1367 {
1368 return true;
1369 }
1370 }
1371 }
1372
Jamie Madill1d37bc52017-02-02 19:59:58 -05001373 // Validate depth-stencil feedback loop.
1374 const auto &dsState = state.getDepthStencilState();
1375
1376 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1377 const FramebufferAttachment *depth = getDepthbuffer();
1378 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1379 {
1380 if (program->samplesFromTexture(state, depth->id()))
1381 {
1382 return true;
1383 }
1384 }
1385
1386 // Note: we assume the front and back masks are the same for WebGL.
1387 const FramebufferAttachment *stencil = getStencilbuffer();
1388 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1389 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1390 dsState.stencilWritemask != 0)
1391 {
1392 // Skip the feedback loop check if depth/stencil point to the same resource.
1393 if (!depth || *stencil != *depth)
1394 {
1395 if (program->samplesFromTexture(state, stencil->id()))
1396 {
1397 return true;
1398 }
1399 }
1400 }
1401
Jamie Madilla4595b82017-01-11 17:36:34 -05001402 return false;
1403}
1404
Jamie Madillfd3dd432017-02-02 19:59:59 -05001405bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1406 GLint copyTextureLevel,
1407 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001408{
1409 if (mId == 0)
1410 {
1411 // It seems impossible to form a texture copying feedback loop with the default FBO.
1412 return false;
1413 }
1414
1415 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1416 ASSERT(readAttachment);
1417
1418 if (readAttachment->isTextureWithId(copyTextureID))
1419 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001420 const auto &imageIndex = readAttachment->getTextureImageIndex();
1421 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001422 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001423 // Check 3D/Array texture layers.
1424 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1425 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1426 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001427 }
1428 }
1429 return false;
1430}
1431
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001432GLint Framebuffer::getDefaultWidth() const
1433{
1434 return mState.getDefaultWidth();
1435}
1436
1437GLint Framebuffer::getDefaultHeight() const
1438{
1439 return mState.getDefaultHeight();
1440}
1441
1442GLint Framebuffer::getDefaultSamples() const
1443{
1444 return mState.getDefaultSamples();
1445}
1446
1447GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1448{
1449 return mState.getDefaultFixedSampleLocations();
1450}
1451
1452void Framebuffer::setDefaultWidth(GLint defaultWidth)
1453{
1454 mState.mDefaultWidth = defaultWidth;
1455 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1456}
1457
1458void Framebuffer::setDefaultHeight(GLint defaultHeight)
1459{
1460 mState.mDefaultHeight = defaultHeight;
1461 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1462}
1463
1464void Framebuffer::setDefaultSamples(GLint defaultSamples)
1465{
1466 mState.mDefaultSamples = defaultSamples;
1467 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1468}
1469
1470void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1471{
1472 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1473 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1474}
1475
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001476// TODO(jmadill): Remove this kludge.
1477GLenum Framebuffer::checkStatus(const ValidationContext *context)
1478{
1479 return checkStatus(static_cast<const Context *>(context));
1480}
1481
1482int Framebuffer::getSamples(const ValidationContext *context)
1483{
1484 return getSamples(static_cast<const Context *>(context));
1485}
1486
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001487} // namespace gl