blob: fe239a0bb573922d0ac2afa601aa107b8ed2ee6b [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),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080048 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
49 mDefaultWidth(0),
50 mDefaultHeight(0),
51 mDefaultSamples(0),
52 mDefaultFixedSampleLocations(GL_FALSE)
Corentin Wallez37c39792015-08-20 14:19:46 -040053{
54 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
Jamie Madilla4595b82017-01-11 17:36:34 -050055 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -040056}
57
Jamie Madill48ef11b2016-04-27 15:21:52 -040058FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -050059 : mLabel(),
60 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050061 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080062 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
63 mDefaultWidth(0),
64 mDefaultHeight(0),
65 mDefaultSamples(0),
66 mDefaultFixedSampleLocations(GL_FALSE)
Jamie Madilld1405e52015-03-05 15:41:39 -050067{
Geoff Langa15472a2015-08-11 11:48:03 -040068 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -050069 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
70}
71
Jamie Madill48ef11b2016-04-27 15:21:52 -040072FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -050073{
Jamie Madilld1405e52015-03-05 15:41:39 -050074}
75
Jamie Madill48ef11b2016-04-27 15:21:52 -040076const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -050077{
78 return mLabel;
79}
80
Geoff Lang4b7f12b2016-06-21 16:47:07 -040081const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
82{
83 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
84 {
85 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
86 }
87
88 switch (attachment)
89 {
90 case GL_COLOR:
91 case GL_BACK:
92 return getColorAttachment(0);
93 case GL_DEPTH:
94 case GL_DEPTH_ATTACHMENT:
95 return getDepthAttachment();
96 case GL_STENCIL:
97 case GL_STENCIL_ATTACHMENT:
98 return getStencilAttachment();
99 case GL_DEPTH_STENCIL:
100 case GL_DEPTH_STENCIL_ATTACHMENT:
101 return getDepthStencilAttachment();
102 default:
103 UNREACHABLE();
104 return nullptr;
105 }
106}
107
Jamie Madill48ef11b2016-04-27 15:21:52 -0400108const FramebufferAttachment *FramebufferState::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500109{
Antoine Labour2ec65dc2016-11-30 16:28:58 -0800110 if (mReadBufferState == GL_NONE)
111 {
112 return nullptr;
113 }
Jamie Madill7147f012015-03-05 15:41:40 -0500114 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
115 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
116 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400117 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500118}
119
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500120const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
121{
122 auto *colorAttachment = getFirstColorAttachment();
123 if (colorAttachment)
124 {
125 return colorAttachment;
126 }
127 return getDepthOrStencilAttachment();
128}
129
Jamie Madill48ef11b2016-04-27 15:21:52 -0400130const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500131{
Jamie Madill2d06b732015-04-20 12:53:28 -0400132 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500133 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400134 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500135 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400136 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500137 }
138 }
139
140 return nullptr;
141}
142
Jamie Madill48ef11b2016-04-27 15:21:52 -0400143const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500144{
Jamie Madill2d06b732015-04-20 12:53:28 -0400145 if (mDepthAttachment.isAttached())
146 {
147 return &mDepthAttachment;
148 }
149 if (mStencilAttachment.isAttached())
150 {
151 return &mStencilAttachment;
152 }
153 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500154}
155
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500156const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
157{
158 if (mStencilAttachment.isAttached())
159 {
160 return &mStencilAttachment;
161 }
162 return getDepthStencilAttachment();
163}
164
Jamie Madill48ef11b2016-04-27 15:21:52 -0400165const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400166{
167 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400168 return mColorAttachments[colorAttachment].isAttached() ?
169 &mColorAttachments[colorAttachment] :
170 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400171}
172
Jamie Madill48ef11b2016-04-27 15:21:52 -0400173const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400174{
Jamie Madill2d06b732015-04-20 12:53:28 -0400175 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400176}
177
Jamie Madill48ef11b2016-04-27 15:21:52 -0400178const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400179{
Jamie Madill2d06b732015-04-20 12:53:28 -0400180 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400181}
182
Jamie Madill48ef11b2016-04-27 15:21:52 -0400183const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400184{
185 // A valid depth-stencil attachment has the same resource bound to both the
186 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400187 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500188 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400189 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400190 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400191 }
192
193 return nullptr;
194}
195
Jamie Madill48ef11b2016-04-27 15:21:52 -0400196bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500197{
198 Optional<Extents> attachmentSize;
199
200 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
201 {
202 if (!attachment.isAttached())
203 {
204 return false;
205 }
206
207 if (!attachmentSize.valid())
208 {
209 attachmentSize = attachment.getSize();
210 return false;
211 }
212
213 return (attachment.getSize() != attachmentSize.value());
214 };
215
216 for (const auto &attachment : mColorAttachments)
217 {
218 if (hasMismatchedSize(attachment))
219 {
220 return false;
221 }
222 }
223
224 if (hasMismatchedSize(mDepthAttachment))
225 {
226 return false;
227 }
228
229 return !hasMismatchedSize(mStencilAttachment);
230}
231
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400232const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
233{
234 ASSERT(drawBufferIdx < mDrawBufferStates.size());
235 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
236 {
237 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
238 // must be COLOR_ATTACHMENTi or NONE"
239 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
240 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
241 return getAttachment(mDrawBufferStates[drawBufferIdx]);
242 }
243 else
244 {
245 return nullptr;
246 }
247}
248
249size_t FramebufferState::getDrawBufferCount() const
250{
251 return mDrawBufferStates.size();
252}
253
Geoff Langb21e20d2016-07-19 15:35:41 -0400254bool FramebufferState::colorAttachmentsAreUniqueImages() const
255{
256 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
257 firstAttachmentIdx++)
258 {
259 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
260 if (!firstAttachment.isAttached())
261 {
262 continue;
263 }
264
265 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
266 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
267 {
268 const gl::FramebufferAttachment &secondAttachment =
269 mColorAttachments[secondAttachmentIdx];
270 if (!secondAttachment.isAttached())
271 {
272 continue;
273 }
274
275 if (firstAttachment == secondAttachment)
276 {
277 return false;
278 }
279 }
280 }
281
282 return true;
283}
284
Jamie Madill7aea7e02016-05-10 10:39:45 -0400285Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400286 : mState(caps),
287 mImpl(factory->createFramebuffer(mState)),
288 mId(id),
289 mCachedStatus(),
290 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
291 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292{
Corentin Wallez37c39792015-08-20 14:19:46 -0400293 ASSERT(mId != 0);
294 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400295 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
296
297 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
298 {
299 mDirtyColorAttachmentBindings.push_back(ChannelBinding(
300 this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
301 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400302}
303
304Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400305 : mState(),
306 mImpl(surface->createDefaultFramebuffer(mState)),
307 mId(0),
308 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
309 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
310 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400311{
Geoff Langda88add2014-12-01 10:22:01 -0500312 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400313 mDirtyColorAttachmentBindings.push_back(
314 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315}
316
Corentin Wallezccab69d2017-01-27 16:57:15 -0500317Framebuffer::Framebuffer(rx::GLImplFactory *factory)
318 : mState(),
319 mImpl(factory->createFramebuffer(mState)),
320 mId(0),
321 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
322 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
323 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
324{
325 mDirtyColorAttachmentBindings.push_back(
326 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
327}
328
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329Framebuffer::~Framebuffer()
330{
Geoff Langda88add2014-12-01 10:22:01 -0500331 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000332}
333
Jamie Madill6c1f6712017-02-14 19:08:04 -0500334void Framebuffer::destroy(const Context *context)
335{
336 mImpl->destroy(rx::SafeGetImpl(context));
337}
338
339void Framebuffer::destroyDefault(const egl::Display *display)
340{
341 mImpl->destroyDefault(rx::SafeGetImpl(display));
342}
343
Geoff Lang70d0f492015-12-10 17:45:46 -0500344void Framebuffer::setLabel(const std::string &label)
345{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400346 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500347}
348
349const std::string &Framebuffer::getLabel() const
350{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400351 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500352}
353
Jamie Madille261b442014-06-25 12:42:21 -0400354void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355{
Jamie Madilld1405e52015-03-05 15:41:39 -0500356 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357}
358
Jamie Madille261b442014-06-25 12:42:21 -0400359void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000360{
Jamie Madilld1405e52015-03-05 15:41:39 -0500361 detachResourceById(GL_RENDERBUFFER, renderbufferId);
362}
Jamie Madille261b442014-06-25 12:42:21 -0400363
Jamie Madilld1405e52015-03-05 15:41:39 -0500364void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
365{
Jamie Madill362876b2016-06-16 14:46:59 -0400366 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500367 {
Jamie Madill362876b2016-06-16 14:46:59 -0400368 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
369 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370 }
371
Jamie Madill362876b2016-06-16 14:46:59 -0400372 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
373 DIRTY_BIT_DEPTH_ATTACHMENT);
374 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
375 DIRTY_BIT_STENCIL_ATTACHMENT);
376}
377
378void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
379 GLenum matchType,
380 GLuint matchId,
381 size_t dirtyBit)
382{
383 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
384 {
385 attachment->detach();
386 mDirtyBits.set(dirtyBit);
387 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388}
389
Corentin Wallez37c39792015-08-20 14:19:46 -0400390const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000391{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400392 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000393}
394
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400395const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400396{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400397 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400398}
399
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400400const FramebufferAttachment *Framebuffer::getStencilbuffer() const
401{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400402 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400403}
404
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400405const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
406{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400407 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400408}
409
410const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000411{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400412 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000413}
414
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500415const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
416{
417 return mState.getStencilOrDepthStencilAttachment();
418}
419
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400420const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000421{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400422 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000423}
424
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000425GLenum Framebuffer::getReadColorbufferType() const
426{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400427 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400428 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000429}
430
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400431const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000432{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400433 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000434}
435
Jamie Madill2d06b732015-04-20 12:53:28 -0400436const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000437{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400438 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400439}
440
Geoff Langa15472a2015-08-11 11:48:03 -0400441size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000442{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400443 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400444}
445
446GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
447{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400448 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
449 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000450}
451
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500452const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
453{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400454 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500455}
456
Geoff Lang164d54e2014-12-01 10:55:33 -0500457void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000458{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400459 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500460
461 ASSERT(count <= drawStates.size());
462 std::copy(buffers, buffers + count, drawStates.begin());
463 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500464 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500465
466 mState.mEnabledDrawBuffers.reset();
467 for (size_t index = 0; index < count; ++index)
468 {
469 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
470 {
471 mState.mEnabledDrawBuffers.set(index);
472 }
473 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500474}
475
Geoff Langa15472a2015-08-11 11:48:03 -0400476const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
477{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400478 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400479}
480
481bool Framebuffer::hasEnabledDrawBuffer() const
482{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400483 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400484 {
485 if (getDrawBuffer(drawbufferIdx) != nullptr)
486 {
487 return true;
488 }
489 }
490
491 return false;
492}
493
Geoff Lang9dd95802014-12-01 11:12:59 -0500494GLenum Framebuffer::getReadBufferState() const
495{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400496 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500497}
498
499void Framebuffer::setReadBuffer(GLenum buffer)
500{
Jamie Madillb885e572015-02-03 16:16:04 -0500501 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
502 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400503 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
504 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500505 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000506}
507
Corentin Wallez37c39792015-08-20 14:19:46 -0400508size_t Framebuffer::getNumColorBuffers() const
509{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400510 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400511}
512
Jamie Madill0df8fe42015-11-24 16:10:24 -0500513bool Framebuffer::hasDepth() const
514{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400515 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500516}
517
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000518bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000519{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400520 return (mState.mStencilAttachment.isAttached() &&
521 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000522}
523
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000524bool Framebuffer::usingExtendedDrawBuffers() const
525{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400526 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000527 {
Geoff Langa15472a2015-08-11 11:48:03 -0400528 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000529 {
530 return true;
531 }
532 }
533
534 return false;
535}
536
Jamie Madill51f40ec2016-06-15 14:06:00 -0400537GLenum Framebuffer::checkStatus(const ContextState &state)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000538{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500539 // The default framebuffer is always complete except when it is surfaceless in which
540 // case it is always unsupported. We return early because the default framebuffer may
541 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500542 if (mId == 0)
543 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500544 ASSERT(mCachedStatus.valid());
545 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
546 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
547 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500548 }
549
Jamie Madill362876b2016-06-16 14:46:59 -0400550 if (hasAnyDirtyBit() || !mCachedStatus.valid())
551 {
552 mCachedStatus = checkStatusImpl(state);
553 }
554
555 return mCachedStatus.value();
556}
557
558GLenum Framebuffer::checkStatusImpl(const ContextState &state)
559{
560 ASSERT(mId != 0);
561
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000562 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000563 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000564 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000565
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800566 // TODO(yizhou): Check status for default framebuffer parameters.
Jamie Madill48ef11b2016-04-27 15:21:52 -0400567 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000568 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400569 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000570 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500571 const Extents &size = colorAttachment.getSize();
572 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000573 {
574 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
575 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000576
Jamie Madilla3944d42016-07-22 22:13:26 -0400577 const Format &format = colorAttachment.getFormat();
578 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400579 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000580 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400581 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000582 {
Jamie Madill81176782015-11-24 16:10:23 -0500583 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000584 }
585
Jamie Madilla3944d42016-07-22 22:13:26 -0400586 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000587 {
588 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
589 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500590
591 if (colorAttachment.layer() >= size.depth)
592 {
593 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
594 }
Jamie Madill3215b202015-12-15 16:41:39 -0500595
596 // ES3 specifies that cube map texture attachments must be cube complete.
597 // This language is missing from the ES2 spec, but we enforce it here because some
598 // desktop OpenGL drivers also enforce this validation.
599 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
600 const Texture *texture = colorAttachment.getTexture();
601 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300602 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
603 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500604 {
605 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
606 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000607 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400608 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000609 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400610 if (!formatCaps.renderable || format.info->depthBits > 0 ||
611 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400612 {
613 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
614 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000615 }
616
617 if (!missingAttachment)
618 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000619 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
620 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400621 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000622 {
623 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
624 }
625
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000626 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
627 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300628 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000629 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400630 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000631 {
632 return GL_FRAMEBUFFER_UNSUPPORTED;
633 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000634 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000635 }
636 else
637 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400638 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400639 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000640 missingAttachment = false;
641 }
642 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000643 }
644
Jamie Madill48ef11b2016-04-27 15:21:52 -0400645 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400646 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000647 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500648 const Extents &size = depthAttachment.getSize();
649 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000651 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000652 }
653
Jamie Madilla3944d42016-07-22 22:13:26 -0400654 const Format &format = depthAttachment.getFormat();
655 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400656 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000657 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400658 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400659 {
Jamie Madill81176782015-11-24 16:10:23 -0500660 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400661 }
662
Jamie Madilla3944d42016-07-22 22:13:26 -0400663 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000664 {
665 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
666 }
667 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400668 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000669 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400670 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400671 {
672 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
673 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000674 }
675
676 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000677 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400678 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000679 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000680 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400681 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000682 {
Sami Väisänena797e062016-05-12 15:23:40 +0300683 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
684 // considered complete when its depth or stencil samples are a
685 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700686 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300687 if (!mixedSamples)
688 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
689
690 const int colorSamples = samples ? samples : 1;
691 const int depthSamples = depthAttachment.getSamples();
692 if ((depthSamples % colorSamples) != 0)
693 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000694 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000695 }
696
Jamie Madill48ef11b2016-04-27 15:21:52 -0400697 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400698 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000699 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500700 const Extents &size = stencilAttachment.getSize();
701 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000702 {
703 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
704 }
705
Jamie Madilla3944d42016-07-22 22:13:26 -0400706 const Format &format = stencilAttachment.getFormat();
707 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400708 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000709 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400710 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400711 {
Jamie Madill81176782015-11-24 16:10:23 -0500712 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400713 }
714
Jamie Madilla3944d42016-07-22 22:13:26 -0400715 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000716 {
717 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
718 }
719 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400720 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000721 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400722 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400723 {
724 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
725 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000726 }
727
728 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000729 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400730 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000731 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000732 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400733 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000734 {
Sami Väisänena797e062016-05-12 15:23:40 +0300735 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700736 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300737 if (!mixedSamples)
738 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
739
740 const int colorSamples = samples ? samples : 1;
741 const int stencilSamples = stencilAttachment.getSamples();
742 if ((stencilSamples % colorSamples) != 0)
743 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000744 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400745
746 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300747 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400748 stencilAttachment != depthAttachment)
749 {
750 return GL_FRAMEBUFFER_UNSUPPORTED;
751 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000752 }
753
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000754 // we need to have at least one attachment to be complete
755 if (missingAttachment)
756 {
757 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000758 }
759
Jamie Madillcc86d642015-11-24 13:00:07 -0500760 // In ES 2.0, all color attachments must have the same width and height.
761 // In ES 3.0, there is no such restriction.
Martin Radev1be913c2016-07-11 17:59:16 +0300762 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500763 {
764 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
765 }
766
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500767 syncState();
Jamie Madillcc86d642015-11-24 13:00:07 -0500768 if (!mImpl->checkStatus())
769 {
770 return GL_FRAMEBUFFER_UNSUPPORTED;
771 }
772
773 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000774}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000775
Austin Kinross08332632015-05-05 13:35:47 -0700776Error Framebuffer::discard(size_t count, const GLenum *attachments)
777{
778 return mImpl->discard(count, attachments);
779}
780
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500781Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400782{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500783 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400784}
785
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500786Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400787{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500788 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400789}
790
Jamie Madill8415b5f2016-04-26 13:41:39 -0400791Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500792{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700793 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500794 {
Jamie Madill362876b2016-06-16 14:46:59 -0400795 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500796 }
797
Jamie Madill8415b5f2016-04-26 13:41:39 -0400798 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500799}
800
Jamie Madill8415b5f2016-04-26 13:41:39 -0400801Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400802 GLenum buffer,
803 GLint drawbuffer,
804 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500805{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700806 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500807 {
Jamie Madill362876b2016-06-16 14:46:59 -0400808 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500809 }
810
Jamie Madill8415b5f2016-04-26 13:41:39 -0400811 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500812}
813
Jamie Madill8415b5f2016-04-26 13:41:39 -0400814Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400815 GLenum buffer,
816 GLint drawbuffer,
817 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500818{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700819 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500820 {
Jamie Madill362876b2016-06-16 14:46:59 -0400821 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500822 }
823
Jamie Madill8415b5f2016-04-26 13:41:39 -0400824 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500825}
826
Jamie Madill8415b5f2016-04-26 13:41:39 -0400827Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400828 GLenum buffer,
829 GLint drawbuffer,
830 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500831{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700832 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500833 {
Jamie Madill362876b2016-06-16 14:46:59 -0400834 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500835 }
836
Jamie Madill8415b5f2016-04-26 13:41:39 -0400837 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500838}
839
Jamie Madill8415b5f2016-04-26 13:41:39 -0400840Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400841 GLenum buffer,
842 GLint drawbuffer,
843 GLfloat depth,
844 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500845{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700846 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500847 {
Jamie Madill362876b2016-06-16 14:46:59 -0400848 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500849 }
850
Jamie Madill8415b5f2016-04-26 13:41:39 -0400851 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500852}
853
Geoff Langbce529e2014-12-01 12:48:41 -0500854GLenum Framebuffer::getImplementationColorReadFormat() const
855{
856 return mImpl->getImplementationColorReadFormat();
857}
858
859GLenum Framebuffer::getImplementationColorReadType() const
860{
861 return mImpl->getImplementationColorReadType();
862}
863
Jamie Madill8415b5f2016-04-26 13:41:39 -0400864Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500865 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400866 GLenum format,
867 GLenum type,
868 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500869{
Jamie Madill362876b2016-06-16 14:46:59 -0400870 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400871
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700872 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400873 if (unpackBuffer)
874 {
875 unpackBuffer->onPixelUnpack();
876 }
877
Jamie Madill362876b2016-06-16 14:46:59 -0400878 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500879}
880
Jamie Madill8415b5f2016-04-26 13:41:39 -0400881Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500882 const Rectangle &sourceArea,
883 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400884 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400885 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500886{
He Yunchao6be602d2016-12-22 14:33:07 +0800887 GLbitfield blitMask = mask;
888
889 // Note that blitting is called against draw framebuffer.
890 // See the code in gl::Context::blitFramebuffer.
891 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
892 {
893 blitMask &= ~GL_COLOR_BUFFER_BIT;
894 }
895
896 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
897 {
898 blitMask &= ~GL_STENCIL_BUFFER_BIT;
899 }
900
901 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
902 {
903 blitMask &= ~GL_DEPTH_BUFFER_BIT;
904 }
905
906 if (!blitMask)
907 {
908 return NoError();
909 }
910
911 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -0500912}
913
Jamie Madill51f40ec2016-06-15 14:06:00 -0400914int Framebuffer::getSamples(const ContextState &state)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000915{
Jamie Madill362876b2016-06-16 14:46:59 -0400916 if (complete(state))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000917 {
Jamie Madill362876b2016-06-16 14:46:59 -0400918 // For a complete framebuffer, all attachments must have the same sample count.
919 // In this case return the first nonzero sample size.
920 const auto *firstColorAttachment = mState.getFirstColorAttachment();
921 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000922 {
Jamie Madill362876b2016-06-16 14:46:59 -0400923 ASSERT(firstColorAttachment->isAttached());
924 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000925 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000926 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000927
928 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000929}
930
Corentin Wallezccab69d2017-01-27 16:57:15 -0500931Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
932{
933 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
934 return gl::NoError();
935}
936
Jamie Madille261b442014-06-25 12:42:21 -0400937bool Framebuffer::hasValidDepthStencil() const
938{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400939 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400940}
941
Jamie Madill2d06b732015-04-20 12:53:28 -0400942void Framebuffer::setAttachment(GLenum type,
943 GLenum binding,
944 const ImageIndex &textureIndex,
945 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400946{
Jamie Madill2d06b732015-04-20 12:53:28 -0400947 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400948 {
Geoff Langab75a052014-10-15 12:56:37 -0400949 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400950 FramebufferAttachmentObject *attachmentObj = resource;
951 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400952 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400953 FramebufferAttachment::Target target(binding, textureIndex);
Jamie Madilla3944d42016-07-22 22:13:26 -0400954 const Format &format = resource->getAttachmentFormat(target);
955 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
Jamie Madill375c37c2015-07-21 15:14:08 -0400956 {
957 // Attaching nullptr detaches the current attachment.
958 attachmentObj = nullptr;
959 }
Geoff Langab75a052014-10-15 12:56:37 -0400960 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400961
Jamie Madill48ef11b2016-04-27 15:21:52 -0400962 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
963 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500964 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
965 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400966 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
967 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
Geoff Langab75a052014-10-15 12:56:37 -0400968 }
969 else
970 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400971 switch (binding)
972 {
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500973 case GL_DEPTH:
974 case GL_DEPTH_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400975 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500976 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400977 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
978 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500979 case GL_STENCIL:
980 case GL_STENCIL_ATTACHMENT:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400981 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500982 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -0400983 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
984 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500985 case GL_BACK:
Jamie Madill48ef11b2016-04-27 15:21:52 -0400986 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500987 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
Jamie Madill362876b2016-06-16 14:46:59 -0400988 // No need for a resource binding for the default FBO, it's always complete.
989 break;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500990 default:
Jamie Madill2d06b732015-04-20 12:53:28 -0400991 {
992 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
Jamie Madill48ef11b2016-04-27 15:21:52 -0400993 ASSERT(colorIndex < mState.mColorAttachments.size());
994 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500995 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
Jamie Madill362876b2016-06-16 14:46:59 -0400996 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
Jamie Madilla4595b82017-01-11 17:36:34 -0500997
998 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
999 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001000 }
1001 break;
1002 }
Geoff Langab75a052014-10-15 12:56:37 -04001003 }
1004}
1005
Jamie Madill2d06b732015-04-20 12:53:28 -04001006void Framebuffer::resetAttachment(GLenum binding)
1007{
1008 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
1009}
1010
Jamie Madill362876b2016-06-16 14:46:59 -04001011void Framebuffer::syncState()
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001012{
1013 if (mDirtyBits.any())
1014 {
1015 mImpl->syncState(mDirtyBits);
1016 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001017 if (mId != 0)
1018 {
1019 mCachedStatus.reset();
1020 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001021 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001022}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001023
Jamie Madill362876b2016-06-16 14:46:59 -04001024void Framebuffer::signal(SignalToken token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001025{
Jamie Madill362876b2016-06-16 14:46:59 -04001026 // TOOD(jmadill): Make this only update individual attachments to do less work.
1027 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001028}
1029
Jamie Madill362876b2016-06-16 14:46:59 -04001030bool Framebuffer::complete(const ContextState &state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001031{
Jamie Madill362876b2016-06-16 14:46:59 -04001032 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001033}
1034
Jamie Madilla4595b82017-01-11 17:36:34 -05001035bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1036{
1037 const Program *program = state.getProgram();
1038
1039 // TODO(jmadill): Default framebuffer feedback loops.
1040 if (mId == 0)
1041 {
1042 return false;
1043 }
1044
1045 // The bitset will skip inactive draw buffers.
1046 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1047 {
1048 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1049 if (attachment && attachment->type() == GL_TEXTURE)
1050 {
1051 // Validate the feedback loop.
1052 if (program->samplesFromTexture(state, attachment->id()))
1053 {
1054 return true;
1055 }
1056 }
1057 }
1058
Jamie Madill1d37bc52017-02-02 19:59:58 -05001059 // Validate depth-stencil feedback loop.
1060 const auto &dsState = state.getDepthStencilState();
1061
1062 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1063 const FramebufferAttachment *depth = getDepthbuffer();
1064 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1065 {
1066 if (program->samplesFromTexture(state, depth->id()))
1067 {
1068 return true;
1069 }
1070 }
1071
1072 // Note: we assume the front and back masks are the same for WebGL.
1073 const FramebufferAttachment *stencil = getStencilbuffer();
1074 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1075 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1076 dsState.stencilWritemask != 0)
1077 {
1078 // Skip the feedback loop check if depth/stencil point to the same resource.
1079 if (!depth || *stencil != *depth)
1080 {
1081 if (program->samplesFromTexture(state, stencil->id()))
1082 {
1083 return true;
1084 }
1085 }
1086 }
1087
Jamie Madilla4595b82017-01-11 17:36:34 -05001088 return false;
1089}
1090
Jamie Madillfd3dd432017-02-02 19:59:59 -05001091bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1092 GLint copyTextureLevel,
1093 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001094{
1095 if (mId == 0)
1096 {
1097 // It seems impossible to form a texture copying feedback loop with the default FBO.
1098 return false;
1099 }
1100
1101 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1102 ASSERT(readAttachment);
1103
1104 if (readAttachment->isTextureWithId(copyTextureID))
1105 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001106 const auto &imageIndex = readAttachment->getTextureImageIndex();
1107 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001108 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001109 // Check 3D/Array texture layers.
1110 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1111 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1112 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001113 }
1114 }
1115 return false;
1116}
1117
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001118GLint Framebuffer::getDefaultWidth() const
1119{
1120 return mState.getDefaultWidth();
1121}
1122
1123GLint Framebuffer::getDefaultHeight() const
1124{
1125 return mState.getDefaultHeight();
1126}
1127
1128GLint Framebuffer::getDefaultSamples() const
1129{
1130 return mState.getDefaultSamples();
1131}
1132
1133GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1134{
1135 return mState.getDefaultFixedSampleLocations();
1136}
1137
1138void Framebuffer::setDefaultWidth(GLint defaultWidth)
1139{
1140 mState.mDefaultWidth = defaultWidth;
1141 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1142}
1143
1144void Framebuffer::setDefaultHeight(GLint defaultHeight)
1145{
1146 mState.mDefaultHeight = defaultHeight;
1147 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1148}
1149
1150void Framebuffer::setDefaultSamples(GLint defaultSamples)
1151{
1152 mState.mDefaultSamples = defaultSamples;
1153 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1154}
1155
1156void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1157{
1158 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1159 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1160}
1161
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001162} // namespace gl