blob: 10a957853d63fbfe64a1d5bee26b3dca721a40ee [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
Jamie Madill48faf802014-11-06 15:27:22 -0500103Framebuffer::Framebuffer(GLuint id)
104 : mId(id),
Jamie Madille261b442014-06-25 12:42:21 -0400105 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
106 mDepthbuffer(NULL),
107 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000109 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
110 {
Jamie Madille261b442014-06-25 12:42:21 -0400111 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000112 mDrawBufferStates[colorAttachment] = GL_NONE;
113 }
114 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115}
116
117Framebuffer::~Framebuffer()
118{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000119 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
120 {
Jamie Madille261b442014-06-25 12:42:21 -0400121 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000122 }
Jamie Madille261b442014-06-25 12:42:21 -0400123 SafeDelete(mDepthbuffer);
124 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000125}
126
Jamie Madille261b442014-06-25 12:42:21 -0400127void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000128{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000129 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130 {
Jamie Madille261b442014-06-25 12:42:21 -0400131 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
132
133 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000134 {
Jamie Madille261b442014-06-25 12:42:21 -0400135 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000136 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000138
Jamie Madille261b442014-06-25 12:42:21 -0400139 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000140 {
Jamie Madille261b442014-06-25 12:42:21 -0400141 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000142 }
143
Jamie Madille261b442014-06-25 12:42:21 -0400144 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000145 {
Jamie Madille261b442014-06-25 12:42:21 -0400146 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000147 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148}
149
Jamie Madille261b442014-06-25 12:42:21 -0400150void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000152 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153 {
Jamie Madille261b442014-06-25 12:42:21 -0400154 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
155
156 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000157 {
Jamie Madille261b442014-06-25 12:42:21 -0400158 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000159 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160 }
161
Jamie Madille261b442014-06-25 12:42:21 -0400162 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163 {
Jamie Madille261b442014-06-25 12:42:21 -0400164 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000165 }
166
Jamie Madille261b442014-06-25 12:42:21 -0400167 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000168 {
Jamie Madille261b442014-06-25 12:42:21 -0400169 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170 }
171}
172
Jamie Madill3c7fa222014-06-05 13:08:51 -0400173FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000174{
175 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400176 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000177}
178
Jamie Madill3c7fa222014-06-05 13:08:51 -0400179FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180{
Jamie Madille261b442014-06-25 12:42:21 -0400181 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182}
183
Jamie Madill3c7fa222014-06-05 13:08:51 -0400184FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185{
Jamie Madille261b442014-06-25 12:42:21 -0400186 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187}
188
Jamie Madill3c7fa222014-06-05 13:08:51 -0400189FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400190{
Jamie Madille261b442014-06-25 12:42:21 -0400191 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400192}
193
Jamie Madill3c7fa222014-06-05 13:08:51 -0400194FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000195{
Jamie Madille261b442014-06-25 12:42:21 -0400196 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000197
198 if (!depthstencilbuffer)
199 {
Jamie Madille261b442014-06-25 12:42:21 -0400200 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000201 }
202
203 return depthstencilbuffer;
204}
205
Jamie Madill3c7fa222014-06-05 13:08:51 -0400206FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000207{
208 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400209 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000210}
211
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000212GLenum Framebuffer::getReadColorbufferType() const
213{
214 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400215 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000216}
217
Jamie Madill3c7fa222014-06-05 13:08:51 -0400218FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000219{
220 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
221 {
Jamie Madille261b442014-06-25 12:42:21 -0400222 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000223 {
Jamie Madille261b442014-06-25 12:42:21 -0400224 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000225 }
226 }
227
228 return NULL;
229}
230
Jamie Madille92a3542014-07-03 10:38:58 -0400231FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000232{
Jamie Madille92a3542014-07-03 10:38:58 -0400233 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
234 {
235 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
236 }
237 else
238 {
239 switch (attachment)
240 {
241 case GL_DEPTH_ATTACHMENT:
242 return getDepthbuffer();
243 case GL_STENCIL_ATTACHMENT:
244 return getStencilbuffer();
245 case GL_DEPTH_STENCIL_ATTACHMENT:
246 return getDepthStencilBuffer();
247 default:
248 UNREACHABLE();
249 return NULL;
250 }
251 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400252}
253
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000254GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
255{
256 return mDrawBufferStates[colorAttachment];
257}
258
259void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
260{
261 mDrawBufferStates[colorAttachment] = drawBuffer;
262}
263
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000264bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
265{
Jamie Madille261b442014-06-25 12:42:21 -0400266 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000267}
268
269bool Framebuffer::hasEnabledColorAttachment() const
270{
271 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
272 {
273 if (isEnabledColorAttachment(colorAttachment))
274 {
275 return true;
276 }
277 }
278
279 return false;
280}
281
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000282bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000283{
Geoff Lange4a492b2014-06-19 14:14:41 -0400284 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000285}
286
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000287bool Framebuffer::usingExtendedDrawBuffers() const
288{
289 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
290 {
291 if (isEnabledColorAttachment(colorAttachment))
292 {
293 return true;
294 }
295 }
296
297 return false;
298}
299
Jamie Madill48faf802014-11-06 15:27:22 -0500300GLenum Framebuffer::completeness(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302 int width = 0;
303 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000304 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000305 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000306 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000308 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400310 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
311
312 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000314 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000315 {
316 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
317 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000318
Geoff Langcec35902014-04-16 10:52:36 -0400319 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500320 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400321 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500322 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000323 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400324 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000325 {
326 return GL_FRAMEBUFFER_UNSUPPORTED;
327 }
328
Geoff Lang5d601382014-07-22 15:14:06 -0400329 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000330 {
331 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
332 }
333 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500334 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000335 {
Geoff Lang5d601382014-07-22 15:14:06 -0400336 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400337 {
338 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
339 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000340 }
341
342 if (!missingAttachment)
343 {
344 // all color attachments must have the same width and height
345 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
346 {
347 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
348 }
349
350 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
351 // all color attachments have the same number of samples for the FBO to be complete.
352 if (colorbuffer->getSamples() != samples)
353 {
354 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
355 }
356
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000357 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
358 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500359 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000360 {
Geoff Lang5d601382014-07-22 15:14:06 -0400361 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000362 {
363 return GL_FRAMEBUFFER_UNSUPPORTED;
364 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000365 }
366
367 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
368 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
369 {
Jamie Madille92a3542014-07-03 10:38:58 -0400370 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
371
372 if (previousAttachment &&
373 (colorbuffer->id() == previousAttachment->id() &&
374 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000375 {
376 return GL_FRAMEBUFFER_UNSUPPORTED;
377 }
378 }
379 }
380 else
381 {
382 width = colorbuffer->getWidth();
383 height = colorbuffer->getHeight();
384 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400385 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000386 missingAttachment = false;
387 }
388 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000389 }
390
Jamie Madille261b442014-06-25 12:42:21 -0400391 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000392 {
Jamie Madille261b442014-06-25 12:42:21 -0400393 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000394 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000395 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396 }
397
Jamie Madille261b442014-06-25 12:42:21 -0400398 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500399 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400400 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500401 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000402 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000403 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500404 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000405 {
406 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
407 }
408
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400409 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400410 {
411 return GL_FRAMEBUFFER_UNSUPPORTED;
412 }
413
Geoff Lang5d601382014-07-22 15:14:06 -0400414 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000415 {
416 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
417 }
418 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500419 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000420 {
Geoff Lang5d601382014-07-22 15:14:06 -0400421 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400422 {
423 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
424 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000425 }
426
427 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000428 {
Jamie Madille261b442014-06-25 12:42:21 -0400429 width = mDepthbuffer->getWidth();
430 height = mDepthbuffer->getHeight();
431 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000432 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000433 }
Jamie Madille261b442014-06-25 12:42:21 -0400434 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000435 {
436 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
437 }
Jamie Madille261b442014-06-25 12:42:21 -0400438 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000439 {
440 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
441 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000442 }
443
Jamie Madille261b442014-06-25 12:42:21 -0400444 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000445 {
Jamie Madille261b442014-06-25 12:42:21 -0400446 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000447 {
448 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
449 }
450
Jamie Madille261b442014-06-25 12:42:21 -0400451 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500452 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400453 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500454 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000455 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000456 // texture stencil attachments come along as part
457 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500458 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000459 {
460 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
461 }
462
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400463 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400464 {
465 return GL_FRAMEBUFFER_UNSUPPORTED;
466 }
467
Geoff Lang5d601382014-07-22 15:14:06 -0400468 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000469 {
470 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
471 }
472 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500473 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000474 {
Geoff Lang5d601382014-07-22 15:14:06 -0400475 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400476 {
477 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
478 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000479 }
480
481 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000482 {
Jamie Madille261b442014-06-25 12:42:21 -0400483 width = mStencilbuffer->getWidth();
484 height = mStencilbuffer->getHeight();
485 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000486 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000487 }
Jamie Madille261b442014-06-25 12:42:21 -0400488 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000489 {
490 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
491 }
Jamie Madille261b442014-06-25 12:42:21 -0400492 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000493 {
494 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
495 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000496 }
497
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000498 // if we have both a depth and stencil buffer, they must refer to the same object
499 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400500 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000501 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000502 return GL_FRAMEBUFFER_UNSUPPORTED;
503 }
504
505 // we need to have at least one attachment to be complete
506 if (missingAttachment)
507 {
508 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000509 }
510
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000511 return GL_FRAMEBUFFER_COMPLETE;
512}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000513
Geoff Lang64f23f62014-09-10 14:40:12 -0400514Error Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400515{
516 GLuint maxDimension = caps.maxRenderbufferSize;
Geoff Lang64f23f62014-09-10 14:40:12 -0400517 return invalidateSub(numAttachments, attachments, 0, 0, maxDimension, maxDimension);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400518}
519
Geoff Lang64f23f62014-09-10 14:40:12 -0400520Error Framebuffer::invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400521{
Jamie Madill6d708262014-09-03 15:07:13 -0400522 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400523 {
Jamie Madill6d708262014-09-03 15:07:13 -0400524 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400525
Geoff Lang64f23f62014-09-10 14:40:12 -0400526 FramebufferAttachment *attachment = (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer()
527 : getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400528
Jamie Madill6d708262014-09-03 15:07:13 -0400529 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400530 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400531 rx::RenderTarget *renderTarget = NULL;
532 Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget);
533 if (error.isError())
Jamie Madill6d708262014-09-03 15:07:13 -0400534 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400535 return error;
Jamie Madill6d708262014-09-03 15:07:13 -0400536 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400537
538 renderTarget->invalidate(x, y, width, height);
Jamie Madill400a4412014-08-29 15:46:45 -0400539 }
540 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400541
542 return Error(GL_NO_ERROR);
Jamie Madill400a4412014-08-29 15:46:45 -0400543}
544
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500545DefaultFramebuffer::DefaultFramebuffer(rx::DefaultAttachmentImpl *colorAttachment, rx::DefaultAttachmentImpl *depthAttachment,
546 rx::DefaultAttachmentImpl *stencilAttachment)
Jamie Madill48faf802014-11-06 15:27:22 -0500547 : Framebuffer(0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000548{
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500549 ASSERT(colorAttachment);
550 mColorbuffers[0] = new DefaultAttachment(GL_BACK, colorAttachment);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000551
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500552 if (depthAttachment)
Austin Kinross44f4d742014-11-11 13:37:00 -0800553 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500554 mDepthbuffer = new DefaultAttachment(GL_DEPTH, depthAttachment);
555 }
556 if (stencilAttachment)
557 {
558 mStencilbuffer = new DefaultAttachment(GL_STENCIL, stencilAttachment);
Austin Kinross44f4d742014-11-11 13:37:00 -0800559 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000560
561 mDrawBufferStates[0] = GL_BACK;
562 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000563}
564
Jamie Madill48faf802014-11-06 15:27:22 -0500565int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000566{
Jamie Madill48faf802014-11-06 15:27:22 -0500567 if (completeness(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000568 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000569 // for a complete framebuffer, all attachments must have the same sample count
570 // in this case return the first nonzero sample size
571 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
572 {
Jamie Madille261b442014-06-25 12:42:21 -0400573 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000574 {
Jamie Madille261b442014-06-25 12:42:21 -0400575 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000576 }
577 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000578 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000579
580 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000581}
582
Jamie Madille261b442014-06-25 12:42:21 -0400583bool Framebuffer::hasValidDepthStencil() const
584{
585 // A valid depth-stencil attachment has the same resource bound to both the
586 // depth and stencil attachment points.
587 return (mDepthbuffer && mStencilbuffer &&
588 mDepthbuffer->type() == mStencilbuffer->type() &&
589 mDepthbuffer->id() == mStencilbuffer->id());
590}
591
Jamie Madill48faf802014-11-06 15:27:22 -0500592ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400593{
594 ColorbufferInfo colorbuffersForRender;
595
596 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
597 {
598 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
599 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
600
601 if (colorbuffer != NULL && drawBufferState != GL_NONE)
602 {
603 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
604 colorbuffersForRender.push_back(colorbuffer);
605 }
Jamie Madill48faf802014-11-06 15:27:22 -0500606 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400607 {
608 colorbuffersForRender.push_back(NULL);
609 }
610 }
611
612 return colorbuffersForRender;
613}
614
Geoff Langab75a052014-10-15 12:56:37 -0400615void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
616{
617 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
618}
619
620void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
621{
622 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
623}
624
625void Framebuffer::setNULLAttachment(GLenum attachment)
626{
627 setAttachment(attachment, NULL);
628}
629
630void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
631{
632 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
633 {
634 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
635 SafeDelete(mColorbuffers[colorAttachment]);
636 mColorbuffers[colorAttachment] = attachmentObj;
637 }
638 else if (attachment == GL_DEPTH_ATTACHMENT)
639 {
640 SafeDelete(mDepthbuffer);
641 mDepthbuffer = attachmentObj;
642 }
643 else if (attachment == GL_STENCIL_ATTACHMENT)
644 {
645 SafeDelete(mStencilbuffer);
646 mStencilbuffer = attachmentObj;
647 }
648 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
649 {
650 SafeDelete(mDepthbuffer);
651 SafeDelete(mStencilbuffer);
652
653 // ensure this is a legitimate depth+stencil format
654 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
655 {
656 mDepthbuffer = attachmentObj;
657
658 // Make a new attachment object to ensure we do not double-delete
659 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500660 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400661 {
662 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
663 *attachmentObj->getTextureImageIndex());
664 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500665 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400666 {
667 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
668 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500669 else
670 {
671 UNREACHABLE();
672 }
Geoff Langab75a052014-10-15 12:56:37 -0400673 }
674 }
675 else
676 {
677 UNREACHABLE();
678 }
679}
680
Jamie Madill48faf802014-11-06 15:27:22 -0500681GLenum DefaultFramebuffer::completeness(const gl::Data &) const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000682{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000683 // The default framebuffer *must* always be complete, though it may not be
684 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000685 return GL_FRAMEBUFFER_COMPLETE;
686}
687
Jamie Madille92a3542014-07-03 10:38:58 -0400688FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
689{
690 switch (attachment)
691 {
Jamie Madill6d708262014-09-03 15:07:13 -0400692 case GL_COLOR:
Jamie Madille92a3542014-07-03 10:38:58 -0400693 case GL_BACK:
694 return getColorbuffer(0);
695 case GL_DEPTH:
696 return getDepthbuffer();
697 case GL_STENCIL:
698 return getStencilbuffer();
699 case GL_DEPTH_STENCIL:
700 return getDepthStencilBuffer();
701 default:
702 UNREACHABLE();
703 return NULL;
704 }
705}
706
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000707}