blob: 2f866c31ec0cd497c576bcacec0376e92fbf4fb3 [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);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000198}
199
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000200bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
201{
Jamie Madille261b442014-06-25 12:42:21 -0400202 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000203}
204
205bool Framebuffer::hasEnabledColorAttachment() const
206{
207 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
208 {
209 if (isEnabledColorAttachment(colorAttachment))
210 {
211 return true;
212 }
213 }
214
215 return false;
216}
217
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000218bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000219{
Geoff Lange4a492b2014-06-19 14:14:41 -0400220 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000221}
222
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000223bool Framebuffer::usingExtendedDrawBuffers() const
224{
225 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
226 {
227 if (isEnabledColorAttachment(colorAttachment))
228 {
229 return true;
230 }
231 }
232
233 return false;
234}
235
Jamie Madill48faf802014-11-06 15:27:22 -0500236GLenum Framebuffer::completeness(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000237{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500238 // The default framebuffer *must* always be complete, though it may not be
239 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
240 if (mId == 0)
241 {
242 return GL_FRAMEBUFFER_COMPLETE;
243 }
244
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245 int width = 0;
246 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000247 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000248 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000249 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000251 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400253 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
254
255 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000257 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000258 {
259 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
260 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000261
Geoff Langcec35902014-04-16 10:52:36 -0400262 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500263 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400264 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500265 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000266 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400267 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000268 {
269 return GL_FRAMEBUFFER_UNSUPPORTED;
270 }
271
Geoff Lang5d601382014-07-22 15:14:06 -0400272 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000273 {
274 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
275 }
276 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500277 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000278 {
Geoff Lang5d601382014-07-22 15:14:06 -0400279 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400280 {
281 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
282 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000283 }
284
285 if (!missingAttachment)
286 {
287 // all color attachments must have the same width and height
288 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
289 {
290 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
291 }
292
293 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
294 // all color attachments have the same number of samples for the FBO to be complete.
295 if (colorbuffer->getSamples() != samples)
296 {
297 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
298 }
299
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000300 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
301 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500302 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000303 {
Geoff Lang5d601382014-07-22 15:14:06 -0400304 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000305 {
306 return GL_FRAMEBUFFER_UNSUPPORTED;
307 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000308 }
309
310 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
311 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
312 {
Jamie Madille92a3542014-07-03 10:38:58 -0400313 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
314
315 if (previousAttachment &&
316 (colorbuffer->id() == previousAttachment->id() &&
317 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000318 {
319 return GL_FRAMEBUFFER_UNSUPPORTED;
320 }
321 }
322 }
323 else
324 {
325 width = colorbuffer->getWidth();
326 height = colorbuffer->getHeight();
327 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400328 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000329 missingAttachment = false;
330 }
331 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000332 }
333
Jamie Madille261b442014-06-25 12:42:21 -0400334 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000335 {
Jamie Madille261b442014-06-25 12:42:21 -0400336 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000338 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000339 }
340
Jamie Madille261b442014-06-25 12:42:21 -0400341 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500342 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400343 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500344 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000345 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000346 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500347 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000348 {
349 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
350 }
351
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400352 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400353 {
354 return GL_FRAMEBUFFER_UNSUPPORTED;
355 }
356
Geoff Lang5d601382014-07-22 15:14:06 -0400357 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000358 {
359 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
360 }
361 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500362 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000363 {
Geoff Lang5d601382014-07-22 15:14:06 -0400364 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400365 {
366 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
367 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000368 }
369
370 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000371 {
Jamie Madille261b442014-06-25 12:42:21 -0400372 width = mDepthbuffer->getWidth();
373 height = mDepthbuffer->getHeight();
374 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000375 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000376 }
Jamie Madille261b442014-06-25 12:42:21 -0400377 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000378 {
379 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
380 }
Jamie Madille261b442014-06-25 12:42:21 -0400381 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000382 {
383 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
384 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000385 }
386
Jamie Madille261b442014-06-25 12:42:21 -0400387 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000388 {
Jamie Madille261b442014-06-25 12:42:21 -0400389 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000390 {
391 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
392 }
393
Jamie Madille261b442014-06-25 12:42:21 -0400394 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500395 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400396 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500397 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000398 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000399 // texture stencil attachments come along as part
400 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500401 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000402 {
403 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
404 }
405
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400406 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400407 {
408 return GL_FRAMEBUFFER_UNSUPPORTED;
409 }
410
Geoff Lang5d601382014-07-22 15:14:06 -0400411 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000412 {
413 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
414 }
415 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500416 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000417 {
Geoff Lang5d601382014-07-22 15:14:06 -0400418 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400419 {
420 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
421 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000422 }
423
424 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000425 {
Jamie Madille261b442014-06-25 12:42:21 -0400426 width = mStencilbuffer->getWidth();
427 height = mStencilbuffer->getHeight();
428 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000429 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000430 }
Jamie Madille261b442014-06-25 12:42:21 -0400431 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000432 {
433 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
434 }
Jamie Madille261b442014-06-25 12:42:21 -0400435 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000436 {
437 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
438 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000439 }
440
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000441 // if we have both a depth and stencil buffer, they must refer to the same object
442 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400443 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000444 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000445 return GL_FRAMEBUFFER_UNSUPPORTED;
446 }
447
448 // we need to have at least one attachment to be complete
449 if (missingAttachment)
450 {
451 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000452 }
453
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 return GL_FRAMEBUFFER_COMPLETE;
455}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000456
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500457Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400458{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500459 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400460}
461
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500462Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400463{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500464 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400465}
466
Jamie Madill48faf802014-11-06 15:27:22 -0500467int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000468{
Jamie Madill48faf802014-11-06 15:27:22 -0500469 if (completeness(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000470 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000471 // for a complete framebuffer, all attachments must have the same sample count
472 // in this case return the first nonzero sample size
473 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
474 {
Jamie Madille261b442014-06-25 12:42:21 -0400475 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000476 {
Jamie Madille261b442014-06-25 12:42:21 -0400477 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000478 }
479 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000480 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000481
482 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000483}
484
Jamie Madille261b442014-06-25 12:42:21 -0400485bool Framebuffer::hasValidDepthStencil() const
486{
487 // A valid depth-stencil attachment has the same resource bound to both the
488 // depth and stencil attachment points.
489 return (mDepthbuffer && mStencilbuffer &&
490 mDepthbuffer->type() == mStencilbuffer->type() &&
491 mDepthbuffer->id() == mStencilbuffer->id());
492}
493
Jamie Madill48faf802014-11-06 15:27:22 -0500494ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400495{
496 ColorbufferInfo colorbuffersForRender;
497
498 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
499 {
500 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
501 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
502
503 if (colorbuffer != NULL && drawBufferState != GL_NONE)
504 {
505 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
506 colorbuffersForRender.push_back(colorbuffer);
507 }
Jamie Madill48faf802014-11-06 15:27:22 -0500508 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400509 {
510 colorbuffersForRender.push_back(NULL);
511 }
512 }
513
514 return colorbuffersForRender;
515}
516
Geoff Langab75a052014-10-15 12:56:37 -0400517void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
518{
519 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
520}
521
522void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
523{
524 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
525}
526
527void Framebuffer::setNULLAttachment(GLenum attachment)
528{
529 setAttachment(attachment, NULL);
530}
531
532void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
533{
534 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
535 {
536 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
537 SafeDelete(mColorbuffers[colorAttachment]);
538 mColorbuffers[colorAttachment] = attachmentObj;
539 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500540 else if (attachment == GL_BACK)
541 {
542 SafeDelete(mColorbuffers[0]);
543 mColorbuffers[0] = attachmentObj;
544 }
545 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400546 {
547 SafeDelete(mDepthbuffer);
548 mDepthbuffer = attachmentObj;
549 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500550 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400551 {
552 SafeDelete(mStencilbuffer);
553 mStencilbuffer = attachmentObj;
554 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500555 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400556 {
557 SafeDelete(mDepthbuffer);
558 SafeDelete(mStencilbuffer);
559
560 // ensure this is a legitimate depth+stencil format
561 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
562 {
563 mDepthbuffer = attachmentObj;
564
565 // Make a new attachment object to ensure we do not double-delete
566 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500567 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400568 {
569 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
570 *attachmentObj->getTextureImageIndex());
571 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500572 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400573 {
574 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
575 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500576 else
577 {
578 UNREACHABLE();
579 }
Geoff Langab75a052014-10-15 12:56:37 -0400580 }
581 }
582 else
583 {
584 UNREACHABLE();
585 }
586}
587
Geoff Lang528ce3c2014-12-01 10:44:07 -0500588DefaultFramebuffer::DefaultFramebuffer(rx::FramebufferImpl *impl, rx::DefaultAttachmentImpl *colorAttachment,
589 rx::DefaultAttachmentImpl *depthAttachment, rx::DefaultAttachmentImpl *stencilAttachment)
590 : Framebuffer(impl, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000591{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500592 ASSERT(colorAttachment);
593 setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, colorAttachment));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000594
Geoff Lang528ce3c2014-12-01 10:44:07 -0500595 if (depthAttachment)
Jamie Madille92a3542014-07-03 10:38:58 -0400596 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500597 setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, depthAttachment));
Jamie Madille92a3542014-07-03 10:38:58 -0400598 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500599 if (stencilAttachment)
600 {
601 setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, stencilAttachment));
602 }
603
604 mDrawBufferStates[0] = GL_BACK;
605 mReadBufferState = GL_BACK;
Jamie Madille92a3542014-07-03 10:38:58 -0400606}
607
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608}