blob: 54b6c4b289c3ee8be268e59cde43af3cda1e0487 [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
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/Framebuffer.h"
11#include "libANGLE/formatutils.h"
12#include "libANGLE/Texture.h"
13#include "libANGLE/Context.h"
14#include "libANGLE/Renderbuffer.h"
15#include "libANGLE/FramebufferAttachment.h"
16#include "libANGLE/renderer/Renderer.h"
17#include "libANGLE/renderer/RenderTarget.h"
18#include "libANGLE/renderer/RenderbufferImpl.h"
19#include "libANGLE/renderer/Workarounds.h"
20#include "libANGLE/renderer/d3d/TextureD3D.h"
21#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
22#include "libANGLE/renderer/d3d/FramebufferD3D.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040023
24#include "common/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025
Jamie Madill9f0b42a2014-09-12 10:25:27 -040026namespace rx
27{
Shannon Woodse2632d22014-10-17 13:08:51 -040028// TODO: Move these functions, and the D3D-specific header inclusions above,
29// to FramebufferD3D.
Geoff Lang4f4207f2014-12-01 10:07:56 -050030gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget **outRT)
Jamie Madill9f0b42a2014-09-12 10:25:27 -040031{
Geoff Lang6a1e6b92014-11-06 10:42:45 -050032 if (attachment->type() == GL_TEXTURE)
Jamie Madill9f0b42a2014-09-12 10:25:27 -040033 {
34 gl::Texture *texture = attachment->getTexture();
35 ASSERT(texture);
36 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
Jamie Madillac7579c2014-09-17 16:59:33 -040037 const gl::ImageIndex *index = attachment->getTextureImageIndex();
38 ASSERT(index);
Geoff Lang64f23f62014-09-10 14:40:12 -040039 return textureD3D->getRenderTarget(*index, outRT);
Jamie Madill9f0b42a2014-09-12 10:25:27 -040040 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -050041 else if (attachment->type() == GL_RENDERBUFFER)
Geoff Lang64f23f62014-09-10 14:40:12 -040042 {
43 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
44 ASSERT(renderbuffer);
Shannon Woodse2632d22014-10-17 13:08:51 -040045 RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
46 *outRT = renderbufferD3D->getRenderTarget();
Geoff Lang64f23f62014-09-10 14:40:12 -040047 return gl::Error(GL_NO_ERROR);
48 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -050049 else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
50 {
Geoff Lang4f4207f2014-12-01 10:07:56 -050051 const gl::DefaultAttachment *defaultAttachment = static_cast<const gl::DefaultAttachment *>(attachment);
Geoff Lang6a1e6b92014-11-06 10:42:45 -050052 DefaultAttachmentD3D *defaultAttachmentD3D = DefaultAttachmentD3D::makeDefaultAttachmentD3D(defaultAttachment->getImplementation());
53 ASSERT(defaultAttachmentD3D);
54
55 *outRT = defaultAttachmentD3D->getRenderTarget();
56 return gl::Error(GL_NO_ERROR);
57 }
58 else
59 {
60 UNREACHABLE();
61 return gl::Error(GL_INVALID_OPERATION);
62 }
Jamie Madill9f0b42a2014-09-12 10:25:27 -040063}
64
Jamie Madill612e2e42014-09-12 13:26:55 -040065// Note: RenderTarget serials should ideally be in the RenderTargets themselves.
Geoff Lang4f4207f2014-12-01 10:07:56 -050066unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment)
Jamie Madill612e2e42014-09-12 13:26:55 -040067{
Geoff Lang6a1e6b92014-11-06 10:42:45 -050068 if (attachment->type() == GL_TEXTURE)
Jamie Madill612e2e42014-09-12 13:26:55 -040069 {
70 gl::Texture *texture = attachment->getTexture();
71 ASSERT(texture);
72 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
Jamie Madillac7579c2014-09-17 16:59:33 -040073 const gl::ImageIndex *index = attachment->getTextureImageIndex();
74 ASSERT(index);
75 return textureD3D->getRenderTargetSerial(*index);
Jamie Madill612e2e42014-09-12 13:26:55 -040076 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -050077 else if (attachment->type() == GL_RENDERBUFFER)
78 {
79 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
80 ASSERT(renderbuffer);
81 RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
82 return renderbufferD3D->getRenderTargetSerial();
83 }
84 else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
85 {
Geoff Lang4f4207f2014-12-01 10:07:56 -050086 const gl::DefaultAttachment *defaultAttachment = static_cast<const gl::DefaultAttachment *>(attachment);
Geoff Lang6a1e6b92014-11-06 10:42:45 -050087 DefaultAttachmentD3D *defaultAttachmentD3D = DefaultAttachmentD3D::makeDefaultAttachmentD3D(defaultAttachment->getImplementation());
88 ASSERT(defaultAttachmentD3D);
89 return defaultAttachmentD3D->getRenderTarget()->getSerial();
90 }
91 else
92 {
93 UNREACHABLE();
94 return 0;
95 }
Jamie Madill612e2e42014-09-12 13:26:55 -040096}
97
Jamie Madill9f0b42a2014-09-12 10:25:27 -040098}
99
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100namespace gl
101{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000102
Geoff Langda88add2014-12-01 10:22:01 -0500103Framebuffer::Framebuffer(rx::FramebufferImpl *impl, GLuint id)
104 : mImpl(impl),
105 mId(id),
Jamie Madille261b442014-06-25 12:42:21 -0400106 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
107 mDepthbuffer(NULL),
108 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109{
Geoff Langda88add2014-12-01 10:22:01 -0500110 ASSERT(mImpl != nullptr);
111
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000112 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
113 {
Jamie Madille261b442014-06-25 12:42:21 -0400114 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000115 mDrawBufferStates[colorAttachment] = GL_NONE;
116 }
117 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000118}
119
120Framebuffer::~Framebuffer()
121{
Geoff Langda88add2014-12-01 10:22:01 -0500122 SafeDelete(mImpl);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000123 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
124 {
Jamie Madille261b442014-06-25 12:42:21 -0400125 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000126 }
Jamie Madille261b442014-06-25 12:42:21 -0400127 SafeDelete(mDepthbuffer);
128 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000129}
130
Jamie Madille261b442014-06-25 12:42:21 -0400131void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000132{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000133 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000134 {
Jamie Madille261b442014-06-25 12:42:21 -0400135 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
136
137 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000138 {
Jamie Madille261b442014-06-25 12:42:21 -0400139 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000140 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000142
Jamie Madille261b442014-06-25 12:42:21 -0400143 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000144 {
Jamie Madille261b442014-06-25 12:42:21 -0400145 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000146 }
147
Jamie Madille261b442014-06-25 12:42:21 -0400148 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000149 {
Jamie Madille261b442014-06-25 12:42:21 -0400150 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000151 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152}
153
Jamie Madille261b442014-06-25 12:42:21 -0400154void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000155{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000156 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157 {
Jamie Madille261b442014-06-25 12:42:21 -0400158 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
159
160 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000161 {
Jamie Madille261b442014-06-25 12:42:21 -0400162 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000163 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 }
165
Jamie Madille261b442014-06-25 12:42:21 -0400166 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167 {
Jamie Madille261b442014-06-25 12:42:21 -0400168 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169 }
170
Jamie Madille261b442014-06-25 12:42:21 -0400171 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000172 {
Jamie Madille261b442014-06-25 12:42:21 -0400173 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174 }
175}
176
Jamie Madill3c7fa222014-06-05 13:08:51 -0400177FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000178{
179 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400180 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000181}
182
Jamie Madill3c7fa222014-06-05 13:08:51 -0400183FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184{
Jamie Madille261b442014-06-25 12:42:21 -0400185 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186}
187
Jamie Madill3c7fa222014-06-05 13:08:51 -0400188FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189{
Jamie Madille261b442014-06-25 12:42:21 -0400190 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191}
192
Jamie Madill3c7fa222014-06-05 13:08:51 -0400193FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400194{
Jamie Madille261b442014-06-25 12:42:21 -0400195 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400196}
197
Jamie Madill3c7fa222014-06-05 13:08:51 -0400198FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000199{
Jamie Madille261b442014-06-25 12:42:21 -0400200 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000201
202 if (!depthstencilbuffer)
203 {
Jamie Madille261b442014-06-25 12:42:21 -0400204 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000205 }
206
207 return depthstencilbuffer;
208}
209
Jamie Madill3c7fa222014-06-05 13:08:51 -0400210FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000211{
212 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400213 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000214}
215
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000216GLenum Framebuffer::getReadColorbufferType() const
217{
218 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400219 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000220}
221
Jamie Madill3c7fa222014-06-05 13:08:51 -0400222FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000223{
224 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
225 {
Jamie Madille261b442014-06-25 12:42:21 -0400226 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000227 {
Jamie Madille261b442014-06-25 12:42:21 -0400228 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000229 }
230 }
231
232 return NULL;
233}
234
Jamie Madille92a3542014-07-03 10:38:58 -0400235FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000236{
Jamie Madille92a3542014-07-03 10:38:58 -0400237 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
238 {
239 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
240 }
241 else
242 {
243 switch (attachment)
244 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500245 case GL_COLOR:
246 case GL_BACK:
247 return getColorbuffer(0);
248 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400249 case GL_DEPTH_ATTACHMENT:
250 return getDepthbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500251 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400252 case GL_STENCIL_ATTACHMENT:
253 return getStencilbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500254 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400255 case GL_DEPTH_STENCIL_ATTACHMENT:
256 return getDepthStencilBuffer();
257 default:
258 UNREACHABLE();
259 return NULL;
260 }
261 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400262}
263
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000264GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
265{
266 return mDrawBufferStates[colorAttachment];
267}
268
269void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
270{
271 mDrawBufferStates[colorAttachment] = drawBuffer;
272}
273
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000274bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
275{
Jamie Madille261b442014-06-25 12:42:21 -0400276 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000277}
278
279bool Framebuffer::hasEnabledColorAttachment() const
280{
281 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
282 {
283 if (isEnabledColorAttachment(colorAttachment))
284 {
285 return true;
286 }
287 }
288
289 return false;
290}
291
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000292bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000293{
Geoff Lange4a492b2014-06-19 14:14:41 -0400294 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000295}
296
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000297bool Framebuffer::usingExtendedDrawBuffers() const
298{
299 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
300 {
301 if (isEnabledColorAttachment(colorAttachment))
302 {
303 return true;
304 }
305 }
306
307 return false;
308}
309
Jamie Madill48faf802014-11-06 15:27:22 -0500310GLenum Framebuffer::completeness(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500312 // The default framebuffer *must* always be complete, though it may not be
313 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
314 if (mId == 0)
315 {
316 return GL_FRAMEBUFFER_COMPLETE;
317 }
318
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319 int width = 0;
320 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000321 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000322 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000323 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000324
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000325 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400327 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
328
329 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000331 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000332 {
333 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
334 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000335
Geoff Langcec35902014-04-16 10:52:36 -0400336 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500337 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400338 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500339 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000340 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400341 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000342 {
343 return GL_FRAMEBUFFER_UNSUPPORTED;
344 }
345
Geoff Lang5d601382014-07-22 15:14:06 -0400346 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000347 {
348 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
349 }
350 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500351 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000352 {
Geoff Lang5d601382014-07-22 15:14:06 -0400353 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400354 {
355 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
356 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000357 }
358
359 if (!missingAttachment)
360 {
361 // all color attachments must have the same width and height
362 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
363 {
364 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
365 }
366
367 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
368 // all color attachments have the same number of samples for the FBO to be complete.
369 if (colorbuffer->getSamples() != samples)
370 {
371 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
372 }
373
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000374 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
375 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500376 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000377 {
Geoff Lang5d601382014-07-22 15:14:06 -0400378 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000379 {
380 return GL_FRAMEBUFFER_UNSUPPORTED;
381 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000382 }
383
384 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
385 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
386 {
Jamie Madille92a3542014-07-03 10:38:58 -0400387 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
388
389 if (previousAttachment &&
390 (colorbuffer->id() == previousAttachment->id() &&
391 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000392 {
393 return GL_FRAMEBUFFER_UNSUPPORTED;
394 }
395 }
396 }
397 else
398 {
399 width = colorbuffer->getWidth();
400 height = colorbuffer->getHeight();
401 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400402 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000403 missingAttachment = false;
404 }
405 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000406 }
407
Jamie Madille261b442014-06-25 12:42:21 -0400408 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000409 {
Jamie Madille261b442014-06-25 12:42:21 -0400410 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000412 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 }
414
Jamie Madille261b442014-06-25 12:42:21 -0400415 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500416 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400417 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500418 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000419 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000420 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500421 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000422 {
423 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
424 }
425
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400426 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400427 {
428 return GL_FRAMEBUFFER_UNSUPPORTED;
429 }
430
Geoff Lang5d601382014-07-22 15:14:06 -0400431 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000432 {
433 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
434 }
435 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500436 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000437 {
Geoff Lang5d601382014-07-22 15:14:06 -0400438 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400439 {
440 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
441 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000442 }
443
444 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000445 {
Jamie Madille261b442014-06-25 12:42:21 -0400446 width = mDepthbuffer->getWidth();
447 height = mDepthbuffer->getHeight();
448 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000449 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000450 }
Jamie Madille261b442014-06-25 12:42:21 -0400451 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000452 {
453 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
454 }
Jamie Madille261b442014-06-25 12:42:21 -0400455 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000456 {
457 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
458 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000459 }
460
Jamie Madille261b442014-06-25 12:42:21 -0400461 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000462 {
Jamie Madille261b442014-06-25 12:42:21 -0400463 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000464 {
465 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
466 }
467
Jamie Madille261b442014-06-25 12:42:21 -0400468 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500469 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400470 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500471 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000472 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000473 // texture stencil attachments come along as part
474 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500475 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000476 {
477 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
478 }
479
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400480 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400481 {
482 return GL_FRAMEBUFFER_UNSUPPORTED;
483 }
484
Geoff Lang5d601382014-07-22 15:14:06 -0400485 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000486 {
487 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
488 }
489 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500490 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000491 {
Geoff Lang5d601382014-07-22 15:14:06 -0400492 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400493 {
494 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
495 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000496 }
497
498 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000499 {
Jamie Madille261b442014-06-25 12:42:21 -0400500 width = mStencilbuffer->getWidth();
501 height = mStencilbuffer->getHeight();
502 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000503 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000504 }
Jamie Madille261b442014-06-25 12:42:21 -0400505 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000506 {
507 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
508 }
Jamie Madille261b442014-06-25 12:42:21 -0400509 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000510 {
511 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
512 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000513 }
514
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000515 // if we have both a depth and stencil buffer, they must refer to the same object
516 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400517 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000518 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000519 return GL_FRAMEBUFFER_UNSUPPORTED;
520 }
521
522 // we need to have at least one attachment to be complete
523 if (missingAttachment)
524 {
525 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000526 }
527
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000528 return GL_FRAMEBUFFER_COMPLETE;
529}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000530
Geoff Lang64f23f62014-09-10 14:40:12 -0400531Error Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400532{
533 GLuint maxDimension = caps.maxRenderbufferSize;
Geoff Lang64f23f62014-09-10 14:40:12 -0400534 return invalidateSub(numAttachments, attachments, 0, 0, maxDimension, maxDimension);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400535}
536
Geoff Lang64f23f62014-09-10 14:40:12 -0400537Error Framebuffer::invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400538{
Jamie Madill6d708262014-09-03 15:07:13 -0400539 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400540 {
Jamie Madill6d708262014-09-03 15:07:13 -0400541 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400542
Geoff Lang64f23f62014-09-10 14:40:12 -0400543 FramebufferAttachment *attachment = (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer()
544 : getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400545
Jamie Madill6d708262014-09-03 15:07:13 -0400546 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400547 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400548 rx::RenderTarget *renderTarget = NULL;
549 Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget);
550 if (error.isError())
Jamie Madill6d708262014-09-03 15:07:13 -0400551 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400552 return error;
Jamie Madill6d708262014-09-03 15:07:13 -0400553 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400554
555 renderTarget->invalidate(x, y, width, height);
Jamie Madill400a4412014-08-29 15:46:45 -0400556 }
557 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400558
559 return Error(GL_NO_ERROR);
Jamie Madill400a4412014-08-29 15:46:45 -0400560}
561
Jamie Madill48faf802014-11-06 15:27:22 -0500562int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000563{
Jamie Madill48faf802014-11-06 15:27:22 -0500564 if (completeness(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000565 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000566 // for a complete framebuffer, all attachments must have the same sample count
567 // in this case return the first nonzero sample size
568 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
569 {
Jamie Madille261b442014-06-25 12:42:21 -0400570 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000571 {
Jamie Madille261b442014-06-25 12:42:21 -0400572 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000573 }
574 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000575 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000576
577 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000578}
579
Jamie Madille261b442014-06-25 12:42:21 -0400580bool Framebuffer::hasValidDepthStencil() const
581{
582 // A valid depth-stencil attachment has the same resource bound to both the
583 // depth and stencil attachment points.
584 return (mDepthbuffer && mStencilbuffer &&
585 mDepthbuffer->type() == mStencilbuffer->type() &&
586 mDepthbuffer->id() == mStencilbuffer->id());
587}
588
Jamie Madill48faf802014-11-06 15:27:22 -0500589ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400590{
591 ColorbufferInfo colorbuffersForRender;
592
593 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
594 {
595 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
596 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
597
598 if (colorbuffer != NULL && drawBufferState != GL_NONE)
599 {
600 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
601 colorbuffersForRender.push_back(colorbuffer);
602 }
Jamie Madill48faf802014-11-06 15:27:22 -0500603 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400604 {
605 colorbuffersForRender.push_back(NULL);
606 }
607 }
608
609 return colorbuffersForRender;
610}
611
Geoff Langab75a052014-10-15 12:56:37 -0400612void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
613{
614 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
615}
616
617void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
618{
619 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
620}
621
622void Framebuffer::setNULLAttachment(GLenum attachment)
623{
624 setAttachment(attachment, NULL);
625}
626
627void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
628{
629 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
630 {
631 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
632 SafeDelete(mColorbuffers[colorAttachment]);
633 mColorbuffers[colorAttachment] = attachmentObj;
634 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500635 else if (attachment == GL_BACK)
636 {
637 SafeDelete(mColorbuffers[0]);
638 mColorbuffers[0] = attachmentObj;
639 }
640 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400641 {
642 SafeDelete(mDepthbuffer);
643 mDepthbuffer = attachmentObj;
644 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500645 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400646 {
647 SafeDelete(mStencilbuffer);
648 mStencilbuffer = attachmentObj;
649 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500650 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400651 {
652 SafeDelete(mDepthbuffer);
653 SafeDelete(mStencilbuffer);
654
655 // ensure this is a legitimate depth+stencil format
656 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
657 {
658 mDepthbuffer = attachmentObj;
659
660 // Make a new attachment object to ensure we do not double-delete
661 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500662 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400663 {
664 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
665 *attachmentObj->getTextureImageIndex());
666 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500667 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400668 {
669 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
670 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500671 else
672 {
673 UNREACHABLE();
674 }
Geoff Langab75a052014-10-15 12:56:37 -0400675 }
676 }
677 else
678 {
679 UNREACHABLE();
680 }
681}
682
Geoff Lang528ce3c2014-12-01 10:44:07 -0500683DefaultFramebuffer::DefaultFramebuffer(rx::FramebufferImpl *impl, rx::DefaultAttachmentImpl *colorAttachment,
684 rx::DefaultAttachmentImpl *depthAttachment, rx::DefaultAttachmentImpl *stencilAttachment)
685 : Framebuffer(impl, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000686{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500687 ASSERT(colorAttachment);
688 setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, colorAttachment));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000689
Geoff Lang528ce3c2014-12-01 10:44:07 -0500690 if (depthAttachment)
Jamie Madille92a3542014-07-03 10:38:58 -0400691 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500692 setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, depthAttachment));
Jamie Madille92a3542014-07-03 10:38:58 -0400693 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500694 if (stencilAttachment)
695 {
696 setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, stencilAttachment));
697 }
698
699 mDrawBufferStates[0] = GL_BACK;
700 mReadBufferState = GL_BACK;
Jamie Madille92a3542014-07-03 10:38:58 -0400701}
702
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000703}