blob: ae8f1967f282c269c4b7cfac17f5d2f26bc7d2b5 [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
Corentin Wallezccab69d2017-01-27 16:57:15 -0500308Framebuffer::Framebuffer(rx::GLImplFactory *factory)
309 : mState(),
310 mImpl(factory->createFramebuffer(mState)),
311 mId(0),
312 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
313 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
314 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
315{
316 mDirtyColorAttachmentBindings.push_back(
317 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
318}
319
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000320Framebuffer::~Framebuffer()
321{
Geoff Langda88add2014-12-01 10:22:01 -0500322 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000323}
324
Geoff Lang70d0f492015-12-10 17:45:46 -0500325void Framebuffer::setLabel(const std::string &label)
326{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400327 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500328}
329
330const std::string &Framebuffer::getLabel() const
331{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400332 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500333}
334
Jamie Madille261b442014-06-25 12:42:21 -0400335void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336{
Jamie Madilld1405e52015-03-05 15:41:39 -0500337 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338}
339
Jamie Madille261b442014-06-25 12:42:21 -0400340void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341{
Jamie Madilld1405e52015-03-05 15:41:39 -0500342 detachResourceById(GL_RENDERBUFFER, renderbufferId);
343}
Jamie Madille261b442014-06-25 12:42:21 -0400344
Jamie Madilld1405e52015-03-05 15:41:39 -0500345void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
346{
Jamie Madill362876b2016-06-16 14:46:59 -0400347 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500348 {
Jamie Madill362876b2016-06-16 14:46:59 -0400349 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
350 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351 }
352
Jamie Madill362876b2016-06-16 14:46:59 -0400353 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
354 DIRTY_BIT_DEPTH_ATTACHMENT);
355 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
356 DIRTY_BIT_STENCIL_ATTACHMENT);
357}
358
359void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
360 GLenum matchType,
361 GLuint matchId,
362 size_t dirtyBit)
363{
364 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
365 {
366 attachment->detach();
367 mDirtyBits.set(dirtyBit);
368 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000369}
370
Corentin Wallez37c39792015-08-20 14:19:46 -0400371const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400373 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000374}
375
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400376const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400377{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400378 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400379}
380
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400381const FramebufferAttachment *Framebuffer::getStencilbuffer() const
382{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400383 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400384}
385
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400386const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
387{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400388 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400389}
390
391const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000392{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400393 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000394}
395
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500396const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
397{
398 return mState.getStencilOrDepthStencilAttachment();
399}
400
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400401const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000402{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400403 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000404}
405
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000406GLenum Framebuffer::getReadColorbufferType() const
407{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400408 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400409 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000410}
411
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400412const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000413{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400414 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000415}
416
Jamie Madill2d06b732015-04-20 12:53:28 -0400417const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000418{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400419 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400420}
421
Geoff Langa15472a2015-08-11 11:48:03 -0400422size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000423{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400424 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400425}
426
427GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
428{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400429 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
430 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000431}
432
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500433const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
434{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400435 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500436}
437
Geoff Lang164d54e2014-12-01 10:55:33 -0500438void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000439{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400440 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500441
442 ASSERT(count <= drawStates.size());
443 std::copy(buffers, buffers + count, drawStates.begin());
444 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500445 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500446
447 mState.mEnabledDrawBuffers.reset();
448 for (size_t index = 0; index < count; ++index)
449 {
450 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
451 {
452 mState.mEnabledDrawBuffers.set(index);
453 }
454 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500455}
456
Geoff Langa15472a2015-08-11 11:48:03 -0400457const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
458{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400459 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400460}
461
462bool Framebuffer::hasEnabledDrawBuffer() const
463{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400464 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400465 {
466 if (getDrawBuffer(drawbufferIdx) != nullptr)
467 {
468 return true;
469 }
470 }
471
472 return false;
473}
474
Geoff Lang9dd95802014-12-01 11:12:59 -0500475GLenum Framebuffer::getReadBufferState() const
476{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400477 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500478}
479
480void Framebuffer::setReadBuffer(GLenum buffer)
481{
Jamie Madillb885e572015-02-03 16:16:04 -0500482 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
483 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400484 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
485 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500486 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000487}
488
Corentin Wallez37c39792015-08-20 14:19:46 -0400489size_t Framebuffer::getNumColorBuffers() const
490{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400491 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400492}
493
Jamie Madill0df8fe42015-11-24 16:10:24 -0500494bool Framebuffer::hasDepth() const
495{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400496 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500497}
498
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000499bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000500{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400501 return (mState.mStencilAttachment.isAttached() &&
502 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000503}
504
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000505bool Framebuffer::usingExtendedDrawBuffers() const
506{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400507 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000508 {
Geoff Langa15472a2015-08-11 11:48:03 -0400509 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000510 {
511 return true;
512 }
513 }
514
515 return false;
516}
517
Jamie Madill51f40ec2016-06-15 14:06:00 -0400518GLenum Framebuffer::checkStatus(const ContextState &state)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500520 // The default framebuffer is always complete except when it is surfaceless in which
521 // case it is always unsupported. We return early because the default framebuffer may
522 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500523 if (mId == 0)
524 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500525 ASSERT(mCachedStatus.valid());
526 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
527 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
528 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500529 }
530
Jamie Madill362876b2016-06-16 14:46:59 -0400531 if (hasAnyDirtyBit() || !mCachedStatus.valid())
532 {
533 mCachedStatus = checkStatusImpl(state);
534 }
535
536 return mCachedStatus.value();
537}
538
539GLenum Framebuffer::checkStatusImpl(const ContextState &state)
540{
541 ASSERT(mId != 0);
542
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000543 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000544 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000545 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000546
Jamie Madill48ef11b2016-04-27 15:21:52 -0400547 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400549 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000550 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500551 const Extents &size = colorAttachment.getSize();
552 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000553 {
554 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
555 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000556
Jamie Madilla3944d42016-07-22 22:13:26 -0400557 const Format &format = colorAttachment.getFormat();
558 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400559 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000560 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400561 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000562 {
Jamie Madill81176782015-11-24 16:10:23 -0500563 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000564 }
565
Jamie Madilla3944d42016-07-22 22:13:26 -0400566 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000567 {
568 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
569 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500570
571 if (colorAttachment.layer() >= size.depth)
572 {
573 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
574 }
Jamie Madill3215b202015-12-15 16:41:39 -0500575
576 // ES3 specifies that cube map texture attachments must be cube complete.
577 // This language is missing from the ES2 spec, but we enforce it here because some
578 // desktop OpenGL drivers also enforce this validation.
579 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
580 const Texture *texture = colorAttachment.getTexture();
581 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300582 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
583 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500584 {
585 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
586 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000587 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400588 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000589 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400590 if (!formatCaps.renderable || format.info->depthBits > 0 ||
591 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400592 {
593 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
594 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000595 }
596
597 if (!missingAttachment)
598 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000599 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
600 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400601 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000602 {
603 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
604 }
605
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000606 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
607 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300608 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000609 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400610 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000611 {
612 return GL_FRAMEBUFFER_UNSUPPORTED;
613 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000614 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000615 }
616 else
617 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400618 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400619 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000620 missingAttachment = false;
621 }
622 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000623 }
624
Jamie Madill48ef11b2016-04-27 15:21:52 -0400625 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400626 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000627 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500628 const Extents &size = depthAttachment.getSize();
629 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000630 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000631 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632 }
633
Jamie Madilla3944d42016-07-22 22:13:26 -0400634 const Format &format = depthAttachment.getFormat();
635 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400636 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000637 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400638 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400639 {
Jamie Madill81176782015-11-24 16:10:23 -0500640 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400641 }
642
Jamie Madilla3944d42016-07-22 22:13:26 -0400643 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000644 {
645 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
646 }
647 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400648 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000649 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400650 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400651 {
652 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
653 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000654 }
655
656 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000657 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400658 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000659 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000660 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400661 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000662 {
Sami Väisänena797e062016-05-12 15:23:40 +0300663 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
664 // considered complete when its depth or stencil samples are a
665 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700666 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300667 if (!mixedSamples)
668 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
669
670 const int colorSamples = samples ? samples : 1;
671 const int depthSamples = depthAttachment.getSamples();
672 if ((depthSamples % colorSamples) != 0)
673 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000674 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000675 }
676
Jamie Madill48ef11b2016-04-27 15:21:52 -0400677 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400678 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000679 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500680 const Extents &size = stencilAttachment.getSize();
681 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000682 {
683 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
684 }
685
Jamie Madilla3944d42016-07-22 22:13:26 -0400686 const Format &format = stencilAttachment.getFormat();
687 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400688 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000689 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400690 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400691 {
Jamie Madill81176782015-11-24 16:10:23 -0500692 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400693 }
694
Jamie Madilla3944d42016-07-22 22:13:26 -0400695 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000696 {
697 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
698 }
699 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400700 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000701 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400702 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400703 {
704 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
705 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000706 }
707
708 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000709 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400710 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000711 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000712 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400713 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000714 {
Sami Väisänena797e062016-05-12 15:23:40 +0300715 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700716 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300717 if (!mixedSamples)
718 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
719
720 const int colorSamples = samples ? samples : 1;
721 const int stencilSamples = stencilAttachment.getSamples();
722 if ((stencilSamples % colorSamples) != 0)
723 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000724 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400725
726 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300727 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400728 stencilAttachment != depthAttachment)
729 {
730 return GL_FRAMEBUFFER_UNSUPPORTED;
731 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000732 }
733
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000734 // we need to have at least one attachment to be complete
735 if (missingAttachment)
736 {
737 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000738 }
739
Jamie Madillcc86d642015-11-24 13:00:07 -0500740 // In ES 2.0, all color attachments must have the same width and height.
741 // In ES 3.0, there is no such restriction.
Martin Radev1be913c2016-07-11 17:59:16 +0300742 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500743 {
744 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
745 }
746
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500747 syncState();
Jamie Madillcc86d642015-11-24 13:00:07 -0500748 if (!mImpl->checkStatus())
749 {
750 return GL_FRAMEBUFFER_UNSUPPORTED;
751 }
752
753 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000754}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000755
Austin Kinross08332632015-05-05 13:35:47 -0700756Error Framebuffer::discard(size_t count, const GLenum *attachments)
757{
758 return mImpl->discard(count, attachments);
759}
760
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500761Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400762{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500763 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400764}
765
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500766Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400767{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500768 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400769}
770
Jamie Madill8415b5f2016-04-26 13:41:39 -0400771Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
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->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500779}
780
Jamie Madill8415b5f2016-04-26 13:41:39 -0400781Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400782 GLenum buffer,
783 GLint drawbuffer,
784 const GLfloat *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->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500792}
793
Jamie Madill8415b5f2016-04-26 13:41:39 -0400794Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400795 GLenum buffer,
796 GLint drawbuffer,
797 const GLuint *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->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500805}
806
Jamie Madill8415b5f2016-04-26 13:41:39 -0400807Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400808 GLenum buffer,
809 GLint drawbuffer,
810 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500811{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700812 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500813 {
Jamie Madill362876b2016-06-16 14:46:59 -0400814 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500815 }
816
Jamie Madill8415b5f2016-04-26 13:41:39 -0400817 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500818}
819
Jamie Madill8415b5f2016-04-26 13:41:39 -0400820Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400821 GLenum buffer,
822 GLint drawbuffer,
823 GLfloat depth,
824 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500825{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700826 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500827 {
Jamie Madill362876b2016-06-16 14:46:59 -0400828 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500829 }
830
Jamie Madill8415b5f2016-04-26 13:41:39 -0400831 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500832}
833
Geoff Langbce529e2014-12-01 12:48:41 -0500834GLenum Framebuffer::getImplementationColorReadFormat() const
835{
836 return mImpl->getImplementationColorReadFormat();
837}
838
839GLenum Framebuffer::getImplementationColorReadType() const
840{
841 return mImpl->getImplementationColorReadType();
842}
843
Jamie Madill8415b5f2016-04-26 13:41:39 -0400844Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500845 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400846 GLenum format,
847 GLenum type,
848 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500849{
Jamie Madill362876b2016-06-16 14:46:59 -0400850 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400851
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700852 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400853 if (unpackBuffer)
854 {
855 unpackBuffer->onPixelUnpack();
856 }
857
Jamie Madill362876b2016-06-16 14:46:59 -0400858 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500859}
860
Jamie Madill8415b5f2016-04-26 13:41:39 -0400861Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500862 const Rectangle &sourceArea,
863 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400864 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400865 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500866{
He Yunchao6be602d2016-12-22 14:33:07 +0800867 GLbitfield blitMask = mask;
868
869 // Note that blitting is called against draw framebuffer.
870 // See the code in gl::Context::blitFramebuffer.
871 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
872 {
873 blitMask &= ~GL_COLOR_BUFFER_BIT;
874 }
875
876 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
877 {
878 blitMask &= ~GL_STENCIL_BUFFER_BIT;
879 }
880
881 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
882 {
883 blitMask &= ~GL_DEPTH_BUFFER_BIT;
884 }
885
886 if (!blitMask)
887 {
888 return NoError();
889 }
890
891 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -0500892}
893
Jamie Madill51f40ec2016-06-15 14:06:00 -0400894int Framebuffer::getSamples(const ContextState &state)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000895{
Jamie Madill362876b2016-06-16 14:46:59 -0400896 if (complete(state))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000897 {
Jamie Madill362876b2016-06-16 14:46:59 -0400898 // For a complete framebuffer, all attachments must have the same sample count.
899 // In this case return the first nonzero sample size.
900 const auto *firstColorAttachment = mState.getFirstColorAttachment();
901 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000902 {
Jamie Madill362876b2016-06-16 14:46:59 -0400903 ASSERT(firstColorAttachment->isAttached());
904 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000905 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000906 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000907
908 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000909}
910
Corentin Wallezccab69d2017-01-27 16:57:15 -0500911Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
912{
913 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
914 return gl::NoError();
915}
916
Jamie Madille261b442014-06-25 12:42:21 -0400917bool Framebuffer::hasValidDepthStencil() const
918{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400919 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400920}
921
Jamie Madill2d06b732015-04-20 12:53:28 -0400922void Framebuffer::setAttachment(GLenum type,
923 GLenum binding,
924 const ImageIndex &textureIndex,
925 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400926{
Jamie Madill2d06b732015-04-20 12:53:28 -0400927 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400928 {
Geoff Langab75a052014-10-15 12:56:37 -0400929 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400930 FramebufferAttachmentObject *attachmentObj = resource;
931 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400932 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400933 FramebufferAttachment::Target target(binding, textureIndex);
Jamie Madilla3944d42016-07-22 22:13:26 -0400934 const Format &format = resource->getAttachmentFormat(target);
935 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
Jamie Madill375c37c2015-07-21 15:14:08 -0400936 {
937 // Attaching nullptr detaches the current attachment.
938 attachmentObj = nullptr;
939 }
Geoff Langab75a052014-10-15 12:56:37 -0400940 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400941
Jamie Madill48ef11b2016-04-27 15:21:52 -0400942 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
943 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500944 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
945 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400946 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
947 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
Geoff Langab75a052014-10-15 12:56:37 -0400948 }
949 else
950 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400951 switch (binding)
952 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500953 case GL_DEPTH:
954 case GL_DEPTH_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400955 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500956 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400957 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
958 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500959 case GL_STENCIL:
960 case GL_STENCIL_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400961 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500962 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400963 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
964 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500965 case GL_BACK:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400966 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500967 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill362876b2016-06-16 14:46:59 -0400968 // No need for a resource binding for the default FBO, it's always complete.
969 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500970 default:
Jamie Madill2d06b732015-04-20 12:53:28 -0400971 {
972 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
Jamie Madill48ef11b2016-04-27 15:21:52 -0400973 ASSERT(colorIndex < mState.mColorAttachments.size());
974 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500975 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400976 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
Jamie Madilla4595b82017-01-11 17:36:34 -0500977
978 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
979 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -0400980 }
981 break;
982 }
Geoff Langab75a052014-10-15 12:56:37 -0400983 }
984}
985
Jamie Madill2d06b732015-04-20 12:53:28 -0400986void Framebuffer::resetAttachment(GLenum binding)
987{
988 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
989}
990
Jamie Madill362876b2016-06-16 14:46:59 -0400991void Framebuffer::syncState()
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500992{
993 if (mDirtyBits.any())
994 {
995 mImpl->syncState(mDirtyBits);
996 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -0500997 if (mId != 0)
998 {
999 mCachedStatus.reset();
1000 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001001 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001002}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001003
Jamie Madill362876b2016-06-16 14:46:59 -04001004void Framebuffer::signal(SignalToken token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001005{
Jamie Madill362876b2016-06-16 14:46:59 -04001006 // TOOD(jmadill): Make this only update individual attachments to do less work.
1007 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001008}
1009
Jamie Madill362876b2016-06-16 14:46:59 -04001010bool Framebuffer::complete(const ContextState &state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001011{
Jamie Madill362876b2016-06-16 14:46:59 -04001012 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001013}
1014
Jamie Madilla4595b82017-01-11 17:36:34 -05001015bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1016{
1017 const Program *program = state.getProgram();
1018
1019 // TODO(jmadill): Default framebuffer feedback loops.
1020 if (mId == 0)
1021 {
1022 return false;
1023 }
1024
1025 // The bitset will skip inactive draw buffers.
1026 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1027 {
1028 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1029 if (attachment && attachment->type() == GL_TEXTURE)
1030 {
1031 // Validate the feedback loop.
1032 if (program->samplesFromTexture(state, attachment->id()))
1033 {
1034 return true;
1035 }
1036 }
1037 }
1038
Jamie Madill1d37bc52017-02-02 19:59:58 -05001039 // Validate depth-stencil feedback loop.
1040 const auto &dsState = state.getDepthStencilState();
1041
1042 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1043 const FramebufferAttachment *depth = getDepthbuffer();
1044 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1045 {
1046 if (program->samplesFromTexture(state, depth->id()))
1047 {
1048 return true;
1049 }
1050 }
1051
1052 // Note: we assume the front and back masks are the same for WebGL.
1053 const FramebufferAttachment *stencil = getStencilbuffer();
1054 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1055 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1056 dsState.stencilWritemask != 0)
1057 {
1058 // Skip the feedback loop check if depth/stencil point to the same resource.
1059 if (!depth || *stencil != *depth)
1060 {
1061 if (program->samplesFromTexture(state, stencil->id()))
1062 {
1063 return true;
1064 }
1065 }
1066 }
1067
Jamie Madilla4595b82017-01-11 17:36:34 -05001068 return false;
1069}
1070
Jamie Madillf695a3a2017-01-11 17:36:35 -05001071bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID, GLint copyTextureLevel) const
1072{
1073 if (mId == 0)
1074 {
1075 // It seems impossible to form a texture copying feedback loop with the default FBO.
1076 return false;
1077 }
1078
1079 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1080 ASSERT(readAttachment);
1081
1082 if (readAttachment->isTextureWithId(copyTextureID))
1083 {
1084 // TODO(jmadill): 3D/Array texture layers.
1085 if (readAttachment->getTextureImageIndex().mipIndex == copyTextureLevel)
1086 {
1087 return true;
1088 }
1089 }
1090 return false;
1091}
1092
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001093} // namespace gl