blob: e7afb0a59c31c4bdbf57929bce1870bffba76dfa [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"
Geoff Langb5d8f232014-12-04 15:43:01 -050016#include "libANGLE/renderer/FramebufferImpl.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050017#include "libANGLE/renderer/Renderer.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050018#include "libANGLE/renderer/RenderbufferImpl.h"
19#include "libANGLE/renderer/Workarounds.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "common/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000022
23namespace gl
24{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000025
Jamie Madilld1405e52015-03-05 15:41:39 -050026namespace
27{
28void DeleteMatchingAttachment(FramebufferAttachment *&attachment, GLenum matchType, GLuint matchId)
29{
30 if (attachment && attachment->type() == matchType && attachment->id() == matchId)
31 {
32 SafeDelete(attachment);
33 }
34}
35}
36
37Framebuffer::Data::Data(const Caps &caps)
38 : mColorAttachments(caps.maxColorAttachments, nullptr),
39 mDepthAttachment(nullptr),
40 mStencilAttachment(nullptr),
41 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
42 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
43{
44 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
45}
46
47Framebuffer::Data::~Data()
48{
49 for (auto &colorAttachment : mColorAttachments)
50 {
51 SafeDelete(colorAttachment);
52 }
53 SafeDelete(mDepthAttachment);
54 SafeDelete(mStencilAttachment);
55}
56
57Framebuffer::Framebuffer(const Caps &caps, rx::Renderer *renderer, GLuint id)
58 : mData(caps),
59 mImpl(renderer->createFramebuffer(mData)),
60 mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061{
Geoff Langda88add2014-12-01 10:22:01 -050062 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000063}
64
65Framebuffer::~Framebuffer()
66{
Geoff Langda88add2014-12-01 10:22:01 -050067 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000068}
69
Jamie Madille261b442014-06-25 12:42:21 -040070void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000071{
Jamie Madilld1405e52015-03-05 15:41:39 -050072 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000073}
74
Jamie Madille261b442014-06-25 12:42:21 -040075void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000076{
Jamie Madilld1405e52015-03-05 15:41:39 -050077 detachResourceById(GL_RENDERBUFFER, renderbufferId);
78}
Jamie Madille261b442014-06-25 12:42:21 -040079
Jamie Madilld1405e52015-03-05 15:41:39 -050080void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
81{
82 for (auto &colorAttachment : mData.mColorAttachments)
83 {
84 DeleteMatchingAttachment(colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000085 }
86
Jamie Madilld1405e52015-03-05 15:41:39 -050087 DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId);
88 DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000089}
90
Jamie Madill3c7fa222014-06-05 13:08:51 -040091FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000092{
Jamie Madilld1405e52015-03-05 15:41:39 -050093 ASSERT(colorAttachment < mData.mColorAttachments.size());
94 return mData.mColorAttachments[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +000095}
96
Jamie Madill3c7fa222014-06-05 13:08:51 -040097FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000098{
Jamie Madilld1405e52015-03-05 15:41:39 -050099 return mData.mDepthAttachment;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100}
101
Jamie Madill3c7fa222014-06-05 13:08:51 -0400102FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000103{
Jamie Madilld1405e52015-03-05 15:41:39 -0500104 return mData.mStencilAttachment;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000105}
106
Jamie Madill3c7fa222014-06-05 13:08:51 -0400107FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400108{
Jamie Madilld1405e52015-03-05 15:41:39 -0500109 return (hasValidDepthStencil() ? mData.mDepthAttachment : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400110}
111
Jamie Madill3c7fa222014-06-05 13:08:51 -0400112FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000113{
Jamie Madilld1405e52015-03-05 15:41:39 -0500114 return (mData.mDepthAttachment != nullptr ? mData.mDepthAttachment : mData.mStencilAttachment);
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000115}
116
Jamie Madill3c7fa222014-06-05 13:08:51 -0400117FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000118{
Jamie Madilld1405e52015-03-05 15:41:39 -0500119 size_t readIndex = (mData.mReadBufferState == GL_BACK ? 0 :
120 static_cast<size_t>(mData.mReadBufferState - GL_COLOR_ATTACHMENT0));
121 ASSERT(readIndex < mData.mColorAttachments.size());
122 return mData.mColorAttachments[readIndex];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000123}
124
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000125GLenum Framebuffer::getReadColorbufferType() const
126{
Jamie Madillb885e572015-02-03 16:16:04 -0500127 FramebufferAttachment *readAttachment = getReadColorbuffer();
128 return (readAttachment ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000129}
130
Jamie Madill3c7fa222014-06-05 13:08:51 -0400131FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000132{
Jamie Madilld1405e52015-03-05 15:41:39 -0500133 for (FramebufferAttachment *colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000134 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500135 if (colorAttachment != nullptr)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000136 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500137 return colorAttachment;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000138 }
139 }
140
Jamie Madilld1405e52015-03-05 15:41:39 -0500141 return nullptr;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000142}
143
Jamie Madille92a3542014-07-03 10:38:58 -0400144FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000145{
Jamie Madille92a3542014-07-03 10:38:58 -0400146 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
147 {
148 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
149 }
150 else
151 {
152 switch (attachment)
153 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500154 case GL_COLOR:
155 case GL_BACK:
156 return getColorbuffer(0);
157 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400158 case GL_DEPTH_ATTACHMENT:
159 return getDepthbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500160 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400161 case GL_STENCIL_ATTACHMENT:
162 return getStencilbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500163 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400164 case GL_DEPTH_STENCIL_ATTACHMENT:
165 return getDepthStencilBuffer();
166 default:
167 UNREACHABLE();
168 return NULL;
169 }
170 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400171}
172
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000173GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
174{
Jamie Madilld1405e52015-03-05 15:41:39 -0500175 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
176 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000177}
178
Geoff Lang164d54e2014-12-01 10:55:33 -0500179void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000180{
Jamie Madilld1405e52015-03-05 15:41:39 -0500181 auto &drawStates = mData.mDrawBufferStates;
182
183 ASSERT(count <= drawStates.size());
184 std::copy(buffers, buffers + count, drawStates.begin());
185 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500186 mImpl->setDrawBuffers(count, buffers);
187}
188
189GLenum Framebuffer::getReadBufferState() const
190{
Jamie Madilld1405e52015-03-05 15:41:39 -0500191 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500192}
193
194void Framebuffer::setReadBuffer(GLenum buffer)
195{
Jamie Madillb885e572015-02-03 16:16:04 -0500196 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
197 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500198 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
199 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500200 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000201}
202
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000203bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
204{
Jamie Madilld1405e52015-03-05 15:41:39 -0500205 ASSERT(colorAttachment < mData.mColorAttachments.size());
206 return (mData.mColorAttachments[colorAttachment] &&
207 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000208}
209
210bool Framebuffer::hasEnabledColorAttachment() const
211{
Jamie Madilld1405e52015-03-05 15:41:39 -0500212 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000213 {
214 if (isEnabledColorAttachment(colorAttachment))
215 {
216 return true;
217 }
218 }
219
220 return false;
221}
222
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000223bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000224{
Jamie Madilld1405e52015-03-05 15:41:39 -0500225 return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000226}
227
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000228bool Framebuffer::usingExtendedDrawBuffers() const
229{
Jamie Madilld1405e52015-03-05 15:41:39 -0500230 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000231 {
232 if (isEnabledColorAttachment(colorAttachment))
233 {
234 return true;
235 }
236 }
237
238 return false;
239}
240
Geoff Lang748f74e2014-12-01 11:25:34 -0500241GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500243 // The default framebuffer *must* always be complete, though it may not be
244 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
245 if (mId == 0)
246 {
247 return GL_FRAMEBUFFER_COMPLETE;
248 }
249
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250 int width = 0;
251 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000252 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000253 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000254 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255
Jamie Madilld1405e52015-03-05 15:41:39 -0500256 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500258 if (colorAttachment != nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500260 if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000261 {
262 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
263 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000264
Jamie Madilld1405e52015-03-05 15:41:39 -0500265 GLenum internalformat = colorAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500266 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400267 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500268 if (colorAttachment->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000269 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400270 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000271 {
272 return GL_FRAMEBUFFER_UNSUPPORTED;
273 }
274
Geoff Lang5d601382014-07-22 15:14:06 -0400275 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000276 {
277 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
278 }
279 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500280 else if (colorAttachment->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000281 {
Geoff Lang5d601382014-07-22 15:14:06 -0400282 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400283 {
284 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
285 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000286 }
287
288 if (!missingAttachment)
289 {
290 // all color attachments must have the same width and height
Jamie Madilld1405e52015-03-05 15:41:39 -0500291 if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000292 {
293 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
294 }
295
296 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
297 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madilld1405e52015-03-05 15:41:39 -0500298 if (colorAttachment->getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000299 {
300 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
301 }
302
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000303 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
304 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500305 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000306 {
Geoff Lang5d601382014-07-22 15:14:06 -0400307 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000308 {
309 return GL_FRAMEBUFFER_UNSUPPORTED;
310 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000311 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000312 }
313 else
314 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500315 width = colorAttachment->getWidth();
316 height = colorAttachment->getHeight();
317 samples = colorAttachment->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400318 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000319 missingAttachment = false;
320 }
321 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000322 }
323
Jamie Madilld1405e52015-03-05 15:41:39 -0500324 const FramebufferAttachment *depthAttachment = mData.mDepthAttachment;
325 if (depthAttachment != nullptr)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000326 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500327 if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000329 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330 }
331
Jamie Madilld1405e52015-03-05 15:41:39 -0500332 GLenum internalformat = depthAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500333 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400334 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500335 if (depthAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000336 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000337 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500338 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000339 {
340 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
341 }
342
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400343 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400344 {
345 return GL_FRAMEBUFFER_UNSUPPORTED;
346 }
347
Geoff Lang5d601382014-07-22 15:14:06 -0400348 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000349 {
350 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
351 }
352 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500353 else if (depthAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000354 {
Geoff Lang5d601382014-07-22 15:14:06 -0400355 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400356 {
357 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
358 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000359 }
360
361 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000362 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500363 width = depthAttachment->getWidth();
364 height = depthAttachment->getHeight();
365 samples = depthAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000366 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000367 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500368 else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000369 {
370 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
371 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500372 else if (samples != depthAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000373 {
374 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
375 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000376 }
377
Jamie Madilld1405e52015-03-05 15:41:39 -0500378 const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment;
379 if (stencilAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000380 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500381 if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000382 {
383 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
384 }
385
Jamie Madilld1405e52015-03-05 15:41:39 -0500386 GLenum internalformat = stencilAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500387 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400388 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500389 if (stencilAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000390 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000391 // texture stencil attachments come along as part
392 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500393 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000394 {
395 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
396 }
397
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400398 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400399 {
400 return GL_FRAMEBUFFER_UNSUPPORTED;
401 }
402
Geoff Lang5d601382014-07-22 15:14:06 -0400403 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000404 {
405 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
406 }
407 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500408 else if (stencilAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000409 {
Geoff Lang5d601382014-07-22 15:14:06 -0400410 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400411 {
412 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
413 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000414 }
415
416 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000417 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500418 width = stencilAttachment->getWidth();
419 height = stencilAttachment->getHeight();
420 samples = stencilAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000421 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000422 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500423 else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000424 {
425 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
426 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500427 else if (samples != stencilAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000428 {
429 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
430 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000431 }
432
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000433 // if we have both a depth and stencil buffer, they must refer to the same object
434 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madilld1405e52015-03-05 15:41:39 -0500435 if (depthAttachment && stencilAttachment && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000436 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000437 return GL_FRAMEBUFFER_UNSUPPORTED;
438 }
439
440 // we need to have at least one attachment to be complete
441 if (missingAttachment)
442 {
443 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000444 }
445
Geoff Lang748f74e2014-12-01 11:25:34 -0500446 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000448
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500449Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400450{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500451 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400452}
453
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500454Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400455{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500456 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400457}
458
Geoff Langb04dc822014-12-01 12:02:02 -0500459Error Framebuffer::clear(const State &state, GLbitfield mask)
460{
461 return mImpl->clear(state, mask);
462}
463
464Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
465{
466 return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
467}
468
469Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
470{
471 return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
472}
473
474Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
475{
476 return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
477}
478
479Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
480{
481 return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
482}
483
Geoff Langbce529e2014-12-01 12:48:41 -0500484GLenum Framebuffer::getImplementationColorReadFormat() const
485{
486 return mImpl->getImplementationColorReadFormat();
487}
488
489GLenum Framebuffer::getImplementationColorReadType() const
490{
491 return mImpl->getImplementationColorReadType();
492}
493
494Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
495{
496 return mImpl->readPixels(state, area, format, type, pixels);
497}
498
Geoff Lang54bd5a42014-12-01 12:51:04 -0500499Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
500 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
501{
502 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
503}
504
Jamie Madill48faf802014-11-06 15:27:22 -0500505int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000506{
Geoff Lang748f74e2014-12-01 11:25:34 -0500507 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000508 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000509 // for a complete framebuffer, all attachments must have the same sample count
510 // in this case return the first nonzero sample size
Jamie Madilld1405e52015-03-05 15:41:39 -0500511 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000512 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500513 if (colorAttachment != nullptr)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000514 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500515 return colorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000516 }
517 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000518 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000519
520 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000521}
522
Jamie Madille261b442014-06-25 12:42:21 -0400523bool Framebuffer::hasValidDepthStencil() const
524{
525 // A valid depth-stencil attachment has the same resource bound to both the
526 // depth and stencil attachment points.
Jamie Madilld1405e52015-03-05 15:41:39 -0500527 return (mData.mDepthAttachment && mData.mStencilAttachment &&
528 mData.mDepthAttachment->type() == mData.mStencilAttachment->type() &&
529 mData.mDepthAttachment->id() == mData.mStencilAttachment->id());
Jamie Madille261b442014-06-25 12:42:21 -0400530}
531
Jamie Madill48faf802014-11-06 15:27:22 -0500532ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const
Jamie Madillce20c7f2014-09-03 11:56:29 -0400533{
534 ColorbufferInfo colorbuffersForRender;
535
Jamie Madilld1405e52015-03-05 15:41:39 -0500536 for (size_t attachmentIndex = 0; attachmentIndex < mData.mColorAttachments.size(); ++attachmentIndex)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400537 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500538 GLenum drawBufferState = mData.mDrawBufferStates[attachmentIndex];
539 FramebufferAttachment *colorAttachment = mData.mColorAttachments[attachmentIndex];
Jamie Madillce20c7f2014-09-03 11:56:29 -0400540
Jamie Madilld1405e52015-03-05 15:41:39 -0500541 if (colorAttachment != nullptr && drawBufferState != GL_NONE)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400542 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500543 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex));
544 colorbuffersForRender.push_back(colorAttachment);
Jamie Madillce20c7f2014-09-03 11:56:29 -0400545 }
Jamie Madill48faf802014-11-06 15:27:22 -0500546 else if (!workarounds.mrtPerfWorkaround)
Jamie Madillce20c7f2014-09-03 11:56:29 -0400547 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500548 colorbuffersForRender.push_back(nullptr);
Jamie Madillce20c7f2014-09-03 11:56:29 -0400549 }
550 }
551
552 return colorbuffersForRender;
553}
554
Geoff Langab75a052014-10-15 12:56:37 -0400555void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
556{
557 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
558}
559
560void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
561{
562 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
563}
564
565void Framebuffer::setNULLAttachment(GLenum attachment)
566{
567 setAttachment(attachment, NULL);
568}
569
570void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
571{
Jamie Madilld1405e52015-03-05 15:41:39 -0500572 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size()))
Geoff Langab75a052014-10-15 12:56:37 -0400573 {
574 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
Jamie Madilld1405e52015-03-05 15:41:39 -0500575 SafeDelete(mData.mColorAttachments[colorAttachment]);
576 mData.mColorAttachments[colorAttachment] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500577 mImpl->setColorAttachment(colorAttachment, attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400578 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500579 else if (attachment == GL_BACK)
580 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500581 SafeDelete(mData.mColorAttachments[0]);
582 mData.mColorAttachments[0] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500583 mImpl->setColorAttachment(0, attachmentObj);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500584 }
585 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400586 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500587 SafeDelete(mData.mDepthAttachment);
588 mData.mDepthAttachment = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500589 mImpl->setDepthttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400590 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500591 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400592 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500593 SafeDelete(mData.mStencilAttachment);
594 mData.mStencilAttachment = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500595 mImpl->setStencilAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400596 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500597 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400598 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500599 SafeDelete(mData.mDepthAttachment);
600 SafeDelete(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400601
602 // ensure this is a legitimate depth+stencil format
603 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
604 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500605 mData.mDepthAttachment = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500606 mImpl->setDepthttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400607
608 // Make a new attachment object to ensure we do not double-delete
609 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500610 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400611 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500612 mData.mStencilAttachment = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
613 *attachmentObj->getTextureImageIndex());
614 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400615 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500616 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400617 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500618 mData.mStencilAttachment = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
619 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400620 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500621 else
622 {
623 UNREACHABLE();
624 }
Geoff Langab75a052014-10-15 12:56:37 -0400625 }
626 }
627 else
628 {
629 UNREACHABLE();
630 }
631}
632
Jamie Madilld1405e52015-03-05 15:41:39 -0500633DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::Renderer *renderer, egl::Surface *surface)
634 : Framebuffer(caps, renderer, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000635{
Jamie Madilld1405e52015-03-05 15:41:39 -0500636 rx::DefaultAttachmentImpl *colorAttachment = renderer->createDefaultAttachment(GL_BACK, surface);
637 rx::DefaultAttachmentImpl *depthAttachment = renderer->createDefaultAttachment(GL_DEPTH, surface);
638 rx::DefaultAttachmentImpl *stencilAttachment = renderer->createDefaultAttachment(GL_STENCIL, surface);
639
Geoff Lang528ce3c2014-12-01 10:44:07 -0500640 ASSERT(colorAttachment);
641 setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, colorAttachment));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000642
Geoff Lang528ce3c2014-12-01 10:44:07 -0500643 if (depthAttachment)
Jamie Madille92a3542014-07-03 10:38:58 -0400644 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500645 setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, depthAttachment));
Jamie Madille92a3542014-07-03 10:38:58 -0400646 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500647 if (stencilAttachment)
648 {
649 setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, stencilAttachment));
650 }
651
Geoff Lang9dd95802014-12-01 11:12:59 -0500652 GLenum drawBufferState = GL_BACK;
653 setDrawBuffers(1, &drawBufferState);
654
655 setReadBuffer(GL_BACK);
Jamie Madille92a3542014-07-03 10:38:58 -0400656}
657
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658}