blob: 27fc3cfb00811159ea3d5614a818c375134328ac [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Framebuffer.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/main.h"
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +000012#include "libGLESv2/formatutils.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000013#include "libGLESv2/Texture.h"
14#include "libGLESv2/Context.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000015#include "libGLESv2/Renderbuffer.h"
Jamie Madille261b442014-06-25 12:42:21 -040016#include "libGLESv2/FramebufferAttachment.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040017#include "libGLESv2/renderer/Renderer.h"
Jamie Madill400a4412014-08-29 15:46:45 -040018#include "libGLESv2/renderer/RenderTarget.h"
Shannon Woodse2632d22014-10-17 13:08:51 -040019#include "libGLESv2/renderer/RenderbufferImpl.h"
Jamie Madill7acae0a2014-09-24 17:10:51 -040020#include "libGLESv2/renderer/Workarounds.h"
Jamie Madill9f0b42a2014-09-12 10:25:27 -040021#include "libGLESv2/renderer/d3d/TextureD3D.h"
Shannon Woodse2632d22014-10-17 13:08:51 -040022#include "libGLESv2/renderer/d3d/RenderbufferD3D.h"
Geoff Lang6a1e6b92014-11-06 10:42:45 -050023#include "libGLESv2/renderer/d3d/FramebufferD3D.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040024
25#include "common/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000026
Jamie Madill9f0b42a2014-09-12 10:25:27 -040027namespace rx
28{
Shannon Woodse2632d22014-10-17 13:08:51 -040029// TODO: Move these functions, and the D3D-specific header inclusions above,
30// to FramebufferD3D.
Geoff Lang64f23f62014-09-10 14:40:12 -040031gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget **outRT)
Jamie Madill9f0b42a2014-09-12 10:25:27 -040032{
Geoff Lang6a1e6b92014-11-06 10:42:45 -050033 if (attachment->type() == GL_TEXTURE)
Jamie Madill9f0b42a2014-09-12 10:25:27 -040034 {
35 gl::Texture *texture = attachment->getTexture();
36 ASSERT(texture);
37 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
Jamie Madillac7579c2014-09-17 16:59:33 -040038 const gl::ImageIndex *index = attachment->getTextureImageIndex();
39 ASSERT(index);
Geoff Lang64f23f62014-09-10 14:40:12 -040040 return textureD3D->getRenderTarget(*index, outRT);
Jamie Madill9f0b42a2014-09-12 10:25:27 -040041 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -050042 else if (attachment->type() == GL_RENDERBUFFER)
Geoff Lang64f23f62014-09-10 14:40:12 -040043 {
44 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
45 ASSERT(renderbuffer);
Shannon Woodse2632d22014-10-17 13:08:51 -040046 RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
47 *outRT = renderbufferD3D->getRenderTarget();
Geoff Lang64f23f62014-09-10 14:40:12 -040048 return gl::Error(GL_NO_ERROR);
49 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -050050 else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
51 {
52 gl::DefaultAttachment *defaultAttachment = static_cast<gl::DefaultAttachment *>(attachment);
53 DefaultAttachmentD3D *defaultAttachmentD3D = DefaultAttachmentD3D::makeDefaultAttachmentD3D(defaultAttachment->getImplementation());
54 ASSERT(defaultAttachmentD3D);
55
56 *outRT = defaultAttachmentD3D->getRenderTarget();
57 return gl::Error(GL_NO_ERROR);
58 }
59 else
60 {
61 UNREACHABLE();
62 return gl::Error(GL_INVALID_OPERATION);
63 }
Jamie Madill9f0b42a2014-09-12 10:25:27 -040064}
65
Jamie Madill612e2e42014-09-12 13:26:55 -040066// Note: RenderTarget serials should ideally be in the RenderTargets themselves.
67unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment)
68{
Geoff Lang6a1e6b92014-11-06 10:42:45 -050069 if (attachment->type() == GL_TEXTURE)
Jamie Madill612e2e42014-09-12 13:26:55 -040070 {
71 gl::Texture *texture = attachment->getTexture();
72 ASSERT(texture);
73 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
Jamie Madillac7579c2014-09-17 16:59:33 -040074 const gl::ImageIndex *index = attachment->getTextureImageIndex();
75 ASSERT(index);
76 return textureD3D->getRenderTargetSerial(*index);
Jamie Madill612e2e42014-09-12 13:26:55 -040077 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -050078 else if (attachment->type() == GL_RENDERBUFFER)
79 {
80 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
81 ASSERT(renderbuffer);
82 RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
83 return renderbufferD3D->getRenderTargetSerial();
84 }
85 else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
86 {
87 gl::DefaultAttachment *defaultAttachment = static_cast<gl::DefaultAttachment *>(attachment);
88 DefaultAttachmentD3D *defaultAttachmentD3D = DefaultAttachmentD3D::makeDefaultAttachmentD3D(defaultAttachment->getImplementation());
89 ASSERT(defaultAttachmentD3D);
90 return defaultAttachmentD3D->getRenderTarget()->getSerial();
91 }
92 else
93 {
94 UNREACHABLE();
95 return 0;
96 }
Jamie Madill612e2e42014-09-12 13:26:55 -040097}
98
Jamie Madill9f0b42a2014-09-12 10:25:27 -040099}
100
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101namespace gl
102{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000103
Jamie Madill48faf802014-11-06 15:27:22 -0500104Framebuffer::Framebuffer(GLuint id)
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{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000110 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
111 {
Jamie Madille261b442014-06-25 12:42:21 -0400112 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000113 mDrawBufferStates[colorAttachment] = GL_NONE;
114 }
115 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000116}
117
118Framebuffer::~Framebuffer()
119{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000120 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
121 {
Jamie Madille261b442014-06-25 12:42:21 -0400122 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000123 }
Jamie Madille261b442014-06-25 12:42:21 -0400124 SafeDelete(mDepthbuffer);
125 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000126}
127
Jamie Madille261b442014-06-25 12:42:21 -0400128void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000130 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131 {
Jamie Madille261b442014-06-25 12:42:21 -0400132 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
133
134 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000135 {
Jamie Madille261b442014-06-25 12:42:21 -0400136 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000137 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000139
Jamie Madille261b442014-06-25 12:42:21 -0400140 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000141 {
Jamie Madille261b442014-06-25 12:42:21 -0400142 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000143 }
144
Jamie Madille261b442014-06-25 12:42:21 -0400145 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000146 {
Jamie Madille261b442014-06-25 12:42:21 -0400147 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000148 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149}
150
Jamie Madille261b442014-06-25 12:42:21 -0400151void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000153 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154 {
Jamie Madille261b442014-06-25 12:42:21 -0400155 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
156
157 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000158 {
Jamie Madille261b442014-06-25 12:42:21 -0400159 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000160 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161 }
162
Jamie Madille261b442014-06-25 12:42:21 -0400163 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 {
Jamie Madille261b442014-06-25 12:42:21 -0400165 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000166 }
167
Jamie Madille261b442014-06-25 12:42:21 -0400168 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169 {
Jamie Madille261b442014-06-25 12:42:21 -0400170 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 }
172}
173
Jamie Madill3c7fa222014-06-05 13:08:51 -0400174FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000175{
176 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400177 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000178}
179
Jamie Madill3c7fa222014-06-05 13:08:51 -0400180FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181{
Jamie Madille261b442014-06-25 12:42:21 -0400182 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183}
184
Jamie Madill3c7fa222014-06-05 13:08:51 -0400185FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186{
Jamie Madille261b442014-06-25 12:42:21 -0400187 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188}
189
Jamie Madill3c7fa222014-06-05 13:08:51 -0400190FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400191{
Jamie Madille261b442014-06-25 12:42:21 -0400192 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400193}
194
Jamie Madill3c7fa222014-06-05 13:08:51 -0400195FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000196{
Jamie Madille261b442014-06-25 12:42:21 -0400197 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000198
199 if (!depthstencilbuffer)
200 {
Jamie Madille261b442014-06-25 12:42:21 -0400201 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000202 }
203
204 return depthstencilbuffer;
205}
206
Jamie Madill3c7fa222014-06-05 13:08:51 -0400207FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000208{
209 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400210 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000211}
212
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000213GLenum Framebuffer::getReadColorbufferType() const
214{
215 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400216 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000217}
218
Jamie Madill3c7fa222014-06-05 13:08:51 -0400219FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000220{
221 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
222 {
Jamie Madille261b442014-06-25 12:42:21 -0400223 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000224 {
Jamie Madille261b442014-06-25 12:42:21 -0400225 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000226 }
227 }
228
229 return NULL;
230}
231
Jamie Madille92a3542014-07-03 10:38:58 -0400232FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000233{
Jamie Madille92a3542014-07-03 10:38:58 -0400234 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
235 {
236 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
237 }
238 else
239 {
240 switch (attachment)
241 {
242 case GL_DEPTH_ATTACHMENT:
243 return getDepthbuffer();
244 case GL_STENCIL_ATTACHMENT:
245 return getStencilbuffer();
246 case GL_DEPTH_STENCIL_ATTACHMENT:
247 return getDepthStencilBuffer();
248 default:
249 UNREACHABLE();
250 return NULL;
251 }
252 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400253}
254
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000255GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
256{
257 return mDrawBufferStates[colorAttachment];
258}
259
260void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
261{
262 mDrawBufferStates[colorAttachment] = drawBuffer;
263}
264
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000265bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
266{
Jamie Madille261b442014-06-25 12:42:21 -0400267 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000268}
269
270bool Framebuffer::hasEnabledColorAttachment() const
271{
272 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
273 {
274 if (isEnabledColorAttachment(colorAttachment))
275 {
276 return true;
277 }
278 }
279
280 return false;
281}
282
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000283bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000284{
Geoff Lange4a492b2014-06-19 14:14:41 -0400285 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000286}
287
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000288bool Framebuffer::usingExtendedDrawBuffers() const
289{
290 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
291 {
292 if (isEnabledColorAttachment(colorAttachment))
293 {
294 return true;
295 }
296 }
297
298 return false;
299}
300
Jamie Madill48faf802014-11-06 15:27:22 -0500301GLenum Framebuffer::completeness(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 int width = 0;
304 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000305 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000306 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000307 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000309 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000310 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400311 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
312
313 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000314 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000315 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000316 {
317 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
318 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000319
Geoff Langcec35902014-04-16 10:52:36 -0400320 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500321 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400322 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500323 if (colorbuffer->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000324 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400325 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000326 {
327 return GL_FRAMEBUFFER_UNSUPPORTED;
328 }
329
Geoff Lang5d601382014-07-22 15:14:06 -0400330 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000331 {
332 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
333 }
334 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500335 else if (colorbuffer->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000336 {
Geoff Lang5d601382014-07-22 15:14:06 -0400337 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400338 {
339 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
340 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000341 }
342
343 if (!missingAttachment)
344 {
345 // all color attachments must have the same width and height
346 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
347 {
348 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
349 }
350
351 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
352 // all color attachments have the same number of samples for the FBO to be complete.
353 if (colorbuffer->getSamples() != samples)
354 {
355 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
356 }
357
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000358 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
359 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500360 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000361 {
Geoff Lang5d601382014-07-22 15:14:06 -0400362 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000363 {
364 return GL_FRAMEBUFFER_UNSUPPORTED;
365 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000366 }
367
368 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
369 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
370 {
Jamie Madille92a3542014-07-03 10:38:58 -0400371 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
372
373 if (previousAttachment &&
374 (colorbuffer->id() == previousAttachment->id() &&
375 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000376 {
377 return GL_FRAMEBUFFER_UNSUPPORTED;
378 }
379 }
380 }
381 else
382 {
383 width = colorbuffer->getWidth();
384 height = colorbuffer->getHeight();
385 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400386 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000387 missingAttachment = false;
388 }
389 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000390 }
391
Jamie Madille261b442014-06-25 12:42:21 -0400392 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000393 {
Jamie Madille261b442014-06-25 12:42:21 -0400394 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000395 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000396 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000397 }
398
Jamie Madille261b442014-06-25 12:42:21 -0400399 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500400 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400401 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500402 if (mDepthbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000403 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000404 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500405 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000406 {
407 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
408 }
409
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400410 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400411 {
412 return GL_FRAMEBUFFER_UNSUPPORTED;
413 }
414
Geoff Lang5d601382014-07-22 15:14:06 -0400415 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000416 {
417 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
418 }
419 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500420 else if (mDepthbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000421 {
Geoff Lang5d601382014-07-22 15:14:06 -0400422 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400423 {
424 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
425 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000426 }
427
428 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000429 {
Jamie Madille261b442014-06-25 12:42:21 -0400430 width = mDepthbuffer->getWidth();
431 height = mDepthbuffer->getHeight();
432 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000433 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000434 }
Jamie Madille261b442014-06-25 12:42:21 -0400435 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000436 {
437 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
438 }
Jamie Madille261b442014-06-25 12:42:21 -0400439 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000440 {
441 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
442 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000443 }
444
Jamie Madille261b442014-06-25 12:42:21 -0400445 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000446 {
Jamie Madille261b442014-06-25 12:42:21 -0400447 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000448 {
449 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
450 }
451
Jamie Madille261b442014-06-25 12:42:21 -0400452 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500453 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400454 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500455 if (mStencilbuffer->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000456 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000457 // texture stencil attachments come along as part
458 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500459 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000460 {
461 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
462 }
463
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400464 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400465 {
466 return GL_FRAMEBUFFER_UNSUPPORTED;
467 }
468
Geoff Lang5d601382014-07-22 15:14:06 -0400469 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000470 {
471 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
472 }
473 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500474 else if (mStencilbuffer->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000475 {
Geoff Lang5d601382014-07-22 15:14:06 -0400476 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400477 {
478 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
479 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000480 }
481
482 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000483 {
Jamie Madille261b442014-06-25 12:42:21 -0400484 width = mStencilbuffer->getWidth();
485 height = mStencilbuffer->getHeight();
486 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000487 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000488 }
Jamie Madille261b442014-06-25 12:42:21 -0400489 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000490 {
491 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
492 }
Jamie Madille261b442014-06-25 12:42:21 -0400493 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000494 {
495 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
496 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000497 }
498
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000499 // if we have both a depth and stencil buffer, they must refer to the same object
500 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400501 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000502 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000503 return GL_FRAMEBUFFER_UNSUPPORTED;
504 }
505
506 // we need to have at least one attachment to be complete
507 if (missingAttachment)
508 {
509 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000510 }
511
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000512 return GL_FRAMEBUFFER_COMPLETE;
513}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000514
Geoff Lang64f23f62014-09-10 14:40:12 -0400515Error Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400516{
517 GLuint maxDimension = caps.maxRenderbufferSize;
Geoff Lang64f23f62014-09-10 14:40:12 -0400518 return invalidateSub(numAttachments, attachments, 0, 0, maxDimension, maxDimension);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400519}
520
Geoff Lang64f23f62014-09-10 14:40:12 -0400521Error Framebuffer::invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400522{
Jamie Madill6d708262014-09-03 15:07:13 -0400523 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400524 {
Jamie Madill6d708262014-09-03 15:07:13 -0400525 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400526
Geoff Lang64f23f62014-09-10 14:40:12 -0400527 FramebufferAttachment *attachment = (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer()
528 : getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400529
Jamie Madill6d708262014-09-03 15:07:13 -0400530 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400531 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400532 rx::RenderTarget *renderTarget = NULL;
533 Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget);
534 if (error.isError())
Jamie Madill6d708262014-09-03 15:07:13 -0400535 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400536 return error;
Jamie Madill6d708262014-09-03 15:07:13 -0400537 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400538
539 renderTarget->invalidate(x, y, width, height);
Jamie Madill400a4412014-08-29 15:46:45 -0400540 }
541 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400542
543 return Error(GL_NO_ERROR);
Jamie Madill400a4412014-08-29 15:46:45 -0400544}
545
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500546DefaultFramebuffer::DefaultFramebuffer(rx::DefaultAttachmentImpl *colorAttachment, rx::DefaultAttachmentImpl *depthAttachment,
547 rx::DefaultAttachmentImpl *stencilAttachment)
Jamie Madill48faf802014-11-06 15:27:22 -0500548 : Framebuffer(0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000549{
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500550 ASSERT(colorAttachment);
551 mColorbuffers[0] = new DefaultAttachment(GL_BACK, colorAttachment);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000552
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500553 if (depthAttachment)
Austin Kinross44f4d742014-11-11 13:37:00 -0800554 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500555 mDepthbuffer = new DefaultAttachment(GL_DEPTH, depthAttachment);
556 }
557 if (stencilAttachment)
558 {
559 mStencilbuffer = new DefaultAttachment(GL_STENCIL, stencilAttachment);
Austin Kinross44f4d742014-11-11 13:37:00 -0800560 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000561
562 mDrawBufferStates[0] = GL_BACK;
563 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000564}
565
Jamie Madill48faf802014-11-06 15:27:22 -0500566int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000567{
Jamie Madill48faf802014-11-06 15:27:22 -0500568 if (completeness(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000569 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000570 // for a complete framebuffer, all attachments must have the same sample count
571 // in this case return the first nonzero sample size
572 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
573 {
Jamie Madille261b442014-06-25 12:42:21 -0400574 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000575 {
Jamie Madille261b442014-06-25 12:42:21 -0400576 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000577 }
578 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000579 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000580
581 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000582}
583
Jamie Madille261b442014-06-25 12:42:21 -0400584bool Framebuffer::hasValidDepthStencil() const
585{
586 // A valid depth-stencil attachment has the same resource bound to both the
587 // depth and stencil attachment points.
588 return (mDepthbuffer && mStencilbuffer &&
589 mDepthbuffer->type() == mStencilbuffer->type() &&
590 mDepthbuffer->id() == mStencilbuffer->id());
591}
592
Jamie Madill48faf802014-11-06 15:27:22 -0500593ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400594{
595 ColorbufferInfo colorbuffersForRender;
596
597 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
598 {
599 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
600 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
601
602 if (colorbuffer != NULL && drawBufferState != GL_NONE)
603 {
604 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
605 colorbuffersForRender.push_back(colorbuffer);
606 }
Jamie Madill48faf802014-11-06 15:27:22 -0500607 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400608 {
609 colorbuffersForRender.push_back(NULL);
610 }
611 }
612
613 return colorbuffersForRender;
614}
615
Geoff Langab75a052014-10-15 12:56:37 -0400616void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
617{
618 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
619}
620
621void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
622{
623 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
624}
625
626void Framebuffer::setNULLAttachment(GLenum attachment)
627{
628 setAttachment(attachment, NULL);
629}
630
631void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
632{
633 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
634 {
635 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
636 SafeDelete(mColorbuffers[colorAttachment]);
637 mColorbuffers[colorAttachment] = attachmentObj;
638 }
639 else if (attachment == GL_DEPTH_ATTACHMENT)
640 {
641 SafeDelete(mDepthbuffer);
642 mDepthbuffer = attachmentObj;
643 }
644 else if (attachment == GL_STENCIL_ATTACHMENT)
645 {
646 SafeDelete(mStencilbuffer);
647 mStencilbuffer = attachmentObj;
648 }
649 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
650 {
651 SafeDelete(mDepthbuffer);
652 SafeDelete(mStencilbuffer);
653
654 // ensure this is a legitimate depth+stencil format
655 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
656 {
657 mDepthbuffer = attachmentObj;
658
659 // Make a new attachment object to ensure we do not double-delete
660 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500661 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400662 {
663 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
664 *attachmentObj->getTextureImageIndex());
665 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500666 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400667 {
668 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
669 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500670 else
671 {
672 UNREACHABLE();
673 }
Geoff Langab75a052014-10-15 12:56:37 -0400674 }
675 }
676 else
677 {
678 UNREACHABLE();
679 }
680}
681
Jamie Madill48faf802014-11-06 15:27:22 -0500682GLenum DefaultFramebuffer::completeness(const gl::Data &) const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000683{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000684 // The default framebuffer *must* always be complete, though it may not be
685 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000686 return GL_FRAMEBUFFER_COMPLETE;
687}
688
Jamie Madille92a3542014-07-03 10:38:58 -0400689FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
690{
691 switch (attachment)
692 {
Jamie Madill6d708262014-09-03 15:07:13 -0400693 case GL_COLOR:
Jamie Madille92a3542014-07-03 10:38:58 -0400694 case GL_BACK:
695 return getColorbuffer(0);
696 case GL_DEPTH:
697 return getDepthbuffer();
698 case GL_STENCIL:
699 return getStencilbuffer();
700 case GL_DEPTH_STENCIL:
701 return getDepthStencilBuffer();
702 default:
703 UNREACHABLE();
704 return NULL;
705 }
706}
707
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000708}