blob: 30b042e94ad6fcee61a5c7f26aa1f316e146b1c3 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
9// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
10
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Framebuffer.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000013#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000014#include "common/utilities.h"
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +000015#include "libGLESv2/formatutils.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000016#include "libGLESv2/Texture.h"
17#include "libGLESv2/Context.h"
18#include "libGLESv2/renderer/Renderer.h"
19#include "libGLESv2/Renderbuffer.h"
Jamie Madille261b442014-06-25 12:42:21 -040020#include "libGLESv2/FramebufferAttachment.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021
22namespace gl
23{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000024
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -040025Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id)
Jamie Madille261b442014-06-25 12:42:21 -040026 : mRenderer(renderer),
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -040027 mId(id),
Jamie Madille261b442014-06-25 12:42:21 -040028 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
29 mDepthbuffer(NULL),
30 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000031{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000032 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
33 {
Jamie Madille261b442014-06-25 12:42:21 -040034 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000035 mDrawBufferStates[colorAttachment] = GL_NONE;
36 }
37 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038}
39
40Framebuffer::~Framebuffer()
41{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000042 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
43 {
Jamie Madille261b442014-06-25 12:42:21 -040044 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000045 }
Jamie Madille261b442014-06-25 12:42:21 -040046 SafeDelete(mDepthbuffer);
47 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000048}
49
Jamie Madille261b442014-06-25 12:42:21 -040050FramebufferAttachment *Framebuffer::createAttachment(GLenum type, GLuint handle, GLint level, GLint layer) const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000051{
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040052 if (handle == 0)
53 {
54 return NULL;
55 }
56
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000057 gl::Context *context = gl::getContext();
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000058
Geoff Lang309c92a2013-07-25 16:23:19 -040059 switch (type)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000060 {
Geoff Lang309c92a2013-07-25 16:23:19 -040061 case GL_NONE:
62 return NULL;
63
64 case GL_RENDERBUFFER:
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040065 return new RenderbufferAttachment(context->getRenderbuffer(handle));
Geoff Lang309c92a2013-07-25 16:23:19 -040066
67 case GL_TEXTURE_2D:
68 {
69 Texture *texture = context->getTexture(handle);
70 if (texture && texture->getTarget() == GL_TEXTURE_2D)
71 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040072 Texture2D *tex2D = static_cast<Texture2D*>(texture);
73 return new Texture2DAttachment(tex2D, level);
Geoff Lang309c92a2013-07-25 16:23:19 -040074 }
75 else
76 {
77 return NULL;
78 }
79 }
80
81 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
82 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
83 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
84 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
85 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
86 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
87 {
88 Texture *texture = context->getTexture(handle);
89 if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP)
90 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040091 TextureCubeMap *texCube = static_cast<TextureCubeMap*>(texture);
92 return new TextureCubeMapAttachment(texCube, type, level);
Geoff Lang309c92a2013-07-25 16:23:19 -040093 }
94 else
95 {
96 return NULL;
97 }
98 }
99
100 case GL_TEXTURE_3D:
101 {
102 Texture *texture = context->getTexture(handle);
103 if (texture && texture->getTarget() == GL_TEXTURE_3D)
104 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400105 Texture3D *tex3D = static_cast<Texture3D*>(texture);
106 return new Texture3DAttachment(tex3D, level, layer);
Geoff Lang309c92a2013-07-25 16:23:19 -0400107 }
108 else
109 {
110 return NULL;
111 }
112 }
113
114 case GL_TEXTURE_2D_ARRAY:
115 {
116 Texture *texture = context->getTexture(handle);
117 if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY)
118 {
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400119 Texture2DArray *tex2DArray = static_cast<Texture2DArray*>(texture);
120 return new Texture2DArrayAttachment(tex2DArray, level, layer);
Geoff Lang309c92a2013-07-25 16:23:19 -0400121 }
122 else
123 {
124 return NULL;
125 }
126 }
127
128 default:
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000129 UNREACHABLE();
Geoff Lang309c92a2013-07-25 16:23:19 -0400130 return NULL;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000131 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000132}
133
Geoff Lang309c92a2013-07-25 16:23:19 -0400134void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000135{
136 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400137 SafeDelete(mColorbuffers[colorAttachment]);
138 mColorbuffers[colorAttachment] = createAttachment(type, colorbuffer, level, layer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000139}
140
Geoff Lang309c92a2013-07-25 16:23:19 -0400141void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142{
Jamie Madille261b442014-06-25 12:42:21 -0400143 SafeDelete(mDepthbuffer);
144 mDepthbuffer = createAttachment(type, depthbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145}
146
Geoff Lang309c92a2013-07-25 16:23:19 -0400147void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148{
Jamie Madille261b442014-06-25 12:42:21 -0400149 SafeDelete(mStencilbuffer);
150 mStencilbuffer = createAttachment(type, stencilbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151}
152
Geoff Lang309c92a2013-07-25 16:23:19 -0400153void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400154{
Jamie Madille261b442014-06-25 12:42:21 -0400155 FramebufferAttachment *attachment = createAttachment(type, depthStencilBuffer, level, layer);
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400156
Jamie Madille261b442014-06-25 12:42:21 -0400157 SafeDelete(mDepthbuffer);
158 SafeDelete(mStencilbuffer);
159
160 // ensure this is a legitimate depth+stencil format
Geoff Lange4a492b2014-06-19 14:14:41 -0400161 if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400162 {
Jamie Madille261b442014-06-25 12:42:21 -0400163 mDepthbuffer = attachment;
Jamie Madill28bedaf2014-06-26 13:17:22 -0400164
165 // Make a new attachment object to ensure we do not double-delete
166 // See angle issue 686
167 mStencilbuffer = createAttachment(type, depthStencilBuffer, level, layer);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400168 }
169}
170
Jamie Madille261b442014-06-25 12:42:21 -0400171void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000172{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000173 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174 {
Jamie Madille261b442014-06-25 12:42:21 -0400175 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
176
177 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000178 {
Jamie Madille261b442014-06-25 12:42:21 -0400179 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000180 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000182
Jamie Madille261b442014-06-25 12:42:21 -0400183 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000184 {
Jamie Madille261b442014-06-25 12:42:21 -0400185 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000186 }
187
Jamie Madille261b442014-06-25 12:42:21 -0400188 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000189 {
Jamie Madille261b442014-06-25 12:42:21 -0400190 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000191 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192}
193
Jamie Madille261b442014-06-25 12:42:21 -0400194void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000196 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197 {
Jamie Madille261b442014-06-25 12:42:21 -0400198 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
199
200 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000201 {
Jamie Madille261b442014-06-25 12:42:21 -0400202 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000203 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204 }
205
Jamie Madille261b442014-06-25 12:42:21 -0400206 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207 {
Jamie Madille261b442014-06-25 12:42:21 -0400208 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209 }
210
Jamie Madille261b442014-06-25 12:42:21 -0400211 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212 {
Jamie Madille261b442014-06-25 12:42:21 -0400213 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000214 }
215}
216
Jamie Madill3c7fa222014-06-05 13:08:51 -0400217FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000218{
219 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400220 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000221}
222
Jamie Madill3c7fa222014-06-05 13:08:51 -0400223FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224{
Jamie Madille261b442014-06-25 12:42:21 -0400225 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226}
227
Jamie Madill3c7fa222014-06-05 13:08:51 -0400228FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229{
Jamie Madille261b442014-06-25 12:42:21 -0400230 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231}
232
Jamie Madill3c7fa222014-06-05 13:08:51 -0400233FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400234{
Jamie Madille261b442014-06-25 12:42:21 -0400235 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400236}
237
Jamie Madill3c7fa222014-06-05 13:08:51 -0400238FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000239{
Jamie Madille261b442014-06-25 12:42:21 -0400240 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000241
242 if (!depthstencilbuffer)
243 {
Jamie Madille261b442014-06-25 12:42:21 -0400244 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000245 }
246
247 return depthstencilbuffer;
248}
249
Jamie Madill3c7fa222014-06-05 13:08:51 -0400250FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000251{
252 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400253 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000254}
255
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000256GLenum Framebuffer::getReadColorbufferType() const
257{
258 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400259 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000260}
261
Jamie Madill3c7fa222014-06-05 13:08:51 -0400262FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000263{
264 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
265 {
Jamie Madille261b442014-06-25 12:42:21 -0400266 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000267 {
Jamie Madille261b442014-06-25 12:42:21 -0400268 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000269 }
270 }
271
272 return NULL;
273}
274
Jamie Madille92a3542014-07-03 10:38:58 -0400275FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000276{
Jamie Madille92a3542014-07-03 10:38:58 -0400277 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
278 {
279 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
280 }
281 else
282 {
283 switch (attachment)
284 {
285 case GL_DEPTH_ATTACHMENT:
286 return getDepthbuffer();
287 case GL_STENCIL_ATTACHMENT:
288 return getStencilbuffer();
289 case GL_DEPTH_STENCIL_ATTACHMENT:
290 return getDepthStencilBuffer();
291 default:
292 UNREACHABLE();
293 return NULL;
294 }
295 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400296}
297
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000298GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
299{
300 return mDrawBufferStates[colorAttachment];
301}
302
303void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
304{
305 mDrawBufferStates[colorAttachment] = drawBuffer;
306}
307
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000308bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
309{
Jamie Madille261b442014-06-25 12:42:21 -0400310 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000311}
312
313bool Framebuffer::hasEnabledColorAttachment() const
314{
315 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
316 {
317 if (isEnabledColorAttachment(colorAttachment))
318 {
319 return true;
320 }
321 }
322
323 return false;
324}
325
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000326bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000327{
Geoff Lange4a492b2014-06-19 14:14:41 -0400328 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000329}
330
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000331bool Framebuffer::usingExtendedDrawBuffers() const
332{
333 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
334 {
335 if (isEnabledColorAttachment(colorAttachment))
336 {
337 return true;
338 }
339 }
340
341 return false;
342}
343
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000344GLenum Framebuffer::completeness() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346 int width = 0;
347 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000348 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000349 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000350 bool missingAttachment = true;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000351 GLuint clientVersion = mRenderer->getCurrentClientVersion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000353 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400355 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
356
357 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000358 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000359 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000360 {
361 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
362 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000363
Geoff Langcec35902014-04-16 10:52:36 -0400364 GLenum internalformat = colorbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400365 // TODO(geofflang): use context's texture caps
366 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400367 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400368 if (colorbuffer->isTexture())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000369 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400370 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000371 {
372 return GL_FRAMEBUFFER_UNSUPPORTED;
373 }
374
Geoff Lang5d601382014-07-22 15:14:06 -0400375 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000376 {
377 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
378 }
379 }
380 else
381 {
Geoff Lang5d601382014-07-22 15:14:06 -0400382 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400383 {
384 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
385 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000386 }
387
388 if (!missingAttachment)
389 {
390 // all color attachments must have the same width and height
391 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
392 {
393 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
394 }
395
396 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
397 // all color attachments have the same number of samples for the FBO to be complete.
398 if (colorbuffer->getSamples() != samples)
399 {
400 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
401 }
402
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000403 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
404 // in GLES 3.0, there is no such restriction
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000405 if (clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000406 {
Geoff Lang5d601382014-07-22 15:14:06 -0400407 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000408 {
409 return GL_FRAMEBUFFER_UNSUPPORTED;
410 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000411 }
412
413 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
414 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
415 {
Jamie Madille92a3542014-07-03 10:38:58 -0400416 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
417
418 if (previousAttachment &&
419 (colorbuffer->id() == previousAttachment->id() &&
420 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000421 {
422 return GL_FRAMEBUFFER_UNSUPPORTED;
423 }
424 }
425 }
426 else
427 {
428 width = colorbuffer->getWidth();
429 height = colorbuffer->getHeight();
430 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400431 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000432 missingAttachment = false;
433 }
434 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000435 }
436
Jamie Madille261b442014-06-25 12:42:21 -0400437 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000438 {
Jamie Madille261b442014-06-25 12:42:21 -0400439 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000440 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000441 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 }
443
Jamie Madille261b442014-06-25 12:42:21 -0400444 GLenum internalformat = mDepthbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400445 // TODO(geofflang): use context's texture caps
446 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400447 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400448 if (mDepthbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000449 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000450 // depth texture attachments require OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400451 // TODO(geofflang): use context's extensions
452 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000453 {
454 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
455 }
456
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400457 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400458 {
459 return GL_FRAMEBUFFER_UNSUPPORTED;
460 }
461
Geoff Lang5d601382014-07-22 15:14:06 -0400462 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000463 {
464 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
465 }
466 }
467 else
468 {
Geoff Lang5d601382014-07-22 15:14:06 -0400469 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400470 {
471 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
472 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000473 }
474
475 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000476 {
Jamie Madille261b442014-06-25 12:42:21 -0400477 width = mDepthbuffer->getWidth();
478 height = mDepthbuffer->getHeight();
479 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000480 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000481 }
Jamie Madille261b442014-06-25 12:42:21 -0400482 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000483 {
484 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
485 }
Jamie Madille261b442014-06-25 12:42:21 -0400486 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000487 {
488 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
489 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000490 }
491
Jamie Madille261b442014-06-25 12:42:21 -0400492 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000493 {
Jamie Madille261b442014-06-25 12:42:21 -0400494 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000495 {
496 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
497 }
498
Jamie Madille261b442014-06-25 12:42:21 -0400499 GLenum internalformat = mStencilbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400500 // TODO(geofflang): use context's texture caps
501 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400502 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400503 if (mStencilbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000504 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000505 // texture stencil attachments come along as part
506 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400507 // TODO(geofflang): use context's extensions
508 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000509 {
510 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
511 }
512
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400513 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400514 {
515 return GL_FRAMEBUFFER_UNSUPPORTED;
516 }
517
Geoff Lang5d601382014-07-22 15:14:06 -0400518 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000519 {
520 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
521 }
522 }
523 else
524 {
Geoff Lang5d601382014-07-22 15:14:06 -0400525 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400526 {
527 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
528 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000529 }
530
531 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000532 {
Jamie Madille261b442014-06-25 12:42:21 -0400533 width = mStencilbuffer->getWidth();
534 height = mStencilbuffer->getHeight();
535 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000536 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000537 }
Jamie Madille261b442014-06-25 12:42:21 -0400538 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000539 {
540 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
541 }
Jamie Madille261b442014-06-25 12:42:21 -0400542 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000543 {
544 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
545 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000546 }
547
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000548 // if we have both a depth and stencil buffer, they must refer to the same object
549 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400550 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000551 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000552 return GL_FRAMEBUFFER_UNSUPPORTED;
553 }
554
555 // we need to have at least one attachment to be complete
556 if (missingAttachment)
557 {
558 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000559 }
560
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000561 return GL_FRAMEBUFFER_COMPLETE;
562}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000563
daniel@transgaming.com16418b12012-11-28 19:32:22 +0000564DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -0400565 : Framebuffer(renderer, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000566{
Geoff Lange4a492b2014-06-19 14:14:41 -0400567 Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer);
Jamie Madille261b442014-06-25 12:42:21 -0400568 mColorbuffers[0] = new RenderbufferAttachment(colorRenderbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000569
Jamie Madill28bedaf2014-06-26 13:17:22 -0400570 Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil);
571
572 // Make a new attachment objects to ensure we do not double-delete
573 // See angle issue 686
574 mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(depthStencilBuffer) : NULL);
575 mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(depthStencilBuffer) : NULL);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000576
577 mDrawBufferStates[0] = GL_BACK;
578 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000579}
580
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000581int Framebuffer::getSamples() const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000582{
583 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
584 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000585 // for a complete framebuffer, all attachments must have the same sample count
586 // in this case return the first nonzero sample size
587 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
588 {
Jamie Madille261b442014-06-25 12:42:21 -0400589 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000590 {
Jamie Madille261b442014-06-25 12:42:21 -0400591 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000592 }
593 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000594 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000595
596 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000597}
598
Jamie Madille261b442014-06-25 12:42:21 -0400599bool Framebuffer::hasValidDepthStencil() const
600{
601 // A valid depth-stencil attachment has the same resource bound to both the
602 // depth and stencil attachment points.
603 return (mDepthbuffer && mStencilbuffer &&
604 mDepthbuffer->type() == mStencilbuffer->type() &&
605 mDepthbuffer->id() == mStencilbuffer->id());
606}
607
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000608GLenum DefaultFramebuffer::completeness() const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000609{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000610 // The default framebuffer *must* always be complete, though it may not be
611 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000612 return GL_FRAMEBUFFER_COMPLETE;
613}
614
Jamie Madille92a3542014-07-03 10:38:58 -0400615FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
616{
617 switch (attachment)
618 {
619 case GL_BACK:
620 return getColorbuffer(0);
621 case GL_DEPTH:
622 return getDepthbuffer();
623 case GL_STENCIL:
624 return getStencilbuffer();
625 case GL_DEPTH_STENCIL:
626 return getDepthStencilBuffer();
627 default:
628 UNREACHABLE();
629 return NULL;
630 }
631}
632
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000633}