blob: 5ab77ad27bf3a5572087179dca5807b8cf53d949 [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 Madilla4595b82017-01-11 17:36:34 -050012#include "common/BitSetIterator.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"
Geoff Lang2b5420c2014-11-19 14:20:15 -050017#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040018#include "libANGLE/Renderbuffer.h"
19#include "libANGLE/Surface.h"
20#include "libANGLE/Texture.h"
21#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040022#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050023#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040024#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050025#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040026#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040027
Jamie Madill362876b2016-06-16 14:46:59 -040028using namespace angle;
29
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030namespace gl
31{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000032
Jamie Madilld1405e52015-03-05 15:41:39 -050033namespace
34{
Jamie Madill362876b2016-06-16 14:46:59 -040035
36void BindResourceChannel(ChannelBinding *binding, FramebufferAttachmentObject *resource)
Jamie Madilld1405e52015-03-05 15:41:39 -050037{
Jamie Madill362876b2016-06-16 14:46:59 -040038 binding->bind(resource ? resource->getDirtyChannel() : nullptr);
Jamie Madilld1405e52015-03-05 15:41:39 -050039}
Jamie Madill362876b2016-06-16 14:46:59 -040040
41} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -050042
Jamie Madill48ef11b2016-04-27 15:21:52 -040043FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -050044 : mLabel(),
45 mColorAttachments(1),
Corentin Wallez37c39792015-08-20 14:19:46 -040046 mDrawBufferStates(1, GL_NONE),
47 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
48{
49 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
Jamie Madilla4595b82017-01-11 17:36:34 -050050 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -040051}
52
Jamie Madill48ef11b2016-04-27 15:21:52 -040053FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -050054 : mLabel(),
55 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050056 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
57 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
58{
Geoff Langa15472a2015-08-11 11:48:03 -040059 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -050060 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
61}
62
Jamie Madill48ef11b2016-04-27 15:21:52 -040063FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -050064{
Jamie Madilld1405e52015-03-05 15:41:39 -050065}
66
Jamie Madill48ef11b2016-04-27 15:21:52 -040067const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -050068{
69 return mLabel;
70}
71
Geoff Lang4b7f12b2016-06-21 16:47:07 -040072const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
73{
74 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
75 {
76 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
77 }
78
79 switch (attachment)
80 {
81 case GL_COLOR:
82 case GL_BACK:
83 return getColorAttachment(0);
84 case GL_DEPTH:
85 case GL_DEPTH_ATTACHMENT:
86 return getDepthAttachment();
87 case GL_STENCIL:
88 case GL_STENCIL_ATTACHMENT:
89 return getStencilAttachment();
90 case GL_DEPTH_STENCIL:
91 case GL_DEPTH_STENCIL_ATTACHMENT:
92 return getDepthStencilAttachment();
93 default:
94 UNREACHABLE();
95 return nullptr;
96 }
97}
98
Jamie Madill48ef11b2016-04-27 15:21:52 -040099const FramebufferAttachment *FramebufferState::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500100{
Antoine Labour2ec65dc2016-11-30 16:28:58 -0800101 if (mReadBufferState == GL_NONE)
102 {
103 return nullptr;
104 }
Jamie Madill7147f012015-03-05 15:41:40 -0500105 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
106 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
107 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400108 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500109}
110
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500111const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
112{
113 auto *colorAttachment = getFirstColorAttachment();
114 if (colorAttachment)
115 {
116 return colorAttachment;
117 }
118 return getDepthOrStencilAttachment();
119}
120
Jamie Madill48ef11b2016-04-27 15:21:52 -0400121const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500122{
Jamie Madill2d06b732015-04-20 12:53:28 -0400123 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500124 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400125 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500126 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400127 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500128 }
129 }
130
131 return nullptr;
132}
133
Jamie Madill48ef11b2016-04-27 15:21:52 -0400134const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500135{
Jamie Madill2d06b732015-04-20 12:53:28 -0400136 if (mDepthAttachment.isAttached())
137 {
138 return &mDepthAttachment;
139 }
140 if (mStencilAttachment.isAttached())
141 {
142 return &mStencilAttachment;
143 }
144 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500145}
146
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500147const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
148{
149 if (mStencilAttachment.isAttached())
150 {
151 return &mStencilAttachment;
152 }
153 return getDepthStencilAttachment();
154}
155
Jamie Madill48ef11b2016-04-27 15:21:52 -0400156const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400157{
158 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400159 return mColorAttachments[colorAttachment].isAttached() ?
160 &mColorAttachments[colorAttachment] :
161 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400162}
163
Jamie Madill48ef11b2016-04-27 15:21:52 -0400164const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400165{
Jamie Madill2d06b732015-04-20 12:53:28 -0400166 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400167}
168
Jamie Madill48ef11b2016-04-27 15:21:52 -0400169const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400170{
Jamie Madill2d06b732015-04-20 12:53:28 -0400171 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400172}
173
Jamie Madill48ef11b2016-04-27 15:21:52 -0400174const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400175{
176 // A valid depth-stencil attachment has the same resource bound to both the
177 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400178 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500179 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400180 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400181 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400182 }
183
184 return nullptr;
185}
186
Jamie Madill48ef11b2016-04-27 15:21:52 -0400187bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500188{
189 Optional<Extents> attachmentSize;
190
191 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
192 {
193 if (!attachment.isAttached())
194 {
195 return false;
196 }
197
198 if (!attachmentSize.valid())
199 {
200 attachmentSize = attachment.getSize();
201 return false;
202 }
203
204 return (attachment.getSize() != attachmentSize.value());
205 };
206
207 for (const auto &attachment : mColorAttachments)
208 {
209 if (hasMismatchedSize(attachment))
210 {
211 return false;
212 }
213 }
214
215 if (hasMismatchedSize(mDepthAttachment))
216 {
217 return false;
218 }
219
220 return !hasMismatchedSize(mStencilAttachment);
221}
222
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400223const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
224{
225 ASSERT(drawBufferIdx < mDrawBufferStates.size());
226 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
227 {
228 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
229 // must be COLOR_ATTACHMENTi or NONE"
230 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
231 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
232 return getAttachment(mDrawBufferStates[drawBufferIdx]);
233 }
234 else
235 {
236 return nullptr;
237 }
238}
239
240size_t FramebufferState::getDrawBufferCount() const
241{
242 return mDrawBufferStates.size();
243}
244
JiangYizhoubddc46b2016-12-09 09:50:51 +0800245Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
246{
247 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
248 return gl::NoError();
249}
250
Geoff Langb21e20d2016-07-19 15:35:41 -0400251bool FramebufferState::colorAttachmentsAreUniqueImages() const
252{
253 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
254 firstAttachmentIdx++)
255 {
256 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
257 if (!firstAttachment.isAttached())
258 {
259 continue;
260 }
261
262 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
263 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
264 {
265 const gl::FramebufferAttachment &secondAttachment =
266 mColorAttachments[secondAttachmentIdx];
267 if (!secondAttachment.isAttached())
268 {
269 continue;
270 }
271
272 if (firstAttachment == secondAttachment)
273 {
274 return false;
275 }
276 }
277 }
278
279 return true;
280}
281
Jamie Madill7aea7e02016-05-10 10:39:45 -0400282Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400283 : mState(caps),
284 mImpl(factory->createFramebuffer(mState)),
285 mId(id),
286 mCachedStatus(),
287 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
288 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289{
Corentin Wallez37c39792015-08-20 14:19:46 -0400290 ASSERT(mId != 0);
291 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400292 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
293
294 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
295 {
296 mDirtyColorAttachmentBindings.push_back(ChannelBinding(
297 this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
298 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400299}
300
301Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400302 : mState(),
303 mImpl(surface->createDefaultFramebuffer(mState)),
304 mId(0),
305 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
306 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
307 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400308{
Geoff Langda88add2014-12-01 10:22:01 -0500309 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400310 mDirtyColorAttachmentBindings.push_back(
311 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000312}
313
314Framebuffer::~Framebuffer()
315{
Geoff Langda88add2014-12-01 10:22:01 -0500316 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000317}
318
Geoff Lang70d0f492015-12-10 17:45:46 -0500319void Framebuffer::setLabel(const std::string &label)
320{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400321 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500322}
323
324const std::string &Framebuffer::getLabel() const
325{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400326 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500327}
328
Jamie Madille261b442014-06-25 12:42:21 -0400329void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330{
Jamie Madilld1405e52015-03-05 15:41:39 -0500331 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332}
333
Jamie Madille261b442014-06-25 12:42:21 -0400334void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335{
Jamie Madilld1405e52015-03-05 15:41:39 -0500336 detachResourceById(GL_RENDERBUFFER, renderbufferId);
337}
Jamie Madille261b442014-06-25 12:42:21 -0400338
Jamie Madilld1405e52015-03-05 15:41:39 -0500339void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
340{
Jamie Madill362876b2016-06-16 14:46:59 -0400341 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500342 {
Jamie Madill362876b2016-06-16 14:46:59 -0400343 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
344 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345 }
346
Jamie Madill362876b2016-06-16 14:46:59 -0400347 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
348 DIRTY_BIT_DEPTH_ATTACHMENT);
349 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
350 DIRTY_BIT_STENCIL_ATTACHMENT);
351}
352
353void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
354 GLenum matchType,
355 GLuint matchId,
356 size_t dirtyBit)
357{
358 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
359 {
360 attachment->detach();
361 mDirtyBits.set(dirtyBit);
362 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000363}
364
Corentin Wallez37c39792015-08-20 14:19:46 -0400365const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000366{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400367 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368}
369
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400370const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400371{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400372 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400373}
374
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400375const FramebufferAttachment *Framebuffer::getStencilbuffer() const
376{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400377 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400378}
379
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400380const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
381{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400382 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400383}
384
385const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000386{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400387 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000388}
389
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500390const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
391{
392 return mState.getStencilOrDepthStencilAttachment();
393}
394
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400395const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000396{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400397 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000398}
399
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000400GLenum Framebuffer::getReadColorbufferType() const
401{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400402 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400403 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000404}
405
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400406const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000407{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400408 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000409}
410
Jamie Madill2d06b732015-04-20 12:53:28 -0400411const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000412{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400413 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400414}
415
Geoff Langa15472a2015-08-11 11:48:03 -0400416size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000417{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400418 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400419}
420
421GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
422{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400423 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
424 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000425}
426
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500427const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
428{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400429 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500430}
431
Geoff Lang164d54e2014-12-01 10:55:33 -0500432void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000433{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400434 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500435
436 ASSERT(count <= drawStates.size());
437 std::copy(buffers, buffers + count, drawStates.begin());
438 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500439 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500440
441 mState.mEnabledDrawBuffers.reset();
442 for (size_t index = 0; index < count; ++index)
443 {
444 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
445 {
446 mState.mEnabledDrawBuffers.set(index);
447 }
448 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500449}
450
Geoff Langa15472a2015-08-11 11:48:03 -0400451const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
452{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400453 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400454}
455
456bool Framebuffer::hasEnabledDrawBuffer() const
457{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400458 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400459 {
460 if (getDrawBuffer(drawbufferIdx) != nullptr)
461 {
462 return true;
463 }
464 }
465
466 return false;
467}
468
Geoff Lang9dd95802014-12-01 11:12:59 -0500469GLenum Framebuffer::getReadBufferState() const
470{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400471 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500472}
473
474void Framebuffer::setReadBuffer(GLenum buffer)
475{
Jamie Madillb885e572015-02-03 16:16:04 -0500476 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
477 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400478 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
479 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500480 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000481}
482
Corentin Wallez37c39792015-08-20 14:19:46 -0400483size_t Framebuffer::getNumColorBuffers() const
484{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400485 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400486}
487
Jamie Madill0df8fe42015-11-24 16:10:24 -0500488bool Framebuffer::hasDepth() const
489{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400490 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500491}
492
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000493bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000494{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400495 return (mState.mStencilAttachment.isAttached() &&
496 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000497}
498
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000499bool Framebuffer::usingExtendedDrawBuffers() const
500{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400501 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000502 {
Geoff Langa15472a2015-08-11 11:48:03 -0400503 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000504 {
505 return true;
506 }
507 }
508
509 return false;
510}
511
Jamie Madill51f40ec2016-06-15 14:06:00 -0400512GLenum Framebuffer::checkStatus(const ContextState &state)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500514 // The default framebuffer *must* always be complete, though it may not be
515 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
516 if (mId == 0)
517 {
518 return GL_FRAMEBUFFER_COMPLETE;
519 }
520
Jamie Madill362876b2016-06-16 14:46:59 -0400521 if (hasAnyDirtyBit() || !mCachedStatus.valid())
522 {
523 mCachedStatus = checkStatusImpl(state);
524 }
525
526 return mCachedStatus.value();
527}
528
529GLenum Framebuffer::checkStatusImpl(const ContextState &state)
530{
531 ASSERT(mId != 0);
532
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000533 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000534 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000535 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000536
Jamie Madill48ef11b2016-04-27 15:21:52 -0400537 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000538 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400539 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000540 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500541 const Extents &size = colorAttachment.getSize();
542 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000543 {
544 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
545 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000546
Jamie Madilla3944d42016-07-22 22:13:26 -0400547 const Format &format = colorAttachment.getFormat();
548 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400549 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000550 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400551 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000552 {
Jamie Madill81176782015-11-24 16:10:23 -0500553 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000554 }
555
Jamie Madilla3944d42016-07-22 22:13:26 -0400556 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000557 {
558 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
559 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500560
561 if (colorAttachment.layer() >= size.depth)
562 {
563 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
564 }
Jamie Madill3215b202015-12-15 16:41:39 -0500565
566 // ES3 specifies that cube map texture attachments must be cube complete.
567 // This language is missing from the ES2 spec, but we enforce it here because some
568 // desktop OpenGL drivers also enforce this validation.
569 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
570 const Texture *texture = colorAttachment.getTexture();
571 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300572 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
573 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500574 {
575 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
576 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000577 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400578 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000579 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400580 if (!formatCaps.renderable || format.info->depthBits > 0 ||
581 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400582 {
583 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
584 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000585 }
586
587 if (!missingAttachment)
588 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000589 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
590 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400591 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000592 {
593 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
594 }
595
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000596 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
597 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300598 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000599 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400600 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000601 {
602 return GL_FRAMEBUFFER_UNSUPPORTED;
603 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000604 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000605 }
606 else
607 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400608 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400609 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000610 missingAttachment = false;
611 }
612 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000613 }
614
Jamie Madill48ef11b2016-04-27 15:21:52 -0400615 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400616 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000617 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500618 const Extents &size = depthAttachment.getSize();
619 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000621 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000622 }
623
Jamie Madilla3944d42016-07-22 22:13:26 -0400624 const Format &format = depthAttachment.getFormat();
625 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400626 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000627 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000628 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700629 if (!state.getExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000630 {
631 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
632 }
633
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400634 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400635 {
Jamie Madill81176782015-11-24 16:10:23 -0500636 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400637 }
638
Jamie Madilla3944d42016-07-22 22:13:26 -0400639 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000640 {
641 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
642 }
643 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400644 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000645 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400646 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400647 {
648 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
649 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000650 }
651
652 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000653 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400654 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000655 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000656 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400657 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000658 {
Sami Väisänena797e062016-05-12 15:23:40 +0300659 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
660 // considered complete when its depth or stencil samples are a
661 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700662 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300663 if (!mixedSamples)
664 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
665
666 const int colorSamples = samples ? samples : 1;
667 const int depthSamples = depthAttachment.getSamples();
668 if ((depthSamples % colorSamples) != 0)
669 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000670 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000671 }
672
Jamie Madill48ef11b2016-04-27 15:21:52 -0400673 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400674 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000675 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500676 const Extents &size = stencilAttachment.getSize();
677 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000678 {
679 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
680 }
681
Jamie Madilla3944d42016-07-22 22:13:26 -0400682 const Format &format = stencilAttachment.getFormat();
683 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400684 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000685 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000686 // texture stencil attachments come along as part
687 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700688 if (!state.getExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000689 {
690 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
691 }
692
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400693 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400694 {
Jamie Madill81176782015-11-24 16:10:23 -0500695 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400696 }
697
Jamie Madilla3944d42016-07-22 22:13:26 -0400698 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000699 {
700 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
701 }
702 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400703 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000704 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400705 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400706 {
707 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
708 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000709 }
710
711 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000712 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400713 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000714 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000715 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400716 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000717 {
Sami Väisänena797e062016-05-12 15:23:40 +0300718 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700719 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300720 if (!mixedSamples)
721 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
722
723 const int colorSamples = samples ? samples : 1;
724 const int stencilSamples = stencilAttachment.getSamples();
725 if ((stencilSamples % colorSamples) != 0)
726 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000727 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400728
729 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300730 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400731 stencilAttachment != depthAttachment)
732 {
733 return GL_FRAMEBUFFER_UNSUPPORTED;
734 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000735 }
736
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000737 // we need to have at least one attachment to be complete
738 if (missingAttachment)
739 {
740 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000741 }
742
Jamie Madillcc86d642015-11-24 13:00:07 -0500743 // In ES 2.0, all color attachments must have the same width and height.
744 // In ES 3.0, there is no such restriction.
Martin Radev1be913c2016-07-11 17:59:16 +0300745 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500746 {
747 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
748 }
749
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500750 syncState();
Jamie Madillcc86d642015-11-24 13:00:07 -0500751 if (!mImpl->checkStatus())
752 {
753 return GL_FRAMEBUFFER_UNSUPPORTED;
754 }
755
756 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000757}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000758
Austin Kinross08332632015-05-05 13:35:47 -0700759Error Framebuffer::discard(size_t count, const GLenum *attachments)
760{
761 return mImpl->discard(count, attachments);
762}
763
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500764Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400765{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500766 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400767}
768
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500769Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400770{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500771 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400772}
773
Jamie Madill8415b5f2016-04-26 13:41:39 -0400774Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500775{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700776 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500777 {
Jamie Madill362876b2016-06-16 14:46:59 -0400778 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500779 }
780
Jamie Madill8415b5f2016-04-26 13:41:39 -0400781 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500782}
783
Jamie Madill8415b5f2016-04-26 13:41:39 -0400784Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400785 GLenum buffer,
786 GLint drawbuffer,
787 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500788{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700789 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500790 {
Jamie Madill362876b2016-06-16 14:46:59 -0400791 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500792 }
793
Jamie Madill8415b5f2016-04-26 13:41:39 -0400794 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500795}
796
Jamie Madill8415b5f2016-04-26 13:41:39 -0400797Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400798 GLenum buffer,
799 GLint drawbuffer,
800 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500801{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700802 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500803 {
Jamie Madill362876b2016-06-16 14:46:59 -0400804 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500805 }
806
Jamie Madill8415b5f2016-04-26 13:41:39 -0400807 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500808}
809
Jamie Madill8415b5f2016-04-26 13:41:39 -0400810Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400811 GLenum buffer,
812 GLint drawbuffer,
813 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500814{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700815 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500816 {
Jamie Madill362876b2016-06-16 14:46:59 -0400817 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500818 }
819
Jamie Madill8415b5f2016-04-26 13:41:39 -0400820 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500821}
822
Jamie Madill8415b5f2016-04-26 13:41:39 -0400823Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400824 GLenum buffer,
825 GLint drawbuffer,
826 GLfloat depth,
827 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500828{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700829 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500830 {
Jamie Madill362876b2016-06-16 14:46:59 -0400831 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500832 }
833
Jamie Madill8415b5f2016-04-26 13:41:39 -0400834 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500835}
836
Geoff Langbce529e2014-12-01 12:48:41 -0500837GLenum Framebuffer::getImplementationColorReadFormat() const
838{
839 return mImpl->getImplementationColorReadFormat();
840}
841
842GLenum Framebuffer::getImplementationColorReadType() const
843{
844 return mImpl->getImplementationColorReadType();
845}
846
Jamie Madill8415b5f2016-04-26 13:41:39 -0400847Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500848 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400849 GLenum format,
850 GLenum type,
851 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500852{
Jamie Madill362876b2016-06-16 14:46:59 -0400853 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400854
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700855 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400856 if (unpackBuffer)
857 {
858 unpackBuffer->onPixelUnpack();
859 }
860
Jamie Madill362876b2016-06-16 14:46:59 -0400861 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500862}
863
Jamie Madill8415b5f2016-04-26 13:41:39 -0400864Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500865 const Rectangle &sourceArea,
866 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400867 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400868 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500869{
He Yunchao6be602d2016-12-22 14:33:07 +0800870 GLbitfield blitMask = mask;
871
872 // Note that blitting is called against draw framebuffer.
873 // See the code in gl::Context::blitFramebuffer.
874 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
875 {
876 blitMask &= ~GL_COLOR_BUFFER_BIT;
877 }
878
879 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
880 {
881 blitMask &= ~GL_STENCIL_BUFFER_BIT;
882 }
883
884 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
885 {
886 blitMask &= ~GL_DEPTH_BUFFER_BIT;
887 }
888
889 if (!blitMask)
890 {
891 return NoError();
892 }
893
894 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -0500895}
896
Jamie Madill51f40ec2016-06-15 14:06:00 -0400897int Framebuffer::getSamples(const ContextState &state)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000898{
Jamie Madill362876b2016-06-16 14:46:59 -0400899 if (complete(state))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000900 {
Jamie Madill362876b2016-06-16 14:46:59 -0400901 // For a complete framebuffer, all attachments must have the same sample count.
902 // In this case return the first nonzero sample size.
903 const auto *firstColorAttachment = mState.getFirstColorAttachment();
904 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000905 {
Jamie Madill362876b2016-06-16 14:46:59 -0400906 ASSERT(firstColorAttachment->isAttached());
907 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000908 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000909 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000910
911 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000912}
913
Jamie Madille261b442014-06-25 12:42:21 -0400914bool Framebuffer::hasValidDepthStencil() const
915{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400916 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400917}
918
Jamie Madill2d06b732015-04-20 12:53:28 -0400919void Framebuffer::setAttachment(GLenum type,
920 GLenum binding,
921 const ImageIndex &textureIndex,
922 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400923{
Jamie Madill2d06b732015-04-20 12:53:28 -0400924 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400925 {
Geoff Langab75a052014-10-15 12:56:37 -0400926 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400927 FramebufferAttachmentObject *attachmentObj = resource;
928 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400929 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400930 FramebufferAttachment::Target target(binding, textureIndex);
Jamie Madilla3944d42016-07-22 22:13:26 -0400931 const Format &format = resource->getAttachmentFormat(target);
932 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
Jamie Madill375c37c2015-07-21 15:14:08 -0400933 {
934 // Attaching nullptr detaches the current attachment.
935 attachmentObj = nullptr;
936 }
Geoff Langab75a052014-10-15 12:56:37 -0400937 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400938
Jamie Madill48ef11b2016-04-27 15:21:52 -0400939 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
940 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500941 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
942 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400943 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
944 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
Geoff Langab75a052014-10-15 12:56:37 -0400945 }
946 else
947 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400948 switch (binding)
949 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500950 case GL_DEPTH:
951 case GL_DEPTH_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400952 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500953 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400954 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
955 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500956 case GL_STENCIL:
957 case GL_STENCIL_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400958 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500959 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400960 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
961 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500962 case GL_BACK:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400963 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500964 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill362876b2016-06-16 14:46:59 -0400965 // No need for a resource binding for the default FBO, it's always complete.
966 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500967 default:
Jamie Madill2d06b732015-04-20 12:53:28 -0400968 {
969 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
Jamie Madill48ef11b2016-04-27 15:21:52 -0400970 ASSERT(colorIndex < mState.mColorAttachments.size());
971 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500972 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400973 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
Jamie Madilla4595b82017-01-11 17:36:34 -0500974
975 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
976 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -0400977 }
978 break;
979 }
Geoff Langab75a052014-10-15 12:56:37 -0400980 }
981}
982
Jamie Madill2d06b732015-04-20 12:53:28 -0400983void Framebuffer::resetAttachment(GLenum binding)
984{
985 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
986}
987
Jamie Madill362876b2016-06-16 14:46:59 -0400988void Framebuffer::syncState()
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500989{
990 if (mDirtyBits.any())
991 {
992 mImpl->syncState(mDirtyBits);
993 mDirtyBits.reset();
Jamie Madill362876b2016-06-16 14:46:59 -0400994 mCachedStatus.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500995 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000996}
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500997
Jamie Madill362876b2016-06-16 14:46:59 -0400998void Framebuffer::signal(SignalToken token)
Jamie Madill51f40ec2016-06-15 14:06:00 -0400999{
Jamie Madill362876b2016-06-16 14:46:59 -04001000 // TOOD(jmadill): Make this only update individual attachments to do less work.
1001 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001002}
1003
Jamie Madill362876b2016-06-16 14:46:59 -04001004bool Framebuffer::complete(const ContextState &state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001005{
Jamie Madill362876b2016-06-16 14:46:59 -04001006 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001007}
1008
Jamie Madilla4595b82017-01-11 17:36:34 -05001009bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1010{
1011 const Program *program = state.getProgram();
1012
1013 // TODO(jmadill): Default framebuffer feedback loops.
1014 if (mId == 0)
1015 {
1016 return false;
1017 }
1018
1019 // The bitset will skip inactive draw buffers.
1020 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1021 {
1022 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1023 if (attachment && attachment->type() == GL_TEXTURE)
1024 {
1025 // Validate the feedback loop.
1026 if (program->samplesFromTexture(state, attachment->id()))
1027 {
1028 return true;
1029 }
1030 }
1031 }
1032
1033 // TODO(jmadill): Validate depth-stencil feedback loop.
1034 return false;
1035}
1036
Jamie Madillf695a3a2017-01-11 17:36:35 -05001037bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID, GLint copyTextureLevel) const
1038{
1039 if (mId == 0)
1040 {
1041 // It seems impossible to form a texture copying feedback loop with the default FBO.
1042 return false;
1043 }
1044
1045 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1046 ASSERT(readAttachment);
1047
1048 if (readAttachment->isTextureWithId(copyTextureID))
1049 {
1050 // TODO(jmadill): 3D/Array texture layers.
1051 if (readAttachment->getTextureImageIndex().mipIndex == copyTextureLevel)
1052 {
1053 return true;
1054 }
1055 }
1056 return false;
1057}
1058
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001059} // namespace gl