blob: 08809846da113172c8516ec078ec54a7f926db8d [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"
Geoff Lang0b7eef72014-06-12 14:10:47 -040023
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024namespace gl
25{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000026
Jamie Madilld1405e52015-03-05 15:41:39 -050027namespace
28{
Jamie Madill2d06b732015-04-20 12:53:28 -040029void DetachMatchingAttachment(FramebufferAttachment *attachment, GLenum matchType, GLuint matchId)
Jamie Madilld1405e52015-03-05 15:41:39 -050030{
Jamie Madill2d06b732015-04-20 12:53:28 -040031 if (attachment->isAttached() &&
32 attachment->type() == matchType &&
33 attachment->id() == matchId)
Jamie Madilld1405e52015-03-05 15:41:39 -050034 {
Jamie Madill2d06b732015-04-20 12:53:28 -040035 attachment->detach();
Jamie Madilld1405e52015-03-05 15:41:39 -050036 }
37}
38}
39
40Framebuffer::Data::Data(const Caps &caps)
Jamie Madill2d06b732015-04-20 12:53:28 -040041 : mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050042 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
43 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
44{
45 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
46}
47
48Framebuffer::Data::~Data()
49{
Jamie Madilld1405e52015-03-05 15:41:39 -050050}
51
Jamie Madillb6bda4a2015-04-20 12:53:26 -040052const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050053{
54 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
55 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
56 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -040057 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -050058}
59
Jamie Madillb6bda4a2015-04-20 12:53:26 -040060const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050061{
Jamie Madill2d06b732015-04-20 12:53:28 -040062 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -050063 {
Jamie Madill2d06b732015-04-20 12:53:28 -040064 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -050065 {
Jamie Madill2d06b732015-04-20 12:53:28 -040066 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -050067 }
68 }
69
70 return nullptr;
71}
72
Jamie Madillb6bda4a2015-04-20 12:53:26 -040073const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050074{
Jamie Madill2d06b732015-04-20 12:53:28 -040075 if (mDepthAttachment.isAttached())
76 {
77 return &mDepthAttachment;
78 }
79 if (mStencilAttachment.isAttached())
80 {
81 return &mStencilAttachment;
82 }
83 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -050084}
85
Jamie Madill18fdcbc2015-08-19 18:12:44 +000086const FramebufferAttachment *Framebuffer::Data::getColorAttachment(unsigned int colorAttachment) const
Jamie Madillb6bda4a2015-04-20 12:53:26 -040087{
88 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -040089 return mColorAttachments[colorAttachment].isAttached() ?
90 &mColorAttachments[colorAttachment] :
91 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -040092}
93
Jamie Madille3ef7152015-04-28 16:55:17 +000094const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -040095{
Jamie Madill2d06b732015-04-20 12:53:28 -040096 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -040097}
98
Jamie Madille3ef7152015-04-28 16:55:17 +000099const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400100{
Jamie Madill2d06b732015-04-20 12:53:28 -0400101 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400102}
103
Jamie Madille3ef7152015-04-28 16:55:17 +0000104const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400105{
106 // A valid depth-stencil attachment has the same resource bound to both the
107 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400108 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
109 mDepthAttachment.type() == mStencilAttachment.type() &&
110 mDepthAttachment.id() == mStencilAttachment.id())
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400111 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400112 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400113 }
114
115 return nullptr;
116}
117
Jamie Madill48115b62015-03-16 10:46:57 -0400118Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
Jamie Madill18fdcbc2015-08-19 18:12:44 +0000119 : mData(caps),
120 mImpl(nullptr),
121 mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122{
Jamie Madill18fdcbc2015-08-19 18:12:44 +0000123 if (mId == 0)
124 {
125 mImpl = factory->createDefaultFramebuffer(mData);
126 }
127 else
128 {
129 mImpl = factory->createFramebuffer(mData);
130 }
Geoff Langda88add2014-12-01 10:22:01 -0500131 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000132}
133
134Framebuffer::~Framebuffer()
135{
Geoff Langda88add2014-12-01 10:22:01 -0500136 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000137}
138
Jamie Madille261b442014-06-25 12:42:21 -0400139void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000140{
Jamie Madilld1405e52015-03-05 15:41:39 -0500141 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142}
143
Jamie Madille261b442014-06-25 12:42:21 -0400144void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145{
Jamie Madilld1405e52015-03-05 15:41:39 -0500146 detachResourceById(GL_RENDERBUFFER, renderbufferId);
147}
Jamie Madille261b442014-06-25 12:42:21 -0400148
Jamie Madilld1405e52015-03-05 15:41:39 -0500149void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
150{
151 for (auto &colorAttachment : mData.mColorAttachments)
152 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400153 DetachMatchingAttachment(&colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154 }
155
Jamie Madill2d06b732015-04-20 12:53:28 -0400156 DetachMatchingAttachment(&mData.mDepthAttachment, resourceType, resourceId);
157 DetachMatchingAttachment(&mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158}
159
Jamie Madill18fdcbc2015-08-19 18:12:44 +0000160const FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400162 return mData.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163}
164
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400165const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400166{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400167 return mData.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400168}
169
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400170const FramebufferAttachment *Framebuffer::getStencilbuffer() const
171{
172 return mData.getStencilAttachment();
173}
174
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400175const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
176{
177 return mData.getDepthStencilAttachment();
178}
179
180const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000181{
Jamie Madill7147f012015-03-05 15:41:40 -0500182 return mData.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000183}
184
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400185const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000186{
Jamie Madill7147f012015-03-05 15:41:40 -0500187 return mData.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000188}
189
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000190GLenum Framebuffer::getReadColorbufferType() const
191{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400192 const FramebufferAttachment *readAttachment = mData.getReadAttachment();
193 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000194}
195
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400196const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000197{
Jamie Madill7147f012015-03-05 15:41:40 -0500198 return mData.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000199}
200
Jamie Madill2d06b732015-04-20 12:53:28 -0400201const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000202{
Jamie Madille92a3542014-07-03 10:38:58 -0400203 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
204 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000205 return mData.getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
Jamie Madille92a3542014-07-03 10:38:58 -0400206 }
207 else
208 {
209 switch (attachment)
210 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500211 case GL_COLOR:
212 case GL_BACK:
Jamie Madille3ef7152015-04-28 16:55:17 +0000213 return mData.getColorAttachment(0);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500214 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400215 case GL_DEPTH_ATTACHMENT:
Jamie Madille3ef7152015-04-28 16:55:17 +0000216 return mData.getDepthAttachment();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500217 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400218 case GL_STENCIL_ATTACHMENT:
Jamie Madille3ef7152015-04-28 16:55:17 +0000219 return mData.getStencilAttachment();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500220 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400221 case GL_DEPTH_STENCIL_ATTACHMENT:
222 return getDepthStencilBuffer();
223 default:
224 UNREACHABLE();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400225 return nullptr;
Jamie Madille92a3542014-07-03 10:38:58 -0400226 }
227 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400228}
229
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000230GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
231{
Jamie Madilld1405e52015-03-05 15:41:39 -0500232 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
233 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000234}
235
Geoff Lang164d54e2014-12-01 10:55:33 -0500236void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000237{
Jamie Madilld1405e52015-03-05 15:41:39 -0500238 auto &drawStates = mData.mDrawBufferStates;
239
240 ASSERT(count <= drawStates.size());
241 std::copy(buffers, buffers + count, drawStates.begin());
242 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500243 mImpl->setDrawBuffers(count, buffers);
244}
245
246GLenum Framebuffer::getReadBufferState() const
247{
Jamie Madilld1405e52015-03-05 15:41:39 -0500248 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500249}
250
251void Framebuffer::setReadBuffer(GLenum buffer)
252{
Jamie Madillb885e572015-02-03 16:16:04 -0500253 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
254 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500255 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
256 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500257 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000258}
259
Jamie Madill18fdcbc2015-08-19 18:12:44 +0000260bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000261{
Jamie Madilld1405e52015-03-05 15:41:39 -0500262 ASSERT(colorAttachment < mData.mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400263 return (mData.mColorAttachments[colorAttachment].isAttached() &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500264 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000265}
266
267bool Framebuffer::hasEnabledColorAttachment() const
268{
Jamie Madilld1405e52015-03-05 15:41:39 -0500269 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000270 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700271 if (isEnabledColorAttachment(static_cast<unsigned int>(colorAttachment)))
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000272 {
273 return true;
274 }
275 }
276
277 return false;
278}
279
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000280bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000281{
Jamie Madill2d06b732015-04-20 12:53:28 -0400282 return (mData.mStencilAttachment.isAttached() && mData.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000283}
284
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000285bool Framebuffer::usingExtendedDrawBuffers() const
286{
Jamie Madilld1405e52015-03-05 15:41:39 -0500287 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000288 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700289 if (isEnabledColorAttachment(static_cast<unsigned int>(colorAttachment)))
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000290 {
291 return true;
292 }
293 }
294
295 return false;
296}
297
Geoff Lang748f74e2014-12-01 11:25:34 -0500298GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500300 // The default framebuffer *must* always be complete, though it may not be
301 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
302 if (mId == 0)
303 {
304 return GL_FRAMEBUFFER_COMPLETE;
305 }
306
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307 int width = 0;
308 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000309 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000310 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000311 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000312
Jamie Madill2d06b732015-04-20 12:53:28 -0400313 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000314 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400315 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000316 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400317 if (colorAttachment.getWidth() == 0 || colorAttachment.getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000318 {
319 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
320 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000321
Jamie Madill2d06b732015-04-20 12:53:28 -0400322 GLenum internalformat = colorAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500323 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400324 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400325 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000326 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400327 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000328 {
329 return GL_FRAMEBUFFER_UNSUPPORTED;
330 }
331
Geoff Lang5d601382014-07-22 15:14:06 -0400332 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000333 {
334 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
335 }
336 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400337 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000338 {
Geoff Lang5d601382014-07-22 15:14:06 -0400339 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400340 {
341 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
342 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000343 }
344
345 if (!missingAttachment)
346 {
347 // all color attachments must have the same width and height
Jamie Madill2d06b732015-04-20 12:53:28 -0400348 if (colorAttachment.getWidth() != width || colorAttachment.getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000349 {
350 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
351 }
352
353 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
354 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400355 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000356 {
357 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
358 }
359
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000360 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
361 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500362 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000363 {
Geoff Lang5d601382014-07-22 15:14:06 -0400364 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000365 {
366 return GL_FRAMEBUFFER_UNSUPPORTED;
367 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000368 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000369 }
370 else
371 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400372 width = colorAttachment.getWidth();
373 height = colorAttachment.getHeight();
374 samples = colorAttachment.getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400375 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000376 missingAttachment = false;
377 }
378 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000379 }
380
Jamie Madill2d06b732015-04-20 12:53:28 -0400381 const FramebufferAttachment &depthAttachment = mData.mDepthAttachment;
382 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000383 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400384 if (depthAttachment.getWidth() == 0 || depthAttachment.getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000386 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387 }
388
Jamie Madill2d06b732015-04-20 12:53:28 -0400389 GLenum internalformat = depthAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500390 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400391 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400392 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000393 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000394 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500395 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000396 {
397 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
398 }
399
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400400 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400401 {
402 return GL_FRAMEBUFFER_UNSUPPORTED;
403 }
404
Geoff Lang5d601382014-07-22 15:14:06 -0400405 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000406 {
407 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
408 }
409 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400410 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000411 {
Geoff Lang5d601382014-07-22 15:14:06 -0400412 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400413 {
414 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
415 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000416 }
417
418 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000419 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400420 width = depthAttachment.getWidth();
421 height = depthAttachment.getHeight();
422 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000423 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000424 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400425 else if (width != depthAttachment.getWidth() || height != depthAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000426 {
427 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
428 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400429 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000430 {
431 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
432 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000433 }
434
Jamie Madill2d06b732015-04-20 12:53:28 -0400435 const FramebufferAttachment &stencilAttachment = mData.mStencilAttachment;
436 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000437 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400438 if (stencilAttachment.getWidth() == 0 || stencilAttachment.getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000439 {
440 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
441 }
442
Jamie Madill2d06b732015-04-20 12:53:28 -0400443 GLenum internalformat = stencilAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500444 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400445 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400446 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000447 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000448 // texture stencil attachments come along as part
449 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500450 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000451 {
452 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
453 }
454
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400455 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400456 {
457 return GL_FRAMEBUFFER_UNSUPPORTED;
458 }
459
Geoff Lang5d601382014-07-22 15:14:06 -0400460 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000461 {
462 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
463 }
464 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400465 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000466 {
Geoff Lang5d601382014-07-22 15:14:06 -0400467 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400468 {
469 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
470 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000471 }
472
473 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000474 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400475 width = stencilAttachment.getWidth();
476 height = stencilAttachment.getHeight();
477 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000478 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000479 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400480 else if (width != stencilAttachment.getWidth() || height != stencilAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000481 {
482 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
483 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400484 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000485 {
486 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
487 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000488 }
489
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000490 // we need to have at least one attachment to be complete
491 if (missingAttachment)
492 {
493 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000494 }
495
Geoff Lang748f74e2014-12-01 11:25:34 -0500496 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000497}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000498
Austin Kinross08332632015-05-05 13:35:47 -0700499Error Framebuffer::discard(size_t count, const GLenum *attachments)
500{
501 return mImpl->discard(count, attachments);
502}
503
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500504Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400505{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500506 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400507}
508
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500509Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400510{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500511 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400512}
513
Jamie Madill1b94d432015-08-07 13:23:23 -0400514Error Framebuffer::clear(Context *context, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500515{
Jamie Madill1b94d432015-08-07 13:23:23 -0400516 // Sync the clear state
517 context->syncRendererState(context->getState().clearStateBitMask());
518
519 return mImpl->clear(context->getData(), mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500520}
521
Jamie Madill1b94d432015-08-07 13:23:23 -0400522Error Framebuffer::clearBufferfv(Context *context,
523 GLenum buffer,
524 GLint drawbuffer,
525 const GLfloat *values)
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->clearBufferfv(context->getState(), buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500531}
532
Jamie Madill1b94d432015-08-07 13:23:23 -0400533Error Framebuffer::clearBufferuiv(Context *context,
534 GLenum buffer,
535 GLint drawbuffer,
536 const GLuint *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->clearBufferuiv(context->getState(), buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500542}
543
Jamie Madill1b94d432015-08-07 13:23:23 -0400544Error Framebuffer::clearBufferiv(Context *context,
545 GLenum buffer,
546 GLint drawbuffer,
547 const GLint *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->clearBufferiv(context->getState(), buffer, drawbuffer, values);
Geoff Langb04dc822014-12-01 12:02:02 -0500553}
554
Jamie Madill1b94d432015-08-07 13:23:23 -0400555Error Framebuffer::clearBufferfi(Context *context,
556 GLenum buffer,
557 GLint drawbuffer,
558 GLfloat depth,
559 GLint stencil)
Geoff Langb04dc822014-12-01 12:02:02 -0500560{
Jamie Madill1b94d432015-08-07 13:23:23 -0400561 // Sync the clear state
562 context->syncRendererState(context->getState().clearStateBitMask());
563
564 return mImpl->clearBufferfi(context->getState(), buffer, drawbuffer, depth, stencil);
Geoff Langb04dc822014-12-01 12:02:02 -0500565}
566
Geoff Langbce529e2014-12-01 12:48:41 -0500567GLenum Framebuffer::getImplementationColorReadFormat() const
568{
569 return mImpl->getImplementationColorReadFormat();
570}
571
572GLenum Framebuffer::getImplementationColorReadType() const
573{
574 return mImpl->getImplementationColorReadType();
575}
576
Jamie Madill1b94d432015-08-07 13:23:23 -0400577Error Framebuffer::readPixels(Context *context,
578 const gl::Rectangle &area,
579 GLenum format,
580 GLenum type,
581 GLvoid *pixels) const
Geoff Langbce529e2014-12-01 12:48:41 -0500582{
Jamie Madill1b94d432015-08-07 13:23:23 -0400583 const State &state = context->getState();
584
585 // Sync pack state
586 context->syncRendererState(state.packStateBitMask());
587
Geoff Lang520c4ae2015-05-05 13:12:36 -0400588 Error error = mImpl->readPixels(state, area, format, type, pixels);
589 if (error.isError())
590 {
591 return error;
592 }
593
594 Buffer *unpackBuffer = state.getUnpackState().pixelBuffer.get();
595 if (unpackBuffer)
596 {
597 unpackBuffer->onPixelUnpack();
598 }
599
600 return Error(GL_NO_ERROR);
Geoff Langbce529e2014-12-01 12:48:41 -0500601}
602
Geoff Lang54bd5a42014-12-01 12:51:04 -0500603Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
604 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
605{
606 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
607}
608
Jamie Madill48faf802014-11-06 15:27:22 -0500609int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000610{
Geoff Lang748f74e2014-12-01 11:25:34 -0500611 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000612 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000613 // for a complete framebuffer, all attachments must have the same sample count
614 // in this case return the first nonzero sample size
Jamie Madill2d06b732015-04-20 12:53:28 -0400615 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000616 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400617 if (colorAttachment.isAttached())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000618 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400619 return colorAttachment.getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000620 }
621 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000622 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000623
624 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000625}
626
Jamie Madille261b442014-06-25 12:42:21 -0400627bool Framebuffer::hasValidDepthStencil() const
628{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400629 return mData.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400630}
631
Jamie Madill2d06b732015-04-20 12:53:28 -0400632void Framebuffer::setAttachment(GLenum type,
633 GLenum binding,
634 const ImageIndex &textureIndex,
635 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400636{
Jamie Madill2d06b732015-04-20 12:53:28 -0400637 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400638 {
Geoff Langab75a052014-10-15 12:56:37 -0400639 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400640 FramebufferAttachmentObject *attachmentObj = resource;
641 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400642 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400643 FramebufferAttachment::Target target(binding, textureIndex);
644 GLenum internalFormat = resource->getAttachmentInternalFormat(target);
645 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
646 if (formatInfo.depthBits == 0 || formatInfo.stencilBits == 0)
647 {
648 // Attaching nullptr detaches the current attachment.
649 attachmentObj = nullptr;
650 }
Geoff Langab75a052014-10-15 12:56:37 -0400651 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400652
653 mData.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
654 mData.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400655 mImpl->onUpdateDepthStencilAttachment();
Geoff Langab75a052014-10-15 12:56:37 -0400656 }
657 else
658 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400659 switch (binding)
660 {
661 case GL_DEPTH:
662 case GL_DEPTH_ATTACHMENT:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400663 mData.mDepthAttachment.attach(type, binding, textureIndex, resource);
664 mImpl->onUpdateDepthAttachment();
Jamie Madill2d06b732015-04-20 12:53:28 -0400665 break;
666 case GL_STENCIL:
667 case GL_STENCIL_ATTACHMENT:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400668 mData.mStencilAttachment.attach(type, binding, textureIndex, resource);
669 mImpl->onUpdateStencilAttachment();
Jamie Madill2d06b732015-04-20 12:53:28 -0400670 break;
671 case GL_BACK:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400672 mData.mColorAttachments[0].attach(type, binding, textureIndex, resource);
673 mImpl->onUpdateColorAttachment(0);
Jamie Madill2d06b732015-04-20 12:53:28 -0400674 break;
675 default:
676 {
677 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
678 ASSERT(colorIndex < mData.mColorAttachments.size());
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400679 mData.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
680 mImpl->onUpdateColorAttachment(colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -0400681 }
682 break;
683 }
Geoff Langab75a052014-10-15 12:56:37 -0400684 }
685}
686
Jamie Madill2d06b732015-04-20 12:53:28 -0400687void Framebuffer::resetAttachment(GLenum binding)
688{
689 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
690}
691
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000692}