blob: 8db41908bc91e49a7f8a171545acbd1bddba4913 [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 Madilleeb7b0e2014-09-03 15:07:20 -040072 return new TextureAttachment(binding, texture, ImageIndex::Make2D(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 Madilleeb7b0e2014-09-03 15:07:20 -040090 return new TextureAttachment(binding, texture, ImageIndex::MakeCube(type, level));
Geoff Lang309c92a2013-07-25 16:23:19 -040091 }
92 else
93 {
94 return NULL;
95 }
96 }
97
98 case GL_TEXTURE_3D:
99 {
100 Texture *texture = context->getTexture(handle);
101 if (texture && texture->getTarget() == GL_TEXTURE_3D)
102 {
Jamie Madilleeb7b0e2014-09-03 15:07:20 -0400103 return new TextureAttachment(binding, texture, ImageIndex::Make3D(level, layer));
Geoff Lang309c92a2013-07-25 16:23:19 -0400104 }
105 else
106 {
107 return NULL;
108 }
109 }
110
111 case GL_TEXTURE_2D_ARRAY:
112 {
113 Texture *texture = context->getTexture(handle);
114 if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY)
115 {
Jamie Madilleeb7b0e2014-09-03 15:07:20 -0400116 return new TextureAttachment(binding, texture, ImageIndex::Make2DArray(level, layer));
Geoff Lang309c92a2013-07-25 16:23:19 -0400117 }
118 else
119 {
120 return NULL;
121 }
122 }
123
124 default:
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000125 UNREACHABLE();
Geoff Lang309c92a2013-07-25 16:23:19 -0400126 return NULL;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000127 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000128}
129
Geoff Lang309c92a2013-07-25 16:23:19 -0400130void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000131{
132 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400133 SafeDelete(mColorbuffers[colorAttachment]);
Jamie Madillaef95de2014-09-05 10:12:41 -0400134 GLenum binding = colorAttachment + GL_COLOR_ATTACHMENT0;
135 mColorbuffers[colorAttachment] = createAttachment(binding, type, colorbuffer, level, layer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000136}
137
Geoff Lang309c92a2013-07-25 16:23:19 -0400138void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139{
Jamie Madille261b442014-06-25 12:42:21 -0400140 SafeDelete(mDepthbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400141 mDepthbuffer = createAttachment(GL_DEPTH_ATTACHMENT, type, depthbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142}
143
Geoff Lang309c92a2013-07-25 16:23:19 -0400144void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145{
Jamie Madille261b442014-06-25 12:42:21 -0400146 SafeDelete(mStencilbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400147 mStencilbuffer = createAttachment(GL_STENCIL_ATTACHMENT, type, stencilbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148}
149
Geoff Lang309c92a2013-07-25 16:23:19 -0400150void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400151{
Jamie Madillaef95de2014-09-05 10:12:41 -0400152 FramebufferAttachment *attachment = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400153
Jamie Madille261b442014-06-25 12:42:21 -0400154 SafeDelete(mDepthbuffer);
155 SafeDelete(mStencilbuffer);
156
157 // ensure this is a legitimate depth+stencil format
Geoff Lange4a492b2014-06-19 14:14:41 -0400158 if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400159 {
Jamie Madille261b442014-06-25 12:42:21 -0400160 mDepthbuffer = attachment;
Jamie Madill28bedaf2014-06-26 13:17:22 -0400161
162 // Make a new attachment object to ensure we do not double-delete
163 // See angle issue 686
Jamie Madillaef95de2014-09-05 10:12:41 -0400164 mStencilbuffer = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400165 }
166}
167
Jamie Madille261b442014-06-25 12:42:21 -0400168void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000170 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 {
Jamie Madille261b442014-06-25 12:42:21 -0400172 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
173
174 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000175 {
Jamie Madille261b442014-06-25 12:42:21 -0400176 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000177 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000178 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000179
Jamie Madille261b442014-06-25 12:42:21 -0400180 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000181 {
Jamie Madille261b442014-06-25 12:42:21 -0400182 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000183 }
184
Jamie Madille261b442014-06-25 12:42:21 -0400185 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000186 {
Jamie Madille261b442014-06-25 12:42:21 -0400187 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000188 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189}
190
Jamie Madille261b442014-06-25 12:42:21 -0400191void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000193 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194 {
Jamie Madille261b442014-06-25 12:42:21 -0400195 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
196
197 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000198 {
Jamie Madille261b442014-06-25 12:42:21 -0400199 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000200 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201 }
202
Jamie Madille261b442014-06-25 12:42:21 -0400203 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204 {
Jamie Madille261b442014-06-25 12:42:21 -0400205 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206 }
207
Jamie Madille261b442014-06-25 12:42:21 -0400208 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209 {
Jamie Madille261b442014-06-25 12:42:21 -0400210 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 }
212}
213
Jamie Madill3c7fa222014-06-05 13:08:51 -0400214FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000215{
216 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400217 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000218}
219
Jamie Madill3c7fa222014-06-05 13:08:51 -0400220FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221{
Jamie Madille261b442014-06-25 12:42:21 -0400222 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223}
224
Jamie Madill3c7fa222014-06-05 13:08:51 -0400225FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226{
Jamie Madille261b442014-06-25 12:42:21 -0400227 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228}
229
Jamie Madill3c7fa222014-06-05 13:08:51 -0400230FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400231{
Jamie Madille261b442014-06-25 12:42:21 -0400232 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400233}
234
Jamie Madill3c7fa222014-06-05 13:08:51 -0400235FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000236{
Jamie Madille261b442014-06-25 12:42:21 -0400237 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000238
239 if (!depthstencilbuffer)
240 {
Jamie Madille261b442014-06-25 12:42:21 -0400241 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000242 }
243
244 return depthstencilbuffer;
245}
246
Jamie Madill3c7fa222014-06-05 13:08:51 -0400247FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000248{
249 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400250 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000251}
252
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000253GLenum Framebuffer::getReadColorbufferType() const
254{
255 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400256 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000257}
258
Jamie Madill3c7fa222014-06-05 13:08:51 -0400259FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000260{
261 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
262 {
Jamie Madille261b442014-06-25 12:42:21 -0400263 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000264 {
Jamie Madille261b442014-06-25 12:42:21 -0400265 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000266 }
267 }
268
269 return NULL;
270}
271
Jamie Madille92a3542014-07-03 10:38:58 -0400272FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000273{
Jamie Madille92a3542014-07-03 10:38:58 -0400274 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
275 {
276 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
277 }
278 else
279 {
280 switch (attachment)
281 {
282 case GL_DEPTH_ATTACHMENT:
283 return getDepthbuffer();
284 case GL_STENCIL_ATTACHMENT:
285 return getStencilbuffer();
286 case GL_DEPTH_STENCIL_ATTACHMENT:
287 return getDepthStencilBuffer();
288 default:
289 UNREACHABLE();
290 return NULL;
291 }
292 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400293}
294
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000295GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
296{
297 return mDrawBufferStates[colorAttachment];
298}
299
300void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
301{
302 mDrawBufferStates[colorAttachment] = drawBuffer;
303}
304
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000305bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
306{
Jamie Madille261b442014-06-25 12:42:21 -0400307 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000308}
309
310bool Framebuffer::hasEnabledColorAttachment() const
311{
312 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
313 {
314 if (isEnabledColorAttachment(colorAttachment))
315 {
316 return true;
317 }
318 }
319
320 return false;
321}
322
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000323bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000324{
Geoff Lange4a492b2014-06-19 14:14:41 -0400325 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000326}
327
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000328bool Framebuffer::usingExtendedDrawBuffers() const
329{
330 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
331 {
332 if (isEnabledColorAttachment(colorAttachment))
333 {
334 return true;
335 }
336 }
337
338 return false;
339}
340
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000341GLenum Framebuffer::completeness() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000342{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343 int width = 0;
344 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000345 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000346 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000347 bool missingAttachment = true;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000348 GLuint clientVersion = mRenderer->getCurrentClientVersion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000350 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400352 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
353
354 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000356 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000357 {
358 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
359 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000360
Geoff Langcec35902014-04-16 10:52:36 -0400361 GLenum internalformat = colorbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400362 // TODO(geofflang): use context's texture caps
363 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400364 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400365 if (colorbuffer->isTexture())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000366 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400367 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000368 {
369 return GL_FRAMEBUFFER_UNSUPPORTED;
370 }
371
Geoff Lang5d601382014-07-22 15:14:06 -0400372 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000373 {
374 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
375 }
376 }
377 else
378 {
Geoff Lang5d601382014-07-22 15:14:06 -0400379 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400380 {
381 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
382 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000383 }
384
385 if (!missingAttachment)
386 {
387 // all color attachments must have the same width and height
388 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
389 {
390 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
391 }
392
393 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
394 // all color attachments have the same number of samples for the FBO to be complete.
395 if (colorbuffer->getSamples() != samples)
396 {
397 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
398 }
399
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000400 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
401 // in GLES 3.0, there is no such restriction
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000402 if (clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000403 {
Geoff Lang5d601382014-07-22 15:14:06 -0400404 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000405 {
406 return GL_FRAMEBUFFER_UNSUPPORTED;
407 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000408 }
409
410 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
411 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
412 {
Jamie Madille92a3542014-07-03 10:38:58 -0400413 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
414
415 if (previousAttachment &&
416 (colorbuffer->id() == previousAttachment->id() &&
417 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000418 {
419 return GL_FRAMEBUFFER_UNSUPPORTED;
420 }
421 }
422 }
423 else
424 {
425 width = colorbuffer->getWidth();
426 height = colorbuffer->getHeight();
427 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400428 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000429 missingAttachment = false;
430 }
431 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000432 }
433
Jamie Madille261b442014-06-25 12:42:21 -0400434 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000435 {
Jamie Madille261b442014-06-25 12:42:21 -0400436 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000438 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439 }
440
Jamie Madille261b442014-06-25 12:42:21 -0400441 GLenum internalformat = mDepthbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400442 // TODO(geofflang): use context's texture caps
443 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400444 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400445 if (mDepthbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000446 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000447 // depth texture attachments require OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400448 // TODO(geofflang): use context's extensions
449 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000450 {
451 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
452 }
453
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400454 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400455 {
456 return GL_FRAMEBUFFER_UNSUPPORTED;
457 }
458
Geoff Lang5d601382014-07-22 15:14:06 -0400459 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000460 {
461 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
462 }
463 }
464 else
465 {
Geoff Lang5d601382014-07-22 15:14:06 -0400466 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400467 {
468 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
469 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000470 }
471
472 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000473 {
Jamie Madille261b442014-06-25 12:42:21 -0400474 width = mDepthbuffer->getWidth();
475 height = mDepthbuffer->getHeight();
476 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000477 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000478 }
Jamie Madille261b442014-06-25 12:42:21 -0400479 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000480 {
481 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
482 }
Jamie Madille261b442014-06-25 12:42:21 -0400483 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000484 {
485 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
486 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000487 }
488
Jamie Madille261b442014-06-25 12:42:21 -0400489 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000490 {
Jamie Madille261b442014-06-25 12:42:21 -0400491 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000492 {
493 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
494 }
495
Jamie Madille261b442014-06-25 12:42:21 -0400496 GLenum internalformat = mStencilbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400497 // TODO(geofflang): use context's texture caps
498 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400499 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400500 if (mStencilbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000501 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000502 // texture stencil attachments come along as part
503 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400504 // TODO(geofflang): use context's extensions
505 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000506 {
507 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
508 }
509
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400510 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400511 {
512 return GL_FRAMEBUFFER_UNSUPPORTED;
513 }
514
Geoff Lang5d601382014-07-22 15:14:06 -0400515 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000516 {
517 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
518 }
519 }
520 else
521 {
Geoff Lang5d601382014-07-22 15:14:06 -0400522 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400523 {
524 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
525 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000526 }
527
528 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000529 {
Jamie Madille261b442014-06-25 12:42:21 -0400530 width = mStencilbuffer->getWidth();
531 height = mStencilbuffer->getHeight();
532 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000533 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000534 }
Jamie Madille261b442014-06-25 12:42:21 -0400535 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000536 {
537 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
538 }
Jamie Madille261b442014-06-25 12:42:21 -0400539 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000540 {
541 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
542 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000543 }
544
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000545 // if we have both a depth and stencil buffer, they must refer to the same object
546 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400547 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000548 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000549 return GL_FRAMEBUFFER_UNSUPPORTED;
550 }
551
552 // we need to have at least one attachment to be complete
553 if (missingAttachment)
554 {
555 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000556 }
557
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000558 return GL_FRAMEBUFFER_COMPLETE;
559}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000560
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400561void Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
562{
563 GLuint maxDimension = caps.maxRenderbufferSize;
564 invalidateSub(caps, numAttachments, attachments, 0, 0, maxDimension, maxDimension);
565}
566
567void Framebuffer::invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments,
568 GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400569{
570 ASSERT(completeness() == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill6d708262014-09-03 15:07:13 -0400571 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400572 {
Jamie Madill6d708262014-09-03 15:07:13 -0400573 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400574
Jamie Madill6d708262014-09-03 15:07:13 -0400575 gl::FramebufferAttachment *attachment =
576 (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() :
577 getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400578
Jamie Madill6d708262014-09-03 15:07:13 -0400579 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400580 {
Jamie Madill6d708262014-09-03 15:07:13 -0400581 rx::RenderTarget *renderTarget = attachment->getRenderTarget();
582 if (renderTarget)
583 {
584 renderTarget->invalidate(x, y, width, height);
585 }
Jamie Madill400a4412014-08-29 15:46:45 -0400586 }
587 }
588}
589
daniel@transgaming.com16418b12012-11-28 19:32:22 +0000590DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -0400591 : Framebuffer(renderer, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000592{
Geoff Lange4a492b2014-06-19 14:14:41 -0400593 Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400594 mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000595
Jamie Madill28bedaf2014-06-26 13:17:22 -0400596 Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil);
597
598 // Make a new attachment objects to ensure we do not double-delete
599 // See angle issue 686
Jamie Madillaef95de2014-09-05 10:12:41 -0400600 mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL);
601 mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000602
603 mDrawBufferStates[0] = GL_BACK;
604 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000605}
606
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000607int Framebuffer::getSamples() const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000608{
609 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
610 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000611 // for a complete framebuffer, all attachments must have the same sample count
612 // in this case return the first nonzero sample size
613 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
614 {
Jamie Madille261b442014-06-25 12:42:21 -0400615 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000616 {
Jamie Madille261b442014-06-25 12:42:21 -0400617 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000618 }
619 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000620 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000621
622 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000623}
624
Jamie Madille261b442014-06-25 12:42:21 -0400625bool Framebuffer::hasValidDepthStencil() const
626{
627 // A valid depth-stencil attachment has the same resource bound to both the
628 // depth and stencil attachment points.
629 return (mDepthbuffer && mStencilbuffer &&
630 mDepthbuffer->type() == mStencilbuffer->type() &&
631 mDepthbuffer->id() == mStencilbuffer->id());
632}
633
Jamie Madillce20c7f2014-09-03 11:56:29 -0400634ColorbufferInfo Framebuffer::getColorbuffersForRender() const
635{
636 ColorbufferInfo colorbuffersForRender;
637
638 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
639 {
640 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
641 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
642
643 if (colorbuffer != NULL && drawBufferState != GL_NONE)
644 {
645 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
646 colorbuffersForRender.push_back(colorbuffer);
647 }
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400648#if (ANGLE_MRT_PERF_WORKAROUND == ANGLE_WORKAROUND_DISABLED)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400649 else
650 {
651 colorbuffersForRender.push_back(NULL);
652 }
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400653#endif
Jamie Madillce20c7f2014-09-03 11:56:29 -0400654 }
655
656 return colorbuffersForRender;
657}
658
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000659GLenum DefaultFramebuffer::completeness() const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000660{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000661 // The default framebuffer *must* always be complete, though it may not be
662 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000663 return GL_FRAMEBUFFER_COMPLETE;
664}
665
Jamie Madille92a3542014-07-03 10:38:58 -0400666FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
667{
668 switch (attachment)
669 {
Jamie Madill6d708262014-09-03 15:07:13 -0400670 case GL_COLOR:
Jamie Madille92a3542014-07-03 10:38:58 -0400671 case GL_BACK:
672 return getColorbuffer(0);
673 case GL_DEPTH:
674 return getDepthbuffer();
675 case GL_STENCIL:
676 return getStencilbuffer();
677 case GL_DEPTH_STENCIL:
678 return getDepthStencilBuffer();
679 default:
680 UNREACHABLE();
681 return NULL;
682 }
683}
684
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000685}