blob: 0dbcf1c0e527d1b89764408c1a8c08336cebd789 [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
Geoff Langb21e20d2016-07-19 15:35:41 -0400245bool FramebufferState::colorAttachmentsAreUniqueImages() const
246{
247 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
248 firstAttachmentIdx++)
249 {
250 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
251 if (!firstAttachment.isAttached())
252 {
253 continue;
254 }
255
256 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
257 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
258 {
259 const gl::FramebufferAttachment &secondAttachment =
260 mColorAttachments[secondAttachmentIdx];
261 if (!secondAttachment.isAttached())
262 {
263 continue;
264 }
265
266 if (firstAttachment == secondAttachment)
267 {
268 return false;
269 }
270 }
271 }
272
273 return true;
274}
275
Jamie Madill7aea7e02016-05-10 10:39:45 -0400276Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400277 : mState(caps),
278 mImpl(factory->createFramebuffer(mState)),
279 mId(id),
280 mCachedStatus(),
281 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
282 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283{
Corentin Wallez37c39792015-08-20 14:19:46 -0400284 ASSERT(mId != 0);
285 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400286 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
287
288 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
289 {
290 mDirtyColorAttachmentBindings.push_back(ChannelBinding(
291 this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
292 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400293}
294
295Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400296 : mState(),
297 mImpl(surface->createDefaultFramebuffer(mState)),
298 mId(0),
299 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
300 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
301 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400302{
Geoff Langda88add2014-12-01 10:22:01 -0500303 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400304 mDirtyColorAttachmentBindings.push_back(
305 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000306}
307
308Framebuffer::~Framebuffer()
309{
Geoff Langda88add2014-12-01 10:22:01 -0500310 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000311}
312
Geoff Lang70d0f492015-12-10 17:45:46 -0500313void Framebuffer::setLabel(const std::string &label)
314{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400315 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500316}
317
318const std::string &Framebuffer::getLabel() const
319{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400320 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500321}
322
Jamie Madille261b442014-06-25 12:42:21 -0400323void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000324{
Jamie Madilld1405e52015-03-05 15:41:39 -0500325 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326}
327
Jamie Madille261b442014-06-25 12:42:21 -0400328void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329{
Jamie Madilld1405e52015-03-05 15:41:39 -0500330 detachResourceById(GL_RENDERBUFFER, renderbufferId);
331}
Jamie Madille261b442014-06-25 12:42:21 -0400332
Jamie Madilld1405e52015-03-05 15:41:39 -0500333void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
334{
Jamie Madill362876b2016-06-16 14:46:59 -0400335 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500336 {
Jamie Madill362876b2016-06-16 14:46:59 -0400337 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
338 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000339 }
340
Jamie Madill362876b2016-06-16 14:46:59 -0400341 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
342 DIRTY_BIT_DEPTH_ATTACHMENT);
343 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
344 DIRTY_BIT_STENCIL_ATTACHMENT);
345}
346
347void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
348 GLenum matchType,
349 GLuint matchId,
350 size_t dirtyBit)
351{
352 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
353 {
354 attachment->detach();
355 mDirtyBits.set(dirtyBit);
356 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357}
358
Corentin Wallez37c39792015-08-20 14:19:46 -0400359const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000360{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400361 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362}
363
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400364const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400365{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400366 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400367}
368
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400369const FramebufferAttachment *Framebuffer::getStencilbuffer() const
370{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400371 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400372}
373
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400374const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
375{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400376 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400377}
378
379const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000380{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400381 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000382}
383
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500384const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
385{
386 return mState.getStencilOrDepthStencilAttachment();
387}
388
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400389const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000390{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400391 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000392}
393
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000394GLenum Framebuffer::getReadColorbufferType() const
395{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400396 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400397 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000398}
399
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400400const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000401{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400402 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000403}
404
Jamie Madill2d06b732015-04-20 12:53:28 -0400405const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000406{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400407 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400408}
409
Geoff Langa15472a2015-08-11 11:48:03 -0400410size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000411{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400412 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400413}
414
415GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
416{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400417 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
418 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000419}
420
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500421const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
422{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400423 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500424}
425
Geoff Lang164d54e2014-12-01 10:55:33 -0500426void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000427{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400428 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500429
430 ASSERT(count <= drawStates.size());
431 std::copy(buffers, buffers + count, drawStates.begin());
432 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500433 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500434
435 mState.mEnabledDrawBuffers.reset();
436 for (size_t index = 0; index < count; ++index)
437 {
438 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
439 {
440 mState.mEnabledDrawBuffers.set(index);
441 }
442 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500443}
444
Geoff Langa15472a2015-08-11 11:48:03 -0400445const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
446{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400447 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400448}
449
450bool Framebuffer::hasEnabledDrawBuffer() const
451{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400452 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400453 {
454 if (getDrawBuffer(drawbufferIdx) != nullptr)
455 {
456 return true;
457 }
458 }
459
460 return false;
461}
462
Geoff Lang9dd95802014-12-01 11:12:59 -0500463GLenum Framebuffer::getReadBufferState() const
464{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400465 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500466}
467
468void Framebuffer::setReadBuffer(GLenum buffer)
469{
Jamie Madillb885e572015-02-03 16:16:04 -0500470 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
471 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400472 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
473 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500474 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000475}
476
Corentin Wallez37c39792015-08-20 14:19:46 -0400477size_t Framebuffer::getNumColorBuffers() const
478{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400479 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400480}
481
Jamie Madill0df8fe42015-11-24 16:10:24 -0500482bool Framebuffer::hasDepth() const
483{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400484 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500485}
486
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000487bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000488{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400489 return (mState.mStencilAttachment.isAttached() &&
490 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000491}
492
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000493bool Framebuffer::usingExtendedDrawBuffers() const
494{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400495 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000496 {
Geoff Langa15472a2015-08-11 11:48:03 -0400497 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000498 {
499 return true;
500 }
501 }
502
503 return false;
504}
505
Jamie Madill51f40ec2016-06-15 14:06:00 -0400506GLenum Framebuffer::checkStatus(const ContextState &state)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500508 // The default framebuffer *must* always be complete, though it may not be
509 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
510 if (mId == 0)
511 {
512 return GL_FRAMEBUFFER_COMPLETE;
513 }
514
Jamie Madill362876b2016-06-16 14:46:59 -0400515 if (hasAnyDirtyBit() || !mCachedStatus.valid())
516 {
517 mCachedStatus = checkStatusImpl(state);
518 }
519
520 return mCachedStatus.value();
521}
522
523GLenum Framebuffer::checkStatusImpl(const ContextState &state)
524{
525 ASSERT(mId != 0);
526
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000527 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000528 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000529 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530
Jamie Madill48ef11b2016-04-27 15:21:52 -0400531 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400533 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000534 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500535 const Extents &size = colorAttachment.getSize();
536 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000537 {
538 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
539 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000540
Jamie Madilla3944d42016-07-22 22:13:26 -0400541 const Format &format = colorAttachment.getFormat();
542 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400543 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000544 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400545 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000546 {
Jamie Madill81176782015-11-24 16:10:23 -0500547 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000548 }
549
Jamie Madilla3944d42016-07-22 22:13:26 -0400550 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000551 {
552 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
553 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500554
555 if (colorAttachment.layer() >= size.depth)
556 {
557 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
558 }
Jamie Madill3215b202015-12-15 16:41:39 -0500559
560 // ES3 specifies that cube map texture attachments must be cube complete.
561 // This language is missing from the ES2 spec, but we enforce it here because some
562 // desktop OpenGL drivers also enforce this validation.
563 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
564 const Texture *texture = colorAttachment.getTexture();
565 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300566 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
567 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500568 {
569 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
570 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000571 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400572 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000573 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400574 if (!formatCaps.renderable || format.info->depthBits > 0 ||
575 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400576 {
577 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
578 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000579 }
580
581 if (!missingAttachment)
582 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000583 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
584 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400585 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000586 {
587 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
588 }
589
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000590 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
591 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300592 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000593 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400594 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000595 {
596 return GL_FRAMEBUFFER_UNSUPPORTED;
597 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000598 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000599 }
600 else
601 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400602 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400603 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000604 missingAttachment = false;
605 }
606 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000607 }
608
Jamie Madill48ef11b2016-04-27 15:21:52 -0400609 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400610 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000611 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500612 const Extents &size = depthAttachment.getSize();
613 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000614 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000615 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000616 }
617
Jamie Madilla3944d42016-07-22 22:13:26 -0400618 const Format &format = depthAttachment.getFormat();
619 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400620 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000621 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000622 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700623 if (!state.getExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000624 {
625 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
626 }
627
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400628 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400629 {
Jamie Madill81176782015-11-24 16:10:23 -0500630 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400631 }
632
Jamie Madilla3944d42016-07-22 22:13:26 -0400633 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000634 {
635 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
636 }
637 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400638 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000639 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400640 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400641 {
642 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
643 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000644 }
645
646 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000647 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400648 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000649 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000650 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400651 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000652 {
Sami Väisänena797e062016-05-12 15:23:40 +0300653 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
654 // considered complete when its depth or stencil samples are a
655 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700656 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300657 if (!mixedSamples)
658 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
659
660 const int colorSamples = samples ? samples : 1;
661 const int depthSamples = depthAttachment.getSamples();
662 if ((depthSamples % colorSamples) != 0)
663 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000664 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000665 }
666
Jamie Madill48ef11b2016-04-27 15:21:52 -0400667 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400668 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000669 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500670 const Extents &size = stencilAttachment.getSize();
671 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000672 {
673 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
674 }
675
Jamie Madilla3944d42016-07-22 22:13:26 -0400676 const Format &format = stencilAttachment.getFormat();
677 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400678 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000679 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000680 // texture stencil attachments come along as part
681 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700682 if (!state.getExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000683 {
684 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
685 }
686
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400687 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400688 {
Jamie Madill81176782015-11-24 16:10:23 -0500689 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400690 }
691
Jamie Madilla3944d42016-07-22 22:13:26 -0400692 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000693 {
694 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
695 }
696 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400697 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000698 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400699 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400700 {
701 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
702 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000703 }
704
705 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000706 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400707 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000708 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000709 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400710 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000711 {
Sami Väisänena797e062016-05-12 15:23:40 +0300712 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700713 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300714 if (!mixedSamples)
715 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
716
717 const int colorSamples = samples ? samples : 1;
718 const int stencilSamples = stencilAttachment.getSamples();
719 if ((stencilSamples % colorSamples) != 0)
720 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000721 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400722
723 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300724 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400725 stencilAttachment != depthAttachment)
726 {
727 return GL_FRAMEBUFFER_UNSUPPORTED;
728 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000729 }
730
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000731 // we need to have at least one attachment to be complete
732 if (missingAttachment)
733 {
734 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000735 }
736
Jamie Madillcc86d642015-11-24 13:00:07 -0500737 // In ES 2.0, all color attachments must have the same width and height.
738 // In ES 3.0, there is no such restriction.
Martin Radev1be913c2016-07-11 17:59:16 +0300739 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500740 {
741 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
742 }
743
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500744 syncState();
Jamie Madillcc86d642015-11-24 13:00:07 -0500745 if (!mImpl->checkStatus())
746 {
747 return GL_FRAMEBUFFER_UNSUPPORTED;
748 }
749
750 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000751}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000752
Austin Kinross08332632015-05-05 13:35:47 -0700753Error Framebuffer::discard(size_t count, const GLenum *attachments)
754{
755 return mImpl->discard(count, attachments);
756}
757
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500758Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400759{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500760 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400761}
762
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500763Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400764{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500765 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400766}
767
Jamie Madill8415b5f2016-04-26 13:41:39 -0400768Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500769{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700770 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500771 {
Jamie Madill362876b2016-06-16 14:46:59 -0400772 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500773 }
774
Jamie Madill8415b5f2016-04-26 13:41:39 -0400775 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500776}
777
Jamie Madill8415b5f2016-04-26 13:41:39 -0400778Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400779 GLenum buffer,
780 GLint drawbuffer,
781 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500782{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700783 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500784 {
Jamie Madill362876b2016-06-16 14:46:59 -0400785 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500786 }
787
Jamie Madill8415b5f2016-04-26 13:41:39 -0400788 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500789}
790
Jamie Madill8415b5f2016-04-26 13:41:39 -0400791Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400792 GLenum buffer,
793 GLint drawbuffer,
794 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500795{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700796 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500797 {
Jamie Madill362876b2016-06-16 14:46:59 -0400798 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500799 }
800
Jamie Madill8415b5f2016-04-26 13:41:39 -0400801 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500802}
803
Jamie Madill8415b5f2016-04-26 13:41:39 -0400804Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400805 GLenum buffer,
806 GLint drawbuffer,
807 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500808{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700809 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500810 {
Jamie Madill362876b2016-06-16 14:46:59 -0400811 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500812 }
813
Jamie Madill8415b5f2016-04-26 13:41:39 -0400814 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500815}
816
Jamie Madill8415b5f2016-04-26 13:41:39 -0400817Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400818 GLenum buffer,
819 GLint drawbuffer,
820 GLfloat depth,
821 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500822{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700823 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500824 {
Jamie Madill362876b2016-06-16 14:46:59 -0400825 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500826 }
827
Jamie Madill8415b5f2016-04-26 13:41:39 -0400828 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500829}
830
Geoff Langbce529e2014-12-01 12:48:41 -0500831GLenum Framebuffer::getImplementationColorReadFormat() const
832{
833 return mImpl->getImplementationColorReadFormat();
834}
835
836GLenum Framebuffer::getImplementationColorReadType() const
837{
838 return mImpl->getImplementationColorReadType();
839}
840
Jamie Madill8415b5f2016-04-26 13:41:39 -0400841Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500842 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400843 GLenum format,
844 GLenum type,
845 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500846{
Jamie Madill362876b2016-06-16 14:46:59 -0400847 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400848
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700849 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400850 if (unpackBuffer)
851 {
852 unpackBuffer->onPixelUnpack();
853 }
854
Jamie Madill362876b2016-06-16 14:46:59 -0400855 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500856}
857
Jamie Madill8415b5f2016-04-26 13:41:39 -0400858Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500859 const Rectangle &sourceArea,
860 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400861 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400862 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500863{
He Yunchao6be602d2016-12-22 14:33:07 +0800864 GLbitfield blitMask = mask;
865
866 // Note that blitting is called against draw framebuffer.
867 // See the code in gl::Context::blitFramebuffer.
868 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
869 {
870 blitMask &= ~GL_COLOR_BUFFER_BIT;
871 }
872
873 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
874 {
875 blitMask &= ~GL_STENCIL_BUFFER_BIT;
876 }
877
878 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
879 {
880 blitMask &= ~GL_DEPTH_BUFFER_BIT;
881 }
882
883 if (!blitMask)
884 {
885 return NoError();
886 }
887
888 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -0500889}
890
Jamie Madill51f40ec2016-06-15 14:06:00 -0400891int Framebuffer::getSamples(const ContextState &state)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000892{
Jamie Madill362876b2016-06-16 14:46:59 -0400893 if (complete(state))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000894 {
Jamie Madill362876b2016-06-16 14:46:59 -0400895 // For a complete framebuffer, all attachments must have the same sample count.
896 // In this case return the first nonzero sample size.
897 const auto *firstColorAttachment = mState.getFirstColorAttachment();
898 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000899 {
Jamie Madill362876b2016-06-16 14:46:59 -0400900 ASSERT(firstColorAttachment->isAttached());
901 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000902 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000903 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000904
905 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000906}
907
Jamie Madille261b442014-06-25 12:42:21 -0400908bool Framebuffer::hasValidDepthStencil() const
909{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400910 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400911}
912
Jamie Madill2d06b732015-04-20 12:53:28 -0400913void Framebuffer::setAttachment(GLenum type,
914 GLenum binding,
915 const ImageIndex &textureIndex,
916 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400917{
Jamie Madill2d06b732015-04-20 12:53:28 -0400918 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400919 {
Geoff Langab75a052014-10-15 12:56:37 -0400920 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400921 FramebufferAttachmentObject *attachmentObj = resource;
922 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400923 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400924 FramebufferAttachment::Target target(binding, textureIndex);
Jamie Madilla3944d42016-07-22 22:13:26 -0400925 const Format &format = resource->getAttachmentFormat(target);
926 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
Jamie Madill375c37c2015-07-21 15:14:08 -0400927 {
928 // Attaching nullptr detaches the current attachment.
929 attachmentObj = nullptr;
930 }
Geoff Langab75a052014-10-15 12:56:37 -0400931 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400932
Jamie Madill48ef11b2016-04-27 15:21:52 -0400933 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
934 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500935 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
936 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400937 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
938 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
Geoff Langab75a052014-10-15 12:56:37 -0400939 }
940 else
941 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400942 switch (binding)
943 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500944 case GL_DEPTH:
945 case GL_DEPTH_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400946 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500947 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400948 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
949 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500950 case GL_STENCIL:
951 case GL_STENCIL_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400952 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500953 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400954 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
955 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500956 case GL_BACK:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400957 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500958 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill362876b2016-06-16 14:46:59 -0400959 // No need for a resource binding for the default FBO, it's always complete.
960 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500961 default:
Jamie Madill2d06b732015-04-20 12:53:28 -0400962 {
963 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
Jamie Madill48ef11b2016-04-27 15:21:52 -0400964 ASSERT(colorIndex < mState.mColorAttachments.size());
965 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500966 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400967 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
Jamie Madilla4595b82017-01-11 17:36:34 -0500968
969 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
970 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -0400971 }
972 break;
973 }
Geoff Langab75a052014-10-15 12:56:37 -0400974 }
975}
976
Jamie Madill2d06b732015-04-20 12:53:28 -0400977void Framebuffer::resetAttachment(GLenum binding)
978{
979 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
980}
981
Jamie Madill362876b2016-06-16 14:46:59 -0400982void Framebuffer::syncState()
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500983{
984 if (mDirtyBits.any())
985 {
986 mImpl->syncState(mDirtyBits);
987 mDirtyBits.reset();
Jamie Madill362876b2016-06-16 14:46:59 -0400988 mCachedStatus.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500989 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000990}
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500991
Jamie Madill362876b2016-06-16 14:46:59 -0400992void Framebuffer::signal(SignalToken token)
Jamie Madill51f40ec2016-06-15 14:06:00 -0400993{
Jamie Madill362876b2016-06-16 14:46:59 -0400994 // TOOD(jmadill): Make this only update individual attachments to do less work.
995 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -0400996}
997
Jamie Madill362876b2016-06-16 14:46:59 -0400998bool Framebuffer::complete(const ContextState &state)
Jamie Madill51f40ec2016-06-15 14:06:00 -0400999{
Jamie Madill362876b2016-06-16 14:46:59 -04001000 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001001}
1002
Jamie Madilla4595b82017-01-11 17:36:34 -05001003bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1004{
1005 const Program *program = state.getProgram();
1006
1007 // TODO(jmadill): Default framebuffer feedback loops.
1008 if (mId == 0)
1009 {
1010 return false;
1011 }
1012
1013 // The bitset will skip inactive draw buffers.
1014 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1015 {
1016 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1017 if (attachment && attachment->type() == GL_TEXTURE)
1018 {
1019 // Validate the feedback loop.
1020 if (program->samplesFromTexture(state, attachment->id()))
1021 {
1022 return true;
1023 }
1024 }
1025 }
1026
1027 // TODO(jmadill): Validate depth-stencil feedback loop.
1028 return false;
1029}
1030
Jamie Madillf695a3a2017-01-11 17:36:35 -05001031bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID, GLint copyTextureLevel) const
1032{
1033 if (mId == 0)
1034 {
1035 // It seems impossible to form a texture copying feedback loop with the default FBO.
1036 return false;
1037 }
1038
1039 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1040 ASSERT(readAttachment);
1041
1042 if (readAttachment->isTextureWithId(copyTextureID))
1043 {
1044 // TODO(jmadill): 3D/Array texture layers.
1045 if (readAttachment->getTextureImageIndex().mipIndex == copyTextureLevel)
1046 {
1047 return true;
1048 }
1049 }
1050 return false;
1051}
1052
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001053} // namespace gl