blob: 8f322e4c35b154301fda7cdd0b413edb4ba24aa1 [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 Madill6f60d052017-02-22 15:20:11 -050044// This constructor is only used for default framebuffers.
Jamie Madill48ef11b2016-04-27 15:21:52 -040045FramebufferState::FramebufferState()
Geoff Lang70d0f492015-12-10 17:45:46 -050046 : mLabel(),
47 mColorAttachments(1),
Jamie Madill6f60d052017-02-22 15:20:11 -050048 mDrawBufferStates(1, GL_BACK),
49 mReadBufferState(GL_BACK),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080050 mDefaultWidth(0),
51 mDefaultHeight(0),
52 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -050053 mDefaultFixedSampleLocations(GL_FALSE),
54 mWebGLDepthStencilConsistent(true)
Corentin Wallez37c39792015-08-20 14:19:46 -040055{
Jamie Madilla4595b82017-01-11 17:36:34 -050056 mEnabledDrawBuffers.set(0);
Corentin Wallez37c39792015-08-20 14:19:46 -040057}
58
Jamie Madill48ef11b2016-04-27 15:21:52 -040059FramebufferState::FramebufferState(const Caps &caps)
Geoff Lang70d0f492015-12-10 17:45:46 -050060 : mLabel(),
61 mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050062 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080063 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
64 mDefaultWidth(0),
65 mDefaultHeight(0),
66 mDefaultSamples(0),
Jamie Madilla02315b2017-02-23 14:14:47 -050067 mDefaultFixedSampleLocations(GL_FALSE),
68 mWebGLDepthStencilConsistent(true)
Jamie Madilld1405e52015-03-05 15:41:39 -050069{
Geoff Langa15472a2015-08-11 11:48:03 -040070 ASSERT(mDrawBufferStates.size() > 0);
Jamie Madilld1405e52015-03-05 15:41:39 -050071 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
72}
73
Jamie Madill48ef11b2016-04-27 15:21:52 -040074FramebufferState::~FramebufferState()
Jamie Madilld1405e52015-03-05 15:41:39 -050075{
Jamie Madilld1405e52015-03-05 15:41:39 -050076}
77
Jamie Madill48ef11b2016-04-27 15:21:52 -040078const std::string &FramebufferState::getLabel()
Geoff Lang70d0f492015-12-10 17:45:46 -050079{
80 return mLabel;
81}
82
Geoff Lang4b7f12b2016-06-21 16:47:07 -040083const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
84{
85 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
86 {
87 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
88 }
89
90 switch (attachment)
91 {
92 case GL_COLOR:
93 case GL_BACK:
94 return getColorAttachment(0);
95 case GL_DEPTH:
96 case GL_DEPTH_ATTACHMENT:
97 return getDepthAttachment();
98 case GL_STENCIL:
99 case GL_STENCIL_ATTACHMENT:
100 return getStencilAttachment();
101 case GL_DEPTH_STENCIL:
102 case GL_DEPTH_STENCIL_ATTACHMENT:
103 return getDepthStencilAttachment();
104 default:
105 UNREACHABLE();
106 return nullptr;
107 }
108}
109
Jamie Madill48ef11b2016-04-27 15:21:52 -0400110const FramebufferAttachment *FramebufferState::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500111{
Antoine Labour2ec65dc2016-11-30 16:28:58 -0800112 if (mReadBufferState == GL_NONE)
113 {
114 return nullptr;
115 }
Jamie Madill7147f012015-03-05 15:41:40 -0500116 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
117 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
118 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400119 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500120}
121
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500122const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const
123{
124 auto *colorAttachment = getFirstColorAttachment();
125 if (colorAttachment)
126 {
127 return colorAttachment;
128 }
129 return getDepthOrStencilAttachment();
130}
131
Jamie Madill48ef11b2016-04-27 15:21:52 -0400132const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500133{
Jamie Madill2d06b732015-04-20 12:53:28 -0400134 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -0500135 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400136 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -0500137 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400138 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -0500139 }
140 }
141
142 return nullptr;
143}
144
Jamie Madill48ef11b2016-04-27 15:21:52 -0400145const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -0500146{
Jamie Madill2d06b732015-04-20 12:53:28 -0400147 if (mDepthAttachment.isAttached())
148 {
149 return &mDepthAttachment;
150 }
151 if (mStencilAttachment.isAttached())
152 {
153 return &mStencilAttachment;
154 }
155 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -0500156}
157
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500158const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
159{
160 if (mStencilAttachment.isAttached())
161 {
162 return &mStencilAttachment;
163 }
164 return getDepthStencilAttachment();
165}
166
Jamie Madill48ef11b2016-04-27 15:21:52 -0400167const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400168{
169 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400170 return mColorAttachments[colorAttachment].isAttached() ?
171 &mColorAttachments[colorAttachment] :
172 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400173}
174
Jamie Madill48ef11b2016-04-27 15:21:52 -0400175const FramebufferAttachment *FramebufferState::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400176{
Jamie Madill2d06b732015-04-20 12:53:28 -0400177 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400178}
179
Jamie Madill48ef11b2016-04-27 15:21:52 -0400180const FramebufferAttachment *FramebufferState::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400181{
Jamie Madill2d06b732015-04-20 12:53:28 -0400182 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400183}
184
Jamie Madill48ef11b2016-04-27 15:21:52 -0400185const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400186{
187 // A valid depth-stencil attachment has the same resource bound to both the
188 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400189 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
Jamie Madill44f26482016-11-18 12:49:15 -0500190 mDepthAttachment == mStencilAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400191 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400192 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400193 }
194
195 return nullptr;
196}
197
Jamie Madill48ef11b2016-04-27 15:21:52 -0400198bool FramebufferState::attachmentsHaveSameDimensions() const
Jamie Madillcc86d642015-11-24 13:00:07 -0500199{
200 Optional<Extents> attachmentSize;
201
202 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
203 {
204 if (!attachment.isAttached())
205 {
206 return false;
207 }
208
209 if (!attachmentSize.valid())
210 {
211 attachmentSize = attachment.getSize();
212 return false;
213 }
214
215 return (attachment.getSize() != attachmentSize.value());
216 };
217
218 for (const auto &attachment : mColorAttachments)
219 {
220 if (hasMismatchedSize(attachment))
221 {
222 return false;
223 }
224 }
225
226 if (hasMismatchedSize(mDepthAttachment))
227 {
228 return false;
229 }
230
231 return !hasMismatchedSize(mStencilAttachment);
232}
233
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400234const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
235{
236 ASSERT(drawBufferIdx < mDrawBufferStates.size());
237 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
238 {
239 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
240 // must be COLOR_ATTACHMENTi or NONE"
241 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
242 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
243 return getAttachment(mDrawBufferStates[drawBufferIdx]);
244 }
245 else
246 {
247 return nullptr;
248 }
249}
250
251size_t FramebufferState::getDrawBufferCount() const
252{
253 return mDrawBufferStates.size();
254}
255
Geoff Langb21e20d2016-07-19 15:35:41 -0400256bool FramebufferState::colorAttachmentsAreUniqueImages() const
257{
258 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
259 firstAttachmentIdx++)
260 {
261 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
262 if (!firstAttachment.isAttached())
263 {
264 continue;
265 }
266
267 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
268 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
269 {
270 const gl::FramebufferAttachment &secondAttachment =
271 mColorAttachments[secondAttachmentIdx];
272 if (!secondAttachment.isAttached())
273 {
274 continue;
275 }
276
277 if (firstAttachment == secondAttachment)
278 {
279 return false;
280 }
281 }
282 }
283
284 return true;
285}
286
Jamie Madill7aea7e02016-05-10 10:39:45 -0400287Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
Jamie Madill362876b2016-06-16 14:46:59 -0400288 : mState(caps),
289 mImpl(factory->createFramebuffer(mState)),
290 mId(id),
291 mCachedStatus(),
292 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
293 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294{
Corentin Wallez37c39792015-08-20 14:19:46 -0400295 ASSERT(mId != 0);
296 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400297 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
298
299 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
300 {
301 mDirtyColorAttachmentBindings.push_back(ChannelBinding(
302 this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
303 }
Corentin Wallez37c39792015-08-20 14:19:46 -0400304}
305
Jamie Madill6f60d052017-02-22 15:20:11 -0500306Framebuffer::Framebuffer(egl::Surface *surface)
Jamie Madill362876b2016-06-16 14:46:59 -0400307 : mState(),
Jamie Madill6f60d052017-02-22 15:20:11 -0500308 mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
Jamie Madill362876b2016-06-16 14:46:59 -0400309 mId(0),
310 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
311 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
312 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
Corentin Wallez37c39792015-08-20 14:19:46 -0400313{
Geoff Langda88add2014-12-01 10:22:01 -0500314 ASSERT(mImpl != nullptr);
Jamie Madill362876b2016-06-16 14:46:59 -0400315 mDirtyColorAttachmentBindings.push_back(
316 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
Jamie Madill6f60d052017-02-22 15:20:11 -0500317
Jamie Madilla02315b2017-02-23 14:14:47 -0500318 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500319
320 if (surface->getConfig()->depthSize > 0)
321 {
Jamie Madilla02315b2017-02-23 14:14:47 -0500322 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500323 }
324
325 if (surface->getConfig()->stencilSize > 0)
326 {
Jamie Madilla02315b2017-02-23 14:14:47 -0500327 setAttachmentImpl(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, gl::ImageIndex::MakeInvalid(),
328 surface);
Jamie Madill6f60d052017-02-22 15:20:11 -0500329 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330}
331
Corentin Wallezccab69d2017-01-27 16:57:15 -0500332Framebuffer::Framebuffer(rx::GLImplFactory *factory)
333 : mState(),
334 mImpl(factory->createFramebuffer(mState)),
335 mId(0),
336 mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
337 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
338 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
339{
340 mDirtyColorAttachmentBindings.push_back(
341 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
342}
343
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344Framebuffer::~Framebuffer()
345{
Geoff Langda88add2014-12-01 10:22:01 -0500346 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000347}
348
Jamie Madill6c1f6712017-02-14 19:08:04 -0500349void Framebuffer::destroy(const Context *context)
350{
351 mImpl->destroy(rx::SafeGetImpl(context));
352}
353
354void Framebuffer::destroyDefault(const egl::Display *display)
355{
356 mImpl->destroyDefault(rx::SafeGetImpl(display));
357}
358
Geoff Lang70d0f492015-12-10 17:45:46 -0500359void Framebuffer::setLabel(const std::string &label)
360{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400361 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500362}
363
364const std::string &Framebuffer::getLabel() const
365{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400366 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500367}
368
Jamie Madilla02315b2017-02-23 14:14:47 -0500369void Framebuffer::detachTexture(const Context *context, GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370{
Jamie Madilla02315b2017-02-23 14:14:47 -0500371 detachResourceById(context, GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372}
373
Jamie Madilla02315b2017-02-23 14:14:47 -0500374void Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000375{
Jamie Madilla02315b2017-02-23 14:14:47 -0500376 detachResourceById(context, GL_RENDERBUFFER, renderbufferId);
Jamie Madilld1405e52015-03-05 15:41:39 -0500377}
Jamie Madille261b442014-06-25 12:42:21 -0400378
Jamie Madilla02315b2017-02-23 14:14:47 -0500379void Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
Jamie Madilld1405e52015-03-05 15:41:39 -0500380{
Jamie Madill362876b2016-06-16 14:46:59 -0400381 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
Jamie Madilld1405e52015-03-05 15:41:39 -0500382 {
Jamie Madill362876b2016-06-16 14:46:59 -0400383 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
384 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385 }
386
Jamie Madilla02315b2017-02-23 14:14:47 -0500387 if (context->isWebGL1())
388 {
389 const std::array<FramebufferAttachment *, 3> attachments = {
390 {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment,
391 &mState.mWebGLStencilAttachment}};
392 for (FramebufferAttachment *attachment : attachments)
393 {
394 if (attachment->isAttached() && attachment->type() == resourceType &&
395 attachment->id() == resourceId)
396 {
397 resetAttachment(context, attachment->getBinding());
398 }
399 }
400 }
401 else
402 {
403 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
404 DIRTY_BIT_DEPTH_ATTACHMENT);
405 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
406 DIRTY_BIT_STENCIL_ATTACHMENT);
407 }
Jamie Madill362876b2016-06-16 14:46:59 -0400408}
409
410void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
411 GLenum matchType,
412 GLuint matchId,
413 size_t dirtyBit)
414{
415 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
416 {
417 attachment->detach();
418 mDirtyBits.set(dirtyBit);
419 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420}
421
Corentin Wallez37c39792015-08-20 14:19:46 -0400422const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000423{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400424 return mState.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425}
426
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400427const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400428{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400429 return mState.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400430}
431
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400432const FramebufferAttachment *Framebuffer::getStencilbuffer() const
433{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400434 return mState.getStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400435}
436
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400437const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
438{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400439 return mState.getDepthStencilAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400440}
441
442const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000443{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400444 return mState.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000445}
446
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500447const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
448{
449 return mState.getStencilOrDepthStencilAttachment();
450}
451
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400452const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000453{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400454 return mState.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000455}
456
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000457GLenum Framebuffer::getReadColorbufferType() const
458{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400459 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400460 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000461}
462
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400463const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000464{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400465 return mState.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000466}
467
Jamie Madill2d06b732015-04-20 12:53:28 -0400468const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000469{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400470 return mState.getAttachment(attachment);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400471}
472
Geoff Langa15472a2015-08-11 11:48:03 -0400473size_t Framebuffer::getDrawbufferStateCount() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000474{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400475 return mState.mDrawBufferStates.size();
Geoff Langa15472a2015-08-11 11:48:03 -0400476}
477
478GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
479{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400480 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
481 return mState.mDrawBufferStates[drawBuffer];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000482}
483
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500484const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
485{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400486 return mState.getDrawBufferStates();
Jamie Madill1fbc59f2016-02-24 15:25:51 -0500487}
488
Geoff Lang164d54e2014-12-01 10:55:33 -0500489void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000490{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400491 auto &drawStates = mState.mDrawBufferStates;
Jamie Madilld1405e52015-03-05 15:41:39 -0500492
493 ASSERT(count <= drawStates.size());
494 std::copy(buffers, buffers + count, drawStates.begin());
495 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500496 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
Jamie Madilla4595b82017-01-11 17:36:34 -0500497
498 mState.mEnabledDrawBuffers.reset();
499 for (size_t index = 0; index < count; ++index)
500 {
501 if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
502 {
503 mState.mEnabledDrawBuffers.set(index);
504 }
505 }
Geoff Lang9dd95802014-12-01 11:12:59 -0500506}
507
Geoff Langa15472a2015-08-11 11:48:03 -0400508const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
509{
Geoff Lang4b7f12b2016-06-21 16:47:07 -0400510 return mState.getDrawBuffer(drawBuffer);
Geoff Langa15472a2015-08-11 11:48:03 -0400511}
512
513bool Framebuffer::hasEnabledDrawBuffer() const
514{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400515 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
Geoff Langa15472a2015-08-11 11:48:03 -0400516 {
517 if (getDrawBuffer(drawbufferIdx) != nullptr)
518 {
519 return true;
520 }
521 }
522
523 return false;
524}
525
Geoff Lang9dd95802014-12-01 11:12:59 -0500526GLenum Framebuffer::getReadBufferState() const
527{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400528 return mState.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500529}
530
531void Framebuffer::setReadBuffer(GLenum buffer)
532{
Jamie Madillb885e572015-02-03 16:16:04 -0500533 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
534 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madill48ef11b2016-04-27 15:21:52 -0400535 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
536 mState.mReadBufferState = buffer;
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500537 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000538}
539
Corentin Wallez37c39792015-08-20 14:19:46 -0400540size_t Framebuffer::getNumColorBuffers() const
541{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400542 return mState.mColorAttachments.size();
Corentin Wallez37c39792015-08-20 14:19:46 -0400543}
544
Jamie Madill0df8fe42015-11-24 16:10:24 -0500545bool Framebuffer::hasDepth() const
546{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400547 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
Jamie Madill0df8fe42015-11-24 16:10:24 -0500548}
549
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000550bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000551{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400552 return (mState.mStencilAttachment.isAttached() &&
553 mState.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000554}
555
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000556bool Framebuffer::usingExtendedDrawBuffers() const
557{
Jamie Madill48ef11b2016-04-27 15:21:52 -0400558 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000559 {
Geoff Langa15472a2015-08-11 11:48:03 -0400560 if (getDrawBuffer(drawbufferIdx) != nullptr)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000561 {
562 return true;
563 }
564 }
565
566 return false;
567}
568
Jamie Madill51f40ec2016-06-15 14:06:00 -0400569GLenum Framebuffer::checkStatus(const ContextState &state)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000570{
Corentin Wallezccab69d2017-01-27 16:57:15 -0500571 // The default framebuffer is always complete except when it is surfaceless in which
572 // case it is always unsupported. We return early because the default framebuffer may
573 // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
Geoff Lang528ce3c2014-12-01 10:44:07 -0500574 if (mId == 0)
575 {
Corentin Wallezccab69d2017-01-27 16:57:15 -0500576 ASSERT(mCachedStatus.valid());
577 ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
578 mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
579 return mCachedStatus.value();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500580 }
581
Jamie Madill362876b2016-06-16 14:46:59 -0400582 if (hasAnyDirtyBit() || !mCachedStatus.valid())
583 {
584 mCachedStatus = checkStatusImpl(state);
585 }
586
587 return mCachedStatus.value();
588}
589
590GLenum Framebuffer::checkStatusImpl(const ContextState &state)
591{
592 ASSERT(mId != 0);
593
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000594 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000595 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000596 bool missingAttachment = true;
JiangYizhou461d9a32017-01-04 16:37:26 +0800597 Optional<GLboolean> fixedSampleLocations;
598 bool hasRenderbuffer = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599
Jamie Madill48ef11b2016-04-27 15:21:52 -0400600 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400602 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000603 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500604 const Extents &size = colorAttachment.getSize();
605 if (size.width == 0 || size.height == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000606 {
607 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
608 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000609
Jamie Madilla3944d42016-07-22 22:13:26 -0400610 const Format &format = colorAttachment.getFormat();
611 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400612 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000613 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400614 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000615 {
Jamie Madill81176782015-11-24 16:10:23 -0500616 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000617 }
618
Jamie Madilla3944d42016-07-22 22:13:26 -0400619 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000620 {
621 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
622 }
Jamie Madill6b120b92015-11-24 13:00:07 -0500623
624 if (colorAttachment.layer() >= size.depth)
625 {
626 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
627 }
Jamie Madill3215b202015-12-15 16:41:39 -0500628
629 // ES3 specifies that cube map texture attachments must be cube complete.
630 // This language is missing from the ES2 spec, but we enforce it here because some
631 // desktop OpenGL drivers also enforce this validation.
632 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
633 const Texture *texture = colorAttachment.getTexture();
634 ASSERT(texture);
Olli Etuahoe8528d82016-05-16 17:50:52 +0300635 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
636 !texture->getTextureState().isCubeComplete())
Jamie Madill3215b202015-12-15 16:41:39 -0500637 {
638 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
639 }
JiangYizhou461d9a32017-01-04 16:37:26 +0800640
641 // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS
642 // should be the same for all attached textures.
643 GLboolean fixedSampleloc = colorAttachment.getTexture()->getFixedSampleLocations(
644 colorAttachment.getTextureImageIndex().type, 0);
645 if (fixedSampleLocations.valid() && fixedSampleloc != fixedSampleLocations.value())
646 {
647 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
648 }
649 else
650 {
651 fixedSampleLocations = fixedSampleloc;
652 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000653 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400654 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000655 {
JiangYizhou461d9a32017-01-04 16:37:26 +0800656 hasRenderbuffer = true;
Jamie Madilla3944d42016-07-22 22:13:26 -0400657 if (!formatCaps.renderable || format.info->depthBits > 0 ||
658 format.info->stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400659 {
660 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
661 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000662 }
663
664 if (!missingAttachment)
665 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000666 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
667 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400668 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000669 {
670 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
671 }
672
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000673 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
674 // in GLES 3.0, there is no such restriction
Martin Radev1be913c2016-07-11 17:59:16 +0300675 if (state.getClientMajorVersion() < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000676 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400677 if (format.info->pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000678 {
679 return GL_FRAMEBUFFER_UNSUPPORTED;
680 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000681 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000682 }
683 else
684 {
JiangYizhou461d9a32017-01-04 16:37:26 +0800685 samples = colorAttachment.getSamples();
Jamie Madilla3944d42016-07-22 22:13:26 -0400686 colorbufferSize = format.info->pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000687 missingAttachment = false;
688 }
689 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000690 }
691
Jamie Madill48ef11b2016-04-27 15:21:52 -0400692 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400693 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000694 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500695 const Extents &size = depthAttachment.getSize();
696 if (size.width == 0 || size.height == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000697 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000698 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000699 }
700
Jamie Madilla3944d42016-07-22 22:13:26 -0400701 const Format &format = depthAttachment.getFormat();
702 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400703 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000704 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400705 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400706 {
Jamie Madill81176782015-11-24 16:10:23 -0500707 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400708 }
709
Jamie Madilla3944d42016-07-22 22:13:26 -0400710 if (format.info->depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000711 {
712 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
713 }
714 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400715 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000716 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400717 if (!formatCaps.renderable || format.info->depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400718 {
719 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
720 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000721 }
722
723 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000724 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400725 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000726 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000727 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400728 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000729 {
Sami Väisänena797e062016-05-12 15:23:40 +0300730 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
731 // considered complete when its depth or stencil samples are a
732 // multiple of the number of color samples.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700733 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300734 if (!mixedSamples)
735 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
736
737 const int colorSamples = samples ? samples : 1;
738 const int depthSamples = depthAttachment.getSamples();
739 if ((depthSamples % colorSamples) != 0)
740 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000741 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000742 }
743
Jamie Madill48ef11b2016-04-27 15:21:52 -0400744 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
Jamie Madill2d06b732015-04-20 12:53:28 -0400745 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000746 {
Jamie Madill6b120b92015-11-24 13:00:07 -0500747 const Extents &size = stencilAttachment.getSize();
748 if (size.width == 0 || size.height == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000749 {
750 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
751 }
752
Jamie Madilla3944d42016-07-22 22:13:26 -0400753 const Format &format = stencilAttachment.getFormat();
754 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
Jamie Madill2d06b732015-04-20 12:53:28 -0400755 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000756 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400757 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400758 {
Jamie Madill81176782015-11-24 16:10:23 -0500759 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
Geoff Langcec35902014-04-16 10:52:36 -0400760 }
761
Jamie Madilla3944d42016-07-22 22:13:26 -0400762 if (format.info->stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000763 {
764 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
765 }
766 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400767 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000768 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400769 if (!formatCaps.renderable || format.info->stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400770 {
771 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
772 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000773 }
774
775 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000776 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400777 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000778 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000779 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400780 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000781 {
Sami Väisänena797e062016-05-12 15:23:40 +0300782 // see the comments in depth attachment check.
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700783 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
Sami Väisänena797e062016-05-12 15:23:40 +0300784 if (!mixedSamples)
785 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
786
787 const int colorSamples = samples ? samples : 1;
788 const int stencilSamples = stencilAttachment.getSamples();
789 if ((stencilSamples % colorSamples) != 0)
790 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000791 }
Corentin Wallez086d59a2016-04-29 09:06:49 -0400792
793 // Starting from ES 3.0 stencil and depth, if present, should be the same image
Martin Radev1be913c2016-07-11 17:59:16 +0300794 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
Corentin Wallez086d59a2016-04-29 09:06:49 -0400795 stencilAttachment != depthAttachment)
796 {
797 return GL_FRAMEBUFFER_UNSUPPORTED;
798 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000799 }
800
Jamie Madilla02315b2017-02-23 14:14:47 -0500801 // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
802 if (state.isWebGL1())
803 {
804 if (!mState.mWebGLDepthStencilConsistent)
805 {
806 return GL_FRAMEBUFFER_UNSUPPORTED;
807 }
808
809 if (mState.mWebGLDepthStencilAttachment.isAttached())
810 {
811 if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 ||
812 mState.mWebGLDepthStencilAttachment.getStencilSize() == 0)
813 {
814 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
815 }
816 }
817 else if (mState.mStencilAttachment.isAttached() &&
818 mState.mStencilAttachment.getDepthSize() > 0)
819 {
820 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
821 }
822 else if (mState.mDepthAttachment.isAttached() &&
823 mState.mDepthAttachment.getStencilSize() > 0)
824 {
825 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
826 }
827 }
828
JiangYizhou461d9a32017-01-04 16:37:26 +0800829 // ES3.1(section 9.4) requires that if no image is attached to the
830 // framebuffer, and either the value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH
831 // or FRAMEBUFFER_DEFAULT_HEIGHT parameters is zero, the framebuffer is
832 // considered incomplete.
833 GLint defaultWidth = mState.getDefaultWidth();
834 GLint defaultHeight = mState.getDefaultHeight();
835
836 if (missingAttachment && (defaultWidth == 0 || defaultHeight == 0))
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000837 {
838 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000839 }
840
Jamie Madillcc86d642015-11-24 13:00:07 -0500841 // In ES 2.0, all color attachments must have the same width and height.
842 // In ES 3.0, there is no such restriction.
Martin Radev1be913c2016-07-11 17:59:16 +0300843 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
Jamie Madillcc86d642015-11-24 13:00:07 -0500844 {
845 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
846 }
847
JiangYizhou461d9a32017-01-04 16:37:26 +0800848 // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers
849 // and textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all
850 // attached textures.
851 if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
852 {
853 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
854 }
855
Jamie Madill60ec6ea2016-01-22 15:27:19 -0500856 syncState();
Jamie Madillcc86d642015-11-24 13:00:07 -0500857 if (!mImpl->checkStatus())
858 {
859 return GL_FRAMEBUFFER_UNSUPPORTED;
860 }
861
862 return GL_FRAMEBUFFER_COMPLETE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000863}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000864
Austin Kinross08332632015-05-05 13:35:47 -0700865Error Framebuffer::discard(size_t count, const GLenum *attachments)
866{
867 return mImpl->discard(count, attachments);
868}
869
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500870Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400871{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500872 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400873}
874
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500875Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400876{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500877 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400878}
879
Jamie Madill8415b5f2016-04-26 13:41:39 -0400880Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500881{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700882 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500883 {
Jamie Madill362876b2016-06-16 14:46:59 -0400884 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500885 }
886
Jamie Madill8415b5f2016-04-26 13:41:39 -0400887 return mImpl->clear(context, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500888}
889
Jamie Madill8415b5f2016-04-26 13:41:39 -0400890Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400891 GLenum buffer,
892 GLint drawbuffer,
893 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500894{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700895 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500896 {
Jamie Madill362876b2016-06-16 14:46:59 -0400897 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500898 }
899
Jamie Madill8415b5f2016-04-26 13:41:39 -0400900 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500901}
902
Jamie Madill8415b5f2016-04-26 13:41:39 -0400903Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400904 GLenum buffer,
905 GLint drawbuffer,
906 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500907{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700908 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500909 {
Jamie Madill362876b2016-06-16 14:46:59 -0400910 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500911 }
912
Jamie Madill8415b5f2016-04-26 13:41:39 -0400913 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500914}
915
Jamie Madill8415b5f2016-04-26 13:41:39 -0400916Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400917 GLenum buffer,
918 GLint drawbuffer,
919 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500920{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700921 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500922 {
Jamie Madill362876b2016-06-16 14:46:59 -0400923 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500924 }
925
Jamie Madill8415b5f2016-04-26 13:41:39 -0400926 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500927}
928
Jamie Madill8415b5f2016-04-26 13:41:39 -0400929Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
Jamie Madill1b94d432015-08-07 13:23:23 -0400930 GLenum buffer,
931 GLint drawbuffer,
932 GLfloat depth,
933 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500934{
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700935 if (context->getGLState().isRasterizerDiscardEnabled())
Jamie Madill984ef412015-11-24 16:10:21 -0500936 {
Jamie Madill362876b2016-06-16 14:46:59 -0400937 return gl::NoError();
Jamie Madill984ef412015-11-24 16:10:21 -0500938 }
939
Jamie Madill8415b5f2016-04-26 13:41:39 -0400940 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500941}
942
Geoff Langbce529e2014-12-01 12:48:41 -0500943GLenum Framebuffer::getImplementationColorReadFormat() const
944{
945 return mImpl->getImplementationColorReadFormat();
946}
947
948GLenum Framebuffer::getImplementationColorReadType() const
949{
950 return mImpl->getImplementationColorReadType();
951}
952
Jamie Madill8415b5f2016-04-26 13:41:39 -0400953Error Framebuffer::readPixels(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500954 const Rectangle &area,
Jamie Madill1b94d432015-08-07 13:23:23 -0400955 GLenum format,
956 GLenum type,
957 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500958{
Jamie Madill362876b2016-06-16 14:46:59 -0400959 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
Geoff Lang520c4ae2015-05-05 13:12:36 -0400960
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700961 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
Geoff Lang520c4ae2015-05-05 13:12:36 -0400962 if (unpackBuffer)
963 {
964 unpackBuffer->onPixelUnpack();
965 }
966
Jamie Madill362876b2016-06-16 14:46:59 -0400967 return NoError();
Geoff Langbce529e2014-12-01 12:48:41 -0500968}
969
Jamie Madill8415b5f2016-04-26 13:41:39 -0400970Error Framebuffer::blit(rx::ContextImpl *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500971 const Rectangle &sourceArea,
972 const Rectangle &destArea,
Geoff Lang242468f2015-09-24 14:15:41 -0400973 GLbitfield mask,
Jamie Madill8415b5f2016-04-26 13:41:39 -0400974 GLenum filter)
Geoff Lang54bd5a42014-12-01 12:51:04 -0500975{
He Yunchao6be602d2016-12-22 14:33:07 +0800976 GLbitfield blitMask = mask;
977
978 // Note that blitting is called against draw framebuffer.
979 // See the code in gl::Context::blitFramebuffer.
980 if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer())
981 {
982 blitMask &= ~GL_COLOR_BUFFER_BIT;
983 }
984
985 if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr)
986 {
987 blitMask &= ~GL_STENCIL_BUFFER_BIT;
988 }
989
990 if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr)
991 {
992 blitMask &= ~GL_DEPTH_BUFFER_BIT;
993 }
994
995 if (!blitMask)
996 {
997 return NoError();
998 }
999
1000 return mImpl->blit(context, sourceArea, destArea, blitMask, filter);
Geoff Lang54bd5a42014-12-01 12:51:04 -05001001}
1002
Jamie Madill51f40ec2016-06-15 14:06:00 -04001003int Framebuffer::getSamples(const ContextState &state)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001004{
Jamie Madill362876b2016-06-16 14:46:59 -04001005 if (complete(state))
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001006 {
Jamie Madill362876b2016-06-16 14:46:59 -04001007 // For a complete framebuffer, all attachments must have the same sample count.
1008 // In this case return the first nonzero sample size.
1009 const auto *firstColorAttachment = mState.getFirstColorAttachment();
1010 if (firstColorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001011 {
Jamie Madill362876b2016-06-16 14:46:59 -04001012 ASSERT(firstColorAttachment->isAttached());
1013 return firstColorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001014 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001015 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +00001016
1017 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +00001018}
1019
Corentin Wallezccab69d2017-01-27 16:57:15 -05001020Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const
1021{
1022 ANGLE_TRY(mImpl->getSamplePosition(index, xy));
1023 return gl::NoError();
1024}
1025
Jamie Madille261b442014-06-25 12:42:21 -04001026bool Framebuffer::hasValidDepthStencil() const
1027{
Jamie Madill48ef11b2016-04-27 15:21:52 -04001028 return mState.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -04001029}
1030
Jamie Madilla02315b2017-02-23 14:14:47 -05001031void Framebuffer::setAttachment(const Context *context,
1032 GLenum type,
Jamie Madill2d06b732015-04-20 12:53:28 -04001033 GLenum binding,
1034 const ImageIndex &textureIndex,
1035 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -04001036{
Jamie Madilla02315b2017-02-23 14:14:47 -05001037 // Context may be null in unit tests.
1038 if (!context || !context->isWebGL1())
1039 {
1040 setAttachmentImpl(type, binding, textureIndex, resource);
1041 return;
1042 }
1043
1044 switch (binding)
1045 {
1046 case GL_DEPTH_STENCIL:
1047 case GL_DEPTH_STENCIL_ATTACHMENT:
1048 mState.mWebGLDepthStencilAttachment.attach(type, binding, textureIndex, resource);
1049 break;
1050 case GL_DEPTH:
1051 case GL_DEPTH_ATTACHMENT:
1052 mState.mWebGLDepthAttachment.attach(type, binding, textureIndex, resource);
1053 break;
1054 case GL_STENCIL:
1055 case GL_STENCIL_ATTACHMENT:
1056 mState.mWebGLStencilAttachment.attach(type, binding, textureIndex, resource);
1057 break;
1058 default:
1059 setAttachmentImpl(type, binding, textureIndex, resource);
1060 return;
1061 }
1062
1063 commitWebGL1DepthStencilIfConsistent();
1064}
1065
1066void Framebuffer::commitWebGL1DepthStencilIfConsistent()
1067{
1068 int count = 0;
1069
1070 std::array<FramebufferAttachment *, 3> attachments = {{&mState.mWebGLDepthStencilAttachment,
1071 &mState.mWebGLDepthAttachment,
1072 &mState.mWebGLStencilAttachment}};
1073 for (FramebufferAttachment *attachment : attachments)
1074 {
1075 if (attachment->isAttached())
1076 {
1077 count++;
1078 }
1079 }
1080
1081 mState.mWebGLDepthStencilConsistent = (count <= 1);
1082 if (!mState.mWebGLDepthStencilConsistent)
1083 {
1084 // Inconsistent.
1085 return;
1086 }
1087
1088 if (mState.mWebGLDepthAttachment.isAttached())
1089 {
1090 const auto &depth = mState.mWebGLDepthAttachment;
1091 setAttachmentImpl(depth.type(), GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(),
1092 depth.getResource());
1093 setAttachmentImpl(GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1094 }
1095 else if (mState.mWebGLStencilAttachment.isAttached())
1096 {
1097 const auto &stencil = mState.mWebGLStencilAttachment;
1098 setAttachmentImpl(GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1099 setAttachmentImpl(stencil.type(), GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1100 stencil.getResource());
1101 }
1102 else if (mState.mWebGLDepthStencilAttachment.isAttached())
1103 {
1104 const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
1105 setAttachmentImpl(depthStencil.type(), GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(),
1106 depthStencil.getResource());
1107 setAttachmentImpl(depthStencil.type(), GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(),
1108 depthStencil.getResource());
1109 }
1110 else
1111 {
1112 setAttachmentImpl(GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1113 setAttachmentImpl(GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr);
1114 }
1115}
1116
1117void Framebuffer::setAttachmentImpl(GLenum type,
1118 GLenum binding,
1119 const ImageIndex &textureIndex,
1120 FramebufferAttachmentObject *resource)
1121{
Jamie Madill2d06b732015-04-20 12:53:28 -04001122 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -04001123 {
Geoff Langab75a052014-10-15 12:56:37 -04001124 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -04001125 FramebufferAttachmentObject *attachmentObj = resource;
1126 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -04001127 {
Jamie Madill375c37c2015-07-21 15:14:08 -04001128 FramebufferAttachment::Target target(binding, textureIndex);
Jamie Madilla3944d42016-07-22 22:13:26 -04001129 const Format &format = resource->getAttachmentFormat(target);
1130 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
Jamie Madill375c37c2015-07-21 15:14:08 -04001131 {
1132 // Attaching nullptr detaches the current attachment.
1133 attachmentObj = nullptr;
1134 }
Geoff Langab75a052014-10-15 12:56:37 -04001135 }
Jamie Madill375c37c2015-07-21 15:14:08 -04001136
Jamie Madill48ef11b2016-04-27 15:21:52 -04001137 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
1138 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001139 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
1140 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
Jamie Madill362876b2016-06-16 14:46:59 -04001141 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
1142 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
Jamie Madilla02315b2017-02-23 14:14:47 -05001143 return;
Geoff Langab75a052014-10-15 12:56:37 -04001144 }
Jamie Madilla4595b82017-01-11 17:36:34 -05001145
Jamie Madilla02315b2017-02-23 14:14:47 -05001146 switch (binding)
1147 {
1148 case GL_DEPTH:
1149 case GL_DEPTH_ATTACHMENT:
1150 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
1151 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
1152 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
Jamie Madill2d06b732015-04-20 12:53:28 -04001153 break;
Jamie Madilla02315b2017-02-23 14:14:47 -05001154 case GL_STENCIL:
1155 case GL_STENCIL_ATTACHMENT:
1156 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
1157 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
1158 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
1159 break;
1160 case GL_BACK:
1161 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
1162 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
1163 // No need for a resource binding for the default FBO, it's always complete.
1164 break;
1165 default:
1166 {
1167 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
1168 ASSERT(colorIndex < mState.mColorAttachments.size());
1169 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
1170 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
1171 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
1172
1173 bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
1174 mState.mEnabledDrawBuffers.set(colorIndex, enabled);
Jamie Madill2d06b732015-04-20 12:53:28 -04001175 }
Jamie Madilla02315b2017-02-23 14:14:47 -05001176 break;
Geoff Langab75a052014-10-15 12:56:37 -04001177 }
1178}
1179
Jamie Madilla02315b2017-02-23 14:14:47 -05001180void Framebuffer::resetAttachment(const Context *context, GLenum binding)
Jamie Madill2d06b732015-04-20 12:53:28 -04001181{
Jamie Madilla02315b2017-02-23 14:14:47 -05001182 setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
Jamie Madill2d06b732015-04-20 12:53:28 -04001183}
1184
Jamie Madill362876b2016-06-16 14:46:59 -04001185void Framebuffer::syncState()
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001186{
1187 if (mDirtyBits.any())
1188 {
1189 mImpl->syncState(mDirtyBits);
1190 mDirtyBits.reset();
Corentin Wallezccab69d2017-01-27 16:57:15 -05001191 if (mId != 0)
1192 {
1193 mCachedStatus.reset();
1194 }
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001195 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001196}
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001197
Jamie Madill362876b2016-06-16 14:46:59 -04001198void Framebuffer::signal(SignalToken token)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001199{
Jamie Madill362876b2016-06-16 14:46:59 -04001200 // TOOD(jmadill): Make this only update individual attachments to do less work.
1201 mCachedStatus.reset();
Jamie Madill51f40ec2016-06-15 14:06:00 -04001202}
1203
Jamie Madill362876b2016-06-16 14:46:59 -04001204bool Framebuffer::complete(const ContextState &state)
Jamie Madill51f40ec2016-06-15 14:06:00 -04001205{
Jamie Madill362876b2016-06-16 14:46:59 -04001206 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill51f40ec2016-06-15 14:06:00 -04001207}
1208
Jamie Madilla4595b82017-01-11 17:36:34 -05001209bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
1210{
1211 const Program *program = state.getProgram();
1212
1213 // TODO(jmadill): Default framebuffer feedback loops.
1214 if (mId == 0)
1215 {
1216 return false;
1217 }
1218
1219 // The bitset will skip inactive draw buffers.
1220 for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
1221 {
1222 const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
1223 if (attachment && attachment->type() == GL_TEXTURE)
1224 {
1225 // Validate the feedback loop.
1226 if (program->samplesFromTexture(state, attachment->id()))
1227 {
1228 return true;
1229 }
1230 }
1231 }
1232
Jamie Madill1d37bc52017-02-02 19:59:58 -05001233 // Validate depth-stencil feedback loop.
1234 const auto &dsState = state.getDepthStencilState();
1235
1236 // We can skip the feedback loop checks if depth/stencil is masked out or disabled.
1237 const FramebufferAttachment *depth = getDepthbuffer();
1238 if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask)
1239 {
1240 if (program->samplesFromTexture(state, depth->id()))
1241 {
1242 return true;
1243 }
1244 }
1245
1246 // Note: we assume the front and back masks are the same for WebGL.
1247 const FramebufferAttachment *stencil = getStencilbuffer();
1248 ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask);
1249 if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest &&
1250 dsState.stencilWritemask != 0)
1251 {
1252 // Skip the feedback loop check if depth/stencil point to the same resource.
1253 if (!depth || *stencil != *depth)
1254 {
1255 if (program->samplesFromTexture(state, stencil->id()))
1256 {
1257 return true;
1258 }
1259 }
1260 }
1261
Jamie Madilla4595b82017-01-11 17:36:34 -05001262 return false;
1263}
1264
Jamie Madillfd3dd432017-02-02 19:59:59 -05001265bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID,
1266 GLint copyTextureLevel,
1267 GLint copyTextureLayer) const
Jamie Madillf695a3a2017-01-11 17:36:35 -05001268{
1269 if (mId == 0)
1270 {
1271 // It seems impossible to form a texture copying feedback loop with the default FBO.
1272 return false;
1273 }
1274
1275 const FramebufferAttachment *readAttachment = getReadColorbuffer();
1276 ASSERT(readAttachment);
1277
1278 if (readAttachment->isTextureWithId(copyTextureID))
1279 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001280 const auto &imageIndex = readAttachment->getTextureImageIndex();
1281 if (imageIndex.mipIndex == copyTextureLevel)
Jamie Madillf695a3a2017-01-11 17:36:35 -05001282 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05001283 // Check 3D/Array texture layers.
1284 return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL ||
1285 copyTextureLayer == ImageIndex::ENTIRE_LEVEL ||
1286 imageIndex.layerIndex == copyTextureLayer;
Jamie Madillf695a3a2017-01-11 17:36:35 -05001287 }
1288 }
1289 return false;
1290}
1291
JiangYizhouf7bbc8a2016-11-16 09:57:22 +08001292GLint Framebuffer::getDefaultWidth() const
1293{
1294 return mState.getDefaultWidth();
1295}
1296
1297GLint Framebuffer::getDefaultHeight() const
1298{
1299 return mState.getDefaultHeight();
1300}
1301
1302GLint Framebuffer::getDefaultSamples() const
1303{
1304 return mState.getDefaultSamples();
1305}
1306
1307GLboolean Framebuffer::getDefaultFixedSampleLocations() const
1308{
1309 return mState.getDefaultFixedSampleLocations();
1310}
1311
1312void Framebuffer::setDefaultWidth(GLint defaultWidth)
1313{
1314 mState.mDefaultWidth = defaultWidth;
1315 mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH);
1316}
1317
1318void Framebuffer::setDefaultHeight(GLint defaultHeight)
1319{
1320 mState.mDefaultHeight = defaultHeight;
1321 mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT);
1322}
1323
1324void Framebuffer::setDefaultSamples(GLint defaultSamples)
1325{
1326 mState.mDefaultSamples = defaultSamples;
1327 mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES);
1328}
1329
1330void Framebuffer::setDefaultFixedSampleLocations(GLboolean defaultFixedSampleLocations)
1331{
1332 mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations;
1333 mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS);
1334}
1335
Jamie Madill60ec6ea2016-01-22 15:27:19 -05001336} // namespace gl