blob: 04c7856a7b33ebaa0b6e1d5e388e17b3a3db50d7 [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 Madille3ef7152015-04-28 16:55:17 +000087const FramebufferAttachment *Framebuffer::Data::getColorAttachment(unsigned int colorAttachment) const
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 Madille3ef7152015-04-28 16:55:17 +000095const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -040096{
Jamie Madill2d06b732015-04-20 12:53:28 -040097 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -040098}
99
Jamie Madille3ef7152015-04-28 16:55:17 +0000100const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400101{
Jamie Madill2d06b732015-04-20 12:53:28 -0400102 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400103}
104
Jamie Madille3ef7152015-04-28 16:55:17 +0000105const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400106{
107 // A valid depth-stencil attachment has the same resource bound to both the
108 // depth and stencil attachment points.
Jamie Madill2d06b732015-04-20 12:53:28 -0400109 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
110 mDepthAttachment.type() == mStencilAttachment.type() &&
111 mDepthAttachment.id() == mStencilAttachment.id())
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400112 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400113 return &mDepthAttachment;
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400114 }
115
116 return nullptr;
117}
118
Jamie Madill48115b62015-03-16 10:46:57 -0400119Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
Jamie Madilld1405e52015-03-05 15:41:39 -0500120 : mData(caps),
Geoff Lang4ad17092015-03-10 16:47:44 -0400121 mImpl(nullptr),
Jamie Madilld1405e52015-03-05 15:41:39 -0500122 mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123{
Geoff Lang4ad17092015-03-10 16:47:44 -0400124 if (mId == 0)
125 {
126 mImpl = factory->createDefaultFramebuffer(mData);
127 }
128 else
129 {
130 mImpl = factory->createFramebuffer(mData);
131 }
Geoff Langda88add2014-12-01 10:22:01 -0500132 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000133}
134
135Framebuffer::~Framebuffer()
136{
Geoff Langda88add2014-12-01 10:22:01 -0500137 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000138}
139
Jamie Madille261b442014-06-25 12:42:21 -0400140void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141{
Jamie Madilld1405e52015-03-05 15:41:39 -0500142 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143}
144
Jamie Madille261b442014-06-25 12:42:21 -0400145void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146{
Jamie Madilld1405e52015-03-05 15:41:39 -0500147 detachResourceById(GL_RENDERBUFFER, renderbufferId);
148}
Jamie Madille261b442014-06-25 12:42:21 -0400149
Jamie Madilld1405e52015-03-05 15:41:39 -0500150void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
151{
152 for (auto &colorAttachment : mData.mColorAttachments)
153 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400154 DetachMatchingAttachment(&colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000155 }
156
Jamie Madill2d06b732015-04-20 12:53:28 -0400157 DetachMatchingAttachment(&mData.mDepthAttachment, resourceType, resourceId);
158 DetachMatchingAttachment(&mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159}
160
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400161const FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400163 return mData.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164}
165
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400166const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400167{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400168 return mData.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400169}
170
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400171const FramebufferAttachment *Framebuffer::getStencilbuffer() const
172{
173 return mData.getStencilAttachment();
174}
175
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400176const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
177{
178 return mData.getDepthStencilAttachment();
179}
180
181const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000182{
Jamie Madill7147f012015-03-05 15:41:40 -0500183 return mData.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000184}
185
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400186const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000187{
Jamie Madill7147f012015-03-05 15:41:40 -0500188 return mData.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000189}
190
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000191GLenum Framebuffer::getReadColorbufferType() const
192{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400193 const FramebufferAttachment *readAttachment = mData.getReadAttachment();
194 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000195}
196
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400197const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000198{
Jamie Madill7147f012015-03-05 15:41:40 -0500199 return mData.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000200}
201
Jamie Madill2d06b732015-04-20 12:53:28 -0400202const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000203{
Jamie Madille92a3542014-07-03 10:38:58 -0400204 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
205 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000206 return mData.getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
Jamie Madille92a3542014-07-03 10:38:58 -0400207 }
208 else
209 {
210 switch (attachment)
211 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500212 case GL_COLOR:
213 case GL_BACK:
Jamie Madille3ef7152015-04-28 16:55:17 +0000214 return mData.getColorAttachment(0);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500215 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400216 case GL_DEPTH_ATTACHMENT:
Jamie Madille3ef7152015-04-28 16:55:17 +0000217 return mData.getDepthAttachment();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500218 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400219 case GL_STENCIL_ATTACHMENT:
Jamie Madille3ef7152015-04-28 16:55:17 +0000220 return mData.getStencilAttachment();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500221 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400222 case GL_DEPTH_STENCIL_ATTACHMENT:
223 return getDepthStencilBuffer();
224 default:
225 UNREACHABLE();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400226 return nullptr;
Jamie Madille92a3542014-07-03 10:38:58 -0400227 }
228 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400229}
230
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000231GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
232{
Jamie Madilld1405e52015-03-05 15:41:39 -0500233 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
234 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000235}
236
Geoff Lang164d54e2014-12-01 10:55:33 -0500237void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000238{
Jamie Madilld1405e52015-03-05 15:41:39 -0500239 auto &drawStates = mData.mDrawBufferStates;
240
241 ASSERT(count <= drawStates.size());
242 std::copy(buffers, buffers + count, drawStates.begin());
243 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500244 mImpl->setDrawBuffers(count, buffers);
245}
246
247GLenum Framebuffer::getReadBufferState() const
248{
Jamie Madilld1405e52015-03-05 15:41:39 -0500249 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500250}
251
252void Framebuffer::setReadBuffer(GLenum buffer)
253{
Jamie Madillb885e572015-02-03 16:16:04 -0500254 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
255 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500256 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
257 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500258 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000259}
260
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000261bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
262{
Jamie Madilld1405e52015-03-05 15:41:39 -0500263 ASSERT(colorAttachment < mData.mColorAttachments.size());
Jamie Madill2d06b732015-04-20 12:53:28 -0400264 return (mData.mColorAttachments[colorAttachment].isAttached() &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500265 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000266}
267
268bool Framebuffer::hasEnabledColorAttachment() const
269{
Jamie Madilld1405e52015-03-05 15:41:39 -0500270 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000271 {
272 if (isEnabledColorAttachment(colorAttachment))
273 {
274 return true;
275 }
276 }
277
278 return false;
279}
280
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000281bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000282{
Jamie Madill2d06b732015-04-20 12:53:28 -0400283 return (mData.mStencilAttachment.isAttached() && mData.mStencilAttachment.getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000284}
285
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000286bool Framebuffer::usingExtendedDrawBuffers() const
287{
Jamie Madilld1405e52015-03-05 15:41:39 -0500288 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000289 {
290 if (isEnabledColorAttachment(colorAttachment))
291 {
292 return true;
293 }
294 }
295
296 return false;
297}
298
Geoff Lang748f74e2014-12-01 11:25:34 -0500299GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500301 // The default framebuffer *must* always be complete, though it may not be
302 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
303 if (mId == 0)
304 {
305 return GL_FRAMEBUFFER_COMPLETE;
306 }
307
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308 int width = 0;
309 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000310 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000311 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000312 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313
Jamie Madill2d06b732015-04-20 12:53:28 -0400314 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400316 if (colorAttachment.isAttached())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400318 if (colorAttachment.getWidth() == 0 || colorAttachment.getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000319 {
320 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
321 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000322
Jamie Madill2d06b732015-04-20 12:53:28 -0400323 GLenum internalformat = colorAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500324 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400325 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400326 if (colorAttachment.type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000327 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400328 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000329 {
330 return GL_FRAMEBUFFER_UNSUPPORTED;
331 }
332
Geoff Lang5d601382014-07-22 15:14:06 -0400333 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000334 {
335 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
336 }
337 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400338 else if (colorAttachment.type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000339 {
Geoff Lang5d601382014-07-22 15:14:06 -0400340 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400341 {
342 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
343 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000344 }
345
346 if (!missingAttachment)
347 {
348 // all color attachments must have the same width and height
Jamie Madill2d06b732015-04-20 12:53:28 -0400349 if (colorAttachment.getWidth() != width || colorAttachment.getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000350 {
351 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
352 }
353
354 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
355 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madill2d06b732015-04-20 12:53:28 -0400356 if (colorAttachment.getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000357 {
358 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
359 }
360
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000361 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
362 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500363 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000364 {
Geoff Lang5d601382014-07-22 15:14:06 -0400365 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000366 {
367 return GL_FRAMEBUFFER_UNSUPPORTED;
368 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000369 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000370 }
371 else
372 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400373 width = colorAttachment.getWidth();
374 height = colorAttachment.getHeight();
375 samples = colorAttachment.getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400376 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000377 missingAttachment = false;
378 }
379 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000380 }
381
Jamie Madill2d06b732015-04-20 12:53:28 -0400382 const FramebufferAttachment &depthAttachment = mData.mDepthAttachment;
383 if (depthAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000384 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400385 if (depthAttachment.getWidth() == 0 || depthAttachment.getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000387 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388 }
389
Jamie Madill2d06b732015-04-20 12:53:28 -0400390 GLenum internalformat = depthAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500391 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400392 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400393 if (depthAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000394 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000395 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500396 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000397 {
398 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
399 }
400
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400401 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400402 {
403 return GL_FRAMEBUFFER_UNSUPPORTED;
404 }
405
Geoff Lang5d601382014-07-22 15:14:06 -0400406 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000407 {
408 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
409 }
410 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400411 else if (depthAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000412 {
Geoff Lang5d601382014-07-22 15:14:06 -0400413 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400414 {
415 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
416 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000417 }
418
419 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000420 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400421 width = depthAttachment.getWidth();
422 height = depthAttachment.getHeight();
423 samples = depthAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000424 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000425 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400426 else if (width != depthAttachment.getWidth() || height != depthAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000427 {
428 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
429 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400430 else if (samples != depthAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000431 {
432 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
433 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000434 }
435
Jamie Madill2d06b732015-04-20 12:53:28 -0400436 const FramebufferAttachment &stencilAttachment = mData.mStencilAttachment;
437 if (stencilAttachment.isAttached())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000438 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400439 if (stencilAttachment.getWidth() == 0 || stencilAttachment.getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000440 {
441 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
442 }
443
Jamie Madill2d06b732015-04-20 12:53:28 -0400444 GLenum internalformat = stencilAttachment.getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500445 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400446 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madill2d06b732015-04-20 12:53:28 -0400447 if (stencilAttachment.type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000448 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000449 // texture stencil attachments come along as part
450 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500451 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000452 {
453 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
454 }
455
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400456 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400457 {
458 return GL_FRAMEBUFFER_UNSUPPORTED;
459 }
460
Geoff Lang5d601382014-07-22 15:14:06 -0400461 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000462 {
463 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
464 }
465 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400466 else if (stencilAttachment.type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000467 {
Geoff Lang5d601382014-07-22 15:14:06 -0400468 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400469 {
470 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
471 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000472 }
473
474 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000475 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400476 width = stencilAttachment.getWidth();
477 height = stencilAttachment.getHeight();
478 samples = stencilAttachment.getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000479 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000480 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400481 else if (width != stencilAttachment.getWidth() || height != stencilAttachment.getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000482 {
483 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
484 }
Jamie Madill2d06b732015-04-20 12:53:28 -0400485 else if (samples != stencilAttachment.getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000486 {
487 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
488 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000489 }
490
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000491 // we need to have at least one attachment to be complete
492 if (missingAttachment)
493 {
494 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000495 }
496
Geoff Lang748f74e2014-12-01 11:25:34 -0500497 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000498}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000499
Austin Kinross08332632015-05-05 13:35:47 -0700500Error Framebuffer::discard(size_t count, const GLenum *attachments)
501{
502 return mImpl->discard(count, attachments);
503}
504
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500505Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400506{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500507 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400508}
509
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500510Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400511{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500512 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400513}
514
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400515Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500516{
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400517 return mImpl->clear(data, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500518}
519
520Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
521{
522 return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
523}
524
525Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
526{
527 return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
528}
529
530Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
531{
532 return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
533}
534
535Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
536{
537 return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
538}
539
Geoff Langbce529e2014-12-01 12:48:41 -0500540GLenum Framebuffer::getImplementationColorReadFormat() const
541{
542 return mImpl->getImplementationColorReadFormat();
543}
544
545GLenum Framebuffer::getImplementationColorReadType() const
546{
547 return mImpl->getImplementationColorReadType();
548}
549
550Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
551{
Geoff Lang520c4ae2015-05-05 13:12:36 -0400552 Error error = mImpl->readPixels(state, area, format, type, pixels);
553 if (error.isError())
554 {
555 return error;
556 }
557
558 Buffer *unpackBuffer = state.getUnpackState().pixelBuffer.get();
559 if (unpackBuffer)
560 {
561 unpackBuffer->onPixelUnpack();
562 }
563
564 return Error(GL_NO_ERROR);
Geoff Langbce529e2014-12-01 12:48:41 -0500565}
566
Geoff Lang54bd5a42014-12-01 12:51:04 -0500567Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
568 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
569{
570 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
571}
572
Jamie Madill48faf802014-11-06 15:27:22 -0500573int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000574{
Geoff Lang748f74e2014-12-01 11:25:34 -0500575 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000576 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000577 // for a complete framebuffer, all attachments must have the same sample count
578 // in this case return the first nonzero sample size
Jamie Madill2d06b732015-04-20 12:53:28 -0400579 for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000580 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400581 if (colorAttachment.isAttached())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000582 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400583 return colorAttachment.getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000584 }
585 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000586 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000587
588 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000589}
590
Jamie Madille261b442014-06-25 12:42:21 -0400591bool Framebuffer::hasValidDepthStencil() const
592{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400593 return mData.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400594}
595
Jamie Madill2d06b732015-04-20 12:53:28 -0400596void Framebuffer::setAttachment(GLenum type,
597 GLenum binding,
598 const ImageIndex &textureIndex,
599 FramebufferAttachmentObject *resource)
Geoff Langab75a052014-10-15 12:56:37 -0400600{
Jamie Madill2d06b732015-04-20 12:53:28 -0400601 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
Geoff Langab75a052014-10-15 12:56:37 -0400602 {
Geoff Langab75a052014-10-15 12:56:37 -0400603 // ensure this is a legitimate depth+stencil format
Jamie Madill375c37c2015-07-21 15:14:08 -0400604 FramebufferAttachmentObject *attachmentObj = resource;
605 if (resource)
Geoff Langab75a052014-10-15 12:56:37 -0400606 {
Jamie Madill375c37c2015-07-21 15:14:08 -0400607 FramebufferAttachment::Target target(binding, textureIndex);
608 GLenum internalFormat = resource->getAttachmentInternalFormat(target);
609 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
610 if (formatInfo.depthBits == 0 || formatInfo.stencilBits == 0)
611 {
612 // Attaching nullptr detaches the current attachment.
613 attachmentObj = nullptr;
614 }
Geoff Langab75a052014-10-15 12:56:37 -0400615 }
Jamie Madill375c37c2015-07-21 15:14:08 -0400616
617 mData.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
618 mData.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400619 mImpl->onUpdateDepthStencilAttachment();
Geoff Langab75a052014-10-15 12:56:37 -0400620 }
621 else
622 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400623 switch (binding)
624 {
625 case GL_DEPTH:
626 case GL_DEPTH_ATTACHMENT:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400627 mData.mDepthAttachment.attach(type, binding, textureIndex, resource);
628 mImpl->onUpdateDepthAttachment();
Jamie Madill2d06b732015-04-20 12:53:28 -0400629 break;
630 case GL_STENCIL:
631 case GL_STENCIL_ATTACHMENT:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400632 mData.mStencilAttachment.attach(type, binding, textureIndex, resource);
633 mImpl->onUpdateStencilAttachment();
Jamie Madill2d06b732015-04-20 12:53:28 -0400634 break;
635 case GL_BACK:
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400636 mData.mColorAttachments[0].attach(type, binding, textureIndex, resource);
637 mImpl->onUpdateColorAttachment(0);
Jamie Madill2d06b732015-04-20 12:53:28 -0400638 break;
639 default:
640 {
641 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
642 ASSERT(colorIndex < mData.mColorAttachments.size());
Jamie Madill7d75e2b2015-04-30 09:42:18 -0400643 mData.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
644 mImpl->onUpdateColorAttachment(colorIndex);
Jamie Madill2d06b732015-04-20 12:53:28 -0400645 }
646 break;
647 }
Geoff Langab75a052014-10-15 12:56:37 -0400648 }
649}
650
Jamie Madill2d06b732015-04-20 12:53:28 -0400651void Framebuffer::resetAttachment(GLenum binding)
652{
653 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
654}
655
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000656}