blob: 3d57262e3c3a6cc4dd938e94d2200fe873bb6cec [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 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 Lang64f23f62014-09-10 14:40:12 -040030gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget **outRT)
Jamie Madill9f0b42a2014-09-12 10:25:27 -040031{
32 if (attachment->isTexture())
33 {
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 Lang64f23f62014-09-10 14:40:12 -040041 else
42 {
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 }
Jamie Madill9f0b42a2014-09-12 10:25:27 -040049}
50
Jamie Madill612e2e42014-09-12 13:26:55 -040051// Note: RenderTarget serials should ideally be in the RenderTargets themselves.
52unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment)
53{
54 if (attachment->isTexture())
55 {
56 gl::Texture *texture = attachment->getTexture();
57 ASSERT(texture);
58 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
Jamie Madillac7579c2014-09-17 16:59:33 -040059 const gl::ImageIndex *index = attachment->getTextureImageIndex();
60 ASSERT(index);
61 return textureD3D->getRenderTargetSerial(*index);
Jamie Madill612e2e42014-09-12 13:26:55 -040062 }
63
64 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
65 ASSERT(renderbuffer);
Shannon Woodse2632d22014-10-17 13:08:51 -040066 RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
67 return renderbufferD3D->getRenderTargetSerial();
Jamie Madill612e2e42014-09-12 13:26:55 -040068}
69
Jamie Madill9f0b42a2014-09-12 10:25:27 -040070}
71
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000072namespace gl
73{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000074
Jamie Madill48faf802014-11-06 15:27:22 -050075Framebuffer::Framebuffer(GLuint id)
76 : mId(id),
Jamie Madille261b442014-06-25 12:42:21 -040077 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
78 mDepthbuffer(NULL),
79 mStencilbuffer(NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000081 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
82 {
Jamie Madille261b442014-06-25 12:42:21 -040083 mColorbuffers[colorAttachment] = NULL;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000084 mDrawBufferStates[colorAttachment] = GL_NONE;
85 }
86 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087}
88
89Framebuffer::~Framebuffer()
90{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000091 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
92 {
Jamie Madille261b442014-06-25 12:42:21 -040093 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000094 }
Jamie Madille261b442014-06-25 12:42:21 -040095 SafeDelete(mDepthbuffer);
96 SafeDelete(mStencilbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000097}
98
Jamie Madille261b442014-06-25 12:42:21 -040099void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000101 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000102 {
Jamie Madille261b442014-06-25 12:42:21 -0400103 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
104
105 if (attachment && attachment->isTextureWithId(textureId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000106 {
Jamie Madille261b442014-06-25 12:42:21 -0400107 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000108 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000110
Jamie Madille261b442014-06-25 12:42:21 -0400111 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000112 {
Jamie Madille261b442014-06-25 12:42:21 -0400113 SafeDelete(mDepthbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000114 }
115
Jamie Madille261b442014-06-25 12:42:21 -0400116 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000117 {
Jamie Madille261b442014-06-25 12:42:21 -0400118 SafeDelete(mStencilbuffer);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +0000119 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120}
121
Jamie Madille261b442014-06-25 12:42:21 -0400122void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123{
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000124 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125 {
Jamie Madille261b442014-06-25 12:42:21 -0400126 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
127
128 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000129 {
Jamie Madille261b442014-06-25 12:42:21 -0400130 SafeDelete(mColorbuffers[colorAttachment]);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000131 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000132 }
133
Jamie Madille261b442014-06-25 12:42:21 -0400134 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135 {
Jamie Madille261b442014-06-25 12:42:21 -0400136 SafeDelete(mDepthbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137 }
138
Jamie Madille261b442014-06-25 12:42:21 -0400139 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000140 {
Jamie Madille261b442014-06-25 12:42:21 -0400141 SafeDelete(mStencilbuffer);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142 }
143}
144
Jamie Madill3c7fa222014-06-05 13:08:51 -0400145FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000146{
147 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
Jamie Madille261b442014-06-25 12:42:21 -0400148 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000149}
150
Jamie Madill3c7fa222014-06-05 13:08:51 -0400151FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152{
Jamie Madille261b442014-06-25 12:42:21 -0400153 return mDepthbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154}
155
Jamie Madill3c7fa222014-06-05 13:08:51 -0400156FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157{
Jamie Madille261b442014-06-25 12:42:21 -0400158 return mStencilbuffer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159}
160
Jamie Madill3c7fa222014-06-05 13:08:51 -0400161FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400162{
Jamie Madille261b442014-06-25 12:42:21 -0400163 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400164}
165
Jamie Madill3c7fa222014-06-05 13:08:51 -0400166FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000167{
Jamie Madille261b442014-06-25 12:42:21 -0400168 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000169
170 if (!depthstencilbuffer)
171 {
Jamie Madille261b442014-06-25 12:42:21 -0400172 depthstencilbuffer = mStencilbuffer;
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000173 }
174
175 return depthstencilbuffer;
176}
177
Jamie Madill3c7fa222014-06-05 13:08:51 -0400178FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000179{
180 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400181 return mColorbuffers[0];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000182}
183
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000184GLenum Framebuffer::getReadColorbufferType() const
185{
186 // Will require more logic if glReadBuffers is supported
Jamie Madille261b442014-06-25 12:42:21 -0400187 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000188}
189
Jamie Madill3c7fa222014-06-05 13:08:51 -0400190FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000191{
192 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
193 {
Jamie Madille261b442014-06-25 12:42:21 -0400194 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000195 {
Jamie Madille261b442014-06-25 12:42:21 -0400196 return mColorbuffers[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000197 }
198 }
199
200 return NULL;
201}
202
Jamie Madille92a3542014-07-03 10:38:58 -0400203FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000204{
Jamie Madille92a3542014-07-03 10:38:58 -0400205 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
206 {
207 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
208 }
209 else
210 {
211 switch (attachment)
212 {
213 case GL_DEPTH_ATTACHMENT:
214 return getDepthbuffer();
215 case GL_STENCIL_ATTACHMENT:
216 return getStencilbuffer();
217 case GL_DEPTH_STENCIL_ATTACHMENT:
218 return getDepthStencilBuffer();
219 default:
220 UNREACHABLE();
221 return NULL;
222 }
223 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400224}
225
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000226GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
227{
228 return mDrawBufferStates[colorAttachment];
229}
230
231void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
232{
233 mDrawBufferStates[colorAttachment] = drawBuffer;
234}
235
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000236bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
237{
Jamie Madille261b442014-06-25 12:42:21 -0400238 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000239}
240
241bool Framebuffer::hasEnabledColorAttachment() const
242{
243 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
244 {
245 if (isEnabledColorAttachment(colorAttachment))
246 {
247 return true;
248 }
249 }
250
251 return false;
252}
253
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000254bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000255{
Geoff Lange4a492b2014-06-19 14:14:41 -0400256 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000257}
258
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000259bool Framebuffer::usingExtendedDrawBuffers() const
260{
261 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
262 {
263 if (isEnabledColorAttachment(colorAttachment))
264 {
265 return true;
266 }
267 }
268
269 return false;
270}
271
Jamie Madill48faf802014-11-06 15:27:22 -0500272GLenum Framebuffer::completeness(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274 int width = 0;
275 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000276 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000277 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000278 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000280 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281 {
Jamie Madillbb94f342014-06-23 15:23:02 -0400282 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
283
284 if (colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000286 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000287 {
288 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
289 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000290
Geoff Langcec35902014-04-16 10:52:36 -0400291 GLenum internalformat = colorbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500292 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400293 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400294 if (colorbuffer->isTexture())
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000295 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400296 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000297 {
298 return GL_FRAMEBUFFER_UNSUPPORTED;
299 }
300
Geoff Lang5d601382014-07-22 15:14:06 -0400301 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000302 {
303 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
304 }
305 }
306 else
307 {
Geoff Lang5d601382014-07-22 15:14:06 -0400308 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400309 {
310 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
311 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000312 }
313
314 if (!missingAttachment)
315 {
316 // all color attachments must have the same width and height
317 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
318 {
319 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
320 }
321
322 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
323 // all color attachments have the same number of samples for the FBO to be complete.
324 if (colorbuffer->getSamples() != samples)
325 {
326 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
327 }
328
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000329 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
330 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500331 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000332 {
Geoff Lang5d601382014-07-22 15:14:06 -0400333 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000334 {
335 return GL_FRAMEBUFFER_UNSUPPORTED;
336 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000337 }
338
339 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
340 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
341 {
Jamie Madille92a3542014-07-03 10:38:58 -0400342 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
343
344 if (previousAttachment &&
345 (colorbuffer->id() == previousAttachment->id() &&
346 colorbuffer->type() == previousAttachment->type()))
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000347 {
348 return GL_FRAMEBUFFER_UNSUPPORTED;
349 }
350 }
351 }
352 else
353 {
354 width = colorbuffer->getWidth();
355 height = colorbuffer->getHeight();
356 samples = colorbuffer->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400357 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000358 missingAttachment = false;
359 }
360 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000361 }
362
Jamie Madille261b442014-06-25 12:42:21 -0400363 if (mDepthbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000364 {
Jamie Madille261b442014-06-25 12:42:21 -0400365 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000366 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000367 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368 }
369
Jamie Madille261b442014-06-25 12:42:21 -0400370 GLenum internalformat = mDepthbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500371 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400372 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400373 if (mDepthbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000374 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000375 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500376 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000377 {
378 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
379 }
380
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400381 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400382 {
383 return GL_FRAMEBUFFER_UNSUPPORTED;
384 }
385
Geoff Lang5d601382014-07-22 15:14:06 -0400386 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000387 {
388 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
389 }
390 }
391 else
392 {
Geoff Lang5d601382014-07-22 15:14:06 -0400393 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400394 {
395 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
396 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000397 }
398
399 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000400 {
Jamie Madille261b442014-06-25 12:42:21 -0400401 width = mDepthbuffer->getWidth();
402 height = mDepthbuffer->getHeight();
403 samples = mDepthbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000404 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000405 }
Jamie Madille261b442014-06-25 12:42:21 -0400406 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000407 {
408 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
409 }
Jamie Madille261b442014-06-25 12:42:21 -0400410 else if (samples != mDepthbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000411 {
412 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
413 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000414 }
415
Jamie Madille261b442014-06-25 12:42:21 -0400416 if (mStencilbuffer)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000417 {
Jamie Madille261b442014-06-25 12:42:21 -0400418 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000419 {
420 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
421 }
422
Jamie Madille261b442014-06-25 12:42:21 -0400423 GLenum internalformat = mStencilbuffer->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500424 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400425 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madillbb94f342014-06-23 15:23:02 -0400426 if (mStencilbuffer->isTexture())
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000427 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000428 // texture stencil attachments come along as part
429 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500430 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000431 {
432 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
433 }
434
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400435 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400436 {
437 return GL_FRAMEBUFFER_UNSUPPORTED;
438 }
439
Geoff Lang5d601382014-07-22 15:14:06 -0400440 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000441 {
442 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
443 }
444 }
445 else
446 {
Geoff Lang5d601382014-07-22 15:14:06 -0400447 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400448 {
449 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
450 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000451 }
452
453 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000454 {
Jamie Madille261b442014-06-25 12:42:21 -0400455 width = mStencilbuffer->getWidth();
456 height = mStencilbuffer->getHeight();
457 samples = mStencilbuffer->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000458 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000459 }
Jamie Madille261b442014-06-25 12:42:21 -0400460 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000461 {
462 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
463 }
Jamie Madille261b442014-06-25 12:42:21 -0400464 else if (samples != mStencilbuffer->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000465 {
466 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
467 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000468 }
469
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000470 // if we have both a depth and stencil buffer, they must refer to the same object
471 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madille261b442014-06-25 12:42:21 -0400472 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000473 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000474 return GL_FRAMEBUFFER_UNSUPPORTED;
475 }
476
477 // we need to have at least one attachment to be complete
478 if (missingAttachment)
479 {
480 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000481 }
482
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000483 return GL_FRAMEBUFFER_COMPLETE;
484}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000485
Geoff Lang64f23f62014-09-10 14:40:12 -0400486Error Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400487{
488 GLuint maxDimension = caps.maxRenderbufferSize;
Geoff Lang64f23f62014-09-10 14:40:12 -0400489 return invalidateSub(numAttachments, attachments, 0, 0, maxDimension, maxDimension);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400490}
491
Geoff Lang64f23f62014-09-10 14:40:12 -0400492Error Framebuffer::invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
Jamie Madill400a4412014-08-29 15:46:45 -0400493{
Jamie Madill6d708262014-09-03 15:07:13 -0400494 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
Jamie Madill400a4412014-08-29 15:46:45 -0400495 {
Jamie Madill6d708262014-09-03 15:07:13 -0400496 GLenum attachmentTarget = attachments[attachIndex];
Jamie Madill400a4412014-08-29 15:46:45 -0400497
Geoff Lang64f23f62014-09-10 14:40:12 -0400498 FramebufferAttachment *attachment = (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer()
499 : getAttachment(attachmentTarget);
Jamie Madill400a4412014-08-29 15:46:45 -0400500
Jamie Madill6d708262014-09-03 15:07:13 -0400501 if (attachment)
Jamie Madill400a4412014-08-29 15:46:45 -0400502 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400503 rx::RenderTarget *renderTarget = NULL;
504 Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget);
505 if (error.isError())
Jamie Madill6d708262014-09-03 15:07:13 -0400506 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400507 return error;
Jamie Madill6d708262014-09-03 15:07:13 -0400508 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400509
510 renderTarget->invalidate(x, y, width, height);
Jamie Madill400a4412014-08-29 15:46:45 -0400511 }
512 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400513
514 return Error(GL_NO_ERROR);
Jamie Madill400a4412014-08-29 15:46:45 -0400515}
516
Jamie Madill48faf802014-11-06 15:27:22 -0500517DefaultFramebuffer::DefaultFramebuffer(rx::RenderbufferImpl *colorbuffer, rx::RenderbufferImpl *depthStencil)
518 : Framebuffer(0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000519{
Shannon Woodse2632d22014-10-17 13:08:51 -0400520 Renderbuffer *colorRenderbuffer = new Renderbuffer(colorbuffer, 0);
Jamie Madillaef95de2014-09-05 10:12:41 -0400521 mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000522
Shannon Woodse2632d22014-10-17 13:08:51 -0400523 Renderbuffer *depthStencilBuffer = new Renderbuffer(depthStencil, 0);
Jamie Madill28bedaf2014-06-26 13:17:22 -0400524
525 // Make a new attachment objects to ensure we do not double-delete
526 // See angle issue 686
Jamie Madillaef95de2014-09-05 10:12:41 -0400527 mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL);
528 mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000529
530 mDrawBufferStates[0] = GL_BACK;
531 mReadBufferState = GL_BACK;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000532}
533
Jamie Madill48faf802014-11-06 15:27:22 -0500534int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000535{
Jamie Madill48faf802014-11-06 15:27:22 -0500536 if (completeness(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000537 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000538 // for a complete framebuffer, all attachments must have the same sample count
539 // in this case return the first nonzero sample size
540 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
541 {
Jamie Madille261b442014-06-25 12:42:21 -0400542 if (mColorbuffers[colorAttachment])
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000543 {
Jamie Madille261b442014-06-25 12:42:21 -0400544 return mColorbuffers[colorAttachment]->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000545 }
546 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000547 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000548
549 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000550}
551
Jamie Madille261b442014-06-25 12:42:21 -0400552bool Framebuffer::hasValidDepthStencil() const
553{
554 // A valid depth-stencil attachment has the same resource bound to both the
555 // depth and stencil attachment points.
556 return (mDepthbuffer && mStencilbuffer &&
557 mDepthbuffer->type() == mStencilbuffer->type() &&
558 mDepthbuffer->id() == mStencilbuffer->id());
559}
560
Jamie Madill48faf802014-11-06 15:27:22 -0500561ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400562{
563 ColorbufferInfo colorbuffersForRender;
564
565 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
566 {
567 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
568 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
569
570 if (colorbuffer != NULL && drawBufferState != GL_NONE)
571 {
572 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
573 colorbuffersForRender.push_back(colorbuffer);
574 }
Jamie Madill48faf802014-11-06 15:27:22 -0500575 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400576 {
577 colorbuffersForRender.push_back(NULL);
578 }
579 }
580
581 return colorbuffersForRender;
582}
583
Geoff Langab75a052014-10-15 12:56:37 -0400584void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
585{
586 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
587}
588
589void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
590{
591 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
592}
593
594void Framebuffer::setNULLAttachment(GLenum attachment)
595{
596 setAttachment(attachment, NULL);
597}
598
599void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
600{
601 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS))
602 {
603 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
604 SafeDelete(mColorbuffers[colorAttachment]);
605 mColorbuffers[colorAttachment] = attachmentObj;
606 }
607 else if (attachment == GL_DEPTH_ATTACHMENT)
608 {
609 SafeDelete(mDepthbuffer);
610 mDepthbuffer = attachmentObj;
611 }
612 else if (attachment == GL_STENCIL_ATTACHMENT)
613 {
614 SafeDelete(mStencilbuffer);
615 mStencilbuffer = attachmentObj;
616 }
617 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
618 {
619 SafeDelete(mDepthbuffer);
620 SafeDelete(mStencilbuffer);
621
622 // ensure this is a legitimate depth+stencil format
623 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
624 {
625 mDepthbuffer = attachmentObj;
626
627 // Make a new attachment object to ensure we do not double-delete
628 // See angle issue 686
629 if (attachmentObj->isTexture())
630 {
631 mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
632 *attachmentObj->getTextureImageIndex());
633 }
634 else
635 {
636 mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
637 }
638 }
639 }
640 else
641 {
642 UNREACHABLE();
643 }
644}
645
Jamie Madill48faf802014-11-06 15:27:22 -0500646GLenum DefaultFramebuffer::completeness(const gl::Data &) const
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000647{
shannon.woods@transgaming.com3e3da582013-02-28 23:09:03 +0000648 // The default framebuffer *must* always be complete, though it may not be
649 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000650 return GL_FRAMEBUFFER_COMPLETE;
651}
652
Jamie Madille92a3542014-07-03 10:38:58 -0400653FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
654{
655 switch (attachment)
656 {
Jamie Madill6d708262014-09-03 15:07:13 -0400657 case GL_COLOR:
Jamie Madille92a3542014-07-03 10:38:58 -0400658 case GL_BACK:
659 return getColorbuffer(0);
660 case GL_DEPTH:
661 return getDepthbuffer();
662 case GL_STENCIL:
663 return getStencilbuffer();
664 case GL_DEPTH_STENCIL:
665 return getDepthStencilBuffer();
666 default:
667 UNREACHABLE();
668 return NULL;
669 }
670}
671
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000672}