blob: fb7a2de2e73c515754da73fcc5e3a59c75d276fc [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"
Jamie Madill48115b62015-03-16 10:46:57 -040017#include "libANGLE/renderer/ImplFactory.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
Jamie Madill7147f012015-03-05 15:41:40 -050057FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
58{
59 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
60 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
61 ASSERT(readIndex < mColorAttachments.size());
62 return mColorAttachments[readIndex];
63}
64
65FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
66{
67 for (FramebufferAttachment *colorAttachment : mColorAttachments)
68 {
69 if (colorAttachment != nullptr)
70 {
71 return colorAttachment;
72 }
73 }
74
75 return nullptr;
76}
77
78FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
79{
80 return (mDepthAttachment != nullptr ? mDepthAttachment : mStencilAttachment);
81}
82
Jamie Madill48115b62015-03-16 10:46:57 -040083Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
Jamie Madilld1405e52015-03-05 15:41:39 -050084 : mData(caps),
Jamie Madill48115b62015-03-16 10:46:57 -040085 mImpl(factory->createFramebuffer(mData)),
Jamie Madilld1405e52015-03-05 15:41:39 -050086 mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087{
Geoff Langda88add2014-12-01 10:22:01 -050088 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000089}
90
91Framebuffer::~Framebuffer()
92{
Geoff Langda88add2014-12-01 10:22:01 -050093 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000094}
95
Jamie Madille261b442014-06-25 12:42:21 -040096void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000097{
Jamie Madilld1405e52015-03-05 15:41:39 -050098 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000099}
100
Jamie Madille261b442014-06-25 12:42:21 -0400101void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000102{
Jamie Madilld1405e52015-03-05 15:41:39 -0500103 detachResourceById(GL_RENDERBUFFER, renderbufferId);
104}
Jamie Madille261b442014-06-25 12:42:21 -0400105
Jamie Madilld1405e52015-03-05 15:41:39 -0500106void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
107{
108 for (auto &colorAttachment : mData.mColorAttachments)
109 {
110 DeleteMatchingAttachment(colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000111 }
112
Jamie Madilld1405e52015-03-05 15:41:39 -0500113 DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId);
114 DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115}
116
Jamie Madill3c7fa222014-06-05 13:08:51 -0400117FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000118{
Jamie Madilld1405e52015-03-05 15:41:39 -0500119 ASSERT(colorAttachment < mData.mColorAttachments.size());
120 return mData.mColorAttachments[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000121}
122
Jamie Madill3c7fa222014-06-05 13:08:51 -0400123FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124{
Jamie Madilld1405e52015-03-05 15:41:39 -0500125 return mData.mDepthAttachment;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000126}
127
Jamie Madill3c7fa222014-06-05 13:08:51 -0400128FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000129{
Jamie Madilld1405e52015-03-05 15:41:39 -0500130 return mData.mStencilAttachment;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131}
132
Jamie Madill3c7fa222014-06-05 13:08:51 -0400133FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400134{
Jamie Madilld1405e52015-03-05 15:41:39 -0500135 return (hasValidDepthStencil() ? mData.mDepthAttachment : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400136}
137
Jamie Madill3c7fa222014-06-05 13:08:51 -0400138FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000139{
Jamie Madill7147f012015-03-05 15:41:40 -0500140 return mData.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000141}
142
Jamie Madill3c7fa222014-06-05 13:08:51 -0400143FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000144{
Jamie Madill7147f012015-03-05 15:41:40 -0500145 return mData.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000146}
147
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000148GLenum Framebuffer::getReadColorbufferType() const
149{
Jamie Madill7147f012015-03-05 15:41:40 -0500150 FramebufferAttachment *readAttachment = mData.getReadAttachment();
Jamie Madillb885e572015-02-03 16:16:04 -0500151 return (readAttachment ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000152}
153
Jamie Madill3c7fa222014-06-05 13:08:51 -0400154FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000155{
Jamie Madill7147f012015-03-05 15:41:40 -0500156 return mData.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000157}
158
Jamie Madille92a3542014-07-03 10:38:58 -0400159FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000160{
Jamie Madille92a3542014-07-03 10:38:58 -0400161 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
162 {
163 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
164 }
165 else
166 {
167 switch (attachment)
168 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500169 case GL_COLOR:
170 case GL_BACK:
171 return getColorbuffer(0);
172 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400173 case GL_DEPTH_ATTACHMENT:
174 return getDepthbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500175 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400176 case GL_STENCIL_ATTACHMENT:
177 return getStencilbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500178 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400179 case GL_DEPTH_STENCIL_ATTACHMENT:
180 return getDepthStencilBuffer();
181 default:
182 UNREACHABLE();
183 return NULL;
184 }
185 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400186}
187
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000188GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
189{
Jamie Madilld1405e52015-03-05 15:41:39 -0500190 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
191 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000192}
193
Geoff Lang164d54e2014-12-01 10:55:33 -0500194void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000195{
Jamie Madilld1405e52015-03-05 15:41:39 -0500196 auto &drawStates = mData.mDrawBufferStates;
197
198 ASSERT(count <= drawStates.size());
199 std::copy(buffers, buffers + count, drawStates.begin());
200 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500201 mImpl->setDrawBuffers(count, buffers);
202}
203
204GLenum Framebuffer::getReadBufferState() const
205{
Jamie Madilld1405e52015-03-05 15:41:39 -0500206 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500207}
208
209void Framebuffer::setReadBuffer(GLenum buffer)
210{
Jamie Madillb885e572015-02-03 16:16:04 -0500211 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
212 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500213 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
214 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500215 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000216}
217
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000218bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
219{
Jamie Madilld1405e52015-03-05 15:41:39 -0500220 ASSERT(colorAttachment < mData.mColorAttachments.size());
221 return (mData.mColorAttachments[colorAttachment] &&
222 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000223}
224
225bool Framebuffer::hasEnabledColorAttachment() const
226{
Jamie Madilld1405e52015-03-05 15:41:39 -0500227 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000228 {
229 if (isEnabledColorAttachment(colorAttachment))
230 {
231 return true;
232 }
233 }
234
235 return false;
236}
237
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000238bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000239{
Jamie Madilld1405e52015-03-05 15:41:39 -0500240 return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000241}
242
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000243bool Framebuffer::usingExtendedDrawBuffers() const
244{
Jamie Madilld1405e52015-03-05 15:41:39 -0500245 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000246 {
247 if (isEnabledColorAttachment(colorAttachment))
248 {
249 return true;
250 }
251 }
252
253 return false;
254}
255
Geoff Lang748f74e2014-12-01 11:25:34 -0500256GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500258 // The default framebuffer *must* always be complete, though it may not be
259 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
260 if (mId == 0)
261 {
262 return GL_FRAMEBUFFER_COMPLETE;
263 }
264
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265 int width = 0;
266 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000267 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000268 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000269 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270
Jamie Madilld1405e52015-03-05 15:41:39 -0500271 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500273 if (colorAttachment != nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500275 if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000276 {
277 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
278 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000279
Jamie Madilld1405e52015-03-05 15:41:39 -0500280 GLenum internalformat = colorAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500281 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400282 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500283 if (colorAttachment->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000284 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400285 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000286 {
287 return GL_FRAMEBUFFER_UNSUPPORTED;
288 }
289
Geoff Lang5d601382014-07-22 15:14:06 -0400290 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000291 {
292 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
293 }
294 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500295 else if (colorAttachment->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000296 {
Geoff Lang5d601382014-07-22 15:14:06 -0400297 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400298 {
299 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
300 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000301 }
302
303 if (!missingAttachment)
304 {
305 // all color attachments must have the same width and height
Jamie Madilld1405e52015-03-05 15:41:39 -0500306 if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000307 {
308 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
309 }
310
311 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
312 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madilld1405e52015-03-05 15:41:39 -0500313 if (colorAttachment->getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000314 {
315 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
316 }
317
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000318 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
319 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500320 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000321 {
Geoff Lang5d601382014-07-22 15:14:06 -0400322 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000323 {
324 return GL_FRAMEBUFFER_UNSUPPORTED;
325 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000326 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000327 }
328 else
329 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500330 width = colorAttachment->getWidth();
331 height = colorAttachment->getHeight();
332 samples = colorAttachment->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400333 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000334 missingAttachment = false;
335 }
336 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000337 }
338
Jamie Madilld1405e52015-03-05 15:41:39 -0500339 const FramebufferAttachment *depthAttachment = mData.mDepthAttachment;
340 if (depthAttachment != nullptr)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000341 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500342 if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000344 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345 }
346
Jamie Madilld1405e52015-03-05 15:41:39 -0500347 GLenum internalformat = depthAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500348 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400349 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500350 if (depthAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000351 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000352 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500353 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000354 {
355 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
356 }
357
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400358 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400359 {
360 return GL_FRAMEBUFFER_UNSUPPORTED;
361 }
362
Geoff Lang5d601382014-07-22 15:14:06 -0400363 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000364 {
365 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
366 }
367 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500368 else if (depthAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000369 {
Geoff Lang5d601382014-07-22 15:14:06 -0400370 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400371 {
372 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
373 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000374 }
375
376 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000377 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500378 width = depthAttachment->getWidth();
379 height = depthAttachment->getHeight();
380 samples = depthAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000381 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000382 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500383 else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000384 {
385 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
386 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500387 else if (samples != depthAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000388 {
389 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
390 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000391 }
392
Jamie Madilld1405e52015-03-05 15:41:39 -0500393 const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment;
394 if (stencilAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000395 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500396 if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000397 {
398 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
399 }
400
Jamie Madilld1405e52015-03-05 15:41:39 -0500401 GLenum internalformat = stencilAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500402 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400403 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500404 if (stencilAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000405 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000406 // texture stencil attachments come along as part
407 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500408 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000409 {
410 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
411 }
412
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400413 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400414 {
415 return GL_FRAMEBUFFER_UNSUPPORTED;
416 }
417
Geoff Lang5d601382014-07-22 15:14:06 -0400418 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000419 {
420 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
421 }
422 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500423 else if (stencilAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000424 {
Geoff Lang5d601382014-07-22 15:14:06 -0400425 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400426 {
427 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
428 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000429 }
430
431 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000432 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500433 width = stencilAttachment->getWidth();
434 height = stencilAttachment->getHeight();
435 samples = stencilAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000436 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000437 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500438 else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000439 {
440 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
441 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500442 else if (samples != stencilAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000443 {
444 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
445 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000446 }
447
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000448 // if we have both a depth and stencil buffer, they must refer to the same object
449 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madilld1405e52015-03-05 15:41:39 -0500450 if (depthAttachment && stencilAttachment && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000451 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000452 return GL_FRAMEBUFFER_UNSUPPORTED;
453 }
454
455 // we need to have at least one attachment to be complete
456 if (missingAttachment)
457 {
458 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000459 }
460
Geoff Lang748f74e2014-12-01 11:25:34 -0500461 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000462}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000463
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500464Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400465{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500466 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400467}
468
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500469Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400470{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500471 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400472}
473
Geoff Langb04dc822014-12-01 12:02:02 -0500474Error Framebuffer::clear(const State &state, GLbitfield mask)
475{
476 return mImpl->clear(state, mask);
477}
478
479Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
480{
481 return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
482}
483
484Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
485{
486 return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
487}
488
489Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
490{
491 return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
492}
493
494Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
495{
496 return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
497}
498
Geoff Langbce529e2014-12-01 12:48:41 -0500499GLenum Framebuffer::getImplementationColorReadFormat() const
500{
501 return mImpl->getImplementationColorReadFormat();
502}
503
504GLenum Framebuffer::getImplementationColorReadType() const
505{
506 return mImpl->getImplementationColorReadType();
507}
508
509Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
510{
511 return mImpl->readPixels(state, area, format, type, pixels);
512}
513
Geoff Lang54bd5a42014-12-01 12:51:04 -0500514Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
515 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
516{
517 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
518}
519
Jamie Madill48faf802014-11-06 15:27:22 -0500520int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000521{
Geoff Lang748f74e2014-12-01 11:25:34 -0500522 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000523 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000524 // for a complete framebuffer, all attachments must have the same sample count
525 // in this case return the first nonzero sample size
Jamie Madilld1405e52015-03-05 15:41:39 -0500526 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000527 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500528 if (colorAttachment != nullptr)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000529 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500530 return colorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000531 }
532 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000533 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000534
535 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000536}
537
Jamie Madille261b442014-06-25 12:42:21 -0400538bool Framebuffer::hasValidDepthStencil() const
539{
540 // A valid depth-stencil attachment has the same resource bound to both the
541 // depth and stencil attachment points.
Jamie Madilld1405e52015-03-05 15:41:39 -0500542 return (mData.mDepthAttachment && mData.mStencilAttachment &&
543 mData.mDepthAttachment->type() == mData.mStencilAttachment->type() &&
544 mData.mDepthAttachment->id() == mData.mStencilAttachment->id());
Jamie Madille261b442014-06-25 12:42:21 -0400545}
546
Geoff Langab75a052014-10-15 12:56:37 -0400547void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
548{
549 setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
550}
551
552void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
553{
554 setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
555}
556
557void Framebuffer::setNULLAttachment(GLenum attachment)
558{
559 setAttachment(attachment, NULL);
560}
561
562void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
563{
Jamie Madilld1405e52015-03-05 15:41:39 -0500564 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size()))
Geoff Langab75a052014-10-15 12:56:37 -0400565 {
566 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
Jamie Madilld1405e52015-03-05 15:41:39 -0500567 SafeDelete(mData.mColorAttachments[colorAttachment]);
568 mData.mColorAttachments[colorAttachment] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500569 mImpl->setColorAttachment(colorAttachment, attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400570 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500571 else if (attachment == GL_BACK)
572 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500573 SafeDelete(mData.mColorAttachments[0]);
574 mData.mColorAttachments[0] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500575 mImpl->setColorAttachment(0, attachmentObj);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500576 }
577 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400578 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500579 SafeDelete(mData.mDepthAttachment);
580 mData.mDepthAttachment = attachmentObj;
Jamie Madillf90353e2015-03-05 19:37:58 -0500581 mImpl->setDepthAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400582 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500583 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400584 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500585 SafeDelete(mData.mStencilAttachment);
586 mData.mStencilAttachment = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500587 mImpl->setStencilAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400588 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500589 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400590 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500591 SafeDelete(mData.mDepthAttachment);
592 SafeDelete(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400593
594 // ensure this is a legitimate depth+stencil format
595 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
596 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500597 mData.mDepthAttachment = attachmentObj;
Jamie Madillf90353e2015-03-05 19:37:58 -0500598 mImpl->setDepthAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400599
600 // Make a new attachment object to ensure we do not double-delete
601 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500602 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400603 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500604 mData.mStencilAttachment = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
605 *attachmentObj->getTextureImageIndex());
606 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400607 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500608 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400609 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500610 mData.mStencilAttachment = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
611 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400612 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500613 else
614 {
615 UNREACHABLE();
616 }
Geoff Langab75a052014-10-15 12:56:37 -0400617 }
618 }
619 else
620 {
621 UNREACHABLE();
622 }
623}
624
Jamie Madill48115b62015-03-16 10:46:57 -0400625DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface)
626 : Framebuffer(caps, factory, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000627{
Jamie Madill48115b62015-03-16 10:46:57 -0400628 rx::DefaultAttachmentImpl *colorAttachment = factory->createDefaultAttachment(GL_BACK, surface);
629 rx::DefaultAttachmentImpl *depthAttachment = factory->createDefaultAttachment(GL_DEPTH, surface);
630 rx::DefaultAttachmentImpl *stencilAttachment = factory->createDefaultAttachment(GL_STENCIL, surface);
Jamie Madilld1405e52015-03-05 15:41:39 -0500631
Geoff Lang528ce3c2014-12-01 10:44:07 -0500632 ASSERT(colorAttachment);
633 setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, colorAttachment));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000634
Geoff Lang528ce3c2014-12-01 10:44:07 -0500635 if (depthAttachment)
Jamie Madille92a3542014-07-03 10:38:58 -0400636 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500637 setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, depthAttachment));
Jamie Madille92a3542014-07-03 10:38:58 -0400638 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500639 if (stencilAttachment)
640 {
641 setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, stencilAttachment));
642 }
643
Geoff Lang9dd95802014-12-01 11:12:59 -0500644 GLenum drawBufferState = GL_BACK;
645 setDrawBuffers(1, &drawBufferState);
646
647 setReadBuffer(GL_BACK);
Jamie Madille92a3542014-07-03 10:38:58 -0400648}
649
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650}