blob: 10525b21b2833e474b5ce4f824a1148528c8cb6c [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 Madill2d06b732015-04-20 12:53:28 -0400625const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000626{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400627 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400628}
629
Geoff Langa15472a2015-08-11 11:48:03 -0400630size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000631{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400632 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400633}
634
635GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
636{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400637 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
638 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000639}
640
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500641const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
642{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400643 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500644}
645
Geoff Lang164d54e2014-12-01 10:55:33 -0500646void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000647{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400648 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500649
650 ASSERT(count <= drawStates.size());
651 std::copy(buffers, buffers + count, drawStates.begin());
652 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500653 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500654
655 mState.mEnabledDrawBuffers.reset();
656 for (size_t index = 0; index < count; ++index)
657 {
658 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
659 {
660 mState.mEnabledDrawBuffers.set(index);
661 }
662 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500663}
664
Geoff Langa15472a2015-08-11 11:48:03 -0400665const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
666{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400667 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400668}
669
Geoff Lange0cff192017-05-30 13:04:56 -0400670GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
671{
672 const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
673 if (attachment == nullptr)
674 {
675 return GL_NONE;
676 }
677
678 GLenum componentType = attachment->getFormat().info->componentType;
679 switch (componentType)
680 {
681 case GL_INT:
682 case GL_UNSIGNED_INT:
683 return componentType;
684
685 default:
686 return GL_FLOAT;
687 }
688}
689
Geoff Langa15472a2015-08-11 11:48:03 -0400690bool Framebuffer::hasEnabledDrawBuffer() const
691{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400692 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400693 {
694 if (getDrawBuffer(drawbufferIdx) != nullptr)
695 {
696 return true;
697 }
698 }
699
700 return false;
701}
702
Geoff Lang9dd95802014-12-01 11:12:59 -0500703GLenum Framebuffer::getReadBufferState() const
704{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400705 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500706}
707
708void Framebuffer::setReadBuffer(GLenum buffer)
709{
Jamie Madillb885e572015-02-03 16:16:04 -0500710 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
711 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400712 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
713 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500714 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000715}
716
Corentin Wallez37c39792015-08-20 14:19:46 -0400717size_t Framebuffer::getNumColorBuffers() const
718{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400719 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400720}
721
Jamie Madill0df8fe42015-11-24 16:10:24 -0500722bool Framebuffer::hasDepth() const
723{
Jamie Madill9c335862017-07-18 11:51:38 -0400724 return mState.hasDepth();
Jamie Madill0df8fe42015-11-24 16:10:24 -0500725}
726
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000727bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000728{
Jamie Madill9c335862017-07-18 11:51:38 -0400729 return mState.hasStencil();
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000730}
731
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000732bool Framebuffer::usingExtendedDrawBuffers() const
733{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400734 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000735 {
Geoff Langa15472a2015-08-11 11:48:03 -0400736 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000737 {
738 return true;
739 }
740 }
741
742 return false;
743}
744
Geoff Lang9aded172017-04-05 11:07:56 -0400745void Framebuffer::invalidateCompletenessCache()
746{
747 if (mId != 0)
748 {
749 mCachedStatus.reset();
750 }
751}
752
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400753GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000754{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500755 // The default framebuffer is always complete except when it is surfaceless in which
756 // case it is always unsupported. We return early because the default framebuffer may
757 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500758 if (mId == 0)
759 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500760 ASSERT(mCachedStatus.valid());
761 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
762 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
763 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500764 }
765
Jamie Madill362876b2016-06-16 14:46:59 -0400766 if (hasAnyDirtyBit() || !mCachedStatus.valid())
767 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400768 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400769 }
770
771 return mCachedStatus.value();
772}
773
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400774GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400775{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400776 const ContextState &state = context->getContextState();
777
Jamie Madill362876b2016-06-16 14:46:59 -0400778 ASSERT(mId != 0);
779
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400780 bool hasAttachments = false;
781 Optional<unsigned int> colorbufferSize;
782 Optional<int> samples;
JiangYizhou461d9a32017-01-04 16:37:26 +0800783 Optional<GLboolean> fixedSampleLocations;
784 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785
Jamie Madill48ef11b2016-04-27 15:21:52 -0400786 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000787 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400788 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000789 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400790 if (!CheckAttachmentCompleteness(context, colorAttachment))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000791 {
792 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
793 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000794
Geoff Lang677bb6f2017-04-05 12:40:40 -0400795 const InternalFormat &format = *colorAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400796 if (format.depthBits > 0 || format.stencilBits > 0)
797 {
798 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
799 }
800
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400801 if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
802 &fixedSampleLocations))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000803 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400804 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000805 }
806
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400807 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
808 // in GLES 3.0, there is no such restriction
809 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000810 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400811 if (colorbufferSize.valid())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000812 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400813 if (format.pixelBytes != colorbufferSize.value())
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000814 {
815 return GL_FRAMEBUFFER_UNSUPPORTED;
816 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000817 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400818 else
819 {
820 colorbufferSize = format.pixelBytes;
821 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000822 }
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400823
824 hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
825 hasAttachments = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000826 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000827 }
828
Jamie Madill48ef11b2016-04-27 15:21:52 -0400829 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400830 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000831 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400832 if (!CheckAttachmentCompleteness(context, depthAttachment))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000833 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000834 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000835 }
836
Geoff Lang677bb6f2017-04-05 12:40:40 -0400837 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400838 if (format.depthBits == 0)
839 {
840 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000841 }
842
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400843 if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
844 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000845 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400846 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000847 }
Sami Väisänena797e062016-05-12 15:23:40 +0300848
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400849 hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
850 hasAttachments = true;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000851 }
852
Jamie Madill48ef11b2016-04-27 15:21:52 -0400853 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400854 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000855 {
Geoff Lang9f10b772017-05-16 15:51:03 -0400856 if (!CheckAttachmentCompleteness(context, stencilAttachment))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000857 {
858 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
859 }
860
Geoff Lang677bb6f2017-04-05 12:40:40 -0400861 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Lang677bb6f2017-04-05 12:40:40 -0400862 if (format.stencilBits == 0)
863 {
864 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000865 }
866
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400867 if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
868 &fixedSampleLocations))
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000869 {
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400870 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000871 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400872
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400873 hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
874 hasAttachments = true;
875 }
876
877 // Starting from ES 3.0 stencil and depth, if present, should be the same image
878 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
879 stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
880 {
881 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000882 }
883
Jamie Madilla02315b2017-02-23 14:14:47 -0500884 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
885 if (state.isWebGL1())
886 {
887 if (!mState.mWebGLDepthStencilConsistent)
888 {
889 return GL_FRAMEBUFFER_UNSUPPORTED;
890 }
891
892 if (mState.mWebGLDepthStencilAttachment.isAttached())
893 {
894 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
895 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
896 {
897 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
898 }
899 }
900 else if (mState.mStencilAttachment.isAttached() &&
901 mState.mStencilAttachment.getDepthSize() > 0)
902 {
903 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
904 }
905 else if (mState.mDepthAttachment.isAttached() &&
906 mState.mDepthAttachment.getStencilSize() > 0)
907 {
908 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
909 }
910 }
911
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400912 // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
913 // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
914 // is zero, the framebuffer is considered incomplete.
JiangYizhou461d9a32017-01-04 16:37:26 +0800915 GLint defaultWidth = mState.getDefaultWidth();
916 GLint defaultHeight = mState.getDefaultHeight();
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400917 if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000918 {
919 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000920 }
921
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400922 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -0500923 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400924 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
925 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500926 {
927 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
928 }
929
Geoff Langa1b9d5a2017-05-18 11:22:27 -0400930 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
931 // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
JiangYizhou461d9a32017-01-04 16:37:26 +0800932 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
933 {
934 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
935 }
936
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400937 syncState(context);
Jamie Madillcc86d642015-11-24 13:00:07 -0500938 if (!mImpl->checkStatus())
939 {
940 return GL_FRAMEBUFFER_UNSUPPORTED;
941 }
942
943 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000944}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000945
Jamie Madill4928b7c2017-06-20 12:57:39 -0400946Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments)
Austin Kinross08332632015-05-05 13:35:47 -0700947{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400948 return mImpl->discard(context, count, attachments);
Austin Kinross08332632015-05-05 13:35:47 -0700949}
950
Jamie Madill4928b7c2017-06-20 12:57:39 -0400951Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400952{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400953 return mImpl->invalidate(context, count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400954}
955
Jamie Madill4928b7c2017-06-20 12:57:39 -0400956Error Framebuffer::invalidateSub(const Context *context,
957 size_t count,
958 const GLenum *attachments,
959 const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400960{
Jamie Madill4928b7c2017-06-20 12:57:39 -0400961 return mImpl->invalidateSub(context, count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400962}
963
Jamie Madillc564c072017-06-01 12:45:42 -0400964Error Framebuffer::clear(const gl::Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500965{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700966 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500967 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500968 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500969 }
970
Jamie Madill8415b5f2016-04-26 13:41:39 -0400971 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500972}
973
Jamie Madillc564c072017-06-01 12:45:42 -0400974Error Framebuffer::clearBufferfv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400975 GLenum buffer,
976 GLint drawbuffer,
977 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500978{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700979 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500980 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500981 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500982 }
983
Jamie Madill8415b5f2016-04-26 13:41:39 -0400984 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500985}
986
Jamie Madillc564c072017-06-01 12:45:42 -0400987Error Framebuffer::clearBufferuiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400988 GLenum buffer,
989 GLint drawbuffer,
990 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500991{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700992 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500993 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500994 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500995 }
996
Jamie Madill8415b5f2016-04-26 13:41:39 -0400997 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500998}
999
Jamie Madillc564c072017-06-01 12:45:42 -04001000Error Framebuffer::clearBufferiv(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001001 GLenum buffer,
1002 GLint drawbuffer,
1003 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -05001004{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001005 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001006 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001007 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001008 }
1009
Jamie Madill8415b5f2016-04-26 13:41:39 -04001010 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -05001011}
1012
Jamie Madillc564c072017-06-01 12:45:42 -04001013Error Framebuffer::clearBufferfi(const gl::Context *context,
Jamie Madill1b94d432015-08-07 13:23:23 -04001014 GLenum buffer,
1015 GLint drawbuffer,
1016 GLfloat depth,
1017 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -05001018{
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001019 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -05001020 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001021 return NoError();
Jamie Madill984ef412015-11-24 16:10:21 -05001022 }
1023
Jamie Madill8415b5f2016-04-26 13:41:39 -04001024 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -05001025}
1026
Jamie Madill4928b7c2017-06-20 12:57:39 -04001027GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001028{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001029 return mImpl->getImplementationColorReadFormat(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001030}
1031
Jamie Madill4928b7c2017-06-20 12:57:39 -04001032GLenum Framebuffer::getImplementationColorReadType(const Context *context) const
Geoff Langbce529e2014-12-01 12:48:41 -05001033{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001034 return mImpl->getImplementationColorReadType(context);
Geoff Langbce529e2014-12-01 12:48:41 -05001035}
1036
Jamie Madillc564c072017-06-01 12:45:42 -04001037Error Framebuffer::readPixels(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001038 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -04001039 GLenum format,
1040 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04001041 void *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -05001042{
Jamie Madill362876b2016-06-16 14:46:59 -04001043 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -04001044
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001045 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -04001046 if (unpackBuffer)
1047 {
1048 unpackBuffer->onPixelUnpack();
1049 }
1050
Jamie Madill362876b2016-06-16 14:46:59 -04001051 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -05001052}
1053
Jamie Madillc564c072017-06-01 12:45:42 -04001054Error Framebuffer::blit(const gl::Context *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001055 const Rectangle &sourceArea,
1056 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -04001057 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -04001058 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -05001059{
He Yunchao6be602d2016-12-22 14:33:07 +08001060 GLbitfield blitMask = mask;
1061
1062 // Note that blitting is called against draw framebuffer.
1063 // See the code in gl::Context::blitFramebuffer.
1064 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
1065 {
1066 blitMask &= ~GL_COLOR_BUFFER_BIT;
1067 }
1068
1069 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
1070 {
1071 blitMask &= ~GL_STENCIL_BUFFER_BIT;
1072 }
1073
1074 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1075 {
1076 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1077 }
1078
1079 if (!blitMask)
1080 {
1081 return NoError();
1082 }
1083
1084 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001085}
1086
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001087int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001088{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001089 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001090 {
Jamie Madill9c335862017-07-18 11:51:38 -04001091 return getCachedSamples(context);
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001092 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001093
1094 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001095}
1096
Jamie Madill9c335862017-07-18 11:51:38 -04001097int Framebuffer::getCachedSamples(const Context *context)
1098{
1099 // For a complete framebuffer, all attachments must have the same sample count.
1100 // In this case return the first nonzero sample size.
1101 const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment();
1102 if (firstNonNullAttachment)
1103 {
1104 ASSERT(firstNonNullAttachment->isAttached());
1105 return firstNonNullAttachment->getSamples();
1106 }
1107
1108 // No attachments found.
1109 return 0;
1110}
1111
Corentin Wallezccab69d2017-01-27 16:57:15 -05001112Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1113{
1114 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001115 return NoError();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001116}
1117
Jamie Madille261b442014-06-25 12:42:21 -04001118bool Framebuffer::hasValidDepthStencil() const
1119{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001120 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001121}
1122
Jamie Madilla02315b2017-02-23 14:14:47 -05001123void Framebuffer::setAttachment(const Context *context,
1124 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001125 GLenum binding,
1126 const ImageIndex &textureIndex,
1127 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001128{
Jamie Madilla02315b2017-02-23 14:14:47 -05001129 // Context may be null in unit tests.
1130 if (!context || !context->isWebGL1())
1131 {
Jamie Madill4928b7c2017-06-20 12:57:39 -04001132 setAttachmentImpl(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001133 return;
1134 }
1135
1136 switch (binding)
1137 {
1138 case GL_DEPTH_STENCIL:
1139 case GL_DEPTH_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001140 mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
1141 resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001142 break;
1143 case GL_DEPTH:
1144 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001145 mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001146 break;
1147 case GL_STENCIL:
1148 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001149 mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001150 break;
1151 default:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001152 setAttachmentImpl(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001153 return;
1154 }
1155
Jamie Madill4928b7c2017-06-20 12:57:39 -04001156 commitWebGL1DepthStencilIfConsistent(context);
Jamie Madilla02315b2017-02-23 14:14:47 -05001157}
1158
Jamie Madill4928b7c2017-06-20 12:57:39 -04001159void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context)
Jamie Madilla02315b2017-02-23 14:14:47 -05001160{
1161 int count = 0;
1162
1163 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1164 &mState.mWebGLDepthAttachment,
1165 &mState.mWebGLStencilAttachment}};
1166 for (FramebufferAttachment *attachment : attachments)
1167 {
1168 if (attachment->isAttached())
1169 {
1170 count++;
1171 }
1172 }
1173
1174 mState.mWebGLDepthStencilConsistent = (count <= 1);
1175 if (!mState.mWebGLDepthStencilConsistent)
1176 {
1177 // Inconsistent.
1178 return;
1179 }
1180
Geoff Lange466c552017-03-17 15:24:12 -04001181 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1182 if (attachment.type() == GL_TEXTURE)
1183 {
1184 return attachment.getTextureImageIndex();
1185 }
1186 else
1187 {
1188 return ImageIndex::MakeInvalid();
1189 }
1190 };
1191
Jamie Madilla02315b2017-02-23 14:14:47 -05001192 if (mState.mWebGLDepthAttachment.isAttached())
1193 {
1194 const auto &depth = mState.mWebGLDepthAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001195 setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001196 getImageIndexIfTextureAttachment(depth), depth.getResource());
Jamie Madill4928b7c2017-06-20 12:57:39 -04001197 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1198 nullptr);
Jamie Madilla02315b2017-02-23 14:14:47 -05001199 }
1200 else if (mState.mWebGLStencilAttachment.isAttached())
1201 {
1202 const auto &stencil = mState.mWebGLStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001203 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(),
1204 nullptr);
1205 setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001206 getImageIndexIfTextureAttachment(stencil), stencil.getResource());
Jamie Madilla02315b2017-02-23 14:14:47 -05001207 }
1208 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1209 {
1210 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001211 setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001212 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001213 depthStencil.getResource());
Jamie Madill4928b7c2017-06-20 12:57:39 -04001214 setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
Geoff Lange466c552017-03-17 15:24:12 -04001215 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001216 depthStencil.getResource());
1217 }
1218 else
1219 {
Jamie Madill4928b7c2017-06-20 12:57:39 -04001220 setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(),
1221 nullptr);
1222 setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1223 nullptr);
Jamie Madilla02315b2017-02-23 14:14:47 -05001224 }
1225}
1226
Jamie Madill4928b7c2017-06-20 12:57:39 -04001227void Framebuffer::setAttachmentImpl(const Context *context,
1228 GLenum type,
Jamie Madilla02315b2017-02-23 14:14:47 -05001229 GLenum binding,
1230 const ImageIndex &textureIndex,
1231 FramebufferAttachmentObject *resource)
1232{
Jamie Madilla02315b2017-02-23 14:14:47 -05001233 switch (binding)
1234 {
Jamie Madillb8126692017-04-05 11:22:17 -04001235 case GL_DEPTH_STENCIL:
1236 case GL_DEPTH_STENCIL_ATTACHMENT:
1237 {
1238 // ensure this is a legitimate depth+stencil format
1239 FramebufferAttachmentObject *attachmentObj = resource;
1240 if (resource)
1241 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001242 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001243 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1244 {
1245 // Attaching nullptr detaches the current attachment.
1246 attachmentObj = nullptr;
1247 }
1248 }
1249
Jamie Madill4928b7c2017-06-20 12:57:39 -04001250 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001251 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
1252 attachmentObj);
Jamie Madill4928b7c2017-06-20 12:57:39 -04001253 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001254 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1255 attachmentObj);
1256 return;
1257 }
1258
Jamie Madilla02315b2017-02-23 14:14:47 -05001259 case GL_DEPTH:
1260 case GL_DEPTH_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001261 updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001262 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource);
Jamie Madill2d06b732015-04-20 12:53:28 -04001263 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001264
Jamie Madilla02315b2017-02-23 14:14:47 -05001265 case GL_STENCIL:
1266 case GL_STENCIL_ATTACHMENT:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001267 updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
Jamie Madillb8126692017-04-05 11:22:17 -04001268 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1269 resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001270 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001271
Jamie Madilla02315b2017-02-23 14:14:47 -05001272 case GL_BACK:
Jamie Madill4928b7c2017-06-20 12:57:39 -04001273 mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001274 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1275 // No need for a resource binding for the default FBO, it's always complete.
1276 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001277
Jamie Madilla02315b2017-02-23 14:14:47 -05001278 default:
1279 {
1280 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1281 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001282 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
Jamie Madill4928b7c2017-06-20 12:57:39 -04001283 updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
Jamie Madillb8126692017-04-05 11:22:17 -04001284 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
1285 textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001286
Corentin Walleze7557742017-06-01 13:09:57 -04001287 // TODO(jmadill): ASSERT instead of checking the attachment exists in
1288 // formsRenderingFeedbackLoopWith
Jamie Madilla02315b2017-02-23 14:14:47 -05001289 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1290 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001291 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001292 break;
Geoff Langab75a052014-10-15 12:56:37 -04001293 }
1294}
1295
Jamie Madill4928b7c2017-06-20 12:57:39 -04001296void Framebuffer::updateAttachment(const Context *context,
1297 FramebufferAttachment *attachment,
Jamie Madillb8126692017-04-05 11:22:17 -04001298 size_t dirtyBit,
1299 OnAttachmentDirtyBinding *onDirtyBinding,
1300 GLenum type,
1301 GLenum binding,
1302 const ImageIndex &textureIndex,
1303 FramebufferAttachmentObject *resource)
1304{
Jamie Madill4928b7c2017-06-20 12:57:39 -04001305 attachment->attach(context, type, binding, textureIndex, resource);
Jamie Madillb8126692017-04-05 11:22:17 -04001306 mDirtyBits.set(dirtyBit);
1307 BindResourceChannel(onDirtyBinding, resource);
1308}
1309
Jamie Madilla02315b2017-02-23 14:14:47 -05001310void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001311{
Jamie Madilla02315b2017-02-23 14:14:47 -05001312 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001313}
1314
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001315void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001316{
1317 if (mDirtyBits.any())
1318 {
Jamie Madillc564c072017-06-01 12:45:42 -04001319 mImpl->syncState(context, mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001320 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001321 if (mId != 0)
1322 {
1323 mCachedStatus.reset();
1324 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001325 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001326}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001327
Jamie Madill1e5499d2017-04-05 11:22:16 -04001328void Framebuffer::signal(uint32_t token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001329{
Jamie Madill362876b2016-06-16 14:46:59 -04001330 // TOOD(jmadill): Make this only update individual attachments to do less work.
1331 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001332}
1333
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001334bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001335{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001336 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1337}
1338
1339bool Framebuffer::cachedComplete() const
1340{
1341 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001342}
1343
Jamie Madilla4595b82017-01-11 17:36:34 -05001344bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1345{
1346 const Program *program = state.getProgram();
1347
1348 // TODO(jmadill): Default framebuffer feedback loops.
1349 if (mId == 0)
1350 {
1351 return false;
1352 }
1353
1354 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001355 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001356 {
1357 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1358 if (attachment && attachment->type() == GL_TEXTURE)
1359 {
1360 // Validate the feedback loop.
1361 if (program->samplesFromTexture(state, attachment->id()))
1362 {
1363 return true;
1364 }
1365 }
1366 }
1367
Jamie Madill1d37bc52017-02-02 19:59:58 -05001368 // Validate depth-stencil feedback loop.
1369 const auto &dsState = state.getDepthStencilState();
1370
1371 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1372 const FramebufferAttachment *depth = getDepthbuffer();
1373 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1374 {
1375 if (program->samplesFromTexture(state, depth->id()))
1376 {
1377 return true;
1378 }
1379 }
1380
1381 // Note: we assume the front and back masks are the same for WebGL.
1382 const FramebufferAttachment *stencil = getStencilbuffer();
1383 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1384 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1385 dsState.stencilWritemask != 0)
1386 {
1387 // Skip the feedback loop check if depth/stencil point to the same resource.
1388 if (!depth || *stencil != *depth)
1389 {
1390 if (program->samplesFromTexture(state, stencil->id()))
1391 {
1392 return true;
1393 }
1394 }
1395 }
1396
Jamie Madilla4595b82017-01-11 17:36:34 -05001397 return false;
1398}
1399
Jamie Madillfd3dd432017-02-02 19:59:59 -05001400bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1401 GLint copyTextureLevel,
1402 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001403{
1404 if (mId == 0)
1405 {
1406 // It seems impossible to form a texture copying feedback loop with the default FBO.
1407 return false;
1408 }
1409
1410 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1411 ASSERT(readAttachment);
1412
1413 if (readAttachment->isTextureWithId(copyTextureID))
1414 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001415 const auto &imageIndex = readAttachment->getTextureImageIndex();
1416 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001417 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001418 // Check 3D/Array texture layers.
1419 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1420 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1421 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001422 }
1423 }
1424 return false;
1425}
1426
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001427GLint Framebuffer::getDefaultWidth() const
1428{
1429 return mState.getDefaultWidth();
1430}
1431
1432GLint Framebuffer::getDefaultHeight() const
1433{
1434 return mState.getDefaultHeight();
1435}
1436
1437GLint Framebuffer::getDefaultSamples() const
1438{
1439 return mState.getDefaultSamples();
1440}
1441
1442GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1443{
1444 return mState.getDefaultFixedSampleLocations();
1445}
1446
1447void Framebuffer::setDefaultWidth(GLint defaultWidth)
1448{
1449 mState.mDefaultWidth = defaultWidth;
1450 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1451}
1452
1453void Framebuffer::setDefaultHeight(GLint defaultHeight)
1454{
1455 mState.mDefaultHeight = defaultHeight;
1456 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1457}
1458
1459void Framebuffer::setDefaultSamples(GLint defaultSamples)
1460{
1461 mState.mDefaultSamples = defaultSamples;
1462 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1463}
1464
1465void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1466{
1467 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1468 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1469}
1470
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001471// TODO(jmadill): Remove this kludge.
1472GLenum Framebuffer::checkStatus(const ValidationContext *context)
1473{
1474 return checkStatus(static_cast<const Context *>(context));
1475}
1476
1477int Framebuffer::getSamples(const ValidationContext *context)
1478{
1479 return getSamples(static_cast<const Context *>(context));
1480}
1481
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001482} // namespace gl