blob: 54c0894208a2773470de1f163827b8aaffc824e8 [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"
Geoff Lang2b5420c2014-11-19 14:20:15 -050018#include "libANGLE/renderer/RenderbufferImpl.h"
19#include "libANGLE/renderer/Workarounds.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "common/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000022
23namespace gl
24{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000025
Geoff Langda88add2014-12-01 10:22:01 -050026Framebuffer::Framebuffer(rx::FramebufferImpl *impl, GLuint id)
27 : mImpl(impl),
28 mId(id),
Jamie Madille261b442014-06-25 12:42:21 -040029 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
30 mDepthbuffer(NULL),
31 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000032{
Geoff Langda88add2014-12-01 10:22:01 -050033 ASSERT(mImpl != nullptr);
34
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000035 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
36 {
Jamie Madille261b442014-06-25 12:42:21 -040037 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000038 mDrawBufferStates[colorAttachment] = GL_NONE;
39 }
40 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000041}
42
43Framebuffer::~Framebuffer()
44{
Geoff Langda88add2014-12-01 10:22:01 -050045 SafeDelete(mImpl);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000046 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
47 {
Jamie Madille261b442014-06-25 12:42:21 -040048 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000049 }
Jamie Madille261b442014-06-25 12:42:21 -040050 SafeDelete(mDepthbuffer);
51 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000052}
53
Jamie Madille261b442014-06-25 12:42:21 -040054void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000055{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000056 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000057 {
Jamie Madille261b442014-06-25 12:42:21 -040058 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
59
60 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000061 {
Jamie Madille261b442014-06-25 12:42:21 -040062 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000063 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000064 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000065
Jamie Madille261b442014-06-25 12:42:21 -040066 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000067 {
Jamie Madille261b442014-06-25 12:42:21 -040068 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000069 }
70
Jamie Madille261b442014-06-25 12:42:21 -040071 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000072 {
Jamie Madille261b442014-06-25 12:42:21 -040073 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000074 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000075}
76
Jamie Madille261b442014-06-25 12:42:21 -040077void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000078{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000079 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080 {
Jamie Madille261b442014-06-25 12:42:21 -040081 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
82
83 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000084 {
Jamie Madille261b442014-06-25 12:42:21 -040085 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000086 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087 }
88
Jamie Madille261b442014-06-25 12:42:21 -040089 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000090 {
Jamie Madille261b442014-06-25 12:42:21 -040091 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000092 }
93
Jamie Madille261b442014-06-25 12:42:21 -040094 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000095 {
Jamie Madille261b442014-06-25 12:42:21 -040096 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000097 }
98}
99
Jamie Madill3c7fa222014-06-05 13:08:51 -0400100FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000101{
102 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400103 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000104}
105
Jamie Madill3c7fa222014-06-05 13:08:51 -0400106FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107{
Jamie Madille261b442014-06-25 12:42:21 -0400108 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109}
110
Jamie Madill3c7fa222014-06-05 13:08:51 -0400111FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000112{
Jamie Madille261b442014-06-25 12:42:21 -0400113 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114}
115
Jamie Madill3c7fa222014-06-05 13:08:51 -0400116FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400117{
Jamie Madille261b442014-06-25 12:42:21 -0400118 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400119}
120
Jamie Madill3c7fa222014-06-05 13:08:51 -0400121FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000122{
Jamie Madille261b442014-06-25 12:42:21 -0400123 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000124
125 if (!depthstencilbuffer)
126 {
Jamie Madille261b442014-06-25 12:42:21 -0400127 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000128 }
129
130 return depthstencilbuffer;
131}
132
Jamie Madill3c7fa222014-06-05 13:08:51 -0400133FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000134{
Jamie Madillb885e572015-02-03 16:16:04 -0500135 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
136 ASSERT(readIndex < IMPLEMENTATION_MAX_DRAW_BUFFERS);
137 return mColorbuffers[readIndex];
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{
Jamie Madillb885e572015-02-03 16:16:04 -0500142 FramebufferAttachment *readAttachment = getReadColorbuffer();
143 return (readAttachment ? readAttachment->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{
Jamie Madillb885e572015-02-03 16:16:04 -0500208 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
209 (buffer >= GL_COLOR_ATTACHMENT0 &&
210 (buffer - GL_COLOR_ATTACHMENT0) < IMPLEMENTATION_MAX_DRAW_BUFFERS));
Geoff Lang9dd95802014-12-01 11:12:59 -0500211 mReadBufferState = buffer;
212 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000213}
214
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000215bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
216{
Jamie Madille261b442014-06-25 12:42:21 -0400217 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000218}
219
220bool Framebuffer::hasEnabledColorAttachment() const
221{
222 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
223 {
224 if (isEnabledColorAttachment(colorAttachment))
225 {
226 return true;
227 }
228 }
229
230 return false;
231}
232
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000233bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000234{
Geoff Lange4a492b2014-06-19 14:14:41 -0400235 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000236}
237
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000238bool Framebuffer::usingExtendedDrawBuffers() const
239{
240 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
241 {
242 if (isEnabledColorAttachment(colorAttachment))
243 {
244 return true;
245 }
246 }
247
248 return false;
249}
250
Geoff Lang748f74e2014-12-01 11:25:34 -0500251GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500253 // The default framebuffer *must* always be complete, though it may not be
254 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
255 if (mId == 0)
256 {
257 return GL_FRAMEBUFFER_COMPLETE;
258 }
259
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260 int width = 0;
261 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000262 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000263 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000264 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000266 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400268 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
269
270 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000272 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000273 {
274 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
275 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000276
Geoff Langcec35902014-04-16 10:52:36 -0400277 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500278 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400279 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500280 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000281 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400282 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000283 {
284 return GL_FRAMEBUFFER_UNSUPPORTED;
285 }
286
Geoff Lang5d601382014-07-22 15:14:06 -0400287 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000288 {
289 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
290 }
291 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500292 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000293 {
Geoff Lang5d601382014-07-22 15:14:06 -0400294 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400295 {
296 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
297 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000298 }
299
300 if (!missingAttachment)
301 {
302 // all color attachments must have the same width and height
303 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
304 {
305 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
306 }
307
308 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
309 // all color attachments have the same number of samples for the FBO to be complete.
310 if (colorbuffer->getSamples() != samples)
311 {
312 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
313 }
314
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000315 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
316 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500317 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000318 {
Geoff Lang5d601382014-07-22 15:14:06 -0400319 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000320 {
321 return GL_FRAMEBUFFER_UNSUPPORTED;
322 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000323 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000324 }
325 else
326 {
327 width = colorbuffer->getWidth();
328 height = colorbuffer->getHeight();
329 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400330 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000331 missingAttachment = false;
332 }
333 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000334 }
335
Jamie Madille261b442014-06-25 12:42:21 -0400336 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000337 {
Jamie Madille261b442014-06-25 12:42:21 -0400338 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000339 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000340 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341 }
342
Jamie Madille261b442014-06-25 12:42:21 -0400343 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500344 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400345 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500346 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000347 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000348 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500349 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000350 {
351 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
352 }
353
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400354 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400355 {
356 return GL_FRAMEBUFFER_UNSUPPORTED;
357 }
358
Geoff Lang5d601382014-07-22 15:14:06 -0400359 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000360 {
361 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
362 }
363 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500364 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000365 {
Geoff Lang5d601382014-07-22 15:14:06 -0400366 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400367 {
368 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
369 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000370 }
371
372 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000373 {
Jamie Madille261b442014-06-25 12:42:21 -0400374 width = mDepthbuffer->getWidth();
375 height = mDepthbuffer->getHeight();
376 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000377 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000378 }
Jamie Madille261b442014-06-25 12:42:21 -0400379 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000380 {
381 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
382 }
Jamie Madille261b442014-06-25 12:42:21 -0400383 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000384 {
385 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
386 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000387 }
388
Jamie Madille261b442014-06-25 12:42:21 -0400389 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000390 {
Jamie Madille261b442014-06-25 12:42:21 -0400391 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000392 {
393 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
394 }
395
Jamie Madille261b442014-06-25 12:42:21 -0400396 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500397 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400398 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500399 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000400 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000401 // texture stencil attachments come along as part
402 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500403 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000404 {
405 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
406 }
407
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400408 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400409 {
410 return GL_FRAMEBUFFER_UNSUPPORTED;
411 }
412
Geoff Lang5d601382014-07-22 15:14:06 -0400413 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000414 {
415 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
416 }
417 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500418 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000419 {
Geoff Lang5d601382014-07-22 15:14:06 -0400420 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400421 {
422 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
423 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000424 }
425
426 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000427 {
Jamie Madille261b442014-06-25 12:42:21 -0400428 width = mStencilbuffer->getWidth();
429 height = mStencilbuffer->getHeight();
430 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000431 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000432 }
Jamie Madille261b442014-06-25 12:42:21 -0400433 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000434 {
435 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
436 }
Jamie Madille261b442014-06-25 12:42:21 -0400437 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000438 {
439 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
440 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000441 }
442
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000443 // if we have both a depth and stencil buffer, they must refer to the same object
444 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400445 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000446 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000447 return GL_FRAMEBUFFER_UNSUPPORTED;
448 }
449
450 // we need to have at least one attachment to be complete
451 if (missingAttachment)
452 {
453 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000454 }
455
Geoff Lang748f74e2014-12-01 11:25:34 -0500456 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000457}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000458
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500459Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400460{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500461 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400462}
463
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500464Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400465{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500466 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400467}
468
Geoff Langb04dc822014-12-01 12:02:02 -0500469Error Framebuffer::clear(const State &state, GLbitfield mask)
470{
471 return mImpl->clear(state, mask);
472}
473
474Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
475{
476 return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
477}
478
479Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
480{
481 return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
482}
483
484Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
485{
486 return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
487}
488
489Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
490{
491 return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
492}
493
Geoff Langbce529e2014-12-01 12:48:41 -0500494GLenum Framebuffer::getImplementationColorReadFormat() const
495{
496 return mImpl->getImplementationColorReadFormat();
497}
498
499GLenum Framebuffer::getImplementationColorReadType() const
500{
501 return mImpl->getImplementationColorReadType();
502}
503
504Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
505{
506 return mImpl->readPixels(state, area, format, type, pixels);
507}
508
Geoff Lang54bd5a42014-12-01 12:51:04 -0500509Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
510 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
511{
512 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
513}
514
Jamie Madill48faf802014-11-06 15:27:22 -0500515int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000516{
Geoff Lang748f74e2014-12-01 11:25:34 -0500517 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000518 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000519 // for a complete framebuffer, all attachments must have the same sample count
520 // in this case return the first nonzero sample size
521 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
522 {
Jamie Madille261b442014-06-25 12:42:21 -0400523 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000524 {
Jamie Madille261b442014-06-25 12:42:21 -0400525 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000526 }
527 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000528 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000529
530 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000531}
532
Jamie Madille261b442014-06-25 12:42:21 -0400533bool Framebuffer::hasValidDepthStencil() const
534{
535 // A valid depth-stencil attachment has the same resource bound to both the
536 // depth and stencil attachment points.
537 return (mDepthbuffer && mStencilbuffer &&
538 mDepthbuffer->type() == mStencilbuffer->type() &&
539 mDepthbuffer->id() == mStencilbuffer->id());
540}
541
Jamie Madill48faf802014-11-06 15:27:22 -0500542ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400543{
544 ColorbufferInfo colorbuffersForRender;
545
546 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
547 {
548 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
549 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
550
551 if (colorbuffer != NULL && drawBufferState != GL_NONE)
552 {
553 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
554 colorbuffersForRender.push_back(colorbuffer);
555 }
Jamie Madill48faf802014-11-06 15:27:22 -0500556 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400557 {
558 colorbuffersForRender.push_back(NULL);
559 }
560 }
561
562 return colorbuffersForRender;
563}
564
Geoff Langab75a052014-10-15 12:56:37 -0400565void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
566{
567 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
568}
569
570void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
571{
572 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
573}
574
575void Framebuffer::setNULLAttachment(GLenum attachment)
576{
577 setAttachment(attachment, NULL);
578}
579
580void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
581{
582 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
583 {
584 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
585 SafeDelete(mColorbuffers[colorAttachment]);
586 mColorbuffers[colorAttachment] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500587 mImpl->setColorAttachment(colorAttachment, attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400588 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500589 else if (attachment == GL_BACK)
590 {
591 SafeDelete(mColorbuffers[0]);
592 mColorbuffers[0] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500593 mImpl->setColorAttachment(0, attachmentObj);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500594 }
595 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400596 {
597 SafeDelete(mDepthbuffer);
598 mDepthbuffer = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500599 mImpl->setDepthttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400600 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500601 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400602 {
603 SafeDelete(mStencilbuffer);
604 mStencilbuffer = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500605 mImpl->setStencilAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400606 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500607 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400608 {
609 SafeDelete(mDepthbuffer);
610 SafeDelete(mStencilbuffer);
611
612 // ensure this is a legitimate depth+stencil format
613 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
614 {
615 mDepthbuffer = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500616 mImpl->setDepthttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400617
618 // Make a new attachment object to ensure we do not double-delete
619 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500620 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400621 {
622 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
623 *attachmentObj->getTextureImageIndex());
Geoff Lang9dd95802014-12-01 11:12:59 -0500624 mImpl->setStencilAttachment(mStencilbuffer);
Geoff Langab75a052014-10-15 12:56:37 -0400625 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500626 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400627 {
628 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
Geoff Lang9dd95802014-12-01 11:12:59 -0500629 mImpl->setStencilAttachment(mStencilbuffer);
Geoff Langab75a052014-10-15 12:56:37 -0400630 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500631 else
632 {
633 UNREACHABLE();
634 }
Geoff Langab75a052014-10-15 12:56:37 -0400635 }
636 }
637 else
638 {
639 UNREACHABLE();
640 }
641}
642
Geoff Lang528ce3c2014-12-01 10:44:07 -0500643DefaultFramebuffer::DefaultFramebuffer(rx::FramebufferImpl *impl, rx::DefaultAttachmentImpl *colorAttachment,
644 rx::DefaultAttachmentImpl *depthAttachment, rx::DefaultAttachmentImpl *stencilAttachment)
645 : Framebuffer(impl, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000646{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500647 ASSERT(colorAttachment);
648 setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, colorAttachment));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000649
Geoff Lang528ce3c2014-12-01 10:44:07 -0500650 if (depthAttachment)
Jamie Madille92a3542014-07-03 10:38:58 -0400651 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500652 setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, depthAttachment));
Jamie Madille92a3542014-07-03 10:38:58 -0400653 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500654 if (stencilAttachment)
655 {
656 setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, stencilAttachment));
657 }
658
Geoff Lang9dd95802014-12-01 11:12:59 -0500659 GLenum drawBufferState = GL_BACK;
660 setDrawBuffers(1, &drawBufferState);
661
662 setReadBuffer(GL_BACK);
Jamie Madille92a3542014-07-03 10:38:58 -0400663}
664
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000665}