blob: d7e61f8b9e7a0517fa6c1e4ef8a1d19135e05ca2 [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 Madill20e005b2017-04-07 14:19:22 -040012#include "common/bitset_utils.h"
Jamie Madillcc86d642015-11-24 13:00:07 -050013#include "common/Optional.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 Madill7147f012015-03-05 15:41:40 -0500118 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
119 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
120 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400121 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500122}
123
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500124const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
125{
126 auto *colorAttachment = getFirstColorAttachment();
127 if (colorAttachment)
128 {
129 return colorAttachment;
130 }
131 return getDepthOrStencilAttachment();
132}
133
Jamie Madill48ef11b2016-04-27 15:21:52 -0400134const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500135{
Jamie Madill2d06b732015-04-20 12:53:28 -0400136 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500137 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400138 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500139 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400140 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500141 }
142 }
143
144 return nullptr;
145}
146
Jamie Madill48ef11b2016-04-27 15:21:52 -0400147const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500148{
Jamie Madill2d06b732015-04-20 12:53:28 -0400149 if (mDepthAttachment.isAttached())
150 {
151 return &mDepthAttachment;
152 }
153 if (mStencilAttachment.isAttached())
154 {
155 return &mStencilAttachment;
156 }
157 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500158}
159
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500160const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
161{
162 if (mStencilAttachment.isAttached())
163 {
164 return &mStencilAttachment;
165 }
166 return getDepthStencilAttachment();
167}
168
Jamie Madill48ef11b2016-04-27 15:21:52 -0400169const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400170{
171 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400172 return mColorAttachments[colorAttachment].isAttached() ?
173 &mColorAttachments[colorAttachment] :
174 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400175}
176
Jamie Madill48ef11b2016-04-27 15:21:52 -0400177const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400178{
Jamie Madill2d06b732015-04-20 12:53:28 -0400179 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400180}
181
Jamie Madill48ef11b2016-04-27 15:21:52 -0400182const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400183{
Jamie Madill2d06b732015-04-20 12:53:28 -0400184 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400185}
186
Jamie Madill48ef11b2016-04-27 15:21:52 -0400187const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400188{
189 // A valid depth-stencil attachment has the same resource bound to both the
190 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400191 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500192 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400193 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400194 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400195 }
196
197 return nullptr;
198}
199
Jamie Madill48ef11b2016-04-27 15:21:52 -0400200bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500201{
202 Optional<Extents> attachmentSize;
203
204 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
205 {
206 if (!attachment.isAttached())
207 {
208 return false;
209 }
210
211 if (!attachmentSize.valid())
212 {
213 attachmentSize = attachment.getSize();
214 return false;
215 }
216
217 return (attachment.getSize() != attachmentSize.value());
218 };
219
220 for (const auto &attachment : mColorAttachments)
221 {
222 if (hasMismatchedSize(attachment))
223 {
224 return false;
225 }
226 }
227
228 if (hasMismatchedSize(mDepthAttachment))
229 {
230 return false;
231 }
232
233 return !hasMismatchedSize(mStencilAttachment);
234}
235
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400236const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
237{
238 ASSERT(drawBufferIdx < mDrawBufferStates.size());
239 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
240 {
241 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
242 // must be COLOR_ATTACHMENTi or NONE"
243 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
244 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
245 return getAttachment(mDrawBufferStates[drawBufferIdx]);
246 }
247 else
248 {
249 return nullptr;
250 }
251}
252
253size_t FramebufferState::getDrawBufferCount() const
254{
255 return mDrawBufferStates.size();
256}
257
Geoff Langb21e20d2016-07-19 15:35:41 -0400258bool FramebufferState::colorAttachmentsAreUniqueImages() const
259{
260 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
261 firstAttachmentIdx++)
262 {
263 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
264 if (!firstAttachment.isAttached())
265 {
266 continue;
267 }
268
269 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
270 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
271 {
272 const gl::FramebufferAttachment &secondAttachment =
273 mColorAttachments[secondAttachmentIdx];
274 if (!secondAttachment.isAttached())
275 {
276 continue;
277 }
278
279 if (firstAttachment == secondAttachment)
280 {
281 return false;
282 }
283 }
284 }
285
286 return true;
287}
288
Jamie Madill7aea7e02016-05-10 10:39:45 -0400289Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400290 : mState(caps),
291 mImpl(factory->createFramebuffer(mState)),
292 mId(id),
293 mCachedStatus(),
294 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
295 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296{
Corentin Wallez37c39792015-08-20 14:19:46 -0400297 ASSERT(mId != 0);
298 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400299 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
300
Jamie Madill1e5499d2017-04-05 11:22:16 -0400301 for (uint32_t colorIndex = 0;
302 colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex)
Jamie Madill362876b2016-06-16 14:46:59 -0400303 {
Jamie Madill1e5499d2017-04-05 11:22:16 -0400304 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400305 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400306}
307
Jamie Madill6f60d052017-02-22 15:20:11 -0500308Framebuffer::Framebuffer(egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400309 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500310 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400311 mId(0),
312 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
313 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
314 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400315{
Geoff Langda88add2014-12-01 10:22:01 -0500316 ASSERT(mImpl != nullptr);
Jamie Madill1e5499d2017-04-05 11:22:16 -0400317 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill6f60d052017-02-22 15:20:11 -0500318
Jamie Madilla02315b2017-02-23 14:14:47 -0500319 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500320
321 if (surface->getConfig()->depthSize > 0)
322 {
Jamie Madilla02315b2017-02-23 14:14:47 -0500323 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500324 }
325
326 if (surface->getConfig()->stencilSize > 0)
327 {
Jamie Madilla02315b2017-02-23 14:14:47 -0500328 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, gl::ImageIndex::MakeInvalid(),
329 surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500330 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331}
332
Corentin Wallezccab69d2017-01-27 16:57:15 -0500333Framebuffer::Framebuffer(rx::GLImplFactory *factory)
334 : mState(),
335 mImpl(factory->createFramebuffer(mState)),
336 mId(0),
337 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
338 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
339 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
340{
Jamie Madill1e5499d2017-04-05 11:22:16 -0400341 mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
Corentin Wallezccab69d2017-01-27 16:57:15 -0500342}
343
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344Framebuffer::~Framebuffer()
345{
Geoff Langda88add2014-12-01 10:22:01 -0500346 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000347}
348
Jamie Madill6c1f6712017-02-14 19:08:04 -0500349void Framebuffer::destroy(const Context *context)
350{
351 mImpl->destroy(rx::SafeGetImpl(context));
352}
353
354void Framebuffer::destroyDefault(const egl::Display *display)
355{
356 mImpl->destroyDefault(rx::SafeGetImpl(display));
357}
358
Geoff Lang70d0f492015-12-10 17:45:46 -0500359void Framebuffer::setLabel(const std::string &label)
360{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400361 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500362}
363
364const std::string &Framebuffer::getLabel() const
365{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400366 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500367}
368
Jamie Madilla02315b2017-02-23 14:14:47 -0500369void Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370{
Jamie Madilla02315b2017-02-23 14:14:47 -0500371 detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372}
373
Jamie Madilla02315b2017-02-23 14:14:47 -0500374void Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000375{
Jamie Madilla02315b2017-02-23 14:14:47 -0500376 detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500377}
Jamie Madille261b442014-06-25 12:42:21 -0400378
Jamie Madilla02315b2017-02-23 14:14:47 -0500379void Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500380{
Jamie Madill362876b2016-06-16 14:46:59 -0400381 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500382 {
Jamie Madill362876b2016-06-16 14:46:59 -0400383 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
384 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385 }
386
Jamie Madilla02315b2017-02-23 14:14:47 -0500387 if (context->isWebGL1())
388 {
389 const std::array<FramebufferAttachment *, 3> attachments = {
390 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
391 &mState.mWebGLStencilAttachment}};
392 for (FramebufferAttachment *attachment : attachments)
393 {
394 if (attachment->isAttached() && attachment->type() == resourceType &&
395 attachment->id() == resourceId)
396 {
397 resetAttachment(context, attachment->getBinding());
398 }
399 }
400 }
401 else
402 {
403 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
404 DIRTY_BIT_DEPTH_ATTACHMENT);
405 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
406 DIRTY_BIT_STENCIL_ATTACHMENT);
407 }
Jamie Madill362876b2016-06-16 14:46:59 -0400408}
409
410void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
411 GLenum matchType,
412 GLuint matchId,
413 size_t dirtyBit)
414{
415 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
416 {
417 attachment->detach();
418 mDirtyBits.set(dirtyBit);
419 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420}
421
Corentin Wallez37c39792015-08-20 14:19:46 -0400422const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000423{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400424 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425}
426
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400427const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400428{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400429 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400430}
431
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400432const FramebufferAttachment *Framebuffer::getStencilbuffer() const
433{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400434 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400435}
436
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400437const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
438{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400439 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400440}
441
442const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000443{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400444 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000445}
446
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500447const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
448{
449 return mState.getStencilOrDepthStencilAttachment();
450}
451
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400452const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000453{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400454 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000455}
456
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000457GLenum Framebuffer::getReadColorbufferType() const
458{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400459 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400460 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000461}
462
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400463const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000464{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400465 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000466}
467
Jamie Madill2d06b732015-04-20 12:53:28 -0400468const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000469{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400470 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400471}
472
Geoff Langa15472a2015-08-11 11:48:03 -0400473size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000474{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400475 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400476}
477
478GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
479{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400480 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
481 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000482}
483
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500484const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
485{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400486 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500487}
488
Geoff Lang164d54e2014-12-01 10:55:33 -0500489void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000490{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400491 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500492
493 ASSERT(count <= drawStates.size());
494 std::copy(buffers, buffers + count, drawStates.begin());
495 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500496 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500497
498 mState.mEnabledDrawBuffers.reset();
499 for (size_t index = 0; index < count; ++index)
500 {
501 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
502 {
503 mState.mEnabledDrawBuffers.set(index);
504 }
505 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500506}
507
Geoff Langa15472a2015-08-11 11:48:03 -0400508const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
509{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400510 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400511}
512
513bool Framebuffer::hasEnabledDrawBuffer() const
514{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400515 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400516 {
517 if (getDrawBuffer(drawbufferIdx) != nullptr)
518 {
519 return true;
520 }
521 }
522
523 return false;
524}
525
Geoff Lang9dd95802014-12-01 11:12:59 -0500526GLenum Framebuffer::getReadBufferState() const
527{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400528 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500529}
530
531void Framebuffer::setReadBuffer(GLenum buffer)
532{
Jamie Madillb885e572015-02-03 16:16:04 -0500533 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
534 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400535 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
536 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500537 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000538}
539
Corentin Wallez37c39792015-08-20 14:19:46 -0400540size_t Framebuffer::getNumColorBuffers() const
541{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400542 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400543}
544
Jamie Madill0df8fe42015-11-24 16:10:24 -0500545bool Framebuffer::hasDepth() const
546{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400547 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500548}
549
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000550bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000551{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400552 return (mState.mStencilAttachment.isAttached() &&
553 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000554}
555
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000556bool Framebuffer::usingExtendedDrawBuffers() const
557{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400558 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000559 {
Geoff Langa15472a2015-08-11 11:48:03 -0400560 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000561 {
562 return true;
563 }
564 }
565
566 return false;
567}
568
Geoff Lang9aded172017-04-05 11:07:56 -0400569void Framebuffer::invalidateCompletenessCache()
570{
571 if (mId != 0)
572 {
573 mCachedStatus.reset();
574 }
575}
576
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400577GLenum Framebuffer::checkStatus(const Context *context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000578{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500579 // The default framebuffer is always complete except when it is surfaceless in which
580 // case it is always unsupported. We return early because the default framebuffer may
581 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500582 if (mId == 0)
583 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500584 ASSERT(mCachedStatus.valid());
585 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
586 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
587 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500588 }
589
Jamie Madill362876b2016-06-16 14:46:59 -0400590 if (hasAnyDirtyBit() || !mCachedStatus.valid())
591 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400592 mCachedStatus = checkStatusImpl(context);
Jamie Madill362876b2016-06-16 14:46:59 -0400593 }
594
595 return mCachedStatus.value();
596}
597
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400598GLenum Framebuffer::checkStatusImpl(const Context *context)
Jamie Madill362876b2016-06-16 14:46:59 -0400599{
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400600 const ContextState &state = context->getContextState();
601
Jamie Madill362876b2016-06-16 14:46:59 -0400602 ASSERT(mId != 0);
603
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000604 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000605 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000606 bool missingAttachment = true;
JiangYizhou461d9a32017-01-04 16:37:26 +0800607 Optional<GLboolean> fixedSampleLocations;
608 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000609
Jamie Madill48ef11b2016-04-27 15:21:52 -0400610 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400612 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000613 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500614 const Extents &size = colorAttachment.getSize();
615 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000616 {
617 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
618 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000619
Jamie Madilla3944d42016-07-22 22:13:26 -0400620 const Format &format = colorAttachment.getFormat();
621 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400622 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000623 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400624 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000625 {
Jamie Madill81176782015-11-24 16:10:23 -0500626 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000627 }
628
Jamie Madilla3944d42016-07-22 22:13:26 -0400629 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000630 {
631 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
632 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500633
634 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;
Jamie Madilla3944d42016-07-22 22:13:26 -0400667 if (!formatCaps.renderable || format.info->depthBits > 0 ||
668 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400669 {
670 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
671 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000672 }
673
674 if (!missingAttachment)
675 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000676 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
677 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400678 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000679 {
680 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
681 }
682
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000683 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
684 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300685 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000686 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400687 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000688 {
689 return GL_FRAMEBUFFER_UNSUPPORTED;
690 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000691 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000692 }
693 else
694 {
JiangYizhou461d9a32017-01-04 16:37:26 +0800695 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400696 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000697 missingAttachment = false;
698 }
699 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000700 }
701
Jamie Madill48ef11b2016-04-27 15:21:52 -0400702 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400703 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000704 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500705 const Extents &size = depthAttachment.getSize();
706 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000707 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000708 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000709 }
710
Jamie Madilla3944d42016-07-22 22:13:26 -0400711 const Format &format = depthAttachment.getFormat();
712 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400713 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000714 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400715 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400716 {
Jamie Madill81176782015-11-24 16:10:23 -0500717 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400718 }
719
Jamie Madilla3944d42016-07-22 22:13:26 -0400720 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000721 {
722 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
723 }
724 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400725 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000726 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400727 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400728 {
729 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
730 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000731 }
732
733 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000734 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400735 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000736 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000737 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400738 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000739 {
Sami Väisänena797e062016-05-12 15:23:40 +0300740 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
741 // considered complete when its depth or stencil samples are a
742 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700743 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300744 if (!mixedSamples)
745 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
746
747 const int colorSamples = samples ? samples : 1;
748 const int depthSamples = depthAttachment.getSamples();
749 if ((depthSamples % colorSamples) != 0)
750 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000751 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000752 }
753
Jamie Madill48ef11b2016-04-27 15:21:52 -0400754 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400755 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000756 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500757 const Extents &size = stencilAttachment.getSize();
758 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000759 {
760 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
761 }
762
Jamie Madilla3944d42016-07-22 22:13:26 -0400763 const Format &format = stencilAttachment.getFormat();
764 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400765 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000766 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400767 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400768 {
Jamie Madill81176782015-11-24 16:10:23 -0500769 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400770 }
771
Jamie Madilla3944d42016-07-22 22:13:26 -0400772 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000773 {
774 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
775 }
776 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400777 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000778 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400779 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400780 {
781 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
782 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000783 }
784
785 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000786 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400787 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000788 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000789 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400790 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000791 {
Sami Väisänena797e062016-05-12 15:23:40 +0300792 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700793 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300794 if (!mixedSamples)
795 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
796
797 const int colorSamples = samples ? samples : 1;
798 const int stencilSamples = stencilAttachment.getSamples();
799 if ((stencilSamples % colorSamples) != 0)
800 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000801 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400802
803 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300804 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400805 stencilAttachment != depthAttachment)
806 {
807 return GL_FRAMEBUFFER_UNSUPPORTED;
808 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000809 }
810
Jamie Madilla02315b2017-02-23 14:14:47 -0500811 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
812 if (state.isWebGL1())
813 {
814 if (!mState.mWebGLDepthStencilConsistent)
815 {
816 return GL_FRAMEBUFFER_UNSUPPORTED;
817 }
818
819 if (mState.mWebGLDepthStencilAttachment.isAttached())
820 {
821 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
822 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
823 {
824 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
825 }
826 }
827 else if (mState.mStencilAttachment.isAttached() &&
828 mState.mStencilAttachment.getDepthSize() > 0)
829 {
830 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
831 }
832 else if (mState.mDepthAttachment.isAttached() &&
833 mState.mDepthAttachment.getStencilSize() > 0)
834 {
835 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
836 }
837 }
838
JiangYizhou461d9a32017-01-04 16:37:26 +0800839 // ES3.1(section 9.4) requires that if no image is attached to the
840 // framebuffer, and either the value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH
841 // or FRAMEBUFFER_DEFAULT_HEIGHT parameters is zero, the framebuffer is
842 // considered incomplete.
843 GLint defaultWidth = mState.getDefaultWidth();
844 GLint defaultHeight = mState.getDefaultHeight();
845
846 if (missingAttachment && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000847 {
848 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000849 }
850
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400851 // In ES 2.0 and WebGL, all color attachments must have the same width and height.
Jamie Madillcc86d642015-11-24 13:00:07 -0500852 // In ES 3.0, there is no such restriction.
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400853 if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) &&
854 !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500855 {
856 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
857 }
858
JiangYizhou461d9a32017-01-04 16:37:26 +0800859 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers
860 // and textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all
861 // attached textures.
862 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
863 {
864 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
865 }
866
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400867 syncState(context);
Jamie Madillcc86d642015-11-24 13:00:07 -0500868 if (!mImpl->checkStatus())
869 {
870 return GL_FRAMEBUFFER_UNSUPPORTED;
871 }
872
873 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000874}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000875
Austin Kinross08332632015-05-05 13:35:47 -0700876Error Framebuffer::discard(size_t count, const GLenum *attachments)
877{
878 return mImpl->discard(count, attachments);
879}
880
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500881Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400882{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500883 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400884}
885
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500886Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400887{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500888 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400889}
890
Jamie Madill8415b5f2016-04-26 13:41:39 -0400891Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500892{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700893 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500894 {
Jamie Madill362876b2016-06-16 14:46:59 -0400895 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500896 }
897
Jamie Madill8415b5f2016-04-26 13:41:39 -0400898 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500899}
900
Jamie Madill8415b5f2016-04-26 13:41:39 -0400901Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400902 GLenum buffer,
903 GLint drawbuffer,
904 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500905{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700906 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500907 {
Jamie Madill362876b2016-06-16 14:46:59 -0400908 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500909 }
910
Jamie Madill8415b5f2016-04-26 13:41:39 -0400911 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500912}
913
Jamie Madill8415b5f2016-04-26 13:41:39 -0400914Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400915 GLenum buffer,
916 GLint drawbuffer,
917 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500918{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700919 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500920 {
Jamie Madill362876b2016-06-16 14:46:59 -0400921 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500922 }
923
Jamie Madill8415b5f2016-04-26 13:41:39 -0400924 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500925}
926
Jamie Madill8415b5f2016-04-26 13:41:39 -0400927Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400928 GLenum buffer,
929 GLint drawbuffer,
930 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500931{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700932 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500933 {
Jamie Madill362876b2016-06-16 14:46:59 -0400934 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500935 }
936
Jamie Madill8415b5f2016-04-26 13:41:39 -0400937 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500938}
939
Jamie Madill8415b5f2016-04-26 13:41:39 -0400940Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400941 GLenum buffer,
942 GLint drawbuffer,
943 GLfloat depth,
944 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500945{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700946 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500947 {
Jamie Madill362876b2016-06-16 14:46:59 -0400948 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500949 }
950
Jamie Madill8415b5f2016-04-26 13:41:39 -0400951 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500952}
953
Geoff Langbce529e2014-12-01 12:48:41 -0500954GLenum Framebuffer::getImplementationColorReadFormat() const
955{
956 return mImpl->getImplementationColorReadFormat();
957}
958
959GLenum Framebuffer::getImplementationColorReadType() const
960{
961 return mImpl->getImplementationColorReadType();
962}
963
Jamie Madill8415b5f2016-04-26 13:41:39 -0400964Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500965 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400966 GLenum format,
967 GLenum type,
968 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500969{
Jamie Madill362876b2016-06-16 14:46:59 -0400970 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400971
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700972 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400973 if (unpackBuffer)
974 {
975 unpackBuffer->onPixelUnpack();
976 }
977
Jamie Madill362876b2016-06-16 14:46:59 -0400978 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500979}
980
Jamie Madill8415b5f2016-04-26 13:41:39 -0400981Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500982 const Rectangle &sourceArea,
983 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400984 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400985 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500986{
He Yunchao6be602d2016-12-22 14:33:07 +0800987 GLbitfield blitMask = mask;
988
989 // Note that blitting is called against draw framebuffer.
990 // See the code in gl::Context::blitFramebuffer.
991 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
992 {
993 blitMask &= ~GL_COLOR_BUFFER_BIT;
994 }
995
996 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
997 {
998 blitMask &= ~GL_STENCIL_BUFFER_BIT;
999 }
1000
1001 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
1002 {
1003 blitMask &= ~GL_DEPTH_BUFFER_BIT;
1004 }
1005
1006 if (!blitMask)
1007 {
1008 return NoError();
1009 }
1010
1011 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001012}
1013
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001014int Framebuffer::getSamples(const Context *context)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001015{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001016 if (complete(context))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001017 {
Jamie Madill362876b2016-06-16 14:46:59 -04001018 // For a complete framebuffer, all attachments must have the same sample count.
1019 // In this case return the first nonzero sample size.
1020 const auto *firstColorAttachment = mState.getFirstColorAttachment();
1021 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001022 {
Jamie Madill362876b2016-06-16 14:46:59 -04001023 ASSERT(firstColorAttachment->isAttached());
1024 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001025 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001026 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001027
1028 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001029}
1030
Corentin Wallezccab69d2017-01-27 16:57:15 -05001031Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1032{
1033 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
1034 return gl::NoError();
1035}
1036
Jamie Madille261b442014-06-25 12:42:21 -04001037bool Framebuffer::hasValidDepthStencil() const
1038{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001039 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001040}
1041
Jamie Madilla02315b2017-02-23 14:14:47 -05001042void Framebuffer::setAttachment(const Context *context,
1043 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001044 GLenum binding,
1045 const ImageIndex &textureIndex,
1046 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001047{
Jamie Madilla02315b2017-02-23 14:14:47 -05001048 // Context may be null in unit tests.
1049 if (!context || !context->isWebGL1())
1050 {
1051 setAttachmentImpl(type, binding, textureIndex, resource);
1052 return;
1053 }
1054
1055 switch (binding)
1056 {
1057 case GL_DEPTH_STENCIL:
1058 case GL_DEPTH_STENCIL_ATTACHMENT:
1059 mState.mWebGLDepthStencilAttachment.attach(type, binding, textureIndex, resource);
1060 break;
1061 case GL_DEPTH:
1062 case GL_DEPTH_ATTACHMENT:
1063 mState.mWebGLDepthAttachment.attach(type, binding, textureIndex, resource);
1064 break;
1065 case GL_STENCIL:
1066 case GL_STENCIL_ATTACHMENT:
1067 mState.mWebGLStencilAttachment.attach(type, binding, textureIndex, resource);
1068 break;
1069 default:
1070 setAttachmentImpl(type, binding, textureIndex, resource);
1071 return;
1072 }
1073
1074 commitWebGL1DepthStencilIfConsistent();
1075}
1076
1077void Framebuffer::commitWebGL1DepthStencilIfConsistent()
1078{
1079 int count = 0;
1080
1081 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1082 &mState.mWebGLDepthAttachment,
1083 &mState.mWebGLStencilAttachment}};
1084 for (FramebufferAttachment *attachment : attachments)
1085 {
1086 if (attachment->isAttached())
1087 {
1088 count++;
1089 }
1090 }
1091
1092 mState.mWebGLDepthStencilConsistent = (count <= 1);
1093 if (!mState.mWebGLDepthStencilConsistent)
1094 {
1095 // Inconsistent.
1096 return;
1097 }
1098
Geoff Lange466c552017-03-17 15:24:12 -04001099 auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) {
1100 if (attachment.type() == GL_TEXTURE)
1101 {
1102 return attachment.getTextureImageIndex();
1103 }
1104 else
1105 {
1106 return ImageIndex::MakeInvalid();
1107 }
1108 };
1109
Jamie Madilla02315b2017-02-23 14:14:47 -05001110 if (mState.mWebGLDepthAttachment.isAttached())
1111 {
1112 const auto &depth = mState.mWebGLDepthAttachment;
Geoff Lange466c552017-03-17 15:24:12 -04001113 setAttachmentImpl(depth.type(), GL_DEPTH_ATTACHMENT,
1114 getImageIndexIfTextureAttachment(depth), depth.getResource());
Jamie Madilla02315b2017-02-23 14:14:47 -05001115 setAttachmentImpl(GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1116 }
1117 else if (mState.mWebGLStencilAttachment.isAttached())
1118 {
1119 const auto &stencil = mState.mWebGLStencilAttachment;
1120 setAttachmentImpl(GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
Geoff Lange466c552017-03-17 15:24:12 -04001121 setAttachmentImpl(stencil.type(), GL_STENCIL_ATTACHMENT,
1122 getImageIndexIfTextureAttachment(stencil), stencil.getResource());
Jamie Madilla02315b2017-02-23 14:14:47 -05001123 }
1124 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1125 {
1126 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
Geoff Lange466c552017-03-17 15:24:12 -04001127 setAttachmentImpl(depthStencil.type(), GL_DEPTH_ATTACHMENT,
1128 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001129 depthStencil.getResource());
Geoff Lange466c552017-03-17 15:24:12 -04001130 setAttachmentImpl(depthStencil.type(), GL_STENCIL_ATTACHMENT,
1131 getImageIndexIfTextureAttachment(depthStencil),
Jamie Madilla02315b2017-02-23 14:14:47 -05001132 depthStencil.getResource());
1133 }
1134 else
1135 {
1136 setAttachmentImpl(GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1137 setAttachmentImpl(GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1138 }
1139}
1140
1141void Framebuffer::setAttachmentImpl(GLenum type,
1142 GLenum binding,
1143 const ImageIndex &textureIndex,
1144 FramebufferAttachmentObject *resource)
1145{
Jamie Madilla02315b2017-02-23 14:14:47 -05001146 switch (binding)
1147 {
Jamie Madillb8126692017-04-05 11:22:17 -04001148 case GL_DEPTH_STENCIL:
1149 case GL_DEPTH_STENCIL_ATTACHMENT:
1150 {
1151 // ensure this is a legitimate depth+stencil format
1152 FramebufferAttachmentObject *attachmentObj = resource;
1153 if (resource)
1154 {
1155 FramebufferAttachment::Target target(binding, textureIndex);
1156 const Format &format = resource->getAttachmentFormat(target);
1157 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
1158 {
1159 // Attaching nullptr detaches the current attachment.
1160 attachmentObj = nullptr;
1161 }
1162 }
1163
1164 updateAttachment(&mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1165 &mDirtyDepthAttachmentBinding, type, binding, textureIndex,
1166 attachmentObj);
1167 updateAttachment(&mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1168 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1169 attachmentObj);
1170 return;
1171 }
1172
Jamie Madilla02315b2017-02-23 14:14:47 -05001173 case GL_DEPTH:
1174 case GL_DEPTH_ATTACHMENT:
Jamie Madillb8126692017-04-05 11:22:17 -04001175 updateAttachment(&mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
1176 &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource);
Jamie Madill2d06b732015-04-20 12:53:28 -04001177 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001178
Jamie Madilla02315b2017-02-23 14:14:47 -05001179 case GL_STENCIL:
1180 case GL_STENCIL_ATTACHMENT:
Jamie Madillb8126692017-04-05 11:22:17 -04001181 updateAttachment(&mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
1182 &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
1183 resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001184 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001185
Jamie Madilla02315b2017-02-23 14:14:47 -05001186 case GL_BACK:
1187 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
1188 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1189 // No need for a resource binding for the default FBO, it's always complete.
1190 break;
Jamie Madillb8126692017-04-05 11:22:17 -04001191
Jamie Madilla02315b2017-02-23 14:14:47 -05001192 default:
1193 {
1194 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1195 ASSERT(colorIndex < mState.mColorAttachments.size());
Jamie Madillb8126692017-04-05 11:22:17 -04001196 size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
1197 updateAttachment(&mState.mColorAttachments[colorIndex], dirtyBit,
1198 &mDirtyColorAttachmentBindings[colorIndex], type, binding,
1199 textureIndex, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001200
1201 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1202 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001203 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001204 break;
Geoff Langab75a052014-10-15 12:56:37 -04001205 }
1206}
1207
Jamie Madillb8126692017-04-05 11:22:17 -04001208void Framebuffer::updateAttachment(FramebufferAttachment *attachment,
1209 size_t dirtyBit,
1210 OnAttachmentDirtyBinding *onDirtyBinding,
1211 GLenum type,
1212 GLenum binding,
1213 const ImageIndex &textureIndex,
1214 FramebufferAttachmentObject *resource)
1215{
1216 attachment->attach(type, binding, textureIndex, resource);
1217 mDirtyBits.set(dirtyBit);
1218 BindResourceChannel(onDirtyBinding, resource);
1219}
1220
Jamie Madilla02315b2017-02-23 14:14:47 -05001221void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001222{
Jamie Madilla02315b2017-02-23 14:14:47 -05001223 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001224}
1225
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001226void Framebuffer::syncState(const Context *context)
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001227{
1228 if (mDirtyBits.any())
1229 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001230 mImpl->syncState(rx::SafeGetImpl(context), mDirtyBits);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001231 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001232 if (mId != 0)
1233 {
1234 mCachedStatus.reset();
1235 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001236 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001237}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001238
Jamie Madill1e5499d2017-04-05 11:22:16 -04001239void Framebuffer::signal(uint32_t token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001240{
Jamie Madill362876b2016-06-16 14:46:59 -04001241 // TOOD(jmadill): Make this only update individual attachments to do less work.
1242 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001243}
1244
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001245bool Framebuffer::complete(const Context *context)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001246{
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001247 return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
1248}
1249
1250bool Framebuffer::cachedComplete() const
1251{
1252 return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001253}
1254
Jamie Madilla4595b82017-01-11 17:36:34 -05001255bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1256{
1257 const Program *program = state.getProgram();
1258
1259 // TODO(jmadill): Default framebuffer feedback loops.
1260 if (mId == 0)
1261 {
1262 return false;
1263 }
1264
1265 // The bitset will skip inactive draw buffers.
1266 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1267 {
1268 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1269 if (attachment && attachment->type() == GL_TEXTURE)
1270 {
1271 // Validate the feedback loop.
1272 if (program->samplesFromTexture(state, attachment->id()))
1273 {
1274 return true;
1275 }
1276 }
1277 }
1278
Jamie Madill1d37bc52017-02-02 19:59:58 -05001279 // Validate depth-stencil feedback loop.
1280 const auto &dsState = state.getDepthStencilState();
1281
1282 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1283 const FramebufferAttachment *depth = getDepthbuffer();
1284 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1285 {
1286 if (program->samplesFromTexture(state, depth->id()))
1287 {
1288 return true;
1289 }
1290 }
1291
1292 // Note: we assume the front and back masks are the same for WebGL.
1293 const FramebufferAttachment *stencil = getStencilbuffer();
1294 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1295 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1296 dsState.stencilWritemask != 0)
1297 {
1298 // Skip the feedback loop check if depth/stencil point to the same resource.
1299 if (!depth || *stencil != *depth)
1300 {
1301 if (program->samplesFromTexture(state, stencil->id()))
1302 {
1303 return true;
1304 }
1305 }
1306 }
1307
Jamie Madilla4595b82017-01-11 17:36:34 -05001308 return false;
1309}
1310
Jamie Madillfd3dd432017-02-02 19:59:59 -05001311bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1312 GLint copyTextureLevel,
1313 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001314{
1315 if (mId == 0)
1316 {
1317 // It seems impossible to form a texture copying feedback loop with the default FBO.
1318 return false;
1319 }
1320
1321 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1322 ASSERT(readAttachment);
1323
1324 if (readAttachment->isTextureWithId(copyTextureID))
1325 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001326 const auto &imageIndex = readAttachment->getTextureImageIndex();
1327 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001328 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001329 // Check 3D/Array texture layers.
1330 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1331 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1332 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001333 }
1334 }
1335 return false;
1336}
1337
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001338GLint Framebuffer::getDefaultWidth() const
1339{
1340 return mState.getDefaultWidth();
1341}
1342
1343GLint Framebuffer::getDefaultHeight() const
1344{
1345 return mState.getDefaultHeight();
1346}
1347
1348GLint Framebuffer::getDefaultSamples() const
1349{
1350 return mState.getDefaultSamples();
1351}
1352
1353GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1354{
1355 return mState.getDefaultFixedSampleLocations();
1356}
1357
1358void Framebuffer::setDefaultWidth(GLint defaultWidth)
1359{
1360 mState.mDefaultWidth = defaultWidth;
1361 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1362}
1363
1364void Framebuffer::setDefaultHeight(GLint defaultHeight)
1365{
1366 mState.mDefaultHeight = defaultHeight;
1367 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1368}
1369
1370void Framebuffer::setDefaultSamples(GLint defaultSamples)
1371{
1372 mState.mDefaultSamples = defaultSamples;
1373 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1374}
1375
1376void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1377{
1378 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1379 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1380}
1381
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001382// TODO(jmadill): Remove this kludge.
1383GLenum Framebuffer::checkStatus(const ValidationContext *context)
1384{
1385 return checkStatus(static_cast<const Context *>(context));
1386}
1387
1388int Framebuffer::getSamples(const ValidationContext *context)
1389{
1390 return getSamples(static_cast<const Context *>(context));
1391}
1392
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001393} // namespace gl