blob: b9c4a71cd67864bbea0c745e90aec3206537b41c [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"
Jamie Madill400a4412014-08-29 15:46:45 -040018#include "libGLESv2/renderer/RenderTarget.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040019
20#include "common/utilities.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 Madillaef95de2014-09-05 10:12:41 -040050FramebufferAttachment *Framebuffer::createAttachment(GLenum binding, 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 Madillaef95de2014-09-05 10:12:41 -040065 return new RenderbufferAttachment(binding, 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);
Jamie Madillaef95de2014-09-05 10:12:41 -040073 return new Texture2DAttachment(binding, 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);
Jamie Madillaef95de2014-09-05 10:12:41 -040092 return new TextureCubeMapAttachment(binding, 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);
Jamie Madillaef95de2014-09-05 10:12:41 -0400106 return new Texture3DAttachment(binding, 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);
Jamie Madillaef95de2014-09-05 10:12:41 -0400120 return new Texture2DArrayAttachment(binding, 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]);
Jamie Madillaef95de2014-09-05 10:12:41 -0400138 GLenum binding = colorAttachment + GL_COLOR_ATTACHMENT0;
139 mColorbuffers[colorAttachment] = createAttachment(binding, type, colorbuffer, level, layer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000140}
141
Geoff Lang309c92a2013-07-25 16:23:19 -0400142void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143{
Jamie Madille261b442014-06-25 12:42:21 -0400144 SafeDelete(mDepthbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400145 mDepthbuffer = createAttachment(GL_DEPTH_ATTACHMENT, type, depthbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146}
147
Geoff Lang309c92a2013-07-25 16:23:19 -0400148void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
Jamie Madille261b442014-06-25 12:42:21 -0400150 SafeDelete(mStencilbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400151 mStencilbuffer = createAttachment(GL_STENCIL_ATTACHMENT, type, stencilbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152}
153
Geoff Lang309c92a2013-07-25 16:23:19 -0400154void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400155{
Jamie Madillaef95de2014-09-05 10:12:41 -0400156 FramebufferAttachment *attachment = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400157
Jamie Madille261b442014-06-25 12:42:21 -0400158 SafeDelete(mDepthbuffer);
159 SafeDelete(mStencilbuffer);
160
161 // ensure this is a legitimate depth+stencil format
Geoff Lange4a492b2014-06-19 14:14:41 -0400162 if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400163 {
Jamie Madille261b442014-06-25 12:42:21 -0400164 mDepthbuffer = attachment;
Jamie Madill28bedaf2014-06-26 13:17:22 -0400165
166 // Make a new attachment object to ensure we do not double-delete
167 // See angle issue 686
Jamie Madillaef95de2014-09-05 10:12:41 -0400168 mStencilbuffer = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400169 }
170}
171
Jamie Madille261b442014-06-25 12:42:21 -0400172void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000173{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000174 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175 {
Jamie Madille261b442014-06-25 12:42:21 -0400176 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
177
178 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000179 {
Jamie Madille261b442014-06-25 12:42:21 -0400180 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000181 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000183
Jamie Madille261b442014-06-25 12:42:21 -0400184 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000185 {
Jamie Madille261b442014-06-25 12:42:21 -0400186 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000187 }
188
Jamie Madille261b442014-06-25 12:42:21 -0400189 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000190 {
Jamie Madille261b442014-06-25 12:42:21 -0400191 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000192 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193}
194
Jamie Madille261b442014-06-25 12:42:21 -0400195void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000197 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000198 {
Jamie Madille261b442014-06-25 12:42:21 -0400199 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
200
201 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000202 {
Jamie Madille261b442014-06-25 12:42:21 -0400203 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000204 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205 }
206
Jamie Madille261b442014-06-25 12:42:21 -0400207 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208 {
Jamie Madille261b442014-06-25 12:42:21 -0400209 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210 }
211
Jamie Madille261b442014-06-25 12:42:21 -0400212 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213 {
Jamie Madille261b442014-06-25 12:42:21 -0400214 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215 }
216}
217
Jamie Madill3c7fa222014-06-05 13:08:51 -0400218FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000219{
220 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400221 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000222}
223
Jamie Madill3c7fa222014-06-05 13:08:51 -0400224FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225{
Jamie Madille261b442014-06-25 12:42:21 -0400226 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227}
228
Jamie Madill3c7fa222014-06-05 13:08:51 -0400229FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230{
Jamie Madille261b442014-06-25 12:42:21 -0400231 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232}
233
Jamie Madill3c7fa222014-06-05 13:08:51 -0400234FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400235{
Jamie Madille261b442014-06-25 12:42:21 -0400236 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400237}
238
Jamie Madill3c7fa222014-06-05 13:08:51 -0400239FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000240{
Jamie Madille261b442014-06-25 12:42:21 -0400241 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000242
243 if (!depthstencilbuffer)
244 {
Jamie Madille261b442014-06-25 12:42:21 -0400245 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000246 }
247
248 return depthstencilbuffer;
249}
250
Jamie Madill3c7fa222014-06-05 13:08:51 -0400251FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000252{
253 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400254 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000255}
256
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000257GLenum Framebuffer::getReadColorbufferType() const
258{
259 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400260 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000261}
262
Jamie Madill3c7fa222014-06-05 13:08:51 -0400263FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000264{
265 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
266 {
Jamie Madille261b442014-06-25 12:42:21 -0400267 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000268 {
Jamie Madille261b442014-06-25 12:42:21 -0400269 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000270 }
271 }
272
273 return NULL;
274}
275
Jamie Madille92a3542014-07-03 10:38:58 -0400276FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000277{
Jamie Madille92a3542014-07-03 10:38:58 -0400278 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
279 {
280 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
281 }
282 else
283 {
284 switch (attachment)
285 {
286 case GL_DEPTH_ATTACHMENT:
287 return getDepthbuffer();
288 case GL_STENCIL_ATTACHMENT:
289 return getStencilbuffer();
290 case GL_DEPTH_STENCIL_ATTACHMENT:
291 return getDepthStencilBuffer();
292 default:
293 UNREACHABLE();
294 return NULL;
295 }
296 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400297}
298
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000299GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
300{
301 return mDrawBufferStates[colorAttachment];
302}
303
304void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
305{
306 mDrawBufferStates[colorAttachment] = drawBuffer;
307}
308
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000309bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
310{
Jamie Madille261b442014-06-25 12:42:21 -0400311 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000312}
313
314bool Framebuffer::hasEnabledColorAttachment() const
315{
316 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
317 {
318 if (isEnabledColorAttachment(colorAttachment))
319 {
320 return true;
321 }
322 }
323
324 return false;
325}
326
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000327bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000328{
Geoff Lange4a492b2014-06-19 14:14:41 -0400329 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000330}
331
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000332bool Framebuffer::usingExtendedDrawBuffers() const
333{
334 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
335 {
336 if (isEnabledColorAttachment(colorAttachment))
337 {
338 return true;
339 }
340 }
341
342 return false;
343}
344
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000345GLenum Framebuffer::completeness() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347 int width = 0;
348 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000349 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000350 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000351 bool missingAttachment = true;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000352 GLuint clientVersion = mRenderer->getCurrentClientVersion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000354 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400356 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
357
358 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000360 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000361 {
362 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
363 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000364
Geoff Langcec35902014-04-16 10:52:36 -0400365 GLenum internalformat = colorbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400366 // TODO(geofflang): use context's texture caps
367 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400368 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400369 if (colorbuffer->isTexture())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000370 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400371 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000372 {
373 return GL_FRAMEBUFFER_UNSUPPORTED;
374 }
375
Geoff Lang5d601382014-07-22 15:14:06 -0400376 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000377 {
378 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
379 }
380 }
381 else
382 {
Geoff Lang5d601382014-07-22 15:14:06 -0400383 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400384 {
385 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
386 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000387 }
388
389 if (!missingAttachment)
390 {
391 // all color attachments must have the same width and height
392 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
393 {
394 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
395 }
396
397 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
398 // all color attachments have the same number of samples for the FBO to be complete.
399 if (colorbuffer->getSamples() != samples)
400 {
401 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
402 }
403
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000404 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
405 // in GLES 3.0, there is no such restriction
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000406 if (clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000407 {
Geoff Lang5d601382014-07-22 15:14:06 -0400408 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000409 {
410 return GL_FRAMEBUFFER_UNSUPPORTED;
411 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000412 }
413
414 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
415 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
416 {
Jamie Madille92a3542014-07-03 10:38:58 -0400417 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
418
419 if (previousAttachment &&
420 (colorbuffer->id() == previousAttachment->id() &&
421 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000422 {
423 return GL_FRAMEBUFFER_UNSUPPORTED;
424 }
425 }
426 }
427 else
428 {
429 width = colorbuffer->getWidth();
430 height = colorbuffer->getHeight();
431 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400432 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000433 missingAttachment = false;
434 }
435 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000436 }
437
Jamie Madille261b442014-06-25 12:42:21 -0400438 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000439 {
Jamie Madille261b442014-06-25 12:42:21 -0400440 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000442 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 }
444
Jamie Madille261b442014-06-25 12:42:21 -0400445 GLenum internalformat = mDepthbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400446 // TODO(geofflang): use context's texture caps
447 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400448 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400449 if (mDepthbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000450 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000451 // depth texture attachments require OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400452 // TODO(geofflang): use context's extensions
453 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000454 {
455 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
456 }
457
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400458 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400459 {
460 return GL_FRAMEBUFFER_UNSUPPORTED;
461 }
462
Geoff Lang5d601382014-07-22 15:14:06 -0400463 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000464 {
465 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
466 }
467 }
468 else
469 {
Geoff Lang5d601382014-07-22 15:14:06 -0400470 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400471 {
472 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
473 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000474 }
475
476 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000477 {
Jamie Madille261b442014-06-25 12:42:21 -0400478 width = mDepthbuffer->getWidth();
479 height = mDepthbuffer->getHeight();
480 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000481 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000482 }
Jamie Madille261b442014-06-25 12:42:21 -0400483 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000484 {
485 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
486 }
Jamie Madille261b442014-06-25 12:42:21 -0400487 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000488 {
489 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
490 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000491 }
492
Jamie Madille261b442014-06-25 12:42:21 -0400493 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000494 {
Jamie Madille261b442014-06-25 12:42:21 -0400495 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000496 {
497 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
498 }
499
Jamie Madille261b442014-06-25 12:42:21 -0400500 GLenum internalformat = mStencilbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400501 // TODO(geofflang): use context's texture caps
502 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400503 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400504 if (mStencilbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000505 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000506 // texture stencil attachments come along as part
507 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400508 // TODO(geofflang): use context's extensions
509 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000510 {
511 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
512 }
513
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400514 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400515 {
516 return GL_FRAMEBUFFER_UNSUPPORTED;
517 }
518
Geoff Lang5d601382014-07-22 15:14:06 -0400519 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000520 {
521 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
522 }
523 }
524 else
525 {
Geoff Lang5d601382014-07-22 15:14:06 -0400526 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400527 {
528 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
529 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000530 }
531
532 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000533 {
Jamie Madille261b442014-06-25 12:42:21 -0400534 width = mStencilbuffer->getWidth();
535 height = mStencilbuffer->getHeight();
536 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000537 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000538 }
Jamie Madille261b442014-06-25 12:42:21 -0400539 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000540 {
541 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
542 }
Jamie Madille261b442014-06-25 12:42:21 -0400543 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000544 {
545 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
546 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000547 }
548
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000549 // if we have both a depth and stencil buffer, they must refer to the same object
550 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400551 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000552 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000553 return GL_FRAMEBUFFER_UNSUPPORTED;
554 }
555
556 // we need to have at least one attachment to be complete
557 if (missingAttachment)
558 {
559 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000560 }
561
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562 return GL_FRAMEBUFFER_COMPLETE;
563}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000564
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400565void Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
566{
567 GLuint maxDimension = caps.maxRenderbufferSize;
568 invalidateSub(caps, numAttachments, attachments, 0, 0, maxDimension, maxDimension);
569}
570
571void Framebuffer::invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments,
572 GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400573{
574 ASSERT(completeness() == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill6d708262014-09-03 15:07:13 -0400575 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400576 {
Jamie Madill6d708262014-09-03 15:07:13 -0400577 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400578
Jamie Madill6d708262014-09-03 15:07:13 -0400579 gl::FramebufferAttachment *attachment =
580 (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() :
581 getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400582
Jamie Madill6d708262014-09-03 15:07:13 -0400583 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400584 {
Jamie Madill6d708262014-09-03 15:07:13 -0400585 rx::RenderTarget *renderTarget = attachment->getRenderTarget();
586 if (renderTarget)
587 {
588 renderTarget->invalidate(x, y, width, height);
589 }
Jamie Madill400a4412014-08-29 15:46:45 -0400590 }
591 }
592}
593
daniel@transgaming.com16418b12012-11-28 19:32:22 +0000594DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -0400595 : Framebuffer(renderer, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000596{
Geoff Lange4a492b2014-06-19 14:14:41 -0400597 Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400598 mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000599
Jamie Madill28bedaf2014-06-26 13:17:22 -0400600 Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil);
601
602 // Make a new attachment objects to ensure we do not double-delete
603 // See angle issue 686
Jamie Madillaef95de2014-09-05 10:12:41 -0400604 mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL);
605 mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000606
607 mDrawBufferStates[0] = GL_BACK;
608 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000609}
610
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000611int Framebuffer::getSamples() const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000612{
613 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
614 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000615 // for a complete framebuffer, all attachments must have the same sample count
616 // in this case return the first nonzero sample size
617 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
618 {
Jamie Madille261b442014-06-25 12:42:21 -0400619 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000620 {
Jamie Madille261b442014-06-25 12:42:21 -0400621 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000622 }
623 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000624 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000625
626 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000627}
628
Jamie Madille261b442014-06-25 12:42:21 -0400629bool Framebuffer::hasValidDepthStencil() const
630{
631 // A valid depth-stencil attachment has the same resource bound to both the
632 // depth and stencil attachment points.
633 return (mDepthbuffer && mStencilbuffer &&
634 mDepthbuffer->type() == mStencilbuffer->type() &&
635 mDepthbuffer->id() == mStencilbuffer->id());
636}
637
Jamie Madillce20c7f2014-09-03 11:56:29 -0400638ColorbufferInfo Framebuffer::getColorbuffersForRender() const
639{
640 ColorbufferInfo colorbuffersForRender;
641
642 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
643 {
644 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
645 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
646
647 if (colorbuffer != NULL && drawBufferState != GL_NONE)
648 {
649 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
650 colorbuffersForRender.push_back(colorbuffer);
651 }
652 else
653 {
654 colorbuffersForRender.push_back(NULL);
655 }
656 }
657
658 return colorbuffersForRender;
659}
660
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000661GLenum DefaultFramebuffer::completeness() const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000662{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000663 // The default framebuffer *must* always be complete, though it may not be
664 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000665 return GL_FRAMEBUFFER_COMPLETE;
666}
667
Jamie Madille92a3542014-07-03 10:38:58 -0400668FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
669{
670 switch (attachment)
671 {
Jamie Madill6d708262014-09-03 15:07:13 -0400672 case GL_COLOR:
Jamie Madille92a3542014-07-03 10:38:58 -0400673 case GL_BACK:
674 return getColorbuffer(0);
675 case GL_DEPTH:
676 return getDepthbuffer();
677 case GL_STENCIL:
678 return getStencilbuffer();
679 case GL_DEPTH_STENCIL:
680 return getDepthStencilBuffer();
681 default:
682 UNREACHABLE();
683 return NULL;
684 }
685}
686
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000687}