blob: afc16307b1b660555be82705f43fad501e80df5c [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
12#include "common/utilities.h"
13#include "libANGLE/Config.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Context.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050015#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040016#include "libANGLE/Renderbuffer.h"
17#include "libANGLE/Surface.h"
18#include "libANGLE/Texture.h"
19#include "libANGLE/formatutils.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050020#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill48115b62015-03-16 10:46:57 -040021#include "libANGLE/renderer/ImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/renderer/RenderbufferImpl.h"
Corentin Wallez37c39792015-08-20 14:19:46 -040023#include "libANGLE/renderer/SurfaceImpl.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040024
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025namespace gl
26{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000027
Jamie Madilld1405e52015-03-05 15:41:39 -050028namespace
29{
Jamie Madill2d06b732015-04-20 12:53:28 -040030void DetachMatchingAttachment(FramebufferAttachment *attachment, GLenum matchType, GLuint matchId)
Jamie Madilld1405e52015-03-05 15:41:39 -050031{
Jamie Madill2d06b732015-04-20 12:53:28 -040032 if (attachment->isAttached() &&
33 attachment->type() == matchType &&
34 attachment->id() == matchId)
Jamie Madilld1405e52015-03-05 15:41:39 -050035 {
Jamie Madill2d06b732015-04-20 12:53:28 -040036 attachment->detach();
Jamie Madilld1405e52015-03-05 15:41:39 -050037 }
38}
39}
40
Corentin Wallez37c39792015-08-20 14:19:46 -040041Framebuffer::Data::Data()
42 : mColorAttachments(1),
43 mDrawBufferStates(1, GL_NONE),
44 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
45{
46 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
47}
48
Jamie Madilld1405e52015-03-05 15:41:39 -050049Framebuffer::Data::Data(const Caps &caps)
Jamie Madill2d06b732015-04-20 12:53:28 -040050 : mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050051 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
52 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
53{
54 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
55}
56
57Framebuffer::Data::~Data()
58{
Jamie Madilld1405e52015-03-05 15:41:39 -050059}
60
Jamie Madillb6bda4a2015-04-20 12:53:26 -040061const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050062{
63 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
64 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
65 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -040066 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -050067}
68
Jamie Madillb6bda4a2015-04-20 12:53:26 -040069const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050070{
Jamie Madill2d06b732015-04-20 12:53:28 -040071 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -050072 {
Jamie Madill2d06b732015-04-20 12:53:28 -040073 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -050074 {
Jamie Madill2d06b732015-04-20 12:53:28 -040075 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -050076 }
77 }
78
79 return nullptr;
80}
81
Jamie Madillb6bda4a2015-04-20 12:53:26 -040082const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050083{
Jamie Madill2d06b732015-04-20 12:53:28 -040084 if (mDepthAttachment.isAttached())
85 {
86 return &mDepthAttachment;
87 }
88 if (mStencilAttachment.isAttached())
89 {
90 return &mStencilAttachment;
91 }
92 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -050093}
94
Corentin Wallez37c39792015-08-20 14:19:46 -040095const FramebufferAttachment *Framebuffer::Data::getColorAttachment(size_t colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -040096{
97 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -040098 return mColorAttachments[colorAttachment].isAttached() ?
99 &mColorAttachments[colorAttachment] :
100 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400101}
102
Jamie Madille3ef7152015-04-28 16:55:17 +0000103const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400104{
Jamie Madill2d06b732015-04-20 12:53:28 -0400105 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400106}
107
Jamie Madille3ef7152015-04-28 16:55:17 +0000108const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400109{
Jamie Madill2d06b732015-04-20 12:53:28 -0400110 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400111}
112
Jamie Madille3ef7152015-04-28 16:55:17 +0000113const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400114{
115 // A valid depth-stencil attachment has the same resource bound to both the
116 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400117 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
118 mDepthAttachment.type() == mStencilAttachment.type() &&
119 mDepthAttachment.id() == mStencilAttachment.id())
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400120 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400121 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400122 }
123
124 return nullptr;
125}
126
Jamie Madill48115b62015-03-16 10:46:57 -0400127Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
Corentin Wallez37c39792015-08-20 14:19:46 -0400128 : mData(caps), mImpl(factory->createFramebuffer(mData)), mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129{
Corentin Wallez37c39792015-08-20 14:19:46 -0400130 ASSERT(mId != 0);
131 ASSERT(mImpl != nullptr);
132}
133
134Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
135 : mData(), mImpl(surface->createDefaultFramebuffer(mData)), mId(0)
136{
Geoff Langda88add2014-12-01 10:22:01 -0500137 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138}
139
140Framebuffer::~Framebuffer()
141{
Geoff Langda88add2014-12-01 10:22:01 -0500142 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000143}
144
Jamie Madille261b442014-06-25 12:42:21 -0400145void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146{
Jamie Madilld1405e52015-03-05 15:41:39 -0500147 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148}
149
Jamie Madille261b442014-06-25 12:42:21 -0400150void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151{
Jamie Madilld1405e52015-03-05 15:41:39 -0500152 detachResourceById(GL_RENDERBUFFER, renderbufferId);
153}
Jamie Madille261b442014-06-25 12:42:21 -0400154
Jamie Madilld1405e52015-03-05 15:41:39 -0500155void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
156{
157 for (auto &colorAttachment : mData.mColorAttachments)
158 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400159 DetachMatchingAttachment(&colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160 }
161
Jamie Madill2d06b732015-04-20 12:53:28 -0400162 DetachMatchingAttachment(&mData.mDepthAttachment, resourceType, resourceId);
163 DetachMatchingAttachment(&mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164}
165
Corentin Wallez37c39792015-08-20 14:19:46 -0400166const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400168 return mData.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169}
170
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400171const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400172{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400173 return mData.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400174}
175
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400176const FramebufferAttachment *Framebuffer::getStencilbuffer() const
177{
178 return mData.getStencilAttachment();
179}
180
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400181const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
182{
183 return mData.getDepthStencilAttachment();
184}
185
186const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000187{
Jamie Madill7147f012015-03-05 15:41:40 -0500188 return mData.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000189}
190
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400191const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000192{
Jamie Madill7147f012015-03-05 15:41:40 -0500193 return mData.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000194}
195
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000196GLenum Framebuffer::getReadColorbufferType() const
197{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400198 const FramebufferAttachment *readAttachment = mData.getReadAttachment();
199 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000200}
201
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400202const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000203{
Jamie Madill7147f012015-03-05 15:41:40 -0500204 return mData.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000205}
206
Jamie Madill2d06b732015-04-20 12:53:28 -0400207const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000208{
Jamie Madille92a3542014-07-03 10:38:58 -0400209 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
210 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000211 return mData.getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
Jamie Madille92a3542014-07-03 10:38:58 -0400212 }
213 else
214 {
215 switch (attachment)
216 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500217 case GL_COLOR:
218 case GL_BACK:
Jamie Madille3ef7152015-04-28 16:55:17 +0000219 return mData.getColorAttachment(0);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500220 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400221 case GL_DEPTH_ATTACHMENT:
Jamie Madille3ef7152015-04-28 16:55:17 +0000222 return mData.getDepthAttachment();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500223 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400224 case GL_STENCIL_ATTACHMENT:
Jamie Madille3ef7152015-04-28 16:55:17 +0000225 return mData.getStencilAttachment();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500226 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400227 case GL_DEPTH_STENCIL_ATTACHMENT:
228 return getDepthStencilBuffer();
229 default:
230 UNREACHABLE();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400231 return nullptr;
Jamie Madille92a3542014-07-03 10:38:58 -0400232 }
233 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400234}
235
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000236GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
237{
Jamie Madilld1405e52015-03-05 15:41:39 -0500238 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
239 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000240}
241
Geoff Lang164d54e2014-12-01 10:55:33 -0500242void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000243{
Jamie Madilld1405e52015-03-05 15:41:39 -0500244 auto &drawStates = mData.mDrawBufferStates;
245
246 ASSERT(count <= drawStates.size());
247 std::copy(buffers, buffers + count, drawStates.begin());
248 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500249 mImpl->setDrawBuffers(count, buffers);
250}
251
252GLenum Framebuffer::getReadBufferState() const
253{
Jamie Madilld1405e52015-03-05 15:41:39 -0500254 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500255}
256
257void Framebuffer::setReadBuffer(GLenum buffer)
258{
Jamie Madillb885e572015-02-03 16:16:04 -0500259 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
260 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500261 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
262 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500263 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000264}
265
Corentin Wallez37c39792015-08-20 14:19:46 -0400266bool Framebuffer::isEnabledColorAttachment(size_t colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000267{
Jamie Madilld1405e52015-03-05 15:41:39 -0500268 ASSERT(colorAttachment < mData.mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400269 return (mData.mColorAttachments[colorAttachment].isAttached() &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500270 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000271}
272
273bool Framebuffer::hasEnabledColorAttachment() const
274{
Jamie Madilld1405e52015-03-05 15:41:39 -0500275 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000276 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700277 if (isEnabledColorAttachment(static_cast<unsigned int>(colorAttachment)))
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000278 {
279 return true;
280 }
281 }
282
283 return false;
284}
285
Corentin Wallez37c39792015-08-20 14:19:46 -0400286size_t Framebuffer::getNumColorBuffers() const
287{
288 return mData.mColorAttachments.size();
289}
290
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000291bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000292{
Jamie Madill2d06b732015-04-20 12:53:28 -0400293 return (mData.mStencilAttachment.isAttached() && mData.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000294}
295
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000296bool Framebuffer::usingExtendedDrawBuffers() const
297{
Jamie Madilld1405e52015-03-05 15:41:39 -0500298 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000299 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700300 if (isEnabledColorAttachment(static_cast<unsigned int>(colorAttachment)))
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000301 {
302 return true;
303 }
304 }
305
306 return false;
307}
308
Geoff Lang748f74e2014-12-01 11:25:34 -0500309GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500311 // The default framebuffer *must* always be complete, though it may not be
312 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
313 if (mId == 0)
314 {
315 return GL_FRAMEBUFFER_COMPLETE;
316 }
317
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000318 int width = 0;
319 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000320 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000321 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000322 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323
Jamie Madill2d06b732015-04-20 12:53:28 -0400324 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400326 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000327 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400328 if (colorAttachment.getWidth() == 0 || colorAttachment.getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000329 {
330 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
331 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000332
Jamie Madill2d06b732015-04-20 12:53:28 -0400333 GLenum internalformat = colorAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500334 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400335 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400336 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000337 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400338 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000339 {
340 return GL_FRAMEBUFFER_UNSUPPORTED;
341 }
342
Geoff Lang5d601382014-07-22 15:14:06 -0400343 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000344 {
345 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
346 }
347 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400348 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000349 {
Geoff Lang5d601382014-07-22 15:14:06 -0400350 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400351 {
352 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
353 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000354 }
355
356 if (!missingAttachment)
357 {
358 // all color attachments must have the same width and height
Jamie Madill2d06b732015-04-20 12:53:28 -0400359 if (colorAttachment.getWidth() != width || colorAttachment.getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000360 {
361 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
362 }
363
364 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
365 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400366 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000367 {
368 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
369 }
370
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000371 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
372 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500373 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000374 {
Geoff Lang5d601382014-07-22 15:14:06 -0400375 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000376 {
377 return GL_FRAMEBUFFER_UNSUPPORTED;
378 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000379 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000380 }
381 else
382 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400383 width = colorAttachment.getWidth();
384 height = colorAttachment.getHeight();
385 samples = colorAttachment.getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400386 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000387 missingAttachment = false;
388 }
389 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000390 }
391
Jamie Madill2d06b732015-04-20 12:53:28 -0400392 const FramebufferAttachment &depthAttachment = mData.mDepthAttachment;
393 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000394 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400395 if (depthAttachment.getWidth() == 0 || depthAttachment.getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000397 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000398 }
399
Jamie Madill2d06b732015-04-20 12:53:28 -0400400 GLenum internalformat = depthAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500401 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400402 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400403 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000404 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000405 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500406 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000407 {
408 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
409 }
410
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400411 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400412 {
413 return GL_FRAMEBUFFER_UNSUPPORTED;
414 }
415
Geoff Lang5d601382014-07-22 15:14:06 -0400416 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000417 {
418 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
419 }
420 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400421 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000422 {
Geoff Lang5d601382014-07-22 15:14:06 -0400423 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400424 {
425 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
426 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000427 }
428
429 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000430 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400431 width = depthAttachment.getWidth();
432 height = depthAttachment.getHeight();
433 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000434 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000435 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400436 else if (width != depthAttachment.getWidth() || height != depthAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000437 {
438 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
439 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400440 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000441 {
442 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
443 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000444 }
445
Jamie Madill2d06b732015-04-20 12:53:28 -0400446 const FramebufferAttachment &stencilAttachment = mData.mStencilAttachment;
447 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000448 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400449 if (stencilAttachment.getWidth() == 0 || stencilAttachment.getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000450 {
451 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
452 }
453
Jamie Madill2d06b732015-04-20 12:53:28 -0400454 GLenum internalformat = stencilAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500455 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400456 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400457 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000458 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000459 // texture stencil attachments come along as part
460 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500461 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000462 {
463 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
464 }
465
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400466 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400467 {
468 return GL_FRAMEBUFFER_UNSUPPORTED;
469 }
470
Geoff Lang5d601382014-07-22 15:14:06 -0400471 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000472 {
473 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
474 }
475 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400476 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000477 {
Geoff Lang5d601382014-07-22 15:14:06 -0400478 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400479 {
480 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
481 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000482 }
483
484 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000485 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400486 width = stencilAttachment.getWidth();
487 height = stencilAttachment.getHeight();
488 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000489 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000490 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400491 else if (width != stencilAttachment.getWidth() || height != stencilAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000492 {
493 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
494 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400495 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000496 {
497 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
498 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000499 }
500
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000501 // we need to have at least one attachment to be complete
502 if (missingAttachment)
503 {
504 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000505 }
506
Geoff Lang748f74e2014-12-01 11:25:34 -0500507 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000509
Austin Kinross08332632015-05-05 13:35:47 -0700510Error Framebuffer::discard(size_t count, const GLenum *attachments)
511{
512 return mImpl->discard(count, attachments);
513}
514
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500515Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400516{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500517 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400518}
519
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500520Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400521{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500522 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400523}
524
Jamie Madill1b94d432015-08-07 13:23:23 -0400525Error Framebuffer::clear(Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500526{
Jamie Madill1b94d432015-08-07 13:23:23 -0400527 // Sync the clear state
528 context->syncRendererState(context->getState().clearStateBitMask());
529
530 return mImpl->clear(context->getData(), mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500531}
532
Jamie Madill1b94d432015-08-07 13:23:23 -0400533Error Framebuffer::clearBufferfv(Context *context,
534 GLenum buffer,
535 GLint drawbuffer,
536 const GLfloat *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500537{
Jamie Madill1b94d432015-08-07 13:23:23 -0400538 // Sync the clear state
539 context->syncRendererState(context->getState().clearStateBitMask());
540
541 return mImpl->clearBufferfv(context->getState(), buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500542}
543
Jamie Madill1b94d432015-08-07 13:23:23 -0400544Error Framebuffer::clearBufferuiv(Context *context,
545 GLenum buffer,
546 GLint drawbuffer,
547 const GLuint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500548{
Jamie Madill1b94d432015-08-07 13:23:23 -0400549 // Sync the clear state
550 context->syncRendererState(context->getState().clearStateBitMask());
551
552 return mImpl->clearBufferuiv(context->getState(), buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500553}
554
Jamie Madill1b94d432015-08-07 13:23:23 -0400555Error Framebuffer::clearBufferiv(Context *context,
556 GLenum buffer,
557 GLint drawbuffer,
558 const GLint *values)
Geoff Langb04dc822014-12-01 12:02:02 -0500559{
Jamie Madill1b94d432015-08-07 13:23:23 -0400560 // Sync the clear state
561 context->syncRendererState(context->getState().clearStateBitMask());
562
563 return mImpl->clearBufferiv(context->getState(), buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500564}
565
Jamie Madill1b94d432015-08-07 13:23:23 -0400566Error Framebuffer::clearBufferfi(Context *context,
567 GLenum buffer,
568 GLint drawbuffer,
569 GLfloat depth,
570 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500571{
Jamie Madill1b94d432015-08-07 13:23:23 -0400572 // Sync the clear state
573 context->syncRendererState(context->getState().clearStateBitMask());
574
575 return mImpl->clearBufferfi(context->getState(), buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500576}
577
Geoff Langbce529e2014-12-01 12:48:41 -0500578GLenum Framebuffer::getImplementationColorReadFormat() const
579{
580 return mImpl->getImplementationColorReadFormat();
581}
582
583GLenum Framebuffer::getImplementationColorReadType() const
584{
585 return mImpl->getImplementationColorReadType();
586}
587
Jamie Madill1b94d432015-08-07 13:23:23 -0400588Error Framebuffer::readPixels(Context *context,
589 const gl::Rectangle &area,
590 GLenum format,
591 GLenum type,
592 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500593{
Jamie Madill1b94d432015-08-07 13:23:23 -0400594 const State &state = context->getState();
595
596 // Sync pack state
597 context->syncRendererState(state.packStateBitMask());
598
Geoff Lang520c4ae2015-05-05 13:12:36 -0400599 Error error = mImpl->readPixels(state, area, format, type, pixels);
600 if (error.isError())
601 {
602 return error;
603 }
604
605 Buffer *unpackBuffer = state.getUnpackState().pixelBuffer.get();
606 if (unpackBuffer)
607 {
608 unpackBuffer->onPixelUnpack();
609 }
610
611 return Error(GL_NO_ERROR);
Geoff Langbce529e2014-12-01 12:48:41 -0500612}
613
Geoff Lang54bd5a42014-12-01 12:51:04 -0500614Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
615 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
616{
617 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
618}
619
Jamie Madill48faf802014-11-06 15:27:22 -0500620int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000621{
Geoff Lang748f74e2014-12-01 11:25:34 -0500622 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000623 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000624 // for a complete framebuffer, all attachments must have the same sample count
625 // in this case return the first nonzero sample size
Jamie Madill2d06b732015-04-20 12:53:28 -0400626 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000627 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400628 if (colorAttachment.isAttached())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000629 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400630 return colorAttachment.getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000631 }
632 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000633 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000634
635 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000636}
637
Jamie Madille261b442014-06-25 12:42:21 -0400638bool Framebuffer::hasValidDepthStencil() const
639{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400640 return mData.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400641}
642
Jamie Madill2d06b732015-04-20 12:53:28 -0400643void Framebuffer::setAttachment(GLenum type,
644 GLenum binding,
645 const ImageIndex &textureIndex,
646 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400647{
Jamie Madill2d06b732015-04-20 12:53:28 -0400648 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400649 {
Geoff Langab75a052014-10-15 12:56:37 -0400650 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400651 FramebufferAttachmentObject *attachmentObj = resource;
652 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400653 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400654 FramebufferAttachment::Target target(binding, textureIndex);
655 GLenum internalFormat = resource->getAttachmentInternalFormat(target);
656 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
657 if (formatInfo.depthBits == 0 || formatInfo.stencilBits == 0)
658 {
659 // Attaching nullptr detaches the current attachment.
660 attachmentObj = nullptr;
661 }
Geoff Langab75a052014-10-15 12:56:37 -0400662 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400663
664 mData.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
665 mData.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400666 mImpl->onUpdateDepthStencilAttachment();
Geoff Langab75a052014-10-15 12:56:37 -0400667 }
668 else
669 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400670 switch (binding)
671 {
672 case GL_DEPTH:
673 case GL_DEPTH_ATTACHMENT:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400674 mData.mDepthAttachment.attach(type, binding, textureIndex, resource);
675 mImpl->onUpdateDepthAttachment();
Jamie Madill2d06b732015-04-20 12:53:28 -0400676 break;
677 case GL_STENCIL:
678 case GL_STENCIL_ATTACHMENT:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400679 mData.mStencilAttachment.attach(type, binding, textureIndex, resource);
680 mImpl->onUpdateStencilAttachment();
Jamie Madill2d06b732015-04-20 12:53:28 -0400681 break;
682 case GL_BACK:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400683 mData.mColorAttachments[0].attach(type, binding, textureIndex, resource);
684 mImpl->onUpdateColorAttachment(0);
Jamie Madill2d06b732015-04-20 12:53:28 -0400685 break;
686 default:
687 {
688 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
689 ASSERT(colorIndex < mData.mColorAttachments.size());
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400690 mData.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
691 mImpl->onUpdateColorAttachment(colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -0400692 }
693 break;
694 }
Geoff Langab75a052014-10-15 12:56:37 -0400695 }
696}
697
Jamie Madill2d06b732015-04-20 12:53:28 -0400698void Framebuffer::resetAttachment(GLenum binding)
699{
700 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
701}
702
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000703}