blob: e886e3eef708c7ea86b0033b75aed7b328e5870b [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"
11#include "libANGLE/formatutils.h"
12#include "libANGLE/Texture.h"
13#include "libANGLE/Context.h"
14#include "libANGLE/Renderbuffer.h"
15#include "libANGLE/FramebufferAttachment.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050016#include "libANGLE/renderer/FramebufferImpl.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050017#include "libANGLE/renderer/Renderer.h"
18#include "libANGLE/renderer/RenderTarget.h"
19#include "libANGLE/renderer/RenderbufferImpl.h"
20#include "libANGLE/renderer/Workarounds.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040021
22#include "common/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023
24namespace gl
25{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000026
Geoff Langda88add2014-12-01 10:22:01 -050027Framebuffer::Framebuffer(rx::FramebufferImpl *impl, GLuint id)
28 : mImpl(impl),
29 mId(id),
Jamie Madille261b442014-06-25 12:42:21 -040030 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
31 mDepthbuffer(NULL),
32 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000033{
Geoff Langda88add2014-12-01 10:22:01 -050034 ASSERT(mImpl != nullptr);
35
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000036 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
37 {
Jamie Madille261b442014-06-25 12:42:21 -040038 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000039 mDrawBufferStates[colorAttachment] = GL_NONE;
40 }
41 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000042}
43
44Framebuffer::~Framebuffer()
45{
Geoff Langda88add2014-12-01 10:22:01 -050046 SafeDelete(mImpl);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000047 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
48 {
Jamie Madille261b442014-06-25 12:42:21 -040049 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000050 }
Jamie Madille261b442014-06-25 12:42:21 -040051 SafeDelete(mDepthbuffer);
52 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000053}
54
Jamie Madille261b442014-06-25 12:42:21 -040055void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000056{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000057 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000058 {
Jamie Madille261b442014-06-25 12:42:21 -040059 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
60
61 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000062 {
Jamie Madille261b442014-06-25 12:42:21 -040063 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000064 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000065 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000066
Jamie Madille261b442014-06-25 12:42:21 -040067 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000068 {
Jamie Madille261b442014-06-25 12:42:21 -040069 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000070 }
71
Jamie Madille261b442014-06-25 12:42:21 -040072 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000073 {
Jamie Madille261b442014-06-25 12:42:21 -040074 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000075 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000076}
77
Jamie Madille261b442014-06-25 12:42:21 -040078void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000079{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000080 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000081 {
Jamie Madille261b442014-06-25 12:42:21 -040082 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
83
84 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000085 {
Jamie Madille261b442014-06-25 12:42:21 -040086 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000087 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000088 }
89
Jamie Madille261b442014-06-25 12:42:21 -040090 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000091 {
Jamie Madille261b442014-06-25 12:42:21 -040092 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000093 }
94
Jamie Madille261b442014-06-25 12:42:21 -040095 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096 {
Jamie Madille261b442014-06-25 12:42:21 -040097 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000098 }
99}
100
Jamie Madill3c7fa222014-06-05 13:08:51 -0400101FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000102{
103 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400104 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000105}
106
Jamie Madill3c7fa222014-06-05 13:08:51 -0400107FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108{
Jamie Madille261b442014-06-25 12:42:21 -0400109 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000110}
111
Jamie Madill3c7fa222014-06-05 13:08:51 -0400112FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000113{
Jamie Madille261b442014-06-25 12:42:21 -0400114 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115}
116
Jamie Madill3c7fa222014-06-05 13:08:51 -0400117FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400118{
Jamie Madille261b442014-06-25 12:42:21 -0400119 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400120}
121
Jamie Madill3c7fa222014-06-05 13:08:51 -0400122FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000123{
Jamie Madille261b442014-06-25 12:42:21 -0400124 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000125
126 if (!depthstencilbuffer)
127 {
Jamie Madille261b442014-06-25 12:42:21 -0400128 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000129 }
130
131 return depthstencilbuffer;
132}
133
Jamie Madill3c7fa222014-06-05 13:08:51 -0400134FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000135{
136 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400137 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000138}
139
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000140GLenum Framebuffer::getReadColorbufferType() const
141{
142 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400143 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000144}
145
Jamie Madill3c7fa222014-06-05 13:08:51 -0400146FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000147{
148 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
149 {
Jamie Madille261b442014-06-25 12:42:21 -0400150 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000151 {
Jamie Madille261b442014-06-25 12:42:21 -0400152 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000153 }
154 }
155
156 return NULL;
157}
158
Jamie Madille92a3542014-07-03 10:38:58 -0400159FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000160{
Jamie Madille92a3542014-07-03 10:38:58 -0400161 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
162 {
163 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
164 }
165 else
166 {
167 switch (attachment)
168 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500169 case GL_COLOR:
170 case GL_BACK:
171 return getColorbuffer(0);
172 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400173 case GL_DEPTH_ATTACHMENT:
174 return getDepthbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500175 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400176 case GL_STENCIL_ATTACHMENT:
177 return getStencilbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500178 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400179 case GL_DEPTH_STENCIL_ATTACHMENT:
180 return getDepthStencilBuffer();
181 default:
182 UNREACHABLE();
183 return NULL;
184 }
185 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400186}
187
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000188GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
189{
190 return mDrawBufferStates[colorAttachment];
191}
192
Geoff Lang164d54e2014-12-01 10:55:33 -0500193void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000194{
Geoff Lang68439852014-12-04 14:40:16 -0500195 ASSERT(count <= ArraySize(mDrawBufferStates));
Geoff Lang164d54e2014-12-01 10:55:33 -0500196 std::copy(buffers, buffers + count, mDrawBufferStates);
197 std::fill(mDrawBufferStates + count, mDrawBufferStates + ArraySize(mDrawBufferStates), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500198 mImpl->setDrawBuffers(count, buffers);
199}
200
201GLenum Framebuffer::getReadBufferState() const
202{
203 return mReadBufferState;
204}
205
206void Framebuffer::setReadBuffer(GLenum buffer)
207{
208 mReadBufferState = buffer;
209 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000210}
211
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000212bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
213{
Jamie Madille261b442014-06-25 12:42:21 -0400214 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000215}
216
217bool Framebuffer::hasEnabledColorAttachment() const
218{
219 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
220 {
221 if (isEnabledColorAttachment(colorAttachment))
222 {
223 return true;
224 }
225 }
226
227 return false;
228}
229
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000230bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000231{
Geoff Lange4a492b2014-06-19 14:14:41 -0400232 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000233}
234
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000235bool Framebuffer::usingExtendedDrawBuffers() const
236{
237 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
238 {
239 if (isEnabledColorAttachment(colorAttachment))
240 {
241 return true;
242 }
243 }
244
245 return false;
246}
247
Geoff Lang748f74e2014-12-01 11:25:34 -0500248GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000249{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500250 // The default framebuffer *must* always be complete, though it may not be
251 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
252 if (mId == 0)
253 {
254 return GL_FRAMEBUFFER_COMPLETE;
255 }
256
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257 int width = 0;
258 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000259 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000260 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000261 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000262
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000263 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000264 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400265 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
266
267 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000268 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000269 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000270 {
271 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
272 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000273
Geoff Langcec35902014-04-16 10:52:36 -0400274 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500275 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400276 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500277 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000278 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400279 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000280 {
281 return GL_FRAMEBUFFER_UNSUPPORTED;
282 }
283
Geoff Lang5d601382014-07-22 15:14:06 -0400284 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000285 {
286 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
287 }
288 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500289 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000290 {
Geoff Lang5d601382014-07-22 15:14:06 -0400291 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400292 {
293 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
294 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000295 }
296
297 if (!missingAttachment)
298 {
299 // all color attachments must have the same width and height
300 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
301 {
302 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
303 }
304
305 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
306 // all color attachments have the same number of samples for the FBO to be complete.
307 if (colorbuffer->getSamples() != samples)
308 {
309 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
310 }
311
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000312 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
313 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500314 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000315 {
Geoff Lang5d601382014-07-22 15:14:06 -0400316 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000317 {
318 return GL_FRAMEBUFFER_UNSUPPORTED;
319 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000320 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000321 }
322 else
323 {
324 width = colorbuffer->getWidth();
325 height = colorbuffer->getHeight();
326 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400327 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000328 missingAttachment = false;
329 }
330 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000331 }
332
Jamie Madille261b442014-06-25 12:42:21 -0400333 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000334 {
Jamie Madille261b442014-06-25 12:42:21 -0400335 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000337 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338 }
339
Jamie Madille261b442014-06-25 12:42:21 -0400340 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500341 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400342 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500343 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000344 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000345 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500346 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000347 {
348 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
349 }
350
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400351 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400352 {
353 return GL_FRAMEBUFFER_UNSUPPORTED;
354 }
355
Geoff Lang5d601382014-07-22 15:14:06 -0400356 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000357 {
358 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
359 }
360 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500361 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000362 {
Geoff Lang5d601382014-07-22 15:14:06 -0400363 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400364 {
365 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
366 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000367 }
368
369 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000370 {
Jamie Madille261b442014-06-25 12:42:21 -0400371 width = mDepthbuffer->getWidth();
372 height = mDepthbuffer->getHeight();
373 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000374 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000375 }
Jamie Madille261b442014-06-25 12:42:21 -0400376 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000377 {
378 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
379 }
Jamie Madille261b442014-06-25 12:42:21 -0400380 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000381 {
382 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
383 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000384 }
385
Jamie Madille261b442014-06-25 12:42:21 -0400386 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000387 {
Jamie Madille261b442014-06-25 12:42:21 -0400388 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000389 {
390 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
391 }
392
Jamie Madille261b442014-06-25 12:42:21 -0400393 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500394 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400395 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500396 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000397 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000398 // texture stencil attachments come along as part
399 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500400 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000401 {
402 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
403 }
404
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400405 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400406 {
407 return GL_FRAMEBUFFER_UNSUPPORTED;
408 }
409
Geoff Lang5d601382014-07-22 15:14:06 -0400410 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000411 {
412 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
413 }
414 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500415 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000416 {
Geoff Lang5d601382014-07-22 15:14:06 -0400417 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400418 {
419 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
420 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000421 }
422
423 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000424 {
Jamie Madille261b442014-06-25 12:42:21 -0400425 width = mStencilbuffer->getWidth();
426 height = mStencilbuffer->getHeight();
427 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000428 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000429 }
Jamie Madille261b442014-06-25 12:42:21 -0400430 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000431 {
432 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
433 }
Jamie Madille261b442014-06-25 12:42:21 -0400434 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000435 {
436 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
437 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000438 }
439
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000440 // if we have both a depth and stencil buffer, they must refer to the same object
441 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400442 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000443 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000444 return GL_FRAMEBUFFER_UNSUPPORTED;
445 }
446
447 // we need to have at least one attachment to be complete
448 if (missingAttachment)
449 {
450 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000451 }
452
Geoff Lang748f74e2014-12-01 11:25:34 -0500453 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000455
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500456Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400457{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500458 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400459}
460
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500461Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400462{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500463 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400464}
465
Jamie Madill48faf802014-11-06 15:27:22 -0500466int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000467{
Geoff Lang748f74e2014-12-01 11:25:34 -0500468 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000469 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000470 // for a complete framebuffer, all attachments must have the same sample count
471 // in this case return the first nonzero sample size
472 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
473 {
Jamie Madille261b442014-06-25 12:42:21 -0400474 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000475 {
Jamie Madille261b442014-06-25 12:42:21 -0400476 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000477 }
478 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000479 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000480
481 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000482}
483
Jamie Madille261b442014-06-25 12:42:21 -0400484bool Framebuffer::hasValidDepthStencil() const
485{
486 // A valid depth-stencil attachment has the same resource bound to both the
487 // depth and stencil attachment points.
488 return (mDepthbuffer && mStencilbuffer &&
489 mDepthbuffer->type() == mStencilbuffer->type() &&
490 mDepthbuffer->id() == mStencilbuffer->id());
491}
492
Jamie Madill48faf802014-11-06 15:27:22 -0500493ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400494{
495 ColorbufferInfo colorbuffersForRender;
496
497 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
498 {
499 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
500 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
501
502 if (colorbuffer != NULL && drawBufferState != GL_NONE)
503 {
504 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
505 colorbuffersForRender.push_back(colorbuffer);
506 }
Jamie Madill48faf802014-11-06 15:27:22 -0500507 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400508 {
509 colorbuffersForRender.push_back(NULL);
510 }
511 }
512
513 return colorbuffersForRender;
514}
515
Geoff Langab75a052014-10-15 12:56:37 -0400516void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
517{
518 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
519}
520
521void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
522{
523 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
524}
525
526void Framebuffer::setNULLAttachment(GLenum attachment)
527{
528 setAttachment(attachment, NULL);
529}
530
531void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
532{
533 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
534 {
535 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
536 SafeDelete(mColorbuffers[colorAttachment]);
537 mColorbuffers[colorAttachment] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500538 mImpl->setColorAttachment(colorAttachment, attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400539 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500540 else if (attachment == GL_BACK)
541 {
542 SafeDelete(mColorbuffers[0]);
543 mColorbuffers[0] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500544 mImpl->setColorAttachment(0, attachmentObj);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500545 }
546 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400547 {
548 SafeDelete(mDepthbuffer);
549 mDepthbuffer = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500550 mImpl->setDepthttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400551 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500552 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400553 {
554 SafeDelete(mStencilbuffer);
555 mStencilbuffer = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500556 mImpl->setStencilAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400557 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500558 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400559 {
560 SafeDelete(mDepthbuffer);
561 SafeDelete(mStencilbuffer);
562
563 // ensure this is a legitimate depth+stencil format
564 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
565 {
566 mDepthbuffer = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500567 mImpl->setDepthttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400568
569 // Make a new attachment object to ensure we do not double-delete
570 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500571 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400572 {
573 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
574 *attachmentObj->getTextureImageIndex());
Geoff Lang9dd95802014-12-01 11:12:59 -0500575 mImpl->setStencilAttachment(mStencilbuffer);
Geoff Langab75a052014-10-15 12:56:37 -0400576 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500577 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400578 {
579 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
Geoff Lang9dd95802014-12-01 11:12:59 -0500580 mImpl->setStencilAttachment(mStencilbuffer);
Geoff Langab75a052014-10-15 12:56:37 -0400581 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500582 else
583 {
584 UNREACHABLE();
585 }
Geoff Langab75a052014-10-15 12:56:37 -0400586 }
587 }
588 else
589 {
590 UNREACHABLE();
591 }
592}
593
Geoff Lang528ce3c2014-12-01 10:44:07 -0500594DefaultFramebuffer::DefaultFramebuffer(rx::FramebufferImpl *impl, rx::DefaultAttachmentImpl *colorAttachment,
595 rx::DefaultAttachmentImpl *depthAttachment, rx::DefaultAttachmentImpl *stencilAttachment)
596 : Framebuffer(impl, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000597{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500598 ASSERT(colorAttachment);
599 setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, colorAttachment));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000600
Geoff Lang528ce3c2014-12-01 10:44:07 -0500601 if (depthAttachment)
Jamie Madille92a3542014-07-03 10:38:58 -0400602 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500603 setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, depthAttachment));
Jamie Madille92a3542014-07-03 10:38:58 -0400604 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500605 if (stencilAttachment)
606 {
607 setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, stencilAttachment));
608 }
609
Geoff Lang9dd95802014-12-01 11:12:59 -0500610 GLenum drawBufferState = GL_BACK;
611 setDrawBuffers(1, &drawBufferState);
612
613 setReadBuffer(GL_BACK);
Jamie Madille92a3542014-07-03 10:38:58 -0400614}
615
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000616}