blob: 32a2fdaf75f2a6ff9e3e2ffe82876ff24aca55e1 [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
Geoff Lang164d54e2014-12-01 10:55:33 -0500269void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000270{
Geoff Lang68439852014-12-04 14:40:16 -0500271 ASSERT(count <= ArraySize(mDrawBufferStates));
Geoff Lang164d54e2014-12-01 10:55:33 -0500272 std::copy(buffers, buffers + count, mDrawBufferStates);
273 std::fill(mDrawBufferStates + count, mDrawBufferStates + ArraySize(mDrawBufferStates), GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000274}
275
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000276bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
277{
Jamie Madille261b442014-06-25 12:42:21 -0400278 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000279}
280
281bool Framebuffer::hasEnabledColorAttachment() const
282{
283 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
284 {
285 if (isEnabledColorAttachment(colorAttachment))
286 {
287 return true;
288 }
289 }
290
291 return false;
292}
293
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000294bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000295{
Geoff Lange4a492b2014-06-19 14:14:41 -0400296 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000297}
298
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000299bool Framebuffer::usingExtendedDrawBuffers() const
300{
301 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
302 {
303 if (isEnabledColorAttachment(colorAttachment))
304 {
305 return true;
306 }
307 }
308
309 return false;
310}
311
Jamie Madill48faf802014-11-06 15:27:22 -0500312GLenum Framebuffer::completeness(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500314 // The default framebuffer *must* always be complete, though it may not be
315 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
316 if (mId == 0)
317 {
318 return GL_FRAMEBUFFER_COMPLETE;
319 }
320
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321 int width = 0;
322 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000323 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000324 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000325 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000327 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400329 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
330
331 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000333 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000334 {
335 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
336 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000337
Geoff Langcec35902014-04-16 10:52:36 -0400338 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500339 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400340 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500341 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000342 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400343 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000344 {
345 return GL_FRAMEBUFFER_UNSUPPORTED;
346 }
347
Geoff Lang5d601382014-07-22 15:14:06 -0400348 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000349 {
350 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
351 }
352 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500353 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000354 {
Geoff Lang5d601382014-07-22 15:14:06 -0400355 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400356 {
357 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
358 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000359 }
360
361 if (!missingAttachment)
362 {
363 // all color attachments must have the same width and height
364 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
365 {
366 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
367 }
368
369 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
370 // all color attachments have the same number of samples for the FBO to be complete.
371 if (colorbuffer->getSamples() != samples)
372 {
373 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
374 }
375
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000376 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
377 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500378 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000379 {
Geoff Lang5d601382014-07-22 15:14:06 -0400380 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000381 {
382 return GL_FRAMEBUFFER_UNSUPPORTED;
383 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000384 }
385
386 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
387 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
388 {
Jamie Madille92a3542014-07-03 10:38:58 -0400389 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
390
391 if (previousAttachment &&
392 (colorbuffer->id() == previousAttachment->id() &&
393 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000394 {
395 return GL_FRAMEBUFFER_UNSUPPORTED;
396 }
397 }
398 }
399 else
400 {
401 width = colorbuffer->getWidth();
402 height = colorbuffer->getHeight();
403 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400404 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000405 missingAttachment = false;
406 }
407 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000408 }
409
Jamie Madille261b442014-06-25 12:42:21 -0400410 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000411 {
Jamie Madille261b442014-06-25 12:42:21 -0400412 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000414 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415 }
416
Jamie Madille261b442014-06-25 12:42:21 -0400417 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500418 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400419 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500420 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000421 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000422 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500423 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000424 {
425 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
426 }
427
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400428 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400429 {
430 return GL_FRAMEBUFFER_UNSUPPORTED;
431 }
432
Geoff Lang5d601382014-07-22 15:14:06 -0400433 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000434 {
435 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
436 }
437 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500438 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000439 {
Geoff Lang5d601382014-07-22 15:14:06 -0400440 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400441 {
442 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
443 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000444 }
445
446 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000447 {
Jamie Madille261b442014-06-25 12:42:21 -0400448 width = mDepthbuffer->getWidth();
449 height = mDepthbuffer->getHeight();
450 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000451 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000452 }
Jamie Madille261b442014-06-25 12:42:21 -0400453 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000454 {
455 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
456 }
Jamie Madille261b442014-06-25 12:42:21 -0400457 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000458 {
459 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
460 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000461 }
462
Jamie Madille261b442014-06-25 12:42:21 -0400463 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000464 {
Jamie Madille261b442014-06-25 12:42:21 -0400465 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000466 {
467 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
468 }
469
Jamie Madille261b442014-06-25 12:42:21 -0400470 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500471 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400472 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500473 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000474 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000475 // texture stencil attachments come along as part
476 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500477 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000478 {
479 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
480 }
481
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400482 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400483 {
484 return GL_FRAMEBUFFER_UNSUPPORTED;
485 }
486
Geoff Lang5d601382014-07-22 15:14:06 -0400487 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000488 {
489 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
490 }
491 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500492 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000493 {
Geoff Lang5d601382014-07-22 15:14:06 -0400494 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400495 {
496 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
497 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000498 }
499
500 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000501 {
Jamie Madille261b442014-06-25 12:42:21 -0400502 width = mStencilbuffer->getWidth();
503 height = mStencilbuffer->getHeight();
504 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000505 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000506 }
Jamie Madille261b442014-06-25 12:42:21 -0400507 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000508 {
509 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
510 }
Jamie Madille261b442014-06-25 12:42:21 -0400511 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000512 {
513 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
514 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000515 }
516
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000517 // if we have both a depth and stencil buffer, they must refer to the same object
518 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400519 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000520 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000521 return GL_FRAMEBUFFER_UNSUPPORTED;
522 }
523
524 // we need to have at least one attachment to be complete
525 if (missingAttachment)
526 {
527 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000528 }
529
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530 return GL_FRAMEBUFFER_COMPLETE;
531}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000532
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500533Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400534{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500535 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400536}
537
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500538Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400539{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500540 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400541}
542
Jamie Madill48faf802014-11-06 15:27:22 -0500543int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000544{
Jamie Madill48faf802014-11-06 15:27:22 -0500545 if (completeness(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000546 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000547 // for a complete framebuffer, all attachments must have the same sample count
548 // in this case return the first nonzero sample size
549 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
550 {
Jamie Madille261b442014-06-25 12:42:21 -0400551 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000552 {
Jamie Madille261b442014-06-25 12:42:21 -0400553 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000554 }
555 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000556 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000557
558 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000559}
560
Jamie Madille261b442014-06-25 12:42:21 -0400561bool Framebuffer::hasValidDepthStencil() const
562{
563 // A valid depth-stencil attachment has the same resource bound to both the
564 // depth and stencil attachment points.
565 return (mDepthbuffer && mStencilbuffer &&
566 mDepthbuffer->type() == mStencilbuffer->type() &&
567 mDepthbuffer->id() == mStencilbuffer->id());
568}
569
Jamie Madill48faf802014-11-06 15:27:22 -0500570ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400571{
572 ColorbufferInfo colorbuffersForRender;
573
574 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
575 {
576 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
577 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
578
579 if (colorbuffer != NULL && drawBufferState != GL_NONE)
580 {
581 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
582 colorbuffersForRender.push_back(colorbuffer);
583 }
Jamie Madill48faf802014-11-06 15:27:22 -0500584 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400585 {
586 colorbuffersForRender.push_back(NULL);
587 }
588 }
589
590 return colorbuffersForRender;
591}
592
Geoff Langab75a052014-10-15 12:56:37 -0400593void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
594{
595 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
596}
597
598void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
599{
600 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
601}
602
603void Framebuffer::setNULLAttachment(GLenum attachment)
604{
605 setAttachment(attachment, NULL);
606}
607
608void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
609{
610 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
611 {
612 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
613 SafeDelete(mColorbuffers[colorAttachment]);
614 mColorbuffers[colorAttachment] = attachmentObj;
615 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500616 else if (attachment == GL_BACK)
617 {
618 SafeDelete(mColorbuffers[0]);
619 mColorbuffers[0] = attachmentObj;
620 }
621 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400622 {
623 SafeDelete(mDepthbuffer);
624 mDepthbuffer = attachmentObj;
625 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500626 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400627 {
628 SafeDelete(mStencilbuffer);
629 mStencilbuffer = attachmentObj;
630 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500631 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400632 {
633 SafeDelete(mDepthbuffer);
634 SafeDelete(mStencilbuffer);
635
636 // ensure this is a legitimate depth+stencil format
637 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
638 {
639 mDepthbuffer = attachmentObj;
640
641 // Make a new attachment object to ensure we do not double-delete
642 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500643 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400644 {
645 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
646 *attachmentObj->getTextureImageIndex());
647 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500648 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400649 {
650 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
651 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500652 else
653 {
654 UNREACHABLE();
655 }
Geoff Langab75a052014-10-15 12:56:37 -0400656 }
657 }
658 else
659 {
660 UNREACHABLE();
661 }
662}
663
Geoff Lang528ce3c2014-12-01 10:44:07 -0500664DefaultFramebuffer::DefaultFramebuffer(rx::FramebufferImpl *impl, rx::DefaultAttachmentImpl *colorAttachment,
665 rx::DefaultAttachmentImpl *depthAttachment, rx::DefaultAttachmentImpl *stencilAttachment)
666 : Framebuffer(impl, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000667{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500668 ASSERT(colorAttachment);
669 setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, colorAttachment));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000670
Geoff Lang528ce3c2014-12-01 10:44:07 -0500671 if (depthAttachment)
Jamie Madille92a3542014-07-03 10:38:58 -0400672 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500673 setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, depthAttachment));
Jamie Madille92a3542014-07-03 10:38:58 -0400674 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500675 if (stencilAttachment)
676 {
677 setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, stencilAttachment));
678 }
679
680 mDrawBufferStates[0] = GL_BACK;
681 mReadBufferState = GL_BACK;
Jamie Madille92a3542014-07-03 10:38:58 -0400682}
683
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000684}