blob: 2b42d88451f462b2bb041536db259e85f9a02182 [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
42} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -050043
Jamie Madill6f60d052017-02-22 15:20:11 -050044// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -040045FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -050046 : mLabel(),
47 mColorAttachments(1),
Geoff Langd90d3882017-03-21 10:49:54 -040048 mDrawBufferStates(IMPLEMENTATION_MAX_DRAW_BUFFERS, GL_NONE),
Jamie Madill6f60d052017-02-22 15:20:11 -050049 mReadBufferState(GL_BACK),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080050 mDefaultWidth(0),
51 mDefaultHeight(0),
52 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -050053 mDefaultFixedSampleLocations(GL_FALSE),
54 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -040055{
Geoff Langd90d3882017-03-21 10:49:54 -040056 ASSERT(mDrawBufferStates.size() > 0);
57 mDrawBufferStates[0] = GL_BACK;
Jamie Madilla4595b82017-01-11 17:36:34 -050058 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -040059}
60
Jamie Madill48ef11b2016-04-27 15:21:52 -040061FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -050062 : mLabel(),
63 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050064 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080065 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
66 mDefaultWidth(0),
67 mDefaultHeight(0),
68 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -050069 mDefaultFixedSampleLocations(GL_FALSE),
70 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -050071{
Geoff Langa15472a2015-08-11 11:48:03 -040072 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -050073 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
74}
75
Jamie Madill48ef11b2016-04-27 15:21:52 -040076FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -050077{
Jamie Madilld1405e52015-03-05 15:41:39 -050078}
79
Jamie Madill48ef11b2016-04-27 15:21:52 -040080const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -050081{
82 return mLabel;
83}
84
Geoff Lang4b7f12b2016-06-21 16:47:07 -040085const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
86{
87 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
88 {
89 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
90 }
91
92 switch (attachment)
93 {
94 case GL_COLOR:
95 case GL_BACK:
96 return getColorAttachment(0);
97 case GL_DEPTH:
98 case GL_DEPTH_ATTACHMENT:
99 return getDepthAttachment();
100 case GL_STENCIL:
101 case GL_STENCIL_ATTACHMENT:
102 return getStencilAttachment();
103 case GL_DEPTH_STENCIL:
104 case GL_DEPTH_STENCIL_ATTACHMENT:
105 return getDepthStencilAttachment();
106 default:
107 UNREACHABLE();
108 return nullptr;
109 }
110}
111
Jamie Madill48ef11b2016-04-27 15:21:52 -0400112const FramebufferAttachment *FramebufferState::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500113{
Antoine Labour2ec65dc2016-11-30 16:28:58 -0800114 if (mReadBufferState == GL_NONE)
115 {
116 return nullptr;
117 }
Jamie Madill231c7f52017-04-26 13:45:37 -0400118 ASSERT(mReadBufferState == GL_BACK ||
119 (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
120 size_t readIndex = (mReadBufferState == GL_BACK
121 ? 0
122 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
Jamie Madill7147f012015-03-05 15:41:40 -0500123 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400124 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500125}
126
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500127const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
128{
129 auto *colorAttachment = getFirstColorAttachment();
130 if (colorAttachment)
131 {
132 return colorAttachment;
133 }
134 return getDepthOrStencilAttachment();
135}
136
Jamie Madill48ef11b2016-04-27 15:21:52 -0400137const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500138{
Jamie Madill2d06b732015-04-20 12:53:28 -0400139 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500140 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400141 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500142 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400143 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500144 }
145 }
146
147 return nullptr;
148}
149
Jamie Madill48ef11b2016-04-27 15:21:52 -0400150const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500151{
Jamie Madill2d06b732015-04-20 12:53:28 -0400152 if (mDepthAttachment.isAttached())
153 {
154 return &mDepthAttachment;
155 }
156 if (mStencilAttachment.isAttached())
157 {
158 return &mStencilAttachment;
159 }
160 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500161}
162
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500163const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
164{
165 if (mStencilAttachment.isAttached())
166 {
167 return &mStencilAttachment;
168 }
169 return getDepthStencilAttachment();
170}
171
Jamie Madill48ef11b2016-04-27 15:21:52 -0400172const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400173{
174 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill231c7f52017-04-26 13:45:37 -0400175 return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment]
176 : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400177}
178
Jamie Madill48ef11b2016-04-27 15:21:52 -0400179const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400180{
Jamie Madill2d06b732015-04-20 12:53:28 -0400181 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400182}
183
Jamie Madill48ef11b2016-04-27 15:21:52 -0400184const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400185{
Jamie Madill2d06b732015-04-20 12:53:28 -0400186 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400187}
188
Jamie Madill48ef11b2016-04-27 15:21:52 -0400189const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400190{
191 // A valid depth-stencil attachment has the same resource bound to both the
192 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400193 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500194 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400195 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400196 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400197 }
198
199 return nullptr;
200}
201
Jamie Madill48ef11b2016-04-27 15:21:52 -0400202bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500203{
204 Optional<Extents> attachmentSize;
205
Jamie Madill231c7f52017-04-26 13:45:37 -0400206 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) {
Jamie Madillcc86d642015-11-24 13:00:07 -0500207 if (!attachment.isAttached())
208 {
209 return false;
210 }
211
212 if (!attachmentSize.valid())
213 {
214 attachmentSize = attachment.getSize();
215 return false;
216 }
217
218 return (attachment.getSize() != attachmentSize.value());
219 };
220
221 for (const auto &attachment : mColorAttachments)
222 {
223 if (hasMismatchedSize(attachment))
224 {
225 return false;
226 }
227 }
228
229 if (hasMismatchedSize(mDepthAttachment))
230 {
231 return false;
232 }
233
234 return !hasMismatchedSize(mStencilAttachment);
235}
236
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400237const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
238{
239 ASSERT(drawBufferIdx < mDrawBufferStates.size());
240 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
241 {
242 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
243 // must be COLOR_ATTACHMENTi or NONE"
244 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
245 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
246 return getAttachment(mDrawBufferStates[drawBufferIdx]);
247 }
248 else
249 {
250 return nullptr;
251 }
252}
253
254size_t FramebufferState::getDrawBufferCount() const
255{
256 return mDrawBufferStates.size();
257}
258
Geoff Langb21e20d2016-07-19 15:35:41 -0400259bool FramebufferState::colorAttachmentsAreUniqueImages() const
260{
261 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
262 firstAttachmentIdx++)
263 {
264 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
265 if (!firstAttachment.isAttached())
266 {
267 continue;
268 }
269
270 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
271 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
272 {
273 const gl::FramebufferAttachment &secondAttachment =
274 mColorAttachments[secondAttachmentIdx];
275 if (!secondAttachment.isAttached())
276 {
277 continue;
278 }
279
280 if (firstAttachment == secondAttachment)
281 {
282 return false;
283 }
284 }
285 }
286
287 return true;
288}
289
Jamie Madill7aea7e02016-05-10 10:39:45 -0400290Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400291 : mState(caps),
292 mImpl(factory->createFramebuffer(mState)),
293 mId(id),
294 mCachedStatus(),
295 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
296 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297{
Corentin Wallez37c39792015-08-20 14:19:46 -0400298 ASSERT(mId != 0);
299 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400300 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
301
Jamie Madill1e5499d2017-04-05 11:22:16 -0400302 for (uint32_t colorIndex = 0;
303 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400304 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400305 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400306 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400307}
308
Jamie Madill6f60d052017-02-22 15:20:11 -0500309Framebuffer::Framebuffer(egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400310 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500311 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400312 mId(0),
313 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
314 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
315 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400316{
Geoff Langda88add2014-12-01 10:22:01 -0500317 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400318 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500319
Jamie Madilla02315b2017-02-23 14:14:47 -0500320 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500321
322 if (surface->getConfig()->depthSize > 0)
323 {
Jamie Madilla02315b2017-02-23 14:14:47 -0500324 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500325 }
326
327 if (surface->getConfig()->stencilSize > 0)
328 {
Jamie Madilla02315b2017-02-23 14:14:47 -0500329 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, gl::ImageIndex::MakeInvalid(),
330 surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500331 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332}
333
Corentin Wallezccab69d2017-01-27 16:57:15 -0500334Framebuffer::Framebuffer(rx::GLImplFactory *factory)
335 : mState(),
336 mImpl(factory->createFramebuffer(mState)),
337 mId(0),
338 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
339 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
340 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
341{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400342 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500343}
344
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345Framebuffer::~Framebuffer()
346{
Geoff Langda88add2014-12-01 10:22:01 -0500347 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000348}
349
Jamie Madill6c1f6712017-02-14 19:08:04 -0500350void Framebuffer::destroy(const Context *context)
351{
352 mImpl->destroy(rx::SafeGetImpl(context));
353}
354
355void Framebuffer::destroyDefault(const egl::Display *display)
356{
357 mImpl->destroyDefault(rx::SafeGetImpl(display));
358}
359
Geoff Lang70d0f492015-12-10 17:45:46 -0500360void Framebuffer::setLabel(const std::string &label)
361{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400362 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500363}
364
365const std::string &Framebuffer::getLabel() const
366{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400367 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500368}
369
Jamie Madilla02315b2017-02-23 14:14:47 -0500370void Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000371{
Jamie Madilla02315b2017-02-23 14:14:47 -0500372 detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373}
374
Jamie Madilla02315b2017-02-23 14:14:47 -0500375void Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000376{
Jamie Madilla02315b2017-02-23 14:14:47 -0500377 detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500378}
Jamie Madille261b442014-06-25 12:42:21 -0400379
Jamie Madilla02315b2017-02-23 14:14:47 -0500380void Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500381{
Jamie Madill362876b2016-06-16 14:46:59 -0400382 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500383 {
Jamie Madill362876b2016-06-16 14:46:59 -0400384 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
385 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386 }
387
Jamie Madilla02315b2017-02-23 14:14:47 -0500388 if (context->isWebGL1())
389 {
390 const std::array<FramebufferAttachment *, 3> attachments = {
391 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
392 &mState.mWebGLStencilAttachment}};
393 for (FramebufferAttachment *attachment : attachments)
394 {
395 if (attachment->isAttached() && attachment->type() == resourceType &&
396 attachment->id() == resourceId)
397 {
398 resetAttachment(context, attachment->getBinding());
399 }
400 }
401 }
402 else
403 {
404 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
405 DIRTY_BIT_DEPTH_ATTACHMENT);
406 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
407 DIRTY_BIT_STENCIL_ATTACHMENT);
408 }
Jamie Madill362876b2016-06-16 14:46:59 -0400409}
410
411void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
412 GLenum matchType,
413 GLuint matchId,
414 size_t dirtyBit)
415{
416 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
417 {
418 attachment->detach();
419 mDirtyBits.set(dirtyBit);
420 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421}
422
Corentin Wallez37c39792015-08-20 14:19:46 -0400423const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000424{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400425 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426}
427
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400428const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400429{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400430 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400431}
432
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400433const FramebufferAttachment *Framebuffer::getStencilbuffer() const
434{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400435 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400436}
437
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400438const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
439{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400440 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400441}
442
443const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000444{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400445 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000446}
447
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500448const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
449{
450 return mState.getStencilOrDepthStencilAttachment();
451}
452
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400453const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000454{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400455 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000456}
457
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000458GLenum Framebuffer::getReadColorbufferType() const
459{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400460 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400461 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000462}
463
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400464const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000465{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400466 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000467}
468
Jamie Madill2d06b732015-04-20 12:53:28 -0400469const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000470{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400471 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400472}
473
Geoff Langa15472a2015-08-11 11:48:03 -0400474size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000475{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400476 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400477}
478
479GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
480{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400481 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
482 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000483}
484
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500485const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
486{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400487 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500488}
489
Geoff Lang164d54e2014-12-01 10:55:33 -0500490void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000491{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400492 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500493
494 ASSERT(count <= drawStates.size());
495 std::copy(buffers, buffers + count, drawStates.begin());
496 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500497 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500498
499 mState.mEnabledDrawBuffers.reset();
500 for (size_t index = 0; index < count; ++index)
501 {
502 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
503 {
504 mState.mEnabledDrawBuffers.set(index);
505 }
506 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500507}
508
Geoff Langa15472a2015-08-11 11:48:03 -0400509const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
510{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400511 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400512}
513
514bool Framebuffer::hasEnabledDrawBuffer() const
515{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400516 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400517 {
518 if (getDrawBuffer(drawbufferIdx) != nullptr)
519 {
520 return true;
521 }
522 }
523
524 return false;
525}
526
Geoff Lang9dd95802014-12-01 11:12:59 -0500527GLenum Framebuffer::getReadBufferState() const
528{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400529 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500530}
531
532void Framebuffer::setReadBuffer(GLenum buffer)
533{
Jamie Madillb885e572015-02-03 16:16:04 -0500534 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
535 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400536 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
537 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500538 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000539}
540
Corentin Wallez37c39792015-08-20 14:19:46 -0400541size_t Framebuffer::getNumColorBuffers() const
542{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400543 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400544}
545
Jamie Madill0df8fe42015-11-24 16:10:24 -0500546bool Framebuffer::hasDepth() const
547{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400548 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500549}
550
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000551bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000552{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400553 return (mState.mStencilAttachment.isAttached() &&
554 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000555}
556
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000557bool Framebuffer::usingExtendedDrawBuffers() const
558{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400559 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000560 {
Geoff Langa15472a2015-08-11 11:48:03 -0400561 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000562 {
563 return true;
564 }
565 }
566
567 return false;
568}
569
Geoff Lang9aded172017-04-05 11:07:56 -0400570void Framebuffer::invalidateCompletenessCache()
571{
572 if (mId != 0)
573 {
574 mCachedStatus.reset();
575 }
576}
577
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400578GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000579{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500580 // The default framebuffer is always complete except when it is surfaceless in which
581 // case it is always unsupported. We return early because the default framebuffer may
582 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500583 if (mId == 0)
584 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500585 ASSERT(mCachedStatus.valid());
586 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
587 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
588 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500589 }
590
Jamie Madill362876b2016-06-16 14:46:59 -0400591 if (hasAnyDirtyBit() || !mCachedStatus.valid())
592 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400593 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400594 }
595
596 return mCachedStatus.value();
597}
598
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400599GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400600{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400601 const ContextState &state = context->getContextState();
602
Jamie Madill362876b2016-06-16 14:46:59 -0400603 ASSERT(mId != 0);
604
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000605 unsigned int colorbufferSize = 0;
Jamie Madill231c7f52017-04-26 13:45:37 -0400606 int samples = -1;
607 bool missingAttachment = true;
JiangYizhou461d9a32017-01-04 16:37:26 +0800608 Optional<GLboolean> fixedSampleLocations;
609 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000610
Jamie Madill48ef11b2016-04-27 15:21:52 -0400611 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400613 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000614 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500615 const Extents &size = colorAttachment.getSize();
616 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000617 {
618 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
619 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000620
Geoff Lang677bb6f2017-04-05 12:40:40 -0400621 const InternalFormat &format = *colorAttachment.getFormat().info;
622 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
623 {
624 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
625 }
626
627 if (format.depthBits > 0 || format.stencilBits > 0)
628 {
629 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
630 }
631
Jamie Madill2d06b732015-04-20 12:53:28 -0400632 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000633 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500634 if (colorAttachment.layer() >= size.depth)
635 {
636 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
637 }
Jamie Madill3215b202015-12-15 16:41:39 -0500638
639 // ES3 specifies that cube map texture attachments must be cube complete.
640 // This language is missing from the ES2 spec, but we enforce it here because some
641 // desktop OpenGL drivers also enforce this validation.
642 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
643 const Texture *texture = colorAttachment.getTexture();
644 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300645 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
646 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500647 {
648 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
649 }
JiangYizhou461d9a32017-01-04 16:37:26 +0800650
651 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS
652 // should be the same for all attached textures.
653 GLboolean fixedSampleloc = colorAttachment.getTexture()->getFixedSampleLocations(
654 colorAttachment.getTextureImageIndex().type, 0);
655 if (fixedSampleLocations.valid() && fixedSampleloc != fixedSampleLocations.value())
656 {
657 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
658 }
659 else
660 {
661 fixedSampleLocations = fixedSampleloc;
662 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000663 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400664 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000665 {
JiangYizhou461d9a32017-01-04 16:37:26 +0800666 hasRenderbuffer = true;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000667 }
668
669 if (!missingAttachment)
670 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000671 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
672 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400673 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000674 {
675 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
676 }
677
Jamie Madill231c7f52017-04-26 13:45:37 -0400678 // in GLES 2.0, all color attachments attachments must have the same number of
679 // bitplanes in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300680 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000681 {
Geoff Lang677bb6f2017-04-05 12:40:40 -0400682 if (format.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000683 {
684 return GL_FRAMEBUFFER_UNSUPPORTED;
685 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000686 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000687 }
688 else
689 {
JiangYizhou461d9a32017-01-04 16:37:26 +0800690 samples = colorAttachment.getSamples();
Geoff Lang677bb6f2017-04-05 12:40:40 -0400691 colorbufferSize = format.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000692 missingAttachment = false;
693 }
694 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000695 }
696
Jamie Madill48ef11b2016-04-27 15:21:52 -0400697 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400698 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000699 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500700 const Extents &size = depthAttachment.getSize();
701 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000702 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000703 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704 }
705
Geoff Lang677bb6f2017-04-05 12:40:40 -0400706 const InternalFormat &format = *depthAttachment.getFormat().info;
Geoff Langcec35902014-04-16 10:52:36 -0400707
Geoff Lang677bb6f2017-04-05 12:40:40 -0400708 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000709 {
Geoff Lang677bb6f2017-04-05 12:40:40 -0400710 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
711 }
712
713 if (format.depthBits == 0)
714 {
715 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000716 }
717
718 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000719 {
Jamie Madill231c7f52017-04-26 13:45:37 -0400720 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000721 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000722 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400723 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000724 {
Sami Väisänena797e062016-05-12 15:23:40 +0300725 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
726 // considered complete when its depth or stencil samples are a
727 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700728 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300729 if (!mixedSamples)
730 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
731
732 const int colorSamples = samples ? samples : 1;
733 const int depthSamples = depthAttachment.getSamples();
734 if ((depthSamples % colorSamples) != 0)
735 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000736 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000737 }
738
Jamie Madill48ef11b2016-04-27 15:21:52 -0400739 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400740 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000741 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500742 const Extents &size = stencilAttachment.getSize();
743 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000744 {
745 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
746 }
747
Geoff Lang677bb6f2017-04-05 12:40:40 -0400748 const InternalFormat &format = *stencilAttachment.getFormat().info;
Geoff Langcec35902014-04-16 10:52:36 -0400749
Geoff Lang677bb6f2017-04-05 12:40:40 -0400750 if (!format.renderSupport(context->getClientVersion(), context->getExtensions()))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000751 {
Geoff Lang677bb6f2017-04-05 12:40:40 -0400752 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
753 }
754
755 if (format.stencilBits == 0)
756 {
757 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000758 }
759
760 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000761 {
Jamie Madill231c7f52017-04-26 13:45:37 -0400762 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000763 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000764 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400765 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000766 {
Sami Väisänena797e062016-05-12 15:23:40 +0300767 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700768 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300769 if (!mixedSamples)
770 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
771
772 const int colorSamples = samples ? samples : 1;
773 const int stencilSamples = stencilAttachment.getSamples();
774 if ((stencilSamples % colorSamples) != 0)
775 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000776 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400777
778 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300779 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400780 stencilAttachment != depthAttachment)
781 {
782 return GL_FRAMEBUFFER_UNSUPPORTED;
783 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000784 }
785
Jamie Madilla02315b2017-02-23 14:14:47 -0500786 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
787 if (state.isWebGL1())
788 {
789 if (!mState.mWebGLDepthStencilConsistent)
790 {
791 return GL_FRAMEBUFFER_UNSUPPORTED;
792 }
793
794 if (mState.mWebGLDepthStencilAttachment.isAttached())
795 {
796 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
797 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
798 {
799 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
800 }
801 }
802 else if (mState.mStencilAttachment.isAttached() &&
803 mState.mStencilAttachment.getDepthSize() > 0)
804 {
805 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
806 }
807 else if (mState.mDepthAttachment.isAttached() &&
808 mState.mDepthAttachment.getStencilSize() > 0)
809 {
810 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
811 }
812 }
813
JiangYizhou461d9a32017-01-04 16:37:26 +0800814 // ES3.1(section 9.4) requires that if no image is attached to the
815 // framebuffer, and either the value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH
816 // or FRAMEBUFFER_DEFAULT_HEIGHT parameters is zero, the framebuffer is
817 // considered incomplete.
818 GLint defaultWidth = mState.getDefaultWidth();
819 GLint defaultHeight = mState.getDefaultHeight();
820
821 if (missingAttachment && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000822 {
823 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000824 }
825
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400826 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -0500827 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400828 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
829 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500830 {
831 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
832 }
833
JiangYizhou461d9a32017-01-04 16:37:26 +0800834 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers
835 // and textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all
836 // attached textures.
837 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
838 {
839 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
840 }
841
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400842 syncState(context);
Jamie Madillcc86d642015-11-24 13:00:07 -0500843 if (!mImpl->checkStatus())
844 {
845 return GL_FRAMEBUFFER_UNSUPPORTED;
846 }
847
848 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000849}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000850
Austin Kinross08332632015-05-05 13:35:47 -0700851Error Framebuffer::discard(size_t count, const GLenum *attachments)
852{
853 return mImpl->discard(count, attachments);
854}
855
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500856Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400857{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500858 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400859}
860
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500861Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400862{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500863 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400864}
865
Jamie Madill8415b5f2016-04-26 13:41:39 -0400866Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500867{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700868 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500869 {
Jamie Madill362876b2016-06-16 14:46:59 -0400870 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500871 }
872
Jamie Madill8415b5f2016-04-26 13:41:39 -0400873 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500874}
875
Jamie Madill8415b5f2016-04-26 13:41:39 -0400876Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400877 GLenum buffer,
878 GLint drawbuffer,
879 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500880{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700881 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500882 {
Jamie Madill362876b2016-06-16 14:46:59 -0400883 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500884 }
885
Jamie Madill8415b5f2016-04-26 13:41:39 -0400886 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500887}
888
Jamie Madill8415b5f2016-04-26 13:41:39 -0400889Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400890 GLenum buffer,
891 GLint drawbuffer,
892 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500893{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700894 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500895 {
Jamie Madill362876b2016-06-16 14:46:59 -0400896 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500897 }
898
Jamie Madill8415b5f2016-04-26 13:41:39 -0400899 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500900}
901
Jamie Madill8415b5f2016-04-26 13:41:39 -0400902Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400903 GLenum buffer,
904 GLint drawbuffer,
905 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500906{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700907 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500908 {
Jamie Madill362876b2016-06-16 14:46:59 -0400909 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500910 }
911
Jamie Madill8415b5f2016-04-26 13:41:39 -0400912 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500913}
914
Jamie Madill8415b5f2016-04-26 13:41:39 -0400915Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400916 GLenum buffer,
917 GLint drawbuffer,
918 GLfloat depth,
919 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500920{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700921 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500922 {
Jamie Madill362876b2016-06-16 14:46:59 -0400923 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500924 }
925
Jamie Madill8415b5f2016-04-26 13:41:39 -0400926 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500927}
928
Geoff Langbce529e2014-12-01 12:48:41 -0500929GLenum Framebuffer::getImplementationColorReadFormat() const
930{
931 return mImpl->getImplementationColorReadFormat();
932}
933
934GLenum Framebuffer::getImplementationColorReadType() const
935{
936 return mImpl->getImplementationColorReadType();
937}
938
Jamie Madill8415b5f2016-04-26 13:41:39 -0400939Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500940 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400941 GLenum format,
942 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -0400943 void *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500944{
Jamie Madill362876b2016-06-16 14:46:59 -0400945 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400946
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700947 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400948 if (unpackBuffer)
949 {
950 unpackBuffer->onPixelUnpack();
951 }
952
Jamie Madill362876b2016-06-16 14:46:59 -0400953 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500954}
955
Jamie Madill8415b5f2016-04-26 13:41:39 -0400956Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500957 const Rectangle &sourceArea,
958 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400959 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400960 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500961{
He Yunchao6be602d2016-12-22 14:33:07 +0800962 GLbitfield blitMask = mask;
963
964 // Note that blitting is called against draw framebuffer.
965 // See the code in gl::Context::blitFramebuffer.
966 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
967 {
968 blitMask &= ~GL_COLOR_BUFFER_BIT;
969 }
970
971 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
972 {
973 blitMask &= ~GL_STENCIL_BUFFER_BIT;
974 }
975
976 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
977 {
978 blitMask &= ~GL_DEPTH_BUFFER_BIT;
979 }
980
981 if (!blitMask)
982 {
983 return NoError();
984 }
985
986 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -0500987}
988
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400989int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000990{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400991 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000992 {
Jamie Madill362876b2016-06-16 14:46:59 -0400993 // For a complete framebuffer, all attachments must have the same sample count.
994 // In this case return the first nonzero sample size.
995 const auto *firstColorAttachment = mState.getFirstColorAttachment();
996 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000997 {
Jamie Madill362876b2016-06-16 14:46:59 -0400998 ASSERT(firstColorAttachment->isAttached());
999 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001000 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001001 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001002
1003 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001004}
1005
Corentin Wallezccab69d2017-01-27 16:57:15 -05001006Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1007{
1008 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
1009 return gl::NoError();
1010}
1011
Jamie Madille261b442014-06-25 12:42:21 -04001012bool Framebuffer::hasValidDepthStencil() const
1013{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001014 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001015}
1016
Jamie Madilla02315b2017-02-23 14:14:47 -05001017void Framebuffer::setAttachment(const Context *context,
1018 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001019 GLenum binding,
1020 const ImageIndex &textureIndex,
1021 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001022{
Jamie Madilla02315b2017-02-23 14:14:47 -05001023 // Context may be null in unit tests.
1024 if (!context || !context->isWebGL1())
1025 {
1026 setAttachmentImpl(type, binding, textureIndex, resource);
1027 return;
1028 }
1029
1030 switch (binding)
1031 {
1032 case GL_DEPTH_STENCIL:
1033 case GL_DEPTH_STENCIL_ATTACHMENT:
1034 mState.mWebGLDepthStencilAttachment.attach(type, binding, textureIndex, resource);
1035 break;
1036 case GL_DEPTH:
1037 case GL_DEPTH_ATTACHMENT:
1038 mState.mWebGLDepthAttachment.attach(type, binding, textureIndex, resource);
1039 break;
1040 case GL_STENCIL:
1041 case GL_STENCIL_ATTACHMENT:
1042 mState.mWebGLStencilAttachment.attach(type, binding, textureIndex, resource);
1043 break;
1044 default:
1045 setAttachmentImpl(type, binding, textureIndex, resource);
1046 return;
1047 }
1048
1049 commitWebGL1DepthStencilIfConsistent();
1050}
1051
1052void Framebuffer::commitWebGL1DepthStencilIfConsistent()
1053{
1054 int count = 0;
1055
1056 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1057 &mState.mWebGLDepthAttachment,
1058 &mState.mWebGLStencilAttachment}};
1059 for (FramebufferAttachment *attachment : attachments)
1060 {
1061 if (attachment->isAttached())
1062 {
1063 count++;
1064 }
1065 }
1066
1067 mState.mWebGLDepthStencilConsistent = (count <= 1);
1068 if (!mState.mWebGLDepthStencilConsistent)
1069 {
1070 // Inconsistent.
1071 return;
1072 }
1073
Geoff Lange466c552017-03-17 15:24:12 -04001074 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1075 if (attachment.type() == GL_TEXTURE)
1076 {
1077 return attachment.getTextureImageIndex();
1078 }
1079 else
1080 {
1081 return ImageIndex::MakeInvalid();
1082 }
1083 };
1084
Jamie Madilla02315b2017-02-23 14:14:47 -05001085 if (mState.mWebGLDepthAttachment.isAttached())
1086 {
1087 const auto &depth = mState.mWebGLDepthAttachment;
Geoff Lange466c552017-03-17 15:24:12 -04001088 setAttachmentImpl(depth.type(), GL_DEPTH_ATTACHMENT,
1089 getImageIndexIfTextureAttachment(depth), depth.getResource());
Jamie Madilla02315b2017-02-23 14:14:47 -05001090 setAttachmentImpl(GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1091 }
1092 else if (mState.mWebGLStencilAttachment.isAttached())
1093 {
1094 const auto &stencil = mState.mWebGLStencilAttachment;
1095 setAttachmentImpl(GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
Geoff Lange466c552017-03-17 15:24:12 -04001096 setAttachmentImpl(stencil.type(), GL_STENCIL_ATTACHMENT,
1097 getImageIndexIfTextureAttachment(stencil), stencil.getResource());
Jamie Madilla02315b2017-02-23 14:14:47 -05001098 }
1099 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1100 {
1101 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Geoff Lange466c552017-03-17 15:24:12 -04001102 setAttachmentImpl(depthStencil.type(), GL_DEPTH_ATTACHMENT,
1103 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001104 depthStencil.getResource());
Geoff Lange466c552017-03-17 15:24:12 -04001105 setAttachmentImpl(depthStencil.type(), GL_STENCIL_ATTACHMENT,
1106 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001107 depthStencil.getResource());
1108 }
1109 else
1110 {
1111 setAttachmentImpl(GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1112 setAttachmentImpl(GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1113 }
1114}
1115
1116void Framebuffer::setAttachmentImpl(GLenum type,
1117 GLenum binding,
1118 const ImageIndex &textureIndex,
1119 FramebufferAttachmentObject *resource)
1120{
Jamie Madilla02315b2017-02-23 14:14:47 -05001121 switch (binding)
1122 {
Jamie Madillb8126692017-04-05 11:22:17 -04001123 case GL_DEPTH_STENCIL:
1124 case GL_DEPTH_STENCIL_ATTACHMENT:
1125 {
1126 // ensure this is a legitimate depth+stencil format
1127 FramebufferAttachmentObject *attachmentObj = resource;
1128 if (resource)
1129 {
Jamie Madill4fd95d52017-04-05 11:22:18 -04001130 const Format &format = resource->getAttachmentFormat(binding, textureIndex);
Jamie Madillb8126692017-04-05 11:22:17 -04001131 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1132 {
1133 // Attaching nullptr detaches the current attachment.
1134 attachmentObj = nullptr;
1135 }
1136 }
1137
1138 updateAttachment(&mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1139 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
1140 attachmentObj);
1141 updateAttachment(&mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1142 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1143 attachmentObj);
1144 return;
1145 }
1146
Jamie Madilla02315b2017-02-23 14:14:47 -05001147 case GL_DEPTH:
1148 case GL_DEPTH_ATTACHMENT:
Jamie Madillb8126692017-04-05 11:22:17 -04001149 updateAttachment(&mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1150 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource);
Jamie Madill2d06b732015-04-20 12:53:28 -04001151 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001152
Jamie Madilla02315b2017-02-23 14:14:47 -05001153 case GL_STENCIL:
1154 case GL_STENCIL_ATTACHMENT:
Jamie Madillb8126692017-04-05 11:22:17 -04001155 updateAttachment(&mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1156 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1157 resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001158 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001159
Jamie Madilla02315b2017-02-23 14:14:47 -05001160 case GL_BACK:
1161 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
1162 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1163 // No need for a resource binding for the default FBO, it's always complete.
1164 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001165
Jamie Madilla02315b2017-02-23 14:14:47 -05001166 default:
1167 {
1168 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1169 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001170 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
1171 updateAttachment(&mState.mColorAttachments[colorIndex], dirtyBit,
1172 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
1173 textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001174
1175 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1176 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001177 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001178 break;
Geoff Langab75a052014-10-15 12:56:37 -04001179 }
1180}
1181
Jamie Madillb8126692017-04-05 11:22:17 -04001182void Framebuffer::updateAttachment(FramebufferAttachment *attachment,
1183 size_t dirtyBit,
1184 OnAttachmentDirtyBinding *onDirtyBinding,
1185 GLenum type,
1186 GLenum binding,
1187 const ImageIndex &textureIndex,
1188 FramebufferAttachmentObject *resource)
1189{
1190 attachment->attach(type, binding, textureIndex, resource);
1191 mDirtyBits.set(dirtyBit);
1192 BindResourceChannel(onDirtyBinding, resource);
1193}
1194
Jamie Madilla02315b2017-02-23 14:14:47 -05001195void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001196{
Jamie Madilla02315b2017-02-23 14:14:47 -05001197 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001198}
1199
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001200void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001201{
1202 if (mDirtyBits.any())
1203 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001204 mImpl->syncState(rx::SafeGetImpl(context), mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001205 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001206 if (mId != 0)
1207 {
1208 mCachedStatus.reset();
1209 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001210 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001211}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001212
Jamie Madill1e5499d2017-04-05 11:22:16 -04001213void Framebuffer::signal(uint32_t token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001214{
Jamie Madill362876b2016-06-16 14:46:59 -04001215 // TOOD(jmadill): Make this only update individual attachments to do less work.
1216 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001217}
1218
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001219bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001220{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001221 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1222}
1223
1224bool Framebuffer::cachedComplete() const
1225{
1226 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001227}
1228
Jamie Madilla4595b82017-01-11 17:36:34 -05001229bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1230{
1231 const Program *program = state.getProgram();
1232
1233 // TODO(jmadill): Default framebuffer feedback loops.
1234 if (mId == 0)
1235 {
1236 return false;
1237 }
1238
1239 // The bitset will skip inactive draw buffers.
Jamie Madill6de51852017-04-12 09:53:01 -04001240 for (size_t drawIndex : mState.mEnabledDrawBuffers)
Jamie Madilla4595b82017-01-11 17:36:34 -05001241 {
1242 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1243 if (attachment && attachment->type() == GL_TEXTURE)
1244 {
1245 // Validate the feedback loop.
1246 if (program->samplesFromTexture(state, attachment->id()))
1247 {
1248 return true;
1249 }
1250 }
1251 }
1252
Jamie Madill1d37bc52017-02-02 19:59:58 -05001253 // Validate depth-stencil feedback loop.
1254 const auto &dsState = state.getDepthStencilState();
1255
1256 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1257 const FramebufferAttachment *depth = getDepthbuffer();
1258 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1259 {
1260 if (program->samplesFromTexture(state, depth->id()))
1261 {
1262 return true;
1263 }
1264 }
1265
1266 // Note: we assume the front and back masks are the same for WebGL.
1267 const FramebufferAttachment *stencil = getStencilbuffer();
1268 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1269 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1270 dsState.stencilWritemask != 0)
1271 {
1272 // Skip the feedback loop check if depth/stencil point to the same resource.
1273 if (!depth || *stencil != *depth)
1274 {
1275 if (program->samplesFromTexture(state, stencil->id()))
1276 {
1277 return true;
1278 }
1279 }
1280 }
1281
Jamie Madilla4595b82017-01-11 17:36:34 -05001282 return false;
1283}
1284
Jamie Madillfd3dd432017-02-02 19:59:59 -05001285bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1286 GLint copyTextureLevel,
1287 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001288{
1289 if (mId == 0)
1290 {
1291 // It seems impossible to form a texture copying feedback loop with the default FBO.
1292 return false;
1293 }
1294
1295 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1296 ASSERT(readAttachment);
1297
1298 if (readAttachment->isTextureWithId(copyTextureID))
1299 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001300 const auto &imageIndex = readAttachment->getTextureImageIndex();
1301 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001302 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001303 // Check 3D/Array texture layers.
1304 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1305 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1306 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001307 }
1308 }
1309 return false;
1310}
1311
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001312GLint Framebuffer::getDefaultWidth() const
1313{
1314 return mState.getDefaultWidth();
1315}
1316
1317GLint Framebuffer::getDefaultHeight() const
1318{
1319 return mState.getDefaultHeight();
1320}
1321
1322GLint Framebuffer::getDefaultSamples() const
1323{
1324 return mState.getDefaultSamples();
1325}
1326
1327GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1328{
1329 return mState.getDefaultFixedSampleLocations();
1330}
1331
1332void Framebuffer::setDefaultWidth(GLint defaultWidth)
1333{
1334 mState.mDefaultWidth = defaultWidth;
1335 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1336}
1337
1338void Framebuffer::setDefaultHeight(GLint defaultHeight)
1339{
1340 mState.mDefaultHeight = defaultHeight;
1341 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1342}
1343
1344void Framebuffer::setDefaultSamples(GLint defaultSamples)
1345{
1346 mState.mDefaultSamples = defaultSamples;
1347 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1348}
1349
1350void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1351{
1352 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1353 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1354}
1355
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001356// TODO(jmadill): Remove this kludge.
1357GLenum Framebuffer::checkStatus(const ValidationContext *context)
1358{
1359 return checkStatus(static_cast<const Context *>(context));
1360}
1361
1362int Framebuffer::getSamples(const ValidationContext *context)
1363{
1364 return getSamples(static_cast<const Context *>(context));
1365}
1366
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001367} // namespace gl