blob: 61c6bed1aa38eb2e0fb39ed28931674b13f4391e [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 Madill48ef11b2016-04-27 15:21:52 -0400111const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500112{
Jamie Madill2d06b732015-04-20 12:53:28 -0400113 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500114 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400115 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500116 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400117 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500118 }
119 }
120
121 return nullptr;
122}
123
Jamie Madill48ef11b2016-04-27 15:21:52 -0400124const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500125{
Jamie Madill2d06b732015-04-20 12:53:28 -0400126 if (mDepthAttachment.isAttached())
127 {
128 return &mDepthAttachment;
129 }
130 if (mStencilAttachment.isAttached())
131 {
132 return &mStencilAttachment;
133 }
134 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500135}
136
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500137const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
138{
139 if (mStencilAttachment.isAttached())
140 {
141 return &mStencilAttachment;
142 }
143 return getDepthStencilAttachment();
144}
145
Jamie Madill48ef11b2016-04-27 15:21:52 -0400146const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400147{
148 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400149 return mColorAttachments[colorAttachment].isAttached() ?
150 &mColorAttachments[colorAttachment] :
151 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400152}
153
Jamie Madill48ef11b2016-04-27 15:21:52 -0400154const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400155{
Jamie Madill2d06b732015-04-20 12:53:28 -0400156 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400157}
158
Jamie Madill48ef11b2016-04-27 15:21:52 -0400159const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400160{
Jamie Madill2d06b732015-04-20 12:53:28 -0400161 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400162}
163
Jamie Madill48ef11b2016-04-27 15:21:52 -0400164const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400165{
166 // A valid depth-stencil attachment has the same resource bound to both the
167 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400168 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500169 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400170 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400171 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400172 }
173
174 return nullptr;
175}
176
Jamie Madill48ef11b2016-04-27 15:21:52 -0400177bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500178{
179 Optional<Extents> attachmentSize;
180
181 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
182 {
183 if (!attachment.isAttached())
184 {
185 return false;
186 }
187
188 if (!attachmentSize.valid())
189 {
190 attachmentSize = attachment.getSize();
191 return false;
192 }
193
194 return (attachment.getSize() != attachmentSize.value());
195 };
196
197 for (const auto &attachment : mColorAttachments)
198 {
199 if (hasMismatchedSize(attachment))
200 {
201 return false;
202 }
203 }
204
205 if (hasMismatchedSize(mDepthAttachment))
206 {
207 return false;
208 }
209
210 return !hasMismatchedSize(mStencilAttachment);
211}
212
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400213const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
214{
215 ASSERT(drawBufferIdx < mDrawBufferStates.size());
216 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
217 {
218 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
219 // must be COLOR_ATTACHMENTi or NONE"
220 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
221 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
222 return getAttachment(mDrawBufferStates[drawBufferIdx]);
223 }
224 else
225 {
226 return nullptr;
227 }
228}
229
230size_t FramebufferState::getDrawBufferCount() const
231{
232 return mDrawBufferStates.size();
233}
234
Geoff Langb21e20d2016-07-19 15:35:41 -0400235bool FramebufferState::colorAttachmentsAreUniqueImages() const
236{
237 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
238 firstAttachmentIdx++)
239 {
240 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
241 if (!firstAttachment.isAttached())
242 {
243 continue;
244 }
245
246 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
247 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
248 {
249 const gl::FramebufferAttachment &secondAttachment =
250 mColorAttachments[secondAttachmentIdx];
251 if (!secondAttachment.isAttached())
252 {
253 continue;
254 }
255
256 if (firstAttachment == secondAttachment)
257 {
258 return false;
259 }
260 }
261 }
262
263 return true;
264}
265
Jamie Madill7aea7e02016-05-10 10:39:45 -0400266Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400267 : mState(caps),
268 mImpl(factory->createFramebuffer(mState)),
269 mId(id),
270 mCachedStatus(),
271 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
272 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273{
Corentin Wallez37c39792015-08-20 14:19:46 -0400274 ASSERT(mId != 0);
275 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400276 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
277
278 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
279 {
280 mDirtyColorAttachmentBindings.push_back(ChannelBinding(
281 this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
282 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400283}
284
285Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400286 : mState(),
287 mImpl(surface->createDefaultFramebuffer(mState)),
288 mId(0),
289 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
290 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
291 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400292{
Geoff Langda88add2014-12-01 10:22:01 -0500293 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400294 mDirtyColorAttachmentBindings.push_back(
295 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296}
297
298Framebuffer::~Framebuffer()
299{
Geoff Langda88add2014-12-01 10:22:01 -0500300 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000301}
302
Geoff Lang70d0f492015-12-10 17:45:46 -0500303void Framebuffer::setLabel(const std::string &label)
304{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400305 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500306}
307
308const std::string &Framebuffer::getLabel() const
309{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400310 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500311}
312
Jamie Madille261b442014-06-25 12:42:21 -0400313void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000314{
Jamie Madilld1405e52015-03-05 15:41:39 -0500315 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316}
317
Jamie Madille261b442014-06-25 12:42:21 -0400318void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319{
Jamie Madilld1405e52015-03-05 15:41:39 -0500320 detachResourceById(GL_RENDERBUFFER, renderbufferId);
321}
Jamie Madille261b442014-06-25 12:42:21 -0400322
Jamie Madilld1405e52015-03-05 15:41:39 -0500323void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
324{
Jamie Madill362876b2016-06-16 14:46:59 -0400325 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500326 {
Jamie Madill362876b2016-06-16 14:46:59 -0400327 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
328 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329 }
330
Jamie Madill362876b2016-06-16 14:46:59 -0400331 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
332 DIRTY_BIT_DEPTH_ATTACHMENT);
333 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
334 DIRTY_BIT_STENCIL_ATTACHMENT);
335}
336
337void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
338 GLenum matchType,
339 GLuint matchId,
340 size_t dirtyBit)
341{
342 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
343 {
344 attachment->detach();
345 mDirtyBits.set(dirtyBit);
346 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347}
348
Corentin Wallez37c39792015-08-20 14:19:46 -0400349const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000350{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400351 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352}
353
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400354const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400355{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400356 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400357}
358
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400359const FramebufferAttachment *Framebuffer::getStencilbuffer() const
360{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400361 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400362}
363
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400364const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
365{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400366 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400367}
368
369const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000370{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400371 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000372}
373
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500374const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
375{
376 return mState.getStencilOrDepthStencilAttachment();
377}
378
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400379const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000380{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400381 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000382}
383
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000384GLenum Framebuffer::getReadColorbufferType() const
385{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400386 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400387 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000388}
389
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400390const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000391{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400392 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000393}
394
Jamie Madill2d06b732015-04-20 12:53:28 -0400395const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000396{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400397 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400398}
399
Geoff Langa15472a2015-08-11 11:48:03 -0400400size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000401{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400402 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400403}
404
405GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
406{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400407 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
408 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000409}
410
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500411const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
412{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400413 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500414}
415
Geoff Lang164d54e2014-12-01 10:55:33 -0500416void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000417{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400418 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500419
420 ASSERT(count <= drawStates.size());
421 std::copy(buffers, buffers + count, drawStates.begin());
422 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500423 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500424
425 mState.mEnabledDrawBuffers.reset();
426 for (size_t index = 0; index < count; ++index)
427 {
428 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
429 {
430 mState.mEnabledDrawBuffers.set(index);
431 }
432 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500433}
434
Geoff Langa15472a2015-08-11 11:48:03 -0400435const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
436{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400437 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400438}
439
440bool Framebuffer::hasEnabledDrawBuffer() const
441{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400442 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400443 {
444 if (getDrawBuffer(drawbufferIdx) != nullptr)
445 {
446 return true;
447 }
448 }
449
450 return false;
451}
452
Geoff Lang9dd95802014-12-01 11:12:59 -0500453GLenum Framebuffer::getReadBufferState() const
454{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400455 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500456}
457
458void Framebuffer::setReadBuffer(GLenum buffer)
459{
Jamie Madillb885e572015-02-03 16:16:04 -0500460 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
461 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400462 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
463 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500464 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000465}
466
Corentin Wallez37c39792015-08-20 14:19:46 -0400467size_t Framebuffer::getNumColorBuffers() const
468{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400469 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400470}
471
Jamie Madill0df8fe42015-11-24 16:10:24 -0500472bool Framebuffer::hasDepth() const
473{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400474 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500475}
476
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000477bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000478{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400479 return (mState.mStencilAttachment.isAttached() &&
480 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000481}
482
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000483bool Framebuffer::usingExtendedDrawBuffers() const
484{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400485 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000486 {
Geoff Langa15472a2015-08-11 11:48:03 -0400487 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000488 {
489 return true;
490 }
491 }
492
493 return false;
494}
495
Jamie Madill51f40ec2016-06-15 14:06:00 -0400496GLenum Framebuffer::checkStatus(const ContextState &state)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500498 // The default framebuffer *must* always be complete, though it may not be
499 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
500 if (mId == 0)
501 {
502 return GL_FRAMEBUFFER_COMPLETE;
503 }
504
Jamie Madill362876b2016-06-16 14:46:59 -0400505 if (hasAnyDirtyBit() || !mCachedStatus.valid())
506 {
507 mCachedStatus = checkStatusImpl(state);
508 }
509
510 return mCachedStatus.value();
511}
512
513GLenum Framebuffer::checkStatusImpl(const ContextState &state)
514{
515 ASSERT(mId != 0);
516
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000517 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000518 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000519 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000520
Jamie Madill48ef11b2016-04-27 15:21:52 -0400521 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400523 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500525 const Extents &size = colorAttachment.getSize();
526 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000527 {
528 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
529 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000530
Jamie Madilla3944d42016-07-22 22:13:26 -0400531 const Format &format = colorAttachment.getFormat();
532 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400533 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000534 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400535 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000536 {
Jamie Madill81176782015-11-24 16:10:23 -0500537 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000538 }
539
Jamie Madilla3944d42016-07-22 22:13:26 -0400540 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000541 {
542 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
543 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500544
545 if (colorAttachment.layer() >= size.depth)
546 {
547 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
548 }
Jamie Madill3215b202015-12-15 16:41:39 -0500549
550 // ES3 specifies that cube map texture attachments must be cube complete.
551 // This language is missing from the ES2 spec, but we enforce it here because some
552 // desktop OpenGL drivers also enforce this validation.
553 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
554 const Texture *texture = colorAttachment.getTexture();
555 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300556 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
557 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500558 {
559 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
560 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000561 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400562 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000563 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400564 if (!formatCaps.renderable || format.info->depthBits > 0 ||
565 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400566 {
567 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
568 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000569 }
570
571 if (!missingAttachment)
572 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000573 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
574 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400575 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000576 {
577 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
578 }
579
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000580 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
581 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300582 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000583 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400584 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000585 {
586 return GL_FRAMEBUFFER_UNSUPPORTED;
587 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000588 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000589 }
590 else
591 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400592 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400593 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000594 missingAttachment = false;
595 }
596 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000597 }
598
Jamie Madill48ef11b2016-04-27 15:21:52 -0400599 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400600 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000601 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500602 const Extents &size = depthAttachment.getSize();
603 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000604 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000605 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606 }
607
Jamie Madilla3944d42016-07-22 22:13:26 -0400608 const Format &format = depthAttachment.getFormat();
609 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400610 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000611 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000612 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700613 if (!state.getExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000614 {
615 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
616 }
617
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400618 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400619 {
Jamie Madill81176782015-11-24 16:10:23 -0500620 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400621 }
622
Jamie Madilla3944d42016-07-22 22:13:26 -0400623 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000624 {
625 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
626 }
627 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400628 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000629 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400630 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400631 {
632 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
633 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000634 }
635
636 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000637 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400638 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000639 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000640 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400641 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000642 {
Sami Väisänena797e062016-05-12 15:23:40 +0300643 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
644 // considered complete when its depth or stencil samples are a
645 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700646 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300647 if (!mixedSamples)
648 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
649
650 const int colorSamples = samples ? samples : 1;
651 const int depthSamples = depthAttachment.getSamples();
652 if ((depthSamples % colorSamples) != 0)
653 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000654 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000655 }
656
Jamie Madill48ef11b2016-04-27 15:21:52 -0400657 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400658 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000659 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500660 const Extents &size = stencilAttachment.getSize();
661 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000662 {
663 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
664 }
665
Jamie Madilla3944d42016-07-22 22:13:26 -0400666 const Format &format = stencilAttachment.getFormat();
667 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400668 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000669 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000670 // texture stencil attachments come along as part
671 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700672 if (!state.getExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000673 {
674 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
675 }
676
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400677 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400678 {
Jamie Madill81176782015-11-24 16:10:23 -0500679 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400680 }
681
Jamie Madilla3944d42016-07-22 22:13:26 -0400682 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000683 {
684 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
685 }
686 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400687 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000688 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400689 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400690 {
691 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
692 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000693 }
694
695 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000696 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400697 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000698 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000699 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400700 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000701 {
Sami Väisänena797e062016-05-12 15:23:40 +0300702 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700703 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300704 if (!mixedSamples)
705 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
706
707 const int colorSamples = samples ? samples : 1;
708 const int stencilSamples = stencilAttachment.getSamples();
709 if ((stencilSamples % colorSamples) != 0)
710 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000711 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400712
713 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300714 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400715 stencilAttachment != depthAttachment)
716 {
717 return GL_FRAMEBUFFER_UNSUPPORTED;
718 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000719 }
720
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000721 // we need to have at least one attachment to be complete
722 if (missingAttachment)
723 {
724 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000725 }
726
Jamie Madillcc86d642015-11-24 13:00:07 -0500727 // In ES 2.0, all color attachments must have the same width and height.
728 // In ES 3.0, there is no such restriction.
Martin Radev1be913c2016-07-11 17:59:16 +0300729 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500730 {
731 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
732 }
733
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500734 syncState();
Jamie Madillcc86d642015-11-24 13:00:07 -0500735 if (!mImpl->checkStatus())
736 {
737 return GL_FRAMEBUFFER_UNSUPPORTED;
738 }
739
740 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000741}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000742
Austin Kinross08332632015-05-05 13:35:47 -0700743Error Framebuffer::discard(size_t count, const GLenum *attachments)
744{
745 return mImpl->discard(count, attachments);
746}
747
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500748Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400749{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500750 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400751}
752
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500753Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400754{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500755 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400756}
757
Jamie Madill8415b5f2016-04-26 13:41:39 -0400758Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500759{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700760 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500761 {
Jamie Madill362876b2016-06-16 14:46:59 -0400762 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500763 }
764
Jamie Madill8415b5f2016-04-26 13:41:39 -0400765 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500766}
767
Jamie Madill8415b5f2016-04-26 13:41:39 -0400768Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400769 GLenum buffer,
770 GLint drawbuffer,
771 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500772{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700773 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500774 {
Jamie Madill362876b2016-06-16 14:46:59 -0400775 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500776 }
777
Jamie Madill8415b5f2016-04-26 13:41:39 -0400778 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500779}
780
Jamie Madill8415b5f2016-04-26 13:41:39 -0400781Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400782 GLenum buffer,
783 GLint drawbuffer,
784 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500785{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700786 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500787 {
Jamie Madill362876b2016-06-16 14:46:59 -0400788 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500789 }
790
Jamie Madill8415b5f2016-04-26 13:41:39 -0400791 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500792}
793
Jamie Madill8415b5f2016-04-26 13:41:39 -0400794Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400795 GLenum buffer,
796 GLint drawbuffer,
797 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500798{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700799 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500800 {
Jamie Madill362876b2016-06-16 14:46:59 -0400801 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500802 }
803
Jamie Madill8415b5f2016-04-26 13:41:39 -0400804 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500805}
806
Jamie Madill8415b5f2016-04-26 13:41:39 -0400807Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400808 GLenum buffer,
809 GLint drawbuffer,
810 GLfloat depth,
811 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500812{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700813 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500814 {
Jamie Madill362876b2016-06-16 14:46:59 -0400815 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500816 }
817
Jamie Madill8415b5f2016-04-26 13:41:39 -0400818 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500819}
820
Geoff Langbce529e2014-12-01 12:48:41 -0500821GLenum Framebuffer::getImplementationColorReadFormat() const
822{
823 return mImpl->getImplementationColorReadFormat();
824}
825
826GLenum Framebuffer::getImplementationColorReadType() const
827{
828 return mImpl->getImplementationColorReadType();
829}
830
Jamie Madill8415b5f2016-04-26 13:41:39 -0400831Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500832 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400833 GLenum format,
834 GLenum type,
835 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500836{
Jamie Madill362876b2016-06-16 14:46:59 -0400837 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400838
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700839 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400840 if (unpackBuffer)
841 {
842 unpackBuffer->onPixelUnpack();
843 }
844
Jamie Madill362876b2016-06-16 14:46:59 -0400845 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500846}
847
Jamie Madill8415b5f2016-04-26 13:41:39 -0400848Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500849 const Rectangle &sourceArea,
850 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400851 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400852 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500853{
He Yunchao6be602d2016-12-22 14:33:07 +0800854 GLbitfield blitMask = mask;
855
856 // Note that blitting is called against draw framebuffer.
857 // See the code in gl::Context::blitFramebuffer.
858 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
859 {
860 blitMask &= ~GL_COLOR_BUFFER_BIT;
861 }
862
863 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
864 {
865 blitMask &= ~GL_STENCIL_BUFFER_BIT;
866 }
867
868 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
869 {
870 blitMask &= ~GL_DEPTH_BUFFER_BIT;
871 }
872
873 if (!blitMask)
874 {
875 return NoError();
876 }
877
878 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -0500879}
880
Jamie Madill51f40ec2016-06-15 14:06:00 -0400881int Framebuffer::getSamples(const ContextState &state)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000882{
Jamie Madill362876b2016-06-16 14:46:59 -0400883 if (complete(state))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000884 {
Jamie Madill362876b2016-06-16 14:46:59 -0400885 // For a complete framebuffer, all attachments must have the same sample count.
886 // In this case return the first nonzero sample size.
887 const auto *firstColorAttachment = mState.getFirstColorAttachment();
888 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000889 {
Jamie Madill362876b2016-06-16 14:46:59 -0400890 ASSERT(firstColorAttachment->isAttached());
891 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000892 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000893 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000894
895 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000896}
897
Jamie Madille261b442014-06-25 12:42:21 -0400898bool Framebuffer::hasValidDepthStencil() const
899{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400900 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400901}
902
Jamie Madill2d06b732015-04-20 12:53:28 -0400903void Framebuffer::setAttachment(GLenum type,
904 GLenum binding,
905 const ImageIndex &textureIndex,
906 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400907{
Jamie Madill2d06b732015-04-20 12:53:28 -0400908 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400909 {
Geoff Langab75a052014-10-15 12:56:37 -0400910 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400911 FramebufferAttachmentObject *attachmentObj = resource;
912 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400913 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400914 FramebufferAttachment::Target target(binding, textureIndex);
Jamie Madilla3944d42016-07-22 22:13:26 -0400915 const Format &format = resource->getAttachmentFormat(target);
916 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
Jamie Madill375c37c2015-07-21 15:14:08 -0400917 {
918 // Attaching nullptr detaches the current attachment.
919 attachmentObj = nullptr;
920 }
Geoff Langab75a052014-10-15 12:56:37 -0400921 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400922
Jamie Madill48ef11b2016-04-27 15:21:52 -0400923 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
924 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500925 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
926 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400927 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
928 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
Geoff Langab75a052014-10-15 12:56:37 -0400929 }
930 else
931 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400932 switch (binding)
933 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500934 case GL_DEPTH:
935 case GL_DEPTH_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400936 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500937 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400938 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
939 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500940 case GL_STENCIL:
941 case GL_STENCIL_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400942 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500943 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400944 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
945 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500946 case GL_BACK:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400947 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500948 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill362876b2016-06-16 14:46:59 -0400949 // No need for a resource binding for the default FBO, it's always complete.
950 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500951 default:
Jamie Madill2d06b732015-04-20 12:53:28 -0400952 {
953 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
Jamie Madill48ef11b2016-04-27 15:21:52 -0400954 ASSERT(colorIndex < mState.mColorAttachments.size());
955 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500956 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400957 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
Jamie Madilla4595b82017-01-11 17:36:34 -0500958
959 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
960 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -0400961 }
962 break;
963 }
Geoff Langab75a052014-10-15 12:56:37 -0400964 }
965}
966
Jamie Madill2d06b732015-04-20 12:53:28 -0400967void Framebuffer::resetAttachment(GLenum binding)
968{
969 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
970}
971
Jamie Madill362876b2016-06-16 14:46:59 -0400972void Framebuffer::syncState()
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500973{
974 if (mDirtyBits.any())
975 {
976 mImpl->syncState(mDirtyBits);
977 mDirtyBits.reset();
Jamie Madill362876b2016-06-16 14:46:59 -0400978 mCachedStatus.reset();
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500979 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980}
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500981
Jamie Madill362876b2016-06-16 14:46:59 -0400982void Framebuffer::signal(SignalToken token)
Jamie Madill51f40ec2016-06-15 14:06:00 -0400983{
Jamie Madill362876b2016-06-16 14:46:59 -0400984 // TOOD(jmadill): Make this only update individual attachments to do less work.
985 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -0400986}
987
Jamie Madill362876b2016-06-16 14:46:59 -0400988bool Framebuffer::complete(const ContextState &state)
Jamie Madill51f40ec2016-06-15 14:06:00 -0400989{
Jamie Madill362876b2016-06-16 14:46:59 -0400990 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -0400991}
992
Jamie Madilla4595b82017-01-11 17:36:34 -0500993bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
994{
995 const Program *program = state.getProgram();
996
997 // TODO(jmadill): Default framebuffer feedback loops.
998 if (mId == 0)
999 {
1000 return false;
1001 }
1002
1003 // The bitset will skip inactive draw buffers.
1004 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1005 {
1006 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1007 if (attachment && attachment->type() == GL_TEXTURE)
1008 {
1009 // Validate the feedback loop.
1010 if (program->samplesFromTexture(state, attachment->id()))
1011 {
1012 return true;
1013 }
1014 }
1015 }
1016
1017 // TODO(jmadill): Validate depth-stencil feedback loop.
1018 return false;
1019}
1020
Jamie Madillf695a3a2017-01-11 17:36:35 -05001021bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID, GLint copyTextureLevel) const
1022{
1023 if (mId == 0)
1024 {
1025 // It seems impossible to form a texture copying feedback loop with the default FBO.
1026 return false;
1027 }
1028
1029 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1030 ASSERT(readAttachment);
1031
1032 if (readAttachment->isTextureWithId(copyTextureID))
1033 {
1034 // TODO(jmadill): 3D/Array texture layers.
1035 if (readAttachment->getTextureImageIndex().mipIndex == copyTextureLevel)
1036 {
1037 return true;
1038 }
1039 }
1040 return false;
1041}
1042
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001043} // namespace gl