blob: aba016ad4eae3403a4d1c2b9d30afd523a2abcbe [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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Framebuffer.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/main.h"
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +000012#include "libGLESv2/formatutils.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000013#include "libGLESv2/Texture.h"
14#include "libGLESv2/Context.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000015#include "libGLESv2/Renderbuffer.h"
Jamie Madille261b442014-06-25 12:42:21 -040016#include "libGLESv2/FramebufferAttachment.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040017#include "libGLESv2/renderer/Renderer.h"
18
19#include "common/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000020
21namespace gl
22{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000023
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -040024Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id)
Jamie Madille261b442014-06-25 12:42:21 -040025 : mRenderer(renderer),
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -040026 mId(id),
Jamie Madille261b442014-06-25 12:42:21 -040027 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
28 mDepthbuffer(NULL),
29 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000031 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
32 {
Jamie Madille261b442014-06-25 12:42:21 -040033 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000034 mDrawBufferStates[colorAttachment] = GL_NONE;
35 }
36 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000037}
38
39Framebuffer::~Framebuffer()
40{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000041 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
42 {
Jamie Madille261b442014-06-25 12:42:21 -040043 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000044 }
Jamie Madille261b442014-06-25 12:42:21 -040045 SafeDelete(mDepthbuffer);
46 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000047}
48
Jamie Madille261b442014-06-25 12:42:21 -040049FramebufferAttachment *Framebuffer::createAttachment(GLenum type, GLuint handle, GLint level, GLint layer) const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000050{
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040051 if (handle == 0)
52 {
53 return NULL;
54 }
55
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000056 gl::Context *context = gl::getContext();
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000057
Geoff Lang309c92a2013-07-25 16:23:19 -040058 switch (type)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000059 {
Geoff Lang309c92a2013-07-25 16:23:19 -040060 case GL_NONE:
61 return NULL;
62
63 case GL_RENDERBUFFER:
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040064 return new RenderbufferAttachment(context->getRenderbuffer(handle));
Geoff Lang309c92a2013-07-25 16:23:19 -040065
66 case GL_TEXTURE_2D:
67 {
68 Texture *texture = context->getTexture(handle);
69 if (texture && texture->getTarget() == GL_TEXTURE_2D)
70 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040071 Texture2D *tex2D = static_cast<Texture2D*>(texture);
72 return new Texture2DAttachment(tex2D, level);
Geoff Lang309c92a2013-07-25 16:23:19 -040073 }
74 else
75 {
76 return NULL;
77 }
78 }
79
80 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
82 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
83 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
84 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
85 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
86 {
87 Texture *texture = context->getTexture(handle);
88 if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP)
89 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040090 TextureCubeMap *texCube = static_cast<TextureCubeMap*>(texture);
91 return new TextureCubeMapAttachment(texCube, type, level);
Geoff Lang309c92a2013-07-25 16:23:19 -040092 }
93 else
94 {
95 return NULL;
96 }
97 }
98
99 case GL_TEXTURE_3D:
100 {
101 Texture *texture = context->getTexture(handle);
102 if (texture && texture->getTarget() == GL_TEXTURE_3D)
103 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400104 Texture3D *tex3D = static_cast<Texture3D*>(texture);
105 return new Texture3DAttachment(tex3D, level, layer);
Geoff Lang309c92a2013-07-25 16:23:19 -0400106 }
107 else
108 {
109 return NULL;
110 }
111 }
112
113 case GL_TEXTURE_2D_ARRAY:
114 {
115 Texture *texture = context->getTexture(handle);
116 if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY)
117 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400118 Texture2DArray *tex2DArray = static_cast<Texture2DArray*>(texture);
119 return new Texture2DArrayAttachment(tex2DArray, level, layer);
Geoff Lang309c92a2013-07-25 16:23:19 -0400120 }
121 else
122 {
123 return NULL;
124 }
125 }
126
127 default:
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000128 UNREACHABLE();
Geoff Lang309c92a2013-07-25 16:23:19 -0400129 return NULL;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000130 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131}
132
Geoff Lang309c92a2013-07-25 16:23:19 -0400133void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000134{
135 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400136 SafeDelete(mColorbuffers[colorAttachment]);
137 mColorbuffers[colorAttachment] = createAttachment(type, colorbuffer, level, layer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000138}
139
Geoff Lang309c92a2013-07-25 16:23:19 -0400140void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141{
Jamie Madille261b442014-06-25 12:42:21 -0400142 SafeDelete(mDepthbuffer);
143 mDepthbuffer = createAttachment(type, depthbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144}
145
Geoff Lang309c92a2013-07-25 16:23:19 -0400146void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000147{
Jamie Madille261b442014-06-25 12:42:21 -0400148 SafeDelete(mStencilbuffer);
149 mStencilbuffer = createAttachment(type, stencilbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000150}
151
Geoff Lang309c92a2013-07-25 16:23:19 -0400152void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400153{
Jamie Madille261b442014-06-25 12:42:21 -0400154 FramebufferAttachment *attachment = createAttachment(type, depthStencilBuffer, level, layer);
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400155
Jamie Madille261b442014-06-25 12:42:21 -0400156 SafeDelete(mDepthbuffer);
157 SafeDelete(mStencilbuffer);
158
159 // ensure this is a legitimate depth+stencil format
Geoff Lange4a492b2014-06-19 14:14:41 -0400160 if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400161 {
Jamie Madille261b442014-06-25 12:42:21 -0400162 mDepthbuffer = attachment;
Jamie Madill28bedaf2014-06-26 13:17:22 -0400163
164 // Make a new attachment object to ensure we do not double-delete
165 // See angle issue 686
166 mStencilbuffer = createAttachment(type, depthStencilBuffer, level, layer);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400167 }
168}
169
Jamie Madille261b442014-06-25 12:42:21 -0400170void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000172 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000173 {
Jamie Madille261b442014-06-25 12:42:21 -0400174 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
175
176 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000177 {
Jamie Madille261b442014-06-25 12:42:21 -0400178 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000179 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000181
Jamie Madille261b442014-06-25 12:42:21 -0400182 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000183 {
Jamie Madille261b442014-06-25 12:42:21 -0400184 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000185 }
186
Jamie Madille261b442014-06-25 12:42:21 -0400187 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000188 {
Jamie Madille261b442014-06-25 12:42:21 -0400189 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000190 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191}
192
Jamie Madille261b442014-06-25 12:42:21 -0400193void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000195 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 {
Jamie Madille261b442014-06-25 12:42:21 -0400197 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
198
199 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000200 {
Jamie Madille261b442014-06-25 12:42:21 -0400201 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000202 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203 }
204
Jamie Madille261b442014-06-25 12:42:21 -0400205 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206 {
Jamie Madille261b442014-06-25 12:42:21 -0400207 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208 }
209
Jamie Madille261b442014-06-25 12:42:21 -0400210 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 {
Jamie Madille261b442014-06-25 12:42:21 -0400212 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213 }
214}
215
Jamie Madill3c7fa222014-06-05 13:08:51 -0400216FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000217{
218 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400219 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000220}
221
Jamie Madill3c7fa222014-06-05 13:08:51 -0400222FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223{
Jamie Madille261b442014-06-25 12:42:21 -0400224 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225}
226
Jamie Madill3c7fa222014-06-05 13:08:51 -0400227FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228{
Jamie Madille261b442014-06-25 12:42:21 -0400229 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230}
231
Jamie Madill3c7fa222014-06-05 13:08:51 -0400232FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400233{
Jamie Madille261b442014-06-25 12:42:21 -0400234 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400235}
236
Jamie Madill3c7fa222014-06-05 13:08:51 -0400237FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000238{
Jamie Madille261b442014-06-25 12:42:21 -0400239 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000240
241 if (!depthstencilbuffer)
242 {
Jamie Madille261b442014-06-25 12:42:21 -0400243 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000244 }
245
246 return depthstencilbuffer;
247}
248
Jamie Madill3c7fa222014-06-05 13:08:51 -0400249FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000250{
251 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400252 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000253}
254
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000255GLenum Framebuffer::getReadColorbufferType() const
256{
257 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400258 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000259}
260
Jamie Madill3c7fa222014-06-05 13:08:51 -0400261FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000262{
263 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
264 {
Jamie Madille261b442014-06-25 12:42:21 -0400265 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000266 {
Jamie Madille261b442014-06-25 12:42:21 -0400267 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000268 }
269 }
270
271 return NULL;
272}
273
Jamie Madille92a3542014-07-03 10:38:58 -0400274FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000275{
Jamie Madille92a3542014-07-03 10:38:58 -0400276 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
277 {
278 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
279 }
280 else
281 {
282 switch (attachment)
283 {
284 case GL_DEPTH_ATTACHMENT:
285 return getDepthbuffer();
286 case GL_STENCIL_ATTACHMENT:
287 return getStencilbuffer();
288 case GL_DEPTH_STENCIL_ATTACHMENT:
289 return getDepthStencilBuffer();
290 default:
291 UNREACHABLE();
292 return NULL;
293 }
294 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400295}
296
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000297GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
298{
299 return mDrawBufferStates[colorAttachment];
300}
301
302void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
303{
304 mDrawBufferStates[colorAttachment] = drawBuffer;
305}
306
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000307bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
308{
Jamie Madille261b442014-06-25 12:42:21 -0400309 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000310}
311
312bool Framebuffer::hasEnabledColorAttachment() const
313{
314 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
315 {
316 if (isEnabledColorAttachment(colorAttachment))
317 {
318 return true;
319 }
320 }
321
322 return false;
323}
324
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000325bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000326{
Geoff Lange4a492b2014-06-19 14:14:41 -0400327 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000328}
329
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000330bool Framebuffer::usingExtendedDrawBuffers() const
331{
332 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
333 {
334 if (isEnabledColorAttachment(colorAttachment))
335 {
336 return true;
337 }
338 }
339
340 return false;
341}
342
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000343GLenum Framebuffer::completeness() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345 int width = 0;
346 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000347 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000348 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000349 bool missingAttachment = true;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000350 GLuint clientVersion = mRenderer->getCurrentClientVersion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000352 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400354 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
355
356 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000358 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000359 {
360 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
361 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000362
Geoff Langcec35902014-04-16 10:52:36 -0400363 GLenum internalformat = colorbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400364 // TODO(geofflang): use context's texture caps
365 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400366 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400367 if (colorbuffer->isTexture())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000368 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400369 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000370 {
371 return GL_FRAMEBUFFER_UNSUPPORTED;
372 }
373
Geoff Lang5d601382014-07-22 15:14:06 -0400374 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000375 {
376 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
377 }
378 }
379 else
380 {
Geoff Lang5d601382014-07-22 15:14:06 -0400381 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400382 {
383 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
384 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000385 }
386
387 if (!missingAttachment)
388 {
389 // all color attachments must have the same width and height
390 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
391 {
392 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
393 }
394
395 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
396 // all color attachments have the same number of samples for the FBO to be complete.
397 if (colorbuffer->getSamples() != samples)
398 {
399 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
400 }
401
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000402 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
403 // in GLES 3.0, there is no such restriction
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000404 if (clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000405 {
Geoff Lang5d601382014-07-22 15:14:06 -0400406 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000407 {
408 return GL_FRAMEBUFFER_UNSUPPORTED;
409 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000410 }
411
412 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
413 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
414 {
Jamie Madille92a3542014-07-03 10:38:58 -0400415 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
416
417 if (previousAttachment &&
418 (colorbuffer->id() == previousAttachment->id() &&
419 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000420 {
421 return GL_FRAMEBUFFER_UNSUPPORTED;
422 }
423 }
424 }
425 else
426 {
427 width = colorbuffer->getWidth();
428 height = colorbuffer->getHeight();
429 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400430 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000431 missingAttachment = false;
432 }
433 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000434 }
435
Jamie Madille261b442014-06-25 12:42:21 -0400436 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000437 {
Jamie Madille261b442014-06-25 12:42:21 -0400438 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000440 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 }
442
Jamie Madille261b442014-06-25 12:42:21 -0400443 GLenum internalformat = mDepthbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400444 // TODO(geofflang): use context's texture caps
445 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400446 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400447 if (mDepthbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000448 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000449 // depth texture attachments require OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400450 // TODO(geofflang): use context's extensions
451 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000452 {
453 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
454 }
455
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400456 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400457 {
458 return GL_FRAMEBUFFER_UNSUPPORTED;
459 }
460
Geoff Lang5d601382014-07-22 15:14:06 -0400461 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000462 {
463 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
464 }
465 }
466 else
467 {
Geoff Lang5d601382014-07-22 15:14:06 -0400468 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400469 {
470 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
471 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000472 }
473
474 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000475 {
Jamie Madille261b442014-06-25 12:42:21 -0400476 width = mDepthbuffer->getWidth();
477 height = mDepthbuffer->getHeight();
478 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000479 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000480 }
Jamie Madille261b442014-06-25 12:42:21 -0400481 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000482 {
483 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
484 }
Jamie Madille261b442014-06-25 12:42:21 -0400485 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000486 {
487 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
488 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000489 }
490
Jamie Madille261b442014-06-25 12:42:21 -0400491 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000492 {
Jamie Madille261b442014-06-25 12:42:21 -0400493 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000494 {
495 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
496 }
497
Jamie Madille261b442014-06-25 12:42:21 -0400498 GLenum internalformat = mStencilbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400499 // TODO(geofflang): use context's texture caps
500 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400501 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400502 if (mStencilbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000503 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000504 // texture stencil attachments come along as part
505 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400506 // TODO(geofflang): use context's extensions
507 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000508 {
509 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
510 }
511
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400512 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400513 {
514 return GL_FRAMEBUFFER_UNSUPPORTED;
515 }
516
Geoff Lang5d601382014-07-22 15:14:06 -0400517 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000518 {
519 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
520 }
521 }
522 else
523 {
Geoff Lang5d601382014-07-22 15:14:06 -0400524 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400525 {
526 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
527 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000528 }
529
530 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000531 {
Jamie Madille261b442014-06-25 12:42:21 -0400532 width = mStencilbuffer->getWidth();
533 height = mStencilbuffer->getHeight();
534 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000535 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000536 }
Jamie Madille261b442014-06-25 12:42:21 -0400537 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000538 {
539 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
540 }
Jamie Madille261b442014-06-25 12:42:21 -0400541 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000542 {
543 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
544 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000545 }
546
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000547 // if we have both a depth and stencil buffer, they must refer to the same object
548 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400549 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000550 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000551 return GL_FRAMEBUFFER_UNSUPPORTED;
552 }
553
554 // we need to have at least one attachment to be complete
555 if (missingAttachment)
556 {
557 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000558 }
559
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000560 return GL_FRAMEBUFFER_COMPLETE;
561}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000562
daniel@transgaming.com16418b12012-11-28 19:32:22 +0000563DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -0400564 : Framebuffer(renderer, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000565{
Geoff Lange4a492b2014-06-19 14:14:41 -0400566 Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer);
Jamie Madille261b442014-06-25 12:42:21 -0400567 mColorbuffers[0] = new RenderbufferAttachment(colorRenderbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000568
Jamie Madill28bedaf2014-06-26 13:17:22 -0400569 Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil);
570
571 // Make a new attachment objects to ensure we do not double-delete
572 // See angle issue 686
573 mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(depthStencilBuffer) : NULL);
574 mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(depthStencilBuffer) : NULL);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000575
576 mDrawBufferStates[0] = GL_BACK;
577 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000578}
579
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000580int Framebuffer::getSamples() const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000581{
582 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
583 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000584 // for a complete framebuffer, all attachments must have the same sample count
585 // in this case return the first nonzero sample size
586 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
587 {
Jamie Madille261b442014-06-25 12:42:21 -0400588 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000589 {
Jamie Madille261b442014-06-25 12:42:21 -0400590 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000591 }
592 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000593 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000594
595 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000596}
597
Jamie Madille261b442014-06-25 12:42:21 -0400598bool Framebuffer::hasValidDepthStencil() const
599{
600 // A valid depth-stencil attachment has the same resource bound to both the
601 // depth and stencil attachment points.
602 return (mDepthbuffer && mStencilbuffer &&
603 mDepthbuffer->type() == mStencilbuffer->type() &&
604 mDepthbuffer->id() == mStencilbuffer->id());
605}
606
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000607GLenum DefaultFramebuffer::completeness() const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000608{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000609 // The default framebuffer *must* always be complete, though it may not be
610 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000611 return GL_FRAMEBUFFER_COMPLETE;
612}
613
Jamie Madille92a3542014-07-03 10:38:58 -0400614FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
615{
616 switch (attachment)
617 {
618 case GL_BACK:
619 return getColorbuffer(0);
620 case GL_DEPTH:
621 return getDepthbuffer();
622 case GL_STENCIL:
623 return getStencilbuffer();
624 case GL_DEPTH_STENCIL:
625 return getDepthStencilBuffer();
626 default:
627 UNREACHABLE();
628 return NULL;
629 }
630}
631
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632}