blob: 4430e505788af8ca710fced47ce1f13f8c432270 [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"
Jamie Madill9f0b42a2014-09-12 10:25:27 -040019#include "libGLESv2/renderer/d3d/TextureD3D.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "common/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000022
Jamie Madill9f0b42a2014-09-12 10:25:27 -040023namespace rx
24{
25RenderTarget *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment)
26{
27 if (attachment->isTexture())
28 {
29 gl::Texture *texture = attachment->getTexture();
30 ASSERT(texture);
31 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
32 return textureD3D->getRenderTarget(attachment->mipLevel(), attachment->layer());
33 }
34
35 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
36 ASSERT(renderbuffer);
37
38 // TODO: cast to RenderbufferD3D
39 return renderbuffer->getStorage()->getRenderTarget();
40}
41
42}
43
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000044namespace gl
45{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000046
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -040047Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id)
Jamie Madille261b442014-06-25 12:42:21 -040048 : mRenderer(renderer),
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -040049 mId(id),
Jamie Madille261b442014-06-25 12:42:21 -040050 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
51 mDepthbuffer(NULL),
52 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000054 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
55 {
Jamie Madille261b442014-06-25 12:42:21 -040056 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000057 mDrawBufferStates[colorAttachment] = GL_NONE;
58 }
59 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000060}
61
62Framebuffer::~Framebuffer()
63{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000064 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
65 {
Jamie Madille261b442014-06-25 12:42:21 -040066 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000067 }
Jamie Madille261b442014-06-25 12:42:21 -040068 SafeDelete(mDepthbuffer);
69 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000070}
71
Jamie Madillaef95de2014-09-05 10:12:41 -040072FramebufferAttachment *Framebuffer::createAttachment(GLenum binding, GLenum type, GLuint handle, GLint level, GLint layer) const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000073{
Jamie Madill6c7b4ad2014-06-16 10:33:59 -040074 if (handle == 0)
75 {
76 return NULL;
77 }
78
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000079 gl::Context *context = gl::getContext();
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000080
Geoff Lang309c92a2013-07-25 16:23:19 -040081 switch (type)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000082 {
Geoff Lang309c92a2013-07-25 16:23:19 -040083 case GL_NONE:
84 return NULL;
85
86 case GL_RENDERBUFFER:
Jamie Madillaef95de2014-09-05 10:12:41 -040087 return new RenderbufferAttachment(binding, context->getRenderbuffer(handle));
Geoff Lang309c92a2013-07-25 16:23:19 -040088
89 case GL_TEXTURE_2D:
90 {
91 Texture *texture = context->getTexture(handle);
92 if (texture && texture->getTarget() == GL_TEXTURE_2D)
93 {
Jamie Madilleeb7b0e2014-09-03 15:07:20 -040094 return new TextureAttachment(binding, texture, ImageIndex::Make2D(level));
Geoff Lang309c92a2013-07-25 16:23:19 -040095 }
96 else
97 {
98 return NULL;
99 }
100 }
101
102 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
103 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
104 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
105 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
106 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
107 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
108 {
109 Texture *texture = context->getTexture(handle);
110 if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP)
111 {
Jamie Madilleeb7b0e2014-09-03 15:07:20 -0400112 return new TextureAttachment(binding, texture, ImageIndex::MakeCube(type, level));
Geoff Lang309c92a2013-07-25 16:23:19 -0400113 }
114 else
115 {
116 return NULL;
117 }
118 }
119
120 case GL_TEXTURE_3D:
121 {
122 Texture *texture = context->getTexture(handle);
123 if (texture && texture->getTarget() == GL_TEXTURE_3D)
124 {
Jamie Madilleeb7b0e2014-09-03 15:07:20 -0400125 return new TextureAttachment(binding, texture, ImageIndex::Make3D(level, layer));
Geoff Lang309c92a2013-07-25 16:23:19 -0400126 }
127 else
128 {
129 return NULL;
130 }
131 }
132
133 case GL_TEXTURE_2D_ARRAY:
134 {
135 Texture *texture = context->getTexture(handle);
136 if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY)
137 {
Jamie Madilleeb7b0e2014-09-03 15:07:20 -0400138 return new TextureAttachment(binding, texture, ImageIndex::Make2DArray(level, layer));
Geoff Lang309c92a2013-07-25 16:23:19 -0400139 }
140 else
141 {
142 return NULL;
143 }
144 }
145
146 default:
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000147 UNREACHABLE();
Geoff Lang309c92a2013-07-25 16:23:19 -0400148 return NULL;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000149 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000150}
151
Geoff Lang309c92a2013-07-25 16:23:19 -0400152void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000153{
154 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400155 SafeDelete(mColorbuffers[colorAttachment]);
Jamie Madillaef95de2014-09-05 10:12:41 -0400156 GLenum binding = colorAttachment + GL_COLOR_ATTACHMENT0;
157 mColorbuffers[colorAttachment] = createAttachment(binding, type, colorbuffer, level, layer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000158}
159
Geoff Lang309c92a2013-07-25 16:23:19 -0400160void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161{
Jamie Madille261b442014-06-25 12:42:21 -0400162 SafeDelete(mDepthbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400163 mDepthbuffer = createAttachment(GL_DEPTH_ATTACHMENT, type, depthbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164}
165
Geoff Lang309c92a2013-07-25 16:23:19 -0400166void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167{
Jamie Madille261b442014-06-25 12:42:21 -0400168 SafeDelete(mStencilbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400169 mStencilbuffer = createAttachment(GL_STENCIL_ATTACHMENT, type, stencilbuffer, level, layer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170}
171
Geoff Lang309c92a2013-07-25 16:23:19 -0400172void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400173{
Jamie Madillaef95de2014-09-05 10:12:41 -0400174 FramebufferAttachment *attachment = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
Jamie Madill6c7b4ad2014-06-16 10:33:59 -0400175
Jamie Madille261b442014-06-25 12:42:21 -0400176 SafeDelete(mDepthbuffer);
177 SafeDelete(mStencilbuffer);
178
179 // ensure this is a legitimate depth+stencil format
Geoff Lange4a492b2014-06-19 14:14:41 -0400180 if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0)
Geoff Lang55ba29c2013-07-11 16:57:53 -0400181 {
Jamie Madille261b442014-06-25 12:42:21 -0400182 mDepthbuffer = attachment;
Jamie Madill28bedaf2014-06-26 13:17:22 -0400183
184 // Make a new attachment object to ensure we do not double-delete
185 // See angle issue 686
Jamie Madillaef95de2014-09-05 10:12:41 -0400186 mStencilbuffer = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
Geoff Lang55ba29c2013-07-11 16:57:53 -0400187 }
188}
189
Jamie Madille261b442014-06-25 12:42:21 -0400190void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000192 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193 {
Jamie Madille261b442014-06-25 12:42:21 -0400194 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
195
196 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000197 {
Jamie Madille261b442014-06-25 12:42:21 -0400198 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000199 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000201
Jamie Madille261b442014-06-25 12:42:21 -0400202 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000203 {
Jamie Madille261b442014-06-25 12:42:21 -0400204 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000205 }
206
Jamie Madille261b442014-06-25 12:42:21 -0400207 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000208 {
Jamie Madille261b442014-06-25 12:42:21 -0400209 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000210 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211}
212
Jamie Madille261b442014-06-25 12:42:21 -0400213void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000214{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000215 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216 {
Jamie Madille261b442014-06-25 12:42:21 -0400217 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
218
219 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000220 {
Jamie Madille261b442014-06-25 12:42:21 -0400221 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000222 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223 }
224
Jamie Madille261b442014-06-25 12:42:21 -0400225 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226 {
Jamie Madille261b442014-06-25 12:42:21 -0400227 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228 }
229
Jamie Madille261b442014-06-25 12:42:21 -0400230 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231 {
Jamie Madille261b442014-06-25 12:42:21 -0400232 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233 }
234}
235
Jamie Madill3c7fa222014-06-05 13:08:51 -0400236FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000237{
238 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400239 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000240}
241
Jamie Madill3c7fa222014-06-05 13:08:51 -0400242FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243{
Jamie Madille261b442014-06-25 12:42:21 -0400244 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245}
246
Jamie Madill3c7fa222014-06-05 13:08:51 -0400247FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000248{
Jamie Madille261b442014-06-25 12:42:21 -0400249 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250}
251
Jamie Madill3c7fa222014-06-05 13:08:51 -0400252FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400253{
Jamie Madille261b442014-06-25 12:42:21 -0400254 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400255}
256
Jamie Madill3c7fa222014-06-05 13:08:51 -0400257FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000258{
Jamie Madille261b442014-06-25 12:42:21 -0400259 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000260
261 if (!depthstencilbuffer)
262 {
Jamie Madille261b442014-06-25 12:42:21 -0400263 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000264 }
265
266 return depthstencilbuffer;
267}
268
Jamie Madill3c7fa222014-06-05 13:08:51 -0400269FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000270{
271 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400272 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000273}
274
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000275GLenum Framebuffer::getReadColorbufferType() const
276{
277 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400278 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000279}
280
Jamie Madill3c7fa222014-06-05 13:08:51 -0400281FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000282{
283 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
284 {
Jamie Madille261b442014-06-25 12:42:21 -0400285 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000286 {
Jamie Madille261b442014-06-25 12:42:21 -0400287 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000288 }
289 }
290
291 return NULL;
292}
293
Jamie Madille92a3542014-07-03 10:38:58 -0400294FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000295{
Jamie Madille92a3542014-07-03 10:38:58 -0400296 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
297 {
298 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
299 }
300 else
301 {
302 switch (attachment)
303 {
304 case GL_DEPTH_ATTACHMENT:
305 return getDepthbuffer();
306 case GL_STENCIL_ATTACHMENT:
307 return getStencilbuffer();
308 case GL_DEPTH_STENCIL_ATTACHMENT:
309 return getDepthStencilBuffer();
310 default:
311 UNREACHABLE();
312 return NULL;
313 }
314 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400315}
316
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000317GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
318{
319 return mDrawBufferStates[colorAttachment];
320}
321
322void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
323{
324 mDrawBufferStates[colorAttachment] = drawBuffer;
325}
326
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000327bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
328{
Jamie Madille261b442014-06-25 12:42:21 -0400329 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000330}
331
332bool Framebuffer::hasEnabledColorAttachment() const
333{
334 for (unsigned int colorAttachment = 0; colorAttachment < gl::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 +0000345bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000346{
Geoff Lange4a492b2014-06-19 14:14:41 -0400347 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000348}
349
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000350bool Framebuffer::usingExtendedDrawBuffers() const
351{
352 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
353 {
354 if (isEnabledColorAttachment(colorAttachment))
355 {
356 return true;
357 }
358 }
359
360 return false;
361}
362
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000363GLenum Framebuffer::completeness() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000365 int width = 0;
366 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000367 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000368 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000369 bool missingAttachment = true;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000370 GLuint clientVersion = mRenderer->getCurrentClientVersion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000371
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000372 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400374 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
375
376 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000378 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000379 {
380 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
381 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000382
Geoff Langcec35902014-04-16 10:52:36 -0400383 GLenum internalformat = colorbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400384 // TODO(geofflang): use context's texture caps
385 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400386 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400387 if (colorbuffer->isTexture())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000388 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400389 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000390 {
391 return GL_FRAMEBUFFER_UNSUPPORTED;
392 }
393
Geoff Lang5d601382014-07-22 15:14:06 -0400394 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000395 {
396 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
397 }
398 }
399 else
400 {
Geoff Lang5d601382014-07-22 15:14:06 -0400401 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400402 {
403 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
404 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000405 }
406
407 if (!missingAttachment)
408 {
409 // all color attachments must have the same width and height
410 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
411 {
412 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
413 }
414
415 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
416 // all color attachments have the same number of samples for the FBO to be complete.
417 if (colorbuffer->getSamples() != samples)
418 {
419 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
420 }
421
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000422 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
423 // in GLES 3.0, there is no such restriction
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000424 if (clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000425 {
Geoff Lang5d601382014-07-22 15:14:06 -0400426 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000427 {
428 return GL_FRAMEBUFFER_UNSUPPORTED;
429 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000430 }
431
432 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
433 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
434 {
Jamie Madille92a3542014-07-03 10:38:58 -0400435 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
436
437 if (previousAttachment &&
438 (colorbuffer->id() == previousAttachment->id() &&
439 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000440 {
441 return GL_FRAMEBUFFER_UNSUPPORTED;
442 }
443 }
444 }
445 else
446 {
447 width = colorbuffer->getWidth();
448 height = colorbuffer->getHeight();
449 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400450 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000451 missingAttachment = false;
452 }
453 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000454 }
455
Jamie Madille261b442014-06-25 12:42:21 -0400456 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000457 {
Jamie Madille261b442014-06-25 12:42:21 -0400458 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000460 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000461 }
462
Jamie Madille261b442014-06-25 12:42:21 -0400463 GLenum internalformat = mDepthbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400464 // TODO(geofflang): use context's texture caps
465 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400466 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400467 if (mDepthbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000468 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000469 // depth texture attachments require OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400470 // TODO(geofflang): use context's extensions
471 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000472 {
473 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
474 }
475
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400476 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400477 {
478 return GL_FRAMEBUFFER_UNSUPPORTED;
479 }
480
Geoff Lang5d601382014-07-22 15:14:06 -0400481 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000482 {
483 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
484 }
485 }
486 else
487 {
Geoff Lang5d601382014-07-22 15:14:06 -0400488 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400489 {
490 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
491 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000492 }
493
494 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000495 {
Jamie Madille261b442014-06-25 12:42:21 -0400496 width = mDepthbuffer->getWidth();
497 height = mDepthbuffer->getHeight();
498 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000499 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000500 }
Jamie Madille261b442014-06-25 12:42:21 -0400501 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000502 {
503 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
504 }
Jamie Madille261b442014-06-25 12:42:21 -0400505 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000506 {
507 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
508 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000509 }
510
Jamie Madille261b442014-06-25 12:42:21 -0400511 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000512 {
Jamie Madille261b442014-06-25 12:42:21 -0400513 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000514 {
515 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
516 }
517
Jamie Madille261b442014-06-25 12:42:21 -0400518 GLenum internalformat = mStencilbuffer->getInternalFormat();
Geoff Langc0b9ef42014-07-02 10:02:37 -0400519 // TODO(geofflang): use context's texture caps
520 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400521 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400522 if (mStencilbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000523 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000524 // texture stencil attachments come along as part
525 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Geoff Langc0b9ef42014-07-02 10:02:37 -0400526 // TODO(geofflang): use context's extensions
527 if (!mRenderer->getRendererExtensions().depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000528 {
529 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
530 }
531
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400532 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400533 {
534 return GL_FRAMEBUFFER_UNSUPPORTED;
535 }
536
Geoff Lang5d601382014-07-22 15:14:06 -0400537 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000538 {
539 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
540 }
541 }
542 else
543 {
Geoff Lang5d601382014-07-22 15:14:06 -0400544 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400545 {
546 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
547 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000548 }
549
550 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000551 {
Jamie Madille261b442014-06-25 12:42:21 -0400552 width = mStencilbuffer->getWidth();
553 height = mStencilbuffer->getHeight();
554 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000555 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000556 }
Jamie Madille261b442014-06-25 12:42:21 -0400557 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000558 {
559 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
560 }
Jamie Madille261b442014-06-25 12:42:21 -0400561 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000562 {
563 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
564 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000565 }
566
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000567 // if we have both a depth and stencil buffer, they must refer to the same object
568 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400569 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000570 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000571 return GL_FRAMEBUFFER_UNSUPPORTED;
572 }
573
574 // we need to have at least one attachment to be complete
575 if (missingAttachment)
576 {
577 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000578 }
579
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000580 return GL_FRAMEBUFFER_COMPLETE;
581}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000582
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400583void Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
584{
585 GLuint maxDimension = caps.maxRenderbufferSize;
586 invalidateSub(caps, numAttachments, attachments, 0, 0, maxDimension, maxDimension);
587}
588
589void Framebuffer::invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments,
590 GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400591{
592 ASSERT(completeness() == GL_FRAMEBUFFER_COMPLETE);
Jamie Madill6d708262014-09-03 15:07:13 -0400593 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400594 {
Jamie Madill6d708262014-09-03 15:07:13 -0400595 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400596
Jamie Madill6d708262014-09-03 15:07:13 -0400597 gl::FramebufferAttachment *attachment =
598 (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() :
599 getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400600
Jamie Madill6d708262014-09-03 15:07:13 -0400601 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400602 {
Jamie Madill9f0b42a2014-09-12 10:25:27 -0400603 rx::RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment);
Jamie Madill6d708262014-09-03 15:07:13 -0400604 if (renderTarget)
605 {
606 renderTarget->invalidate(x, y, width, height);
607 }
Jamie Madill400a4412014-08-29 15:46:45 -0400608 }
609 }
610}
611
daniel@transgaming.com16418b12012-11-28 19:32:22 +0000612DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
Shannon Woodsaa2ab7d2014-06-24 17:51:51 -0400613 : Framebuffer(renderer, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000614{
Geoff Lange4a492b2014-06-19 14:14:41 -0400615 Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer);
Jamie Madillaef95de2014-09-05 10:12:41 -0400616 mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000617
Jamie Madill28bedaf2014-06-26 13:17:22 -0400618 Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil);
619
620 // Make a new attachment objects to ensure we do not double-delete
621 // See angle issue 686
Jamie Madillaef95de2014-09-05 10:12:41 -0400622 mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL);
623 mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000624
625 mDrawBufferStates[0] = GL_BACK;
626 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000627}
628
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000629int Framebuffer::getSamples() const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000630{
631 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
632 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000633 // for a complete framebuffer, all attachments must have the same sample count
634 // in this case return the first nonzero sample size
635 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
636 {
Jamie Madille261b442014-06-25 12:42:21 -0400637 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000638 {
Jamie Madille261b442014-06-25 12:42:21 -0400639 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000640 }
641 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000642 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000643
644 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000645}
646
Jamie Madille261b442014-06-25 12:42:21 -0400647bool Framebuffer::hasValidDepthStencil() const
648{
649 // A valid depth-stencil attachment has the same resource bound to both the
650 // depth and stencil attachment points.
651 return (mDepthbuffer && mStencilbuffer &&
652 mDepthbuffer->type() == mStencilbuffer->type() &&
653 mDepthbuffer->id() == mStencilbuffer->id());
654}
655
Jamie Madillce20c7f2014-09-03 11:56:29 -0400656ColorbufferInfo Framebuffer::getColorbuffersForRender() const
657{
658 ColorbufferInfo colorbuffersForRender;
659
660 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
661 {
662 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
663 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
664
665 if (colorbuffer != NULL && drawBufferState != GL_NONE)
666 {
667 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
668 colorbuffersForRender.push_back(colorbuffer);
669 }
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400670#if (ANGLE_MRT_PERF_WORKAROUND == ANGLE_WORKAROUND_DISABLED)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400671 else
672 {
673 colorbuffersForRender.push_back(NULL);
674 }
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400675#endif
Jamie Madillce20c7f2014-09-03 11:56:29 -0400676 }
677
678 return colorbuffersForRender;
679}
680
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000681GLenum DefaultFramebuffer::completeness() const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000682{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000683 // The default framebuffer *must* always be complete, though it may not be
684 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000685 return GL_FRAMEBUFFER_COMPLETE;
686}
687
Jamie Madille92a3542014-07-03 10:38:58 -0400688FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
689{
690 switch (attachment)
691 {
Jamie Madill6d708262014-09-03 15:07:13 -0400692 case GL_COLOR:
Jamie Madille92a3542014-07-03 10:38:58 -0400693 case GL_BACK:
694 return getColorbuffer(0);
695 case GL_DEPTH:
696 return getDepthbuffer();
697 case GL_STENCIL:
698 return getStencilbuffer();
699 case GL_DEPTH_STENCIL:
700 return getDepthStencilBuffer();
701 default:
702 UNREACHABLE();
703 return NULL;
704 }
705}
706
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000707}