blob: b20444b3f0cb04ff49d95d7873a83b36087a25cf [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 {
245 case GL_DEPTH_ATTACHMENT:
246 return getDepthbuffer();
247 case GL_STENCIL_ATTACHMENT:
248 return getStencilbuffer();
249 case GL_DEPTH_STENCIL_ATTACHMENT:
250 return getDepthStencilBuffer();
251 default:
252 UNREACHABLE();
253 return NULL;
254 }
255 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400256}
257
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000258GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
259{
260 return mDrawBufferStates[colorAttachment];
261}
262
263void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
264{
265 mDrawBufferStates[colorAttachment] = drawBuffer;
266}
267
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000268bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
269{
Jamie Madille261b442014-06-25 12:42:21 -0400270 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000271}
272
273bool Framebuffer::hasEnabledColorAttachment() const
274{
275 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
276 {
277 if (isEnabledColorAttachment(colorAttachment))
278 {
279 return true;
280 }
281 }
282
283 return false;
284}
285
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000286bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000287{
Geoff Lange4a492b2014-06-19 14:14:41 -0400288 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000289}
290
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000291bool Framebuffer::usingExtendedDrawBuffers() const
292{
293 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
294 {
295 if (isEnabledColorAttachment(colorAttachment))
296 {
297 return true;
298 }
299 }
300
301 return false;
302}
303
Jamie Madill48faf802014-11-06 15:27:22 -0500304GLenum Framebuffer::completeness(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000306 int width = 0;
307 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000308 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000309 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000310 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000312 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400314 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
315
316 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000318 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000319 {
320 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
321 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000322
Geoff Langcec35902014-04-16 10:52:36 -0400323 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500324 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400325 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500326 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000327 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400328 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000329 {
330 return GL_FRAMEBUFFER_UNSUPPORTED;
331 }
332
Geoff Lang5d601382014-07-22 15:14:06 -0400333 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000334 {
335 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
336 }
337 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500338 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000339 {
Geoff Lang5d601382014-07-22 15:14:06 -0400340 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400341 {
342 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
343 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000344 }
345
346 if (!missingAttachment)
347 {
348 // all color attachments must have the same width and height
349 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
350 {
351 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
352 }
353
354 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
355 // all color attachments have the same number of samples for the FBO to be complete.
356 if (colorbuffer->getSamples() != samples)
357 {
358 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
359 }
360
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000361 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
362 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500363 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000364 {
Geoff Lang5d601382014-07-22 15:14:06 -0400365 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000366 {
367 return GL_FRAMEBUFFER_UNSUPPORTED;
368 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000369 }
370
371 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
372 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
373 {
Jamie Madille92a3542014-07-03 10:38:58 -0400374 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
375
376 if (previousAttachment &&
377 (colorbuffer->id() == previousAttachment->id() &&
378 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000379 {
380 return GL_FRAMEBUFFER_UNSUPPORTED;
381 }
382 }
383 }
384 else
385 {
386 width = colorbuffer->getWidth();
387 height = colorbuffer->getHeight();
388 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400389 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000390 missingAttachment = false;
391 }
392 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000393 }
394
Jamie Madille261b442014-06-25 12:42:21 -0400395 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000396 {
Jamie Madille261b442014-06-25 12:42:21 -0400397 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000398 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000399 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400 }
401
Jamie Madille261b442014-06-25 12:42:21 -0400402 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500403 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400404 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500405 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000406 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000407 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500408 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000409 {
410 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
411 }
412
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400413 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400414 {
415 return GL_FRAMEBUFFER_UNSUPPORTED;
416 }
417
Geoff Lang5d601382014-07-22 15:14:06 -0400418 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000419 {
420 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
421 }
422 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500423 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000424 {
Geoff Lang5d601382014-07-22 15:14:06 -0400425 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400426 {
427 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
428 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000429 }
430
431 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000432 {
Jamie Madille261b442014-06-25 12:42:21 -0400433 width = mDepthbuffer->getWidth();
434 height = mDepthbuffer->getHeight();
435 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000436 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000437 }
Jamie Madille261b442014-06-25 12:42:21 -0400438 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000439 {
440 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
441 }
Jamie Madille261b442014-06-25 12:42:21 -0400442 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000443 {
444 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
445 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000446 }
447
Jamie Madille261b442014-06-25 12:42:21 -0400448 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000449 {
Jamie Madille261b442014-06-25 12:42:21 -0400450 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000451 {
452 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
453 }
454
Jamie Madille261b442014-06-25 12:42:21 -0400455 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500456 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400457 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500458 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000459 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000460 // texture stencil attachments come along as part
461 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500462 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000463 {
464 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
465 }
466
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400467 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400468 {
469 return GL_FRAMEBUFFER_UNSUPPORTED;
470 }
471
Geoff Lang5d601382014-07-22 15:14:06 -0400472 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000473 {
474 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
475 }
476 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500477 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000478 {
Geoff Lang5d601382014-07-22 15:14:06 -0400479 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400480 {
481 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
482 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000483 }
484
485 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000486 {
Jamie Madille261b442014-06-25 12:42:21 -0400487 width = mStencilbuffer->getWidth();
488 height = mStencilbuffer->getHeight();
489 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000490 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000491 }
Jamie Madille261b442014-06-25 12:42:21 -0400492 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000493 {
494 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
495 }
Jamie Madille261b442014-06-25 12:42:21 -0400496 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000497 {
498 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
499 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000500 }
501
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000502 // if we have both a depth and stencil buffer, they must refer to the same object
503 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400504 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000505 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000506 return GL_FRAMEBUFFER_UNSUPPORTED;
507 }
508
509 // we need to have at least one attachment to be complete
510 if (missingAttachment)
511 {
512 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000513 }
514
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515 return GL_FRAMEBUFFER_COMPLETE;
516}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000517
Geoff Lang64f23f62014-09-10 14:40:12 -0400518Error Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400519{
520 GLuint maxDimension = caps.maxRenderbufferSize;
Geoff Lang64f23f62014-09-10 14:40:12 -0400521 return invalidateSub(numAttachments, attachments, 0, 0, maxDimension, maxDimension);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400522}
523
Geoff Lang64f23f62014-09-10 14:40:12 -0400524Error Framebuffer::invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400525{
Jamie Madill6d708262014-09-03 15:07:13 -0400526 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400527 {
Jamie Madill6d708262014-09-03 15:07:13 -0400528 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400529
Geoff Lang64f23f62014-09-10 14:40:12 -0400530 FramebufferAttachment *attachment = (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer()
531 : getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400532
Jamie Madill6d708262014-09-03 15:07:13 -0400533 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400534 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400535 rx::RenderTarget *renderTarget = NULL;
536 Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget);
537 if (error.isError())
Jamie Madill6d708262014-09-03 15:07:13 -0400538 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400539 return error;
Jamie Madill6d708262014-09-03 15:07:13 -0400540 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400541
542 renderTarget->invalidate(x, y, width, height);
Jamie Madill400a4412014-08-29 15:46:45 -0400543 }
544 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400545
546 return Error(GL_NO_ERROR);
Jamie Madill400a4412014-08-29 15:46:45 -0400547}
548
Geoff Langda88add2014-12-01 10:22:01 -0500549DefaultFramebuffer::DefaultFramebuffer(rx::FramebufferImpl *impl, rx::DefaultAttachmentImpl *colorAttachment,
550 rx::DefaultAttachmentImpl *depthAttachment, rx::DefaultAttachmentImpl *stencilAttachment)
551 : Framebuffer(impl, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000552{
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500553 ASSERT(colorAttachment);
554 mColorbuffers[0] = new DefaultAttachment(GL_BACK, colorAttachment);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000555
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500556 if (depthAttachment)
Austin Kinross44f4d742014-11-11 13:37:00 -0800557 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500558 mDepthbuffer = new DefaultAttachment(GL_DEPTH, depthAttachment);
559 }
560 if (stencilAttachment)
561 {
562 mStencilbuffer = new DefaultAttachment(GL_STENCIL, stencilAttachment);
Austin Kinross44f4d742014-11-11 13:37:00 -0800563 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000564
565 mDrawBufferStates[0] = GL_BACK;
566 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000567}
568
Jamie Madill48faf802014-11-06 15:27:22 -0500569int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000570{
Jamie Madill48faf802014-11-06 15:27:22 -0500571 if (completeness(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000572 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000573 // for a complete framebuffer, all attachments must have the same sample count
574 // in this case return the first nonzero sample size
575 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
576 {
Jamie Madille261b442014-06-25 12:42:21 -0400577 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000578 {
Jamie Madille261b442014-06-25 12:42:21 -0400579 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000580 }
581 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000582 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000583
584 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000585}
586
Jamie Madille261b442014-06-25 12:42:21 -0400587bool Framebuffer::hasValidDepthStencil() const
588{
589 // A valid depth-stencil attachment has the same resource bound to both the
590 // depth and stencil attachment points.
591 return (mDepthbuffer && mStencilbuffer &&
592 mDepthbuffer->type() == mStencilbuffer->type() &&
593 mDepthbuffer->id() == mStencilbuffer->id());
594}
595
Jamie Madill48faf802014-11-06 15:27:22 -0500596ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400597{
598 ColorbufferInfo colorbuffersForRender;
599
600 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
601 {
602 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
603 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
604
605 if (colorbuffer != NULL && drawBufferState != GL_NONE)
606 {
607 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
608 colorbuffersForRender.push_back(colorbuffer);
609 }
Jamie Madill48faf802014-11-06 15:27:22 -0500610 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400611 {
612 colorbuffersForRender.push_back(NULL);
613 }
614 }
615
616 return colorbuffersForRender;
617}
618
Geoff Langab75a052014-10-15 12:56:37 -0400619void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
620{
621 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
622}
623
624void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
625{
626 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
627}
628
629void Framebuffer::setNULLAttachment(GLenum attachment)
630{
631 setAttachment(attachment, NULL);
632}
633
634void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
635{
636 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
637 {
638 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
639 SafeDelete(mColorbuffers[colorAttachment]);
640 mColorbuffers[colorAttachment] = attachmentObj;
641 }
642 else if (attachment == GL_DEPTH_ATTACHMENT)
643 {
644 SafeDelete(mDepthbuffer);
645 mDepthbuffer = attachmentObj;
646 }
647 else if (attachment == GL_STENCIL_ATTACHMENT)
648 {
649 SafeDelete(mStencilbuffer);
650 mStencilbuffer = attachmentObj;
651 }
652 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
653 {
654 SafeDelete(mDepthbuffer);
655 SafeDelete(mStencilbuffer);
656
657 // ensure this is a legitimate depth+stencil format
658 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
659 {
660 mDepthbuffer = attachmentObj;
661
662 // Make a new attachment object to ensure we do not double-delete
663 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500664 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400665 {
666 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
667 *attachmentObj->getTextureImageIndex());
668 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500669 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400670 {
671 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
672 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500673 else
674 {
675 UNREACHABLE();
676 }
Geoff Langab75a052014-10-15 12:56:37 -0400677 }
678 }
679 else
680 {
681 UNREACHABLE();
682 }
683}
684
Jamie Madill48faf802014-11-06 15:27:22 -0500685GLenum DefaultFramebuffer::completeness(const gl::Data &) const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000686{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000687 // The default framebuffer *must* always be complete, though it may not be
688 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000689 return GL_FRAMEBUFFER_COMPLETE;
690}
691
Jamie Madille92a3542014-07-03 10:38:58 -0400692FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
693{
694 switch (attachment)
695 {
Jamie Madill6d708262014-09-03 15:07:13 -0400696 case GL_COLOR:
Jamie Madille92a3542014-07-03 10:38:58 -0400697 case GL_BACK:
698 return getColorbuffer(0);
699 case GL_DEPTH:
700 return getDepthbuffer();
701 case GL_STENCIL:
702 return getStencilbuffer();
703 case GL_DEPTH_STENCIL:
704 return getDepthStencilBuffer();
705 default:
706 UNREACHABLE();
707 return NULL;
708 }
709}
710
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000711}