blob: 3849f03fbe3ed6b1820812f9a656b463d441c3a1 [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"
Jamie Madill6c1f6712017-02-14 19:08:04 -050017#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050018#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040019#include "libANGLE/Renderbuffer.h"
20#include "libANGLE/Surface.h"
21#include "libANGLE/Texture.h"
22#include "libANGLE/formatutils.h"
Jamie Madill8415b5f2016-04-26 13:41:39 -040023#include "libANGLE/renderer/ContextImpl.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050024#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill7aea7e02016-05-10 10:39:45 -040025#include "libANGLE/renderer/GLImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050026#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040027#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040028
Jamie Madill362876b2016-06-16 14:46:59 -040029using namespace angle;
30
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000031namespace gl
32{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000033
Jamie Madilld1405e52015-03-05 15:41:39 -050034namespace
35{
Jamie Madill362876b2016-06-16 14:46:59 -040036
37void BindResourceChannel(ChannelBinding *binding, FramebufferAttachmentObject *resource)
Jamie Madilld1405e52015-03-05 15:41:39 -050038{
Jamie Madill362876b2016-06-16 14:46:59 -040039 binding->bind(resource ? resource->getDirtyChannel() : nullptr);
Jamie Madilld1405e52015-03-05 15:41:39 -050040}
Jamie Madill362876b2016-06-16 14:46:59 -040041
42} // anonymous namespace
Jamie Madilld1405e52015-03-05 15:41:39 -050043
Jamie Madill48ef11b2016-04-27 15:21:52 -040044FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -050045 : mLabel(),
46 mColorAttachments(1),
Corentin Wallez37c39792015-08-20 14:19:46 -040047 mDrawBufferStates(1, GL_NONE),
48 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
49{
50 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
Jamie Madilla4595b82017-01-11 17:36:34 -050051 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -040052}
53
Jamie Madill48ef11b2016-04-27 15:21:52 -040054FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -050055 : mLabel(),
56 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050057 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
58 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
59{
Geoff Langa15472a2015-08-11 11:48:03 -040060 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -050061 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
62}
63
Jamie Madill48ef11b2016-04-27 15:21:52 -040064FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -050065{
Jamie Madilld1405e52015-03-05 15:41:39 -050066}
67
Jamie Madill48ef11b2016-04-27 15:21:52 -040068const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -050069{
70 return mLabel;
71}
72
Geoff Lang4b7f12b2016-06-21 16:47:07 -040073const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
74{
75 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
76 {
77 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
78 }
79
80 switch (attachment)
81 {
82 case GL_COLOR:
83 case GL_BACK:
84 return getColorAttachment(0);
85 case GL_DEPTH:
86 case GL_DEPTH_ATTACHMENT:
87 return getDepthAttachment();
88 case GL_STENCIL:
89 case GL_STENCIL_ATTACHMENT:
90 return getStencilAttachment();
91 case GL_DEPTH_STENCIL:
92 case GL_DEPTH_STENCIL_ATTACHMENT:
93 return getDepthStencilAttachment();
94 default:
95 UNREACHABLE();
96 return nullptr;
97 }
98}
99
Jamie Madill48ef11b2016-04-27 15:21:52 -0400100const FramebufferAttachment *FramebufferState::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500101{
Antoine Labour2ec65dc2016-11-30 16:28:58 -0800102 if (mReadBufferState == GL_NONE)
103 {
104 return nullptr;
105 }
Jamie Madill7147f012015-03-05 15:41:40 -0500106 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
107 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
108 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400109 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500110}
111
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500112const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
113{
114 auto *colorAttachment = getFirstColorAttachment();
115 if (colorAttachment)
116 {
117 return colorAttachment;
118 }
119 return getDepthOrStencilAttachment();
120}
121
Jamie Madill48ef11b2016-04-27 15:21:52 -0400122const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500123{
Jamie Madill2d06b732015-04-20 12:53:28 -0400124 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500125 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400126 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500127 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400128 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500129 }
130 }
131
132 return nullptr;
133}
134
Jamie Madill48ef11b2016-04-27 15:21:52 -0400135const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500136{
Jamie Madill2d06b732015-04-20 12:53:28 -0400137 if (mDepthAttachment.isAttached())
138 {
139 return &mDepthAttachment;
140 }
141 if (mStencilAttachment.isAttached())
142 {
143 return &mStencilAttachment;
144 }
145 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500146}
147
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500148const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
149{
150 if (mStencilAttachment.isAttached())
151 {
152 return &mStencilAttachment;
153 }
154 return getDepthStencilAttachment();
155}
156
Jamie Madill48ef11b2016-04-27 15:21:52 -0400157const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400158{
159 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400160 return mColorAttachments[colorAttachment].isAttached() ?
161 &mColorAttachments[colorAttachment] :
162 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400163}
164
Jamie Madill48ef11b2016-04-27 15:21:52 -0400165const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400166{
Jamie Madill2d06b732015-04-20 12:53:28 -0400167 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400168}
169
Jamie Madill48ef11b2016-04-27 15:21:52 -0400170const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400171{
Jamie Madill2d06b732015-04-20 12:53:28 -0400172 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400173}
174
Jamie Madill48ef11b2016-04-27 15:21:52 -0400175const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400176{
177 // A valid depth-stencil attachment has the same resource bound to both the
178 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400179 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500180 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400181 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400182 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400183 }
184
185 return nullptr;
186}
187
Jamie Madill48ef11b2016-04-27 15:21:52 -0400188bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500189{
190 Optional<Extents> attachmentSize;
191
192 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
193 {
194 if (!attachment.isAttached())
195 {
196 return false;
197 }
198
199 if (!attachmentSize.valid())
200 {
201 attachmentSize = attachment.getSize();
202 return false;
203 }
204
205 return (attachment.getSize() != attachmentSize.value());
206 };
207
208 for (const auto &attachment : mColorAttachments)
209 {
210 if (hasMismatchedSize(attachment))
211 {
212 return false;
213 }
214 }
215
216 if (hasMismatchedSize(mDepthAttachment))
217 {
218 return false;
219 }
220
221 return !hasMismatchedSize(mStencilAttachment);
222}
223
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400224const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
225{
226 ASSERT(drawBufferIdx < mDrawBufferStates.size());
227 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
228 {
229 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
230 // must be COLOR_ATTACHMENTi or NONE"
231 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
232 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
233 return getAttachment(mDrawBufferStates[drawBufferIdx]);
234 }
235 else
236 {
237 return nullptr;
238 }
239}
240
241size_t FramebufferState::getDrawBufferCount() const
242{
243 return mDrawBufferStates.size();
244}
245
Geoff Langb21e20d2016-07-19 15:35:41 -0400246bool FramebufferState::colorAttachmentsAreUniqueImages() const
247{
248 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
249 firstAttachmentIdx++)
250 {
251 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
252 if (!firstAttachment.isAttached())
253 {
254 continue;
255 }
256
257 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
258 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
259 {
260 const gl::FramebufferAttachment &secondAttachment =
261 mColorAttachments[secondAttachmentIdx];
262 if (!secondAttachment.isAttached())
263 {
264 continue;
265 }
266
267 if (firstAttachment == secondAttachment)
268 {
269 return false;
270 }
271 }
272 }
273
274 return true;
275}
276
Jamie Madill7aea7e02016-05-10 10:39:45 -0400277Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400278 : mState(caps),
279 mImpl(factory->createFramebuffer(mState)),
280 mId(id),
281 mCachedStatus(),
282 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
283 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284{
Corentin Wallez37c39792015-08-20 14:19:46 -0400285 ASSERT(mId != 0);
286 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400287 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
288
289 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
290 {
291 mDirtyColorAttachmentBindings.push_back(ChannelBinding(
292 this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
293 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400294}
295
296Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400297 : mState(),
298 mImpl(surface->createDefaultFramebuffer(mState)),
299 mId(0),
300 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
301 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
302 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400303{
Geoff Langda88add2014-12-01 10:22:01 -0500304 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400305 mDirtyColorAttachmentBindings.push_back(
306 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307}
308
Corentin Wallezccab69d2017-01-27 16:57:15 -0500309Framebuffer::Framebuffer(rx::GLImplFactory *factory)
310 : mState(),
311 mImpl(factory->createFramebuffer(mState)),
312 mId(0),
313 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
314 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
315 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
316{
317 mDirtyColorAttachmentBindings.push_back(
318 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
319}
320
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321Framebuffer::~Framebuffer()
322{
Geoff Langda88add2014-12-01 10:22:01 -0500323 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000324}
325
Jamie Madill6c1f6712017-02-14 19:08:04 -0500326void Framebuffer::destroy(const Context *context)
327{
328 mImpl->destroy(rx::SafeGetImpl(context));
329}
330
331void Framebuffer::destroyDefault(const egl::Display *display)
332{
333 mImpl->destroyDefault(rx::SafeGetImpl(display));
334}
335
Geoff Lang70d0f492015-12-10 17:45:46 -0500336void Framebuffer::setLabel(const std::string &label)
337{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400338 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500339}
340
341const std::string &Framebuffer::getLabel() const
342{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400343 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500344}
345
Jamie Madille261b442014-06-25 12:42:21 -0400346void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347{
Jamie Madilld1405e52015-03-05 15:41:39 -0500348 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349}
350
Jamie Madille261b442014-06-25 12:42:21 -0400351void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352{
Jamie Madilld1405e52015-03-05 15:41:39 -0500353 detachResourceById(GL_RENDERBUFFER, renderbufferId);
354}
Jamie Madille261b442014-06-25 12:42:21 -0400355
Jamie Madilld1405e52015-03-05 15:41:39 -0500356void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
357{
Jamie Madill362876b2016-06-16 14:46:59 -0400358 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500359 {
Jamie Madill362876b2016-06-16 14:46:59 -0400360 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
361 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362 }
363
Jamie Madill362876b2016-06-16 14:46:59 -0400364 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
365 DIRTY_BIT_DEPTH_ATTACHMENT);
366 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
367 DIRTY_BIT_STENCIL_ATTACHMENT);
368}
369
370void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
371 GLenum matchType,
372 GLuint matchId,
373 size_t dirtyBit)
374{
375 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
376 {
377 attachment->detach();
378 mDirtyBits.set(dirtyBit);
379 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000380}
381
Corentin Wallez37c39792015-08-20 14:19:46 -0400382const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000383{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400384 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385}
386
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400387const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400388{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400389 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400390}
391
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400392const FramebufferAttachment *Framebuffer::getStencilbuffer() const
393{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400394 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400395}
396
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400397const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
398{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400399 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400400}
401
402const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000403{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400404 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000405}
406
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500407const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
408{
409 return mState.getStencilOrDepthStencilAttachment();
410}
411
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400412const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000413{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400414 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000415}
416
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000417GLenum Framebuffer::getReadColorbufferType() const
418{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400419 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400420 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000421}
422
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400423const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000424{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400425 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000426}
427
Jamie Madill2d06b732015-04-20 12:53:28 -0400428const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000429{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400430 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400431}
432
Geoff Langa15472a2015-08-11 11:48:03 -0400433size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000434{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400435 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400436}
437
438GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
439{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400440 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
441 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000442}
443
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500444const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
445{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400446 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500447}
448
Geoff Lang164d54e2014-12-01 10:55:33 -0500449void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000450{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400451 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500452
453 ASSERT(count <= drawStates.size());
454 std::copy(buffers, buffers + count, drawStates.begin());
455 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500456 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500457
458 mState.mEnabledDrawBuffers.reset();
459 for (size_t index = 0; index < count; ++index)
460 {
461 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
462 {
463 mState.mEnabledDrawBuffers.set(index);
464 }
465 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500466}
467
Geoff Langa15472a2015-08-11 11:48:03 -0400468const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
469{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400470 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400471}
472
473bool Framebuffer::hasEnabledDrawBuffer() const
474{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400475 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400476 {
477 if (getDrawBuffer(drawbufferIdx) != nullptr)
478 {
479 return true;
480 }
481 }
482
483 return false;
484}
485
Geoff Lang9dd95802014-12-01 11:12:59 -0500486GLenum Framebuffer::getReadBufferState() const
487{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400488 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500489}
490
491void Framebuffer::setReadBuffer(GLenum buffer)
492{
Jamie Madillb885e572015-02-03 16:16:04 -0500493 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
494 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400495 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
496 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500497 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000498}
499
Corentin Wallez37c39792015-08-20 14:19:46 -0400500size_t Framebuffer::getNumColorBuffers() const
501{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400502 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400503}
504
Jamie Madill0df8fe42015-11-24 16:10:24 -0500505bool Framebuffer::hasDepth() const
506{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400507 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500508}
509
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000510bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000511{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400512 return (mState.mStencilAttachment.isAttached() &&
513 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000514}
515
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000516bool Framebuffer::usingExtendedDrawBuffers() const
517{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400518 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000519 {
Geoff Langa15472a2015-08-11 11:48:03 -0400520 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000521 {
522 return true;
523 }
524 }
525
526 return false;
527}
528
Jamie Madill51f40ec2016-06-15 14:06:00 -0400529GLenum Framebuffer::checkStatus(const ContextState &state)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500531 // The default framebuffer is always complete except when it is surfaceless in which
532 // case it is always unsupported. We return early because the default framebuffer may
533 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500534 if (mId == 0)
535 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500536 ASSERT(mCachedStatus.valid());
537 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
538 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
539 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500540 }
541
Jamie Madill362876b2016-06-16 14:46:59 -0400542 if (hasAnyDirtyBit() || !mCachedStatus.valid())
543 {
544 mCachedStatus = checkStatusImpl(state);
545 }
546
547 return mCachedStatus.value();
548}
549
550GLenum Framebuffer::checkStatusImpl(const ContextState &state)
551{
552 ASSERT(mId != 0);
553
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000554 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000555 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000556 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557
Jamie Madill48ef11b2016-04-27 15:21:52 -0400558 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000559 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400560 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000561 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500562 const Extents &size = colorAttachment.getSize();
563 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000564 {
565 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
566 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000567
Jamie Madilla3944d42016-07-22 22:13:26 -0400568 const Format &format = colorAttachment.getFormat();
569 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400570 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000571 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400572 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000573 {
Jamie Madill81176782015-11-24 16:10:23 -0500574 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000575 }
576
Jamie Madilla3944d42016-07-22 22:13:26 -0400577 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000578 {
579 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
580 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500581
582 if (colorAttachment.layer() >= size.depth)
583 {
584 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
585 }
Jamie Madill3215b202015-12-15 16:41:39 -0500586
587 // ES3 specifies that cube map texture attachments must be cube complete.
588 // This language is missing from the ES2 spec, but we enforce it here because some
589 // desktop OpenGL drivers also enforce this validation.
590 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
591 const Texture *texture = colorAttachment.getTexture();
592 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300593 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
594 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500595 {
596 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
597 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000598 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400599 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000600 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400601 if (!formatCaps.renderable || format.info->depthBits > 0 ||
602 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400603 {
604 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
605 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000606 }
607
608 if (!missingAttachment)
609 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000610 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
611 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400612 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000613 {
614 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
615 }
616
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000617 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
618 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300619 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000620 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400621 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000622 {
623 return GL_FRAMEBUFFER_UNSUPPORTED;
624 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000625 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000626 }
627 else
628 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400629 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400630 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000631 missingAttachment = false;
632 }
633 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000634 }
635
Jamie Madill48ef11b2016-04-27 15:21:52 -0400636 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400637 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000638 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500639 const Extents &size = depthAttachment.getSize();
640 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000642 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643 }
644
Jamie Madilla3944d42016-07-22 22:13:26 -0400645 const Format &format = depthAttachment.getFormat();
646 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400647 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000648 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400649 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400650 {
Jamie Madill81176782015-11-24 16:10:23 -0500651 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400652 }
653
Jamie Madilla3944d42016-07-22 22:13:26 -0400654 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000655 {
656 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
657 }
658 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400659 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000660 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400661 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400662 {
663 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
664 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000665 }
666
667 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000668 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400669 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000670 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000671 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400672 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000673 {
Sami Väisänena797e062016-05-12 15:23:40 +0300674 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
675 // considered complete when its depth or stencil samples are a
676 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700677 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300678 if (!mixedSamples)
679 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
680
681 const int colorSamples = samples ? samples : 1;
682 const int depthSamples = depthAttachment.getSamples();
683 if ((depthSamples % colorSamples) != 0)
684 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000685 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000686 }
687
Jamie Madill48ef11b2016-04-27 15:21:52 -0400688 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400689 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000690 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500691 const Extents &size = stencilAttachment.getSize();
692 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000693 {
694 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
695 }
696
Jamie Madilla3944d42016-07-22 22:13:26 -0400697 const Format &format = stencilAttachment.getFormat();
698 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400699 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000700 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400701 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400702 {
Jamie Madill81176782015-11-24 16:10:23 -0500703 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400704 }
705
Jamie Madilla3944d42016-07-22 22:13:26 -0400706 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000707 {
708 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
709 }
710 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400711 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000712 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400713 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400714 {
715 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
716 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000717 }
718
719 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000720 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400721 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000722 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000723 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400724 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000725 {
Sami Väisänena797e062016-05-12 15:23:40 +0300726 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700727 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300728 if (!mixedSamples)
729 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
730
731 const int colorSamples = samples ? samples : 1;
732 const int stencilSamples = stencilAttachment.getSamples();
733 if ((stencilSamples % colorSamples) != 0)
734 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000735 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400736
737 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300738 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400739 stencilAttachment != depthAttachment)
740 {
741 return GL_FRAMEBUFFER_UNSUPPORTED;
742 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000743 }
744
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000745 // we need to have at least one attachment to be complete
746 if (missingAttachment)
747 {
748 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000749 }
750
Jamie Madillcc86d642015-11-24 13:00:07 -0500751 // In ES 2.0, all color attachments must have the same width and height.
752 // In ES 3.0, there is no such restriction.
Martin Radev1be913c2016-07-11 17:59:16 +0300753 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500754 {
755 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
756 }
757
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500758 syncState();
Jamie Madillcc86d642015-11-24 13:00:07 -0500759 if (!mImpl->checkStatus())
760 {
761 return GL_FRAMEBUFFER_UNSUPPORTED;
762 }
763
764 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000765}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000766
Austin Kinross08332632015-05-05 13:35:47 -0700767Error Framebuffer::discard(size_t count, const GLenum *attachments)
768{
769 return mImpl->discard(count, attachments);
770}
771
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500772Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400773{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500774 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400775}
776
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500777Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400778{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500779 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400780}
781
Jamie Madill8415b5f2016-04-26 13:41:39 -0400782Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500783{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700784 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500785 {
Jamie Madill362876b2016-06-16 14:46:59 -0400786 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500787 }
788
Jamie Madill8415b5f2016-04-26 13:41:39 -0400789 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500790}
791
Jamie Madill8415b5f2016-04-26 13:41:39 -0400792Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400793 GLenum buffer,
794 GLint drawbuffer,
795 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500796{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700797 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500798 {
Jamie Madill362876b2016-06-16 14:46:59 -0400799 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500800 }
801
Jamie Madill8415b5f2016-04-26 13:41:39 -0400802 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500803}
804
Jamie Madill8415b5f2016-04-26 13:41:39 -0400805Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400806 GLenum buffer,
807 GLint drawbuffer,
808 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500809{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700810 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500811 {
Jamie Madill362876b2016-06-16 14:46:59 -0400812 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500813 }
814
Jamie Madill8415b5f2016-04-26 13:41:39 -0400815 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500816}
817
Jamie Madill8415b5f2016-04-26 13:41:39 -0400818Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400819 GLenum buffer,
820 GLint drawbuffer,
821 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500822{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700823 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500824 {
Jamie Madill362876b2016-06-16 14:46:59 -0400825 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500826 }
827
Jamie Madill8415b5f2016-04-26 13:41:39 -0400828 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500829}
830
Jamie Madill8415b5f2016-04-26 13:41:39 -0400831Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400832 GLenum buffer,
833 GLint drawbuffer,
834 GLfloat depth,
835 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500836{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700837 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500838 {
Jamie Madill362876b2016-06-16 14:46:59 -0400839 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500840 }
841
Jamie Madill8415b5f2016-04-26 13:41:39 -0400842 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500843}
844
Geoff Langbce529e2014-12-01 12:48:41 -0500845GLenum Framebuffer::getImplementationColorReadFormat() const
846{
847 return mImpl->getImplementationColorReadFormat();
848}
849
850GLenum Framebuffer::getImplementationColorReadType() const
851{
852 return mImpl->getImplementationColorReadType();
853}
854
Jamie Madill8415b5f2016-04-26 13:41:39 -0400855Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500856 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400857 GLenum format,
858 GLenum type,
859 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500860{
Jamie Madill362876b2016-06-16 14:46:59 -0400861 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400862
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700863 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400864 if (unpackBuffer)
865 {
866 unpackBuffer->onPixelUnpack();
867 }
868
Jamie Madill362876b2016-06-16 14:46:59 -0400869 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500870}
871
Jamie Madill8415b5f2016-04-26 13:41:39 -0400872Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500873 const Rectangle &sourceArea,
874 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400875 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400876 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500877{
He Yunchao6be602d2016-12-22 14:33:07 +0800878 GLbitfield blitMask = mask;
879
880 // Note that blitting is called against draw framebuffer.
881 // See the code in gl::Context::blitFramebuffer.
882 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
883 {
884 blitMask &= ~GL_COLOR_BUFFER_BIT;
885 }
886
887 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
888 {
889 blitMask &= ~GL_STENCIL_BUFFER_BIT;
890 }
891
892 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
893 {
894 blitMask &= ~GL_DEPTH_BUFFER_BIT;
895 }
896
897 if (!blitMask)
898 {
899 return NoError();
900 }
901
902 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -0500903}
904
Jamie Madill51f40ec2016-06-15 14:06:00 -0400905int Framebuffer::getSamples(const ContextState &state)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000906{
Jamie Madill362876b2016-06-16 14:46:59 -0400907 if (complete(state))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000908 {
Jamie Madill362876b2016-06-16 14:46:59 -0400909 // For a complete framebuffer, all attachments must have the same sample count.
910 // In this case return the first nonzero sample size.
911 const auto *firstColorAttachment = mState.getFirstColorAttachment();
912 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000913 {
Jamie Madill362876b2016-06-16 14:46:59 -0400914 ASSERT(firstColorAttachment->isAttached());
915 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000916 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000917 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000918
919 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000920}
921
Corentin Wallezccab69d2017-01-27 16:57:15 -0500922Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
923{
924 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
925 return gl::NoError();
926}
927
Jamie Madille261b442014-06-25 12:42:21 -0400928bool Framebuffer::hasValidDepthStencil() const
929{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400930 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400931}
932
Jamie Madill2d06b732015-04-20 12:53:28 -0400933void Framebuffer::setAttachment(GLenum type,
934 GLenum binding,
935 const ImageIndex &textureIndex,
936 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400937{
Jamie Madill2d06b732015-04-20 12:53:28 -0400938 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400939 {
Geoff Langab75a052014-10-15 12:56:37 -0400940 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400941 FramebufferAttachmentObject *attachmentObj = resource;
942 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400943 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400944 FramebufferAttachment::Target target(binding, textureIndex);
Jamie Madilla3944d42016-07-22 22:13:26 -0400945 const Format &format = resource->getAttachmentFormat(target);
946 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
Jamie Madill375c37c2015-07-21 15:14:08 -0400947 {
948 // Attaching nullptr detaches the current attachment.
949 attachmentObj = nullptr;
950 }
Geoff Langab75a052014-10-15 12:56:37 -0400951 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400952
Jamie Madill48ef11b2016-04-27 15:21:52 -0400953 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
954 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500955 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
956 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400957 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
958 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
Geoff Langab75a052014-10-15 12:56:37 -0400959 }
960 else
961 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400962 switch (binding)
963 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500964 case GL_DEPTH:
965 case GL_DEPTH_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400966 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500967 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400968 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
969 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500970 case GL_STENCIL:
971 case GL_STENCIL_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400972 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500973 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400974 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
975 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500976 case GL_BACK:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400977 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500978 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill362876b2016-06-16 14:46:59 -0400979 // No need for a resource binding for the default FBO, it's always complete.
980 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500981 default:
Jamie Madill2d06b732015-04-20 12:53:28 -0400982 {
983 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
Jamie Madill48ef11b2016-04-27 15:21:52 -0400984 ASSERT(colorIndex < mState.mColorAttachments.size());
985 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500986 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400987 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
Jamie Madilla4595b82017-01-11 17:36:34 -0500988
989 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
990 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -0400991 }
992 break;
993 }
Geoff Langab75a052014-10-15 12:56:37 -0400994 }
995}
996
Jamie Madill2d06b732015-04-20 12:53:28 -0400997void Framebuffer::resetAttachment(GLenum binding)
998{
999 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
1000}
1001
Jamie Madill362876b2016-06-16 14:46:59 -04001002void Framebuffer::syncState()
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001003{
1004 if (mDirtyBits.any())
1005 {
1006 mImpl->syncState(mDirtyBits);
1007 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001008 if (mId != 0)
1009 {
1010 mCachedStatus.reset();
1011 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001012 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001013}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001014
Jamie Madill362876b2016-06-16 14:46:59 -04001015void Framebuffer::signal(SignalToken token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001016{
Jamie Madill362876b2016-06-16 14:46:59 -04001017 // TOOD(jmadill): Make this only update individual attachments to do less work.
1018 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001019}
1020
Jamie Madill362876b2016-06-16 14:46:59 -04001021bool Framebuffer::complete(const ContextState &state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001022{
Jamie Madill362876b2016-06-16 14:46:59 -04001023 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001024}
1025
Jamie Madilla4595b82017-01-11 17:36:34 -05001026bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1027{
1028 const Program *program = state.getProgram();
1029
1030 // TODO(jmadill): Default framebuffer feedback loops.
1031 if (mId == 0)
1032 {
1033 return false;
1034 }
1035
1036 // The bitset will skip inactive draw buffers.
1037 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1038 {
1039 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1040 if (attachment && attachment->type() == GL_TEXTURE)
1041 {
1042 // Validate the feedback loop.
1043 if (program->samplesFromTexture(state, attachment->id()))
1044 {
1045 return true;
1046 }
1047 }
1048 }
1049
Jamie Madill1d37bc52017-02-02 19:59:58 -05001050 // Validate depth-stencil feedback loop.
1051 const auto &dsState = state.getDepthStencilState();
1052
1053 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1054 const FramebufferAttachment *depth = getDepthbuffer();
1055 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1056 {
1057 if (program->samplesFromTexture(state, depth->id()))
1058 {
1059 return true;
1060 }
1061 }
1062
1063 // Note: we assume the front and back masks are the same for WebGL.
1064 const FramebufferAttachment *stencil = getStencilbuffer();
1065 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1066 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1067 dsState.stencilWritemask != 0)
1068 {
1069 // Skip the feedback loop check if depth/stencil point to the same resource.
1070 if (!depth || *stencil != *depth)
1071 {
1072 if (program->samplesFromTexture(state, stencil->id()))
1073 {
1074 return true;
1075 }
1076 }
1077 }
1078
Jamie Madilla4595b82017-01-11 17:36:34 -05001079 return false;
1080}
1081
Jamie Madillfd3dd432017-02-02 19:59:59 -05001082bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1083 GLint copyTextureLevel,
1084 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001085{
1086 if (mId == 0)
1087 {
1088 // It seems impossible to form a texture copying feedback loop with the default FBO.
1089 return false;
1090 }
1091
1092 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1093 ASSERT(readAttachment);
1094
1095 if (readAttachment->isTextureWithId(copyTextureID))
1096 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001097 const auto &imageIndex = readAttachment->getTextureImageIndex();
1098 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001099 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001100 // Check 3D/Array texture layers.
1101 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1102 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1103 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001104 }
1105 }
1106 return false;
1107}
1108
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001109} // namespace gl