blob: 3e005b3217fcee6a0025e4164eff4ed57f64b5ca [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"
23#include "libANGLE/renderer/Workarounds.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
41Framebuffer::Data::Data(const Caps &caps)
Jamie Madill2d06b732015-04-20 12:53:28 -040042 : mColorAttachments(caps.maxColorAttachments),
Jamie Madilld1405e52015-03-05 15:41:39 -050043 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
44 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
45{
46 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
47}
48
49Framebuffer::Data::~Data()
50{
Jamie Madilld1405e52015-03-05 15:41:39 -050051}
52
Jamie Madillb6bda4a2015-04-20 12:53:26 -040053const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050054{
55 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
56 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
57 ASSERT(readIndex < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -040058 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -050059}
60
Jamie Madillb6bda4a2015-04-20 12:53:26 -040061const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050062{
Jamie Madill2d06b732015-04-20 12:53:28 -040063 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
Jamie Madill7147f012015-03-05 15:41:40 -050064 {
Jamie Madill2d06b732015-04-20 12:53:28 -040065 if (colorAttachment.isAttached())
Jamie Madill7147f012015-03-05 15:41:40 -050066 {
Jamie Madill2d06b732015-04-20 12:53:28 -040067 return &colorAttachment;
Jamie Madill7147f012015-03-05 15:41:40 -050068 }
69 }
70
71 return nullptr;
72}
73
Jamie Madillb6bda4a2015-04-20 12:53:26 -040074const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050075{
Jamie Madill2d06b732015-04-20 12:53:28 -040076 if (mDepthAttachment.isAttached())
77 {
78 return &mDepthAttachment;
79 }
80 if (mStencilAttachment.isAttached())
81 {
82 return &mStencilAttachment;
83 }
84 return nullptr;
Jamie Madill7147f012015-03-05 15:41:40 -050085}
86
Jamie Madill34771622015-04-21 13:54:34 +000087FramebufferAttachment *Framebuffer::Data::getColorAttachment(unsigned int colorAttachment)
Jamie Madillb6bda4a2015-04-20 12:53:26 -040088{
89 ASSERT(colorAttachment < mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -040090 return mColorAttachments[colorAttachment].isAttached() ?
91 &mColorAttachments[colorAttachment] :
92 nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -040093}
94
Jamie Madill34771622015-04-21 13:54:34 +000095const FramebufferAttachment *Framebuffer::Data::getColorAttachment(unsigned int colorAttachment) const
96{
97 return const_cast<Framebuffer::Data *>(this)->getColorAttachment(colorAttachment);
98}
99
100FramebufferAttachment *Framebuffer::Data::getDepthAttachment()
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400101{
Jamie Madill2d06b732015-04-20 12:53:28 -0400102 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400103}
104
Jamie Madill34771622015-04-21 13:54:34 +0000105const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const
106{
107 return const_cast<Framebuffer::Data *>(this)->getDepthAttachment();
108}
109
110FramebufferAttachment *Framebuffer::Data::getStencilAttachment()
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400111{
Jamie Madill2d06b732015-04-20 12:53:28 -0400112 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400113}
114
Jamie Madill34771622015-04-21 13:54:34 +0000115const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const
116{
117 return const_cast<Framebuffer::Data *>(this)->getStencilAttachment();
118}
119
120FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment()
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400121{
122 // A valid depth-stencil attachment has the same resource bound to both the
123 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400124 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
125 mDepthAttachment.type() == mStencilAttachment.type() &&
126 mDepthAttachment.id() == mStencilAttachment.id())
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400127 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400128 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400129 }
130
131 return nullptr;
132}
133
Jamie Madill34771622015-04-21 13:54:34 +0000134const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const
135{
136 return const_cast<Framebuffer::Data *>(this)->getDepthStencilAttachment();
137}
138
Jamie Madill48115b62015-03-16 10:46:57 -0400139Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
Jamie Madilld1405e52015-03-05 15:41:39 -0500140 : mData(caps),
Geoff Lang4ad17092015-03-10 16:47:44 -0400141 mImpl(nullptr),
Jamie Madilld1405e52015-03-05 15:41:39 -0500142 mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143{
Geoff Lang4ad17092015-03-10 16:47:44 -0400144 if (mId == 0)
145 {
146 mImpl = factory->createDefaultFramebuffer(mData);
147 }
148 else
149 {
150 mImpl = factory->createFramebuffer(mData);
151 }
Geoff Langda88add2014-12-01 10:22:01 -0500152 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153}
154
155Framebuffer::~Framebuffer()
156{
Geoff Langda88add2014-12-01 10:22:01 -0500157 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000158}
159
Jamie Madille261b442014-06-25 12:42:21 -0400160void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161{
Jamie Madilld1405e52015-03-05 15:41:39 -0500162 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163}
164
Jamie Madille261b442014-06-25 12:42:21 -0400165void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000166{
Jamie Madilld1405e52015-03-05 15:41:39 -0500167 detachResourceById(GL_RENDERBUFFER, renderbufferId);
168}
Jamie Madille261b442014-06-25 12:42:21 -0400169
Jamie Madilld1405e52015-03-05 15:41:39 -0500170void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
171{
172 for (auto &colorAttachment : mData.mColorAttachments)
173 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400174 DetachMatchingAttachment(&colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175 }
176
Jamie Madill2d06b732015-04-20 12:53:28 -0400177 DetachMatchingAttachment(&mData.mDepthAttachment, resourceType, resourceId);
178 DetachMatchingAttachment(&mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179}
180
Jamie Madill34771622015-04-21 13:54:34 +0000181FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment)
182{
183 return mData.getColorAttachment(colorAttachment);
184}
185
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400186const FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400188 return mData.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
Jamie Madill34771622015-04-21 13:54:34 +0000191FramebufferAttachment *Framebuffer::getDepthbuffer()
192{
193 return mData.getDepthAttachment();
194}
195
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400196const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400197{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400198 return mData.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400199}
200
Jamie Madill34771622015-04-21 13:54:34 +0000201FramebufferAttachment *Framebuffer::getStencilbuffer()
202{
203 return mData.getStencilAttachment();
204}
205
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400206const FramebufferAttachment *Framebuffer::getStencilbuffer() const
207{
208 return mData.getStencilAttachment();
209}
210
Jamie Madill34771622015-04-21 13:54:34 +0000211FramebufferAttachment *Framebuffer::getDepthStencilBuffer()
212{
213 return mData.getDepthStencilAttachment();
214}
215
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400216const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
217{
218 return mData.getDepthStencilAttachment();
219}
220
221const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000222{
Jamie Madill7147f012015-03-05 15:41:40 -0500223 return mData.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000224}
225
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400226const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000227{
Jamie Madill7147f012015-03-05 15:41:40 -0500228 return mData.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000229}
230
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000231GLenum Framebuffer::getReadColorbufferType() const
232{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400233 const FramebufferAttachment *readAttachment = mData.getReadAttachment();
234 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000235}
236
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400237const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000238{
Jamie Madill7147f012015-03-05 15:41:40 -0500239 return mData.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000240}
241
Jamie Madill2d06b732015-04-20 12:53:28 -0400242const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000243{
Jamie Madille92a3542014-07-03 10:38:58 -0400244 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
245 {
Jamie Madill34771622015-04-21 13:54:34 +0000246 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
Jamie Madille92a3542014-07-03 10:38:58 -0400247 }
248 else
249 {
250 switch (attachment)
251 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500252 case GL_COLOR:
253 case GL_BACK:
Jamie Madill34771622015-04-21 13:54:34 +0000254 return getColorbuffer(0);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500255 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400256 case GL_DEPTH_ATTACHMENT:
Jamie Madill34771622015-04-21 13:54:34 +0000257 return getDepthbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500258 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400259 case GL_STENCIL_ATTACHMENT:
Jamie Madill34771622015-04-21 13:54:34 +0000260 return getStencilbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500261 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400262 case GL_DEPTH_STENCIL_ATTACHMENT:
263 return getDepthStencilBuffer();
264 default:
265 UNREACHABLE();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400266 return nullptr;
Jamie Madille92a3542014-07-03 10:38:58 -0400267 }
268 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400269}
270
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000271GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
272{
Jamie Madilld1405e52015-03-05 15:41:39 -0500273 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
274 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000275}
276
Geoff Lang164d54e2014-12-01 10:55:33 -0500277void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000278{
Jamie Madilld1405e52015-03-05 15:41:39 -0500279 auto &drawStates = mData.mDrawBufferStates;
280
281 ASSERT(count <= drawStates.size());
282 std::copy(buffers, buffers + count, drawStates.begin());
283 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500284 mImpl->setDrawBuffers(count, buffers);
285}
286
287GLenum Framebuffer::getReadBufferState() const
288{
Jamie Madilld1405e52015-03-05 15:41:39 -0500289 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500290}
291
292void Framebuffer::setReadBuffer(GLenum buffer)
293{
Jamie Madillb885e572015-02-03 16:16:04 -0500294 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
295 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500296 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
297 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500298 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000299}
300
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000301bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
302{
Jamie Madilld1405e52015-03-05 15:41:39 -0500303 ASSERT(colorAttachment < mData.mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400304 return (mData.mColorAttachments[colorAttachment].isAttached() &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500305 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000306}
307
308bool Framebuffer::hasEnabledColorAttachment() const
309{
Jamie Madilld1405e52015-03-05 15:41:39 -0500310 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000311 {
312 if (isEnabledColorAttachment(colorAttachment))
313 {
314 return true;
315 }
316 }
317
318 return false;
319}
320
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000321bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000322{
Jamie Madill2d06b732015-04-20 12:53:28 -0400323 return (mData.mStencilAttachment.isAttached() && mData.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000324}
325
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000326bool Framebuffer::usingExtendedDrawBuffers() const
327{
Jamie Madilld1405e52015-03-05 15:41:39 -0500328 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000329 {
330 if (isEnabledColorAttachment(colorAttachment))
331 {
332 return true;
333 }
334 }
335
336 return false;
337}
338
Geoff Lang748f74e2014-12-01 11:25:34 -0500339GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500341 // The default framebuffer *must* always be complete, though it may not be
342 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
343 if (mId == 0)
344 {
345 return GL_FRAMEBUFFER_COMPLETE;
346 }
347
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000348 int width = 0;
349 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000350 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000351 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000352 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353
Jamie Madill2d06b732015-04-20 12:53:28 -0400354 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400356 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400358 if (colorAttachment.getWidth() == 0 || colorAttachment.getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000359 {
360 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
361 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000362
Jamie Madill2d06b732015-04-20 12:53:28 -0400363 GLenum internalformat = colorAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500364 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400365 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400366 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000367 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400368 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000369 {
370 return GL_FRAMEBUFFER_UNSUPPORTED;
371 }
372
Geoff Lang5d601382014-07-22 15:14:06 -0400373 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000374 {
375 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
376 }
377 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400378 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000379 {
Geoff Lang5d601382014-07-22 15:14:06 -0400380 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400381 {
382 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
383 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000384 }
385
386 if (!missingAttachment)
387 {
388 // all color attachments must have the same width and height
Jamie Madill2d06b732015-04-20 12:53:28 -0400389 if (colorAttachment.getWidth() != width || colorAttachment.getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000390 {
391 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
392 }
393
394 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
395 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400396 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000397 {
398 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
399 }
400
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000401 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
402 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500403 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000404 {
Geoff Lang5d601382014-07-22 15:14:06 -0400405 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000406 {
407 return GL_FRAMEBUFFER_UNSUPPORTED;
408 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000409 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000410 }
411 else
412 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400413 width = colorAttachment.getWidth();
414 height = colorAttachment.getHeight();
415 samples = colorAttachment.getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400416 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000417 missingAttachment = false;
418 }
419 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000420 }
421
Jamie Madill2d06b732015-04-20 12:53:28 -0400422 const FramebufferAttachment &depthAttachment = mData.mDepthAttachment;
423 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000424 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400425 if (depthAttachment.getWidth() == 0 || depthAttachment.getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000427 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428 }
429
Jamie Madill2d06b732015-04-20 12:53:28 -0400430 GLenum internalformat = depthAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500431 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400432 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400433 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000434 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000435 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500436 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000437 {
438 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
439 }
440
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400441 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400442 {
443 return GL_FRAMEBUFFER_UNSUPPORTED;
444 }
445
Geoff Lang5d601382014-07-22 15:14:06 -0400446 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000447 {
448 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
449 }
450 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400451 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000452 {
Geoff Lang5d601382014-07-22 15:14:06 -0400453 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400454 {
455 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
456 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000457 }
458
459 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000460 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400461 width = depthAttachment.getWidth();
462 height = depthAttachment.getHeight();
463 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000464 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000465 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400466 else if (width != depthAttachment.getWidth() || height != depthAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000467 {
468 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
469 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400470 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000471 {
472 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
473 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000474 }
475
Jamie Madill2d06b732015-04-20 12:53:28 -0400476 const FramebufferAttachment &stencilAttachment = mData.mStencilAttachment;
477 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000478 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400479 if (stencilAttachment.getWidth() == 0 || stencilAttachment.getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000480 {
481 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
482 }
483
Jamie Madill2d06b732015-04-20 12:53:28 -0400484 GLenum internalformat = stencilAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500485 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400486 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400487 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000488 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000489 // texture stencil attachments come along as part
490 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500491 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000492 {
493 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
494 }
495
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400496 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400497 {
498 return GL_FRAMEBUFFER_UNSUPPORTED;
499 }
500
Geoff Lang5d601382014-07-22 15:14:06 -0400501 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000502 {
503 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
504 }
505 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400506 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000507 {
Geoff Lang5d601382014-07-22 15:14:06 -0400508 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400509 {
510 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
511 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000512 }
513
514 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000515 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400516 width = stencilAttachment.getWidth();
517 height = stencilAttachment.getHeight();
518 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000519 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000520 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400521 else if (width != stencilAttachment.getWidth() || height != stencilAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000522 {
523 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
524 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400525 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000526 {
527 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
528 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000529 }
530
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000531 // if we have both a depth and stencil buffer, they must refer to the same object
532 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madill2d06b732015-04-20 12:53:28 -0400533 if (depthAttachment.isAttached() && stencilAttachment.isAttached() && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000534 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000535 return GL_FRAMEBUFFER_UNSUPPORTED;
536 }
537
538 // we need to have at least one attachment to be complete
539 if (missingAttachment)
540 {
541 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000542 }
543
Geoff Lang748f74e2014-12-01 11:25:34 -0500544 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000546
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500547Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400548{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500549 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400550}
551
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500552Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400553{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500554 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400555}
556
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400557Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500558{
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400559 return mImpl->clear(data, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500560}
561
562Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
563{
564 return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
565}
566
567Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
568{
569 return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
570}
571
572Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
573{
574 return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
575}
576
577Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
578{
579 return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
580}
581
Geoff Langbce529e2014-12-01 12:48:41 -0500582GLenum Framebuffer::getImplementationColorReadFormat() const
583{
584 return mImpl->getImplementationColorReadFormat();
585}
586
587GLenum Framebuffer::getImplementationColorReadType() const
588{
589 return mImpl->getImplementationColorReadType();
590}
591
592Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
593{
594 return mImpl->readPixels(state, area, format, type, pixels);
595}
596
Geoff Lang54bd5a42014-12-01 12:51:04 -0500597Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
598 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
599{
600 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
601}
602
Jamie Madill48faf802014-11-06 15:27:22 -0500603int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000604{
Geoff Lang748f74e2014-12-01 11:25:34 -0500605 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000606 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000607 // for a complete framebuffer, all attachments must have the same sample count
608 // in this case return the first nonzero sample size
Jamie Madill2d06b732015-04-20 12:53:28 -0400609 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000610 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400611 if (colorAttachment.isAttached())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000612 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400613 return colorAttachment.getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000614 }
615 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000616 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000617
618 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000619}
620
Jamie Madille261b442014-06-25 12:42:21 -0400621bool Framebuffer::hasValidDepthStencil() const
622{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400623 return mData.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400624}
625
Jamie Madill2d06b732015-04-20 12:53:28 -0400626void Framebuffer::setAttachment(GLenum type,
627 GLenum binding,
628 const ImageIndex &textureIndex,
629 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400630{
Jamie Madill2d06b732015-04-20 12:53:28 -0400631 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400632 {
Geoff Langab75a052014-10-15 12:56:37 -0400633 // ensure this is a legitimate depth+stencil format
Jamie Madill2d06b732015-04-20 12:53:28 -0400634 FramebufferAttachment::Target target(binding, textureIndex);
635 GLenum internalFormat = resource->getAttachmentInternalFormat(target);
636 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
637 if (resource && formatInfo.depthBits > 0 && formatInfo.stencilBits > 0)
Geoff Langab75a052014-10-15 12:56:37 -0400638 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400639 mData.mDepthAttachment.attach(type, binding, textureIndex, resource);
640 mData.mStencilAttachment.attach(type, binding, textureIndex, resource);
Geoff Langab75a052014-10-15 12:56:37 -0400641 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400642 else
643 {
644 mData.mDepthAttachment.detach();
645 mData.mStencilAttachment.detach();
646 }
647 mImpl->setDepthStencilAttachment(&mData.mDepthAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400648 }
649 else
650 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400651 FramebufferAttachment *attachment = nullptr;
652
653 switch (binding)
654 {
655 case GL_DEPTH:
656 case GL_DEPTH_ATTACHMENT:
657 attachment = &mData.mDepthAttachment;
658 attachment->attach(type, binding, textureIndex, resource);
659 mImpl->setDepthAttachment(attachment);
660 break;
661 case GL_STENCIL:
662 case GL_STENCIL_ATTACHMENT:
663 attachment = &mData.mStencilAttachment;
664 attachment->attach(type, binding, textureIndex, resource);
665 mImpl->setStencilAttachment(attachment);
666 break;
667 case GL_BACK:
668 attachment = &mData.mColorAttachments[0];
669 attachment->attach(type, binding, textureIndex, resource);
670 mImpl->setColorAttachment(0, attachment);
671 break;
672 default:
673 {
674 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
675 ASSERT(colorIndex < mData.mColorAttachments.size());
676 attachment = &mData.mColorAttachments[colorIndex];
677 attachment->attach(type, binding, textureIndex, resource);
678 mImpl->setColorAttachment(colorIndex, attachment);
679 }
680 break;
681 }
Geoff Langab75a052014-10-15 12:56:37 -0400682 }
683}
684
Jamie Madill2d06b732015-04-20 12:53:28 -0400685void Framebuffer::resetAttachment(GLenum binding)
686{
687 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
688}
689
Jamie Madill48115b62015-03-16 10:46:57 -0400690DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface)
691 : Framebuffer(caps, factory, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000692{
Jamie Madillc46f45d2015-03-31 13:20:55 -0400693 const egl::Config *config = surface->getConfig();
Jamie Madilld1405e52015-03-05 15:41:39 -0500694
Jamie Madill2d06b732015-04-20 12:53:28 -0400695 setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex::MakeInvalid(), surface);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000696
Jamie Madillc46f45d2015-03-31 13:20:55 -0400697 if (config->depthSize > 0)
Jamie Madille92a3542014-07-03 10:38:58 -0400698 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400699 setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex::MakeInvalid(), surface);
Jamie Madille92a3542014-07-03 10:38:58 -0400700 }
Jamie Madillc46f45d2015-03-31 13:20:55 -0400701 if (config->stencilSize > 0)
Geoff Lang528ce3c2014-12-01 10:44:07 -0500702 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400703 setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex::MakeInvalid(), surface);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500704 }
705
Geoff Lang9dd95802014-12-01 11:12:59 -0500706 GLenum drawBufferState = GL_BACK;
707 setDrawBuffers(1, &drawBufferState);
708
709 setReadBuffer(GL_BACK);
Jamie Madille92a3542014-07-03 10:38:58 -0400710}
711
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000712}