blob: f434ac4ab903191c4bc274b189431891ca49a62a [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"
Jamie Madillc46f45d2015-03-31 13:20:55 -040011
12#include "common/utilities.h"
13#include "libANGLE/Config.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Context.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050015#include "libANGLE/FramebufferAttachment.h"
Jamie Madillc46f45d2015-03-31 13:20:55 -040016#include "libANGLE/Renderbuffer.h"
17#include "libANGLE/Surface.h"
18#include "libANGLE/Texture.h"
19#include "libANGLE/formatutils.h"
Geoff Langb5d8f232014-12-04 15:43:01 -050020#include "libANGLE/renderer/FramebufferImpl.h"
Jamie Madill48115b62015-03-16 10:46:57 -040021#include "libANGLE/renderer/ImplFactory.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/renderer/RenderbufferImpl.h"
23#include "libANGLE/renderer/Workarounds.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040024
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025namespace gl
26{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000027
Jamie Madilld1405e52015-03-05 15:41:39 -050028namespace
29{
30void DeleteMatchingAttachment(FramebufferAttachment *&attachment, GLenum matchType, GLuint matchId)
31{
32 if (attachment && attachment->type() == matchType && attachment->id() == matchId)
33 {
34 SafeDelete(attachment);
35 }
36}
37}
38
39Framebuffer::Data::Data(const Caps &caps)
40 : mColorAttachments(caps.maxColorAttachments, nullptr),
41 mDepthAttachment(nullptr),
42 mStencilAttachment(nullptr),
43 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
44 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
45{
46 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
47}
48
49Framebuffer::Data::~Data()
50{
51 for (auto &colorAttachment : mColorAttachments)
52 {
53 SafeDelete(colorAttachment);
54 }
55 SafeDelete(mDepthAttachment);
56 SafeDelete(mStencilAttachment);
57}
58
Jamie Madill7147f012015-03-05 15:41:40 -050059FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
60{
61 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
62 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
63 ASSERT(readIndex < mColorAttachments.size());
64 return mColorAttachments[readIndex];
65}
66
67FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
68{
69 for (FramebufferAttachment *colorAttachment : mColorAttachments)
70 {
71 if (colorAttachment != nullptr)
72 {
73 return colorAttachment;
74 }
75 }
76
77 return nullptr;
78}
79
80FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
81{
82 return (mDepthAttachment != nullptr ? mDepthAttachment : mStencilAttachment);
83}
84
Jamie Madill48115b62015-03-16 10:46:57 -040085Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
Jamie Madilld1405e52015-03-05 15:41:39 -050086 : mData(caps),
Geoff Lang4ad17092015-03-10 16:47:44 -040087 mImpl(nullptr),
Jamie Madilld1405e52015-03-05 15:41:39 -050088 mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000089{
Geoff Lang4ad17092015-03-10 16:47:44 -040090 if (mId == 0)
91 {
92 mImpl = factory->createDefaultFramebuffer(mData);
93 }
94 else
95 {
96 mImpl = factory->createFramebuffer(mData);
97 }
Geoff Langda88add2014-12-01 10:22:01 -050098 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000099}
100
101Framebuffer::~Framebuffer()
102{
Geoff Langda88add2014-12-01 10:22:01 -0500103 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000104}
105
Jamie Madille261b442014-06-25 12:42:21 -0400106void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107{
Jamie Madilld1405e52015-03-05 15:41:39 -0500108 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109}
110
Jamie Madille261b442014-06-25 12:42:21 -0400111void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000112{
Jamie Madilld1405e52015-03-05 15:41:39 -0500113 detachResourceById(GL_RENDERBUFFER, renderbufferId);
114}
Jamie Madille261b442014-06-25 12:42:21 -0400115
Jamie Madilld1405e52015-03-05 15:41:39 -0500116void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
117{
118 for (auto &colorAttachment : mData.mColorAttachments)
119 {
120 DeleteMatchingAttachment(colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121 }
122
Jamie Madilld1405e52015-03-05 15:41:39 -0500123 DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId);
124 DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125}
126
Jamie Madill3c7fa222014-06-05 13:08:51 -0400127FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000128{
Jamie Madilld1405e52015-03-05 15:41:39 -0500129 ASSERT(colorAttachment < mData.mColorAttachments.size());
130 return mData.mColorAttachments[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000131}
132
Jamie Madill3c7fa222014-06-05 13:08:51 -0400133FramebufferAttachment *Framebuffer::getDepthbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000134{
Jamie Madilld1405e52015-03-05 15:41:39 -0500135 return mData.mDepthAttachment;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136}
137
Jamie Madill3c7fa222014-06-05 13:08:51 -0400138FramebufferAttachment *Framebuffer::getStencilbuffer() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139{
Jamie Madilld1405e52015-03-05 15:41:39 -0500140 return mData.mStencilAttachment;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141}
142
Jamie Madill3c7fa222014-06-05 13:08:51 -0400143FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400144{
Jamie Madilld1405e52015-03-05 15:41:39 -0500145 return (hasValidDepthStencil() ? mData.mDepthAttachment : NULL);
Geoff Lang646559f2013-08-15 11:08:15 -0400146}
147
Jamie Madill3c7fa222014-06-05 13:08:51 -0400148FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000149{
Jamie Madill7147f012015-03-05 15:41:40 -0500150 return mData.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000151}
152
Jamie Madill3c7fa222014-06-05 13:08:51 -0400153FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000154{
Jamie Madill7147f012015-03-05 15:41:40 -0500155 return mData.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000156}
157
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000158GLenum Framebuffer::getReadColorbufferType() const
159{
Jamie Madill7147f012015-03-05 15:41:40 -0500160 FramebufferAttachment *readAttachment = mData.getReadAttachment();
Jamie Madillb885e572015-02-03 16:16:04 -0500161 return (readAttachment ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000162}
163
Jamie Madill3c7fa222014-06-05 13:08:51 -0400164FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000165{
Jamie Madill7147f012015-03-05 15:41:40 -0500166 return mData.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000167}
168
Jamie Madille92a3542014-07-03 10:38:58 -0400169FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000170{
Jamie Madille92a3542014-07-03 10:38:58 -0400171 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
172 {
173 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
174 }
175 else
176 {
177 switch (attachment)
178 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500179 case GL_COLOR:
180 case GL_BACK:
181 return getColorbuffer(0);
182 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400183 case GL_DEPTH_ATTACHMENT:
184 return getDepthbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500185 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400186 case GL_STENCIL_ATTACHMENT:
187 return getStencilbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500188 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400189 case GL_DEPTH_STENCIL_ATTACHMENT:
190 return getDepthStencilBuffer();
191 default:
192 UNREACHABLE();
193 return NULL;
194 }
195 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400196}
197
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000198GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
199{
Jamie Madilld1405e52015-03-05 15:41:39 -0500200 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
201 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000202}
203
Geoff Lang164d54e2014-12-01 10:55:33 -0500204void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000205{
Jamie Madilld1405e52015-03-05 15:41:39 -0500206 auto &drawStates = mData.mDrawBufferStates;
207
208 ASSERT(count <= drawStates.size());
209 std::copy(buffers, buffers + count, drawStates.begin());
210 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500211 mImpl->setDrawBuffers(count, buffers);
212}
213
214GLenum Framebuffer::getReadBufferState() const
215{
Jamie Madilld1405e52015-03-05 15:41:39 -0500216 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500217}
218
219void Framebuffer::setReadBuffer(GLenum buffer)
220{
Jamie Madillb885e572015-02-03 16:16:04 -0500221 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
222 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500223 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
224 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500225 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000226}
227
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000228bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
229{
Jamie Madilld1405e52015-03-05 15:41:39 -0500230 ASSERT(colorAttachment < mData.mColorAttachments.size());
231 return (mData.mColorAttachments[colorAttachment] &&
232 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000233}
234
235bool Framebuffer::hasEnabledColorAttachment() const
236{
Jamie Madilld1405e52015-03-05 15:41:39 -0500237 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000238 {
239 if (isEnabledColorAttachment(colorAttachment))
240 {
241 return true;
242 }
243 }
244
245 return false;
246}
247
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000248bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000249{
Jamie Madilld1405e52015-03-05 15:41:39 -0500250 return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000251}
252
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000253bool Framebuffer::usingExtendedDrawBuffers() const
254{
Jamie Madilld1405e52015-03-05 15:41:39 -0500255 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000256 {
257 if (isEnabledColorAttachment(colorAttachment))
258 {
259 return true;
260 }
261 }
262
263 return false;
264}
265
Geoff Lang748f74e2014-12-01 11:25:34 -0500266GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500268 // The default framebuffer *must* always be complete, though it may not be
269 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
270 if (mId == 0)
271 {
272 return GL_FRAMEBUFFER_COMPLETE;
273 }
274
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000275 int width = 0;
276 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000277 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000278 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000279 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280
Jamie Madilld1405e52015-03-05 15:41:39 -0500281 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500283 if (colorAttachment != nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500285 if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000286 {
287 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
288 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000289
Jamie Madilld1405e52015-03-05 15:41:39 -0500290 GLenum internalformat = colorAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500291 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400292 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500293 if (colorAttachment->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000294 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400295 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000296 {
297 return GL_FRAMEBUFFER_UNSUPPORTED;
298 }
299
Geoff Lang5d601382014-07-22 15:14:06 -0400300 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000301 {
302 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
303 }
304 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500305 else if (colorAttachment->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000306 {
Geoff Lang5d601382014-07-22 15:14:06 -0400307 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400308 {
309 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
310 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000311 }
312
313 if (!missingAttachment)
314 {
315 // all color attachments must have the same width and height
Jamie Madilld1405e52015-03-05 15:41:39 -0500316 if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000317 {
318 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
319 }
320
321 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
322 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madilld1405e52015-03-05 15:41:39 -0500323 if (colorAttachment->getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000324 {
325 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
326 }
327
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000328 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
329 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500330 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000331 {
Geoff Lang5d601382014-07-22 15:14:06 -0400332 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000333 {
334 return GL_FRAMEBUFFER_UNSUPPORTED;
335 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000336 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000337 }
338 else
339 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500340 width = colorAttachment->getWidth();
341 height = colorAttachment->getHeight();
342 samples = colorAttachment->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400343 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000344 missingAttachment = false;
345 }
346 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000347 }
348
Jamie Madilld1405e52015-03-05 15:41:39 -0500349 const FramebufferAttachment *depthAttachment = mData.mDepthAttachment;
350 if (depthAttachment != nullptr)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000351 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500352 if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000354 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355 }
356
Jamie Madilld1405e52015-03-05 15:41:39 -0500357 GLenum internalformat = depthAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500358 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400359 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500360 if (depthAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000361 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000362 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500363 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000364 {
365 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
366 }
367
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400368 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400369 {
370 return GL_FRAMEBUFFER_UNSUPPORTED;
371 }
372
Geoff Lang5d601382014-07-22 15:14:06 -0400373 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000374 {
375 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
376 }
377 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500378 else if (depthAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000379 {
Geoff Lang5d601382014-07-22 15:14:06 -0400380 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400381 {
382 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
383 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000384 }
385
386 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000387 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500388 width = depthAttachment->getWidth();
389 height = depthAttachment->getHeight();
390 samples = depthAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000391 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000392 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500393 else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000394 {
395 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
396 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500397 else if (samples != depthAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000398 {
399 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
400 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000401 }
402
Jamie Madilld1405e52015-03-05 15:41:39 -0500403 const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment;
404 if (stencilAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000405 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500406 if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000407 {
408 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
409 }
410
Jamie Madilld1405e52015-03-05 15:41:39 -0500411 GLenum internalformat = stencilAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500412 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400413 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500414 if (stencilAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000415 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000416 // texture stencil attachments come along as part
417 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500418 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000419 {
420 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
421 }
422
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400423 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400424 {
425 return GL_FRAMEBUFFER_UNSUPPORTED;
426 }
427
Geoff Lang5d601382014-07-22 15:14:06 -0400428 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000429 {
430 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
431 }
432 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500433 else if (stencilAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000434 {
Geoff Lang5d601382014-07-22 15:14:06 -0400435 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400436 {
437 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
438 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000439 }
440
441 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000442 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500443 width = stencilAttachment->getWidth();
444 height = stencilAttachment->getHeight();
445 samples = stencilAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000446 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000447 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500448 else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000449 {
450 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
451 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500452 else if (samples != stencilAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000453 {
454 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
455 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000456 }
457
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000458 // if we have both a depth and stencil buffer, they must refer to the same object
459 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madilld1405e52015-03-05 15:41:39 -0500460 if (depthAttachment && stencilAttachment && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000461 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000462 return GL_FRAMEBUFFER_UNSUPPORTED;
463 }
464
465 // we need to have at least one attachment to be complete
466 if (missingAttachment)
467 {
468 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000469 }
470
Geoff Lang748f74e2014-12-01 11:25:34 -0500471 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000473
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500474Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400475{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500476 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400477}
478
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500479Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400480{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500481 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400482}
483
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400484Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500485{
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400486 return mImpl->clear(data, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500487}
488
489Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
490{
491 return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
492}
493
494Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
495{
496 return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
497}
498
499Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
500{
501 return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
502}
503
504Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
505{
506 return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
507}
508
Geoff Langbce529e2014-12-01 12:48:41 -0500509GLenum Framebuffer::getImplementationColorReadFormat() const
510{
511 return mImpl->getImplementationColorReadFormat();
512}
513
514GLenum Framebuffer::getImplementationColorReadType() const
515{
516 return mImpl->getImplementationColorReadType();
517}
518
519Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
520{
521 return mImpl->readPixels(state, area, format, type, pixels);
522}
523
Geoff Lang54bd5a42014-12-01 12:51:04 -0500524Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
525 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
526{
527 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
528}
529
Jamie Madill48faf802014-11-06 15:27:22 -0500530int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000531{
Geoff Lang748f74e2014-12-01 11:25:34 -0500532 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000533 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000534 // for a complete framebuffer, all attachments must have the same sample count
535 // in this case return the first nonzero sample size
Jamie Madilld1405e52015-03-05 15:41:39 -0500536 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000537 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500538 if (colorAttachment != nullptr)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000539 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500540 return colorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000541 }
542 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000543 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000544
545 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000546}
547
Jamie Madille261b442014-06-25 12:42:21 -0400548bool Framebuffer::hasValidDepthStencil() const
549{
550 // A valid depth-stencil attachment has the same resource bound to both the
551 // depth and stencil attachment points.
Jamie Madilld1405e52015-03-05 15:41:39 -0500552 return (mData.mDepthAttachment && mData.mStencilAttachment &&
553 mData.mDepthAttachment->type() == mData.mStencilAttachment->type() &&
554 mData.mDepthAttachment->id() == mData.mStencilAttachment->id());
Jamie Madille261b442014-06-25 12:42:21 -0400555}
556
Geoff Langab75a052014-10-15 12:56:37 -0400557void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
558{
Jamie Madill5160ec12015-04-14 08:13:48 -0400559 setAttachment(attachment, new FramebufferAttachment(GL_TEXTURE, attachment, imageIndex, texture));
Geoff Langab75a052014-10-15 12:56:37 -0400560}
561
562void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
563{
Jamie Madill5160ec12015-04-14 08:13:48 -0400564 setAttachment(attachment, new FramebufferAttachment(GL_RENDERBUFFER, attachment, ImageIndex::MakeInvalid(), renderbuffer));
Geoff Langab75a052014-10-15 12:56:37 -0400565}
566
567void Framebuffer::setNULLAttachment(GLenum attachment)
568{
569 setAttachment(attachment, NULL);
570}
571
572void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
573{
Jamie Madilld1405e52015-03-05 15:41:39 -0500574 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size()))
Geoff Langab75a052014-10-15 12:56:37 -0400575 {
576 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
Jamie Madilld1405e52015-03-05 15:41:39 -0500577 SafeDelete(mData.mColorAttachments[colorAttachment]);
578 mData.mColorAttachments[colorAttachment] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500579 mImpl->setColorAttachment(colorAttachment, attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400580 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500581 else if (attachment == GL_BACK)
582 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500583 SafeDelete(mData.mColorAttachments[0]);
584 mData.mColorAttachments[0] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500585 mImpl->setColorAttachment(0, attachmentObj);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500586 }
587 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400588 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500589 SafeDelete(mData.mDepthAttachment);
590 mData.mDepthAttachment = attachmentObj;
Jamie Madillf90353e2015-03-05 19:37:58 -0500591 mImpl->setDepthAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400592 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500593 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400594 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500595 SafeDelete(mData.mStencilAttachment);
596 mData.mStencilAttachment = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500597 mImpl->setStencilAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400598 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500599 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400600 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500601 SafeDelete(mData.mDepthAttachment);
602 SafeDelete(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400603
604 // ensure this is a legitimate depth+stencil format
605 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
606 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500607 mData.mDepthAttachment = attachmentObj;
Jamie Madillf90353e2015-03-05 19:37:58 -0500608 mImpl->setDepthAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400609
610 // Make a new attachment object to ensure we do not double-delete
611 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500612 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400613 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400614 mData.mStencilAttachment = new FramebufferAttachment(GL_TEXTURE,
615 GL_DEPTH_STENCIL_ATTACHMENT,
616 attachmentObj->getTextureImageIndex(),
617 attachmentObj->getTexture());
Jamie Madilld1405e52015-03-05 15:41:39 -0500618 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400619 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500620 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400621 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400622 mData.mStencilAttachment = new FramebufferAttachment(GL_RENDERBUFFER,
623 GL_DEPTH_STENCIL_ATTACHMENT,
624 ImageIndex::MakeInvalid(),
625 attachmentObj->getRenderbuffer());
Jamie Madilld1405e52015-03-05 15:41:39 -0500626 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400627 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500628 else
629 {
630 UNREACHABLE();
631 }
Geoff Langab75a052014-10-15 12:56:37 -0400632 }
633 }
634 else
635 {
636 UNREACHABLE();
637 }
638}
639
Jamie Madill48115b62015-03-16 10:46:57 -0400640DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface)
641 : Framebuffer(caps, factory, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000642{
Jamie Madillc46f45d2015-03-31 13:20:55 -0400643 const egl::Config *config = surface->getConfig();
Jamie Madilld1405e52015-03-05 15:41:39 -0500644
Jamie Madill5160ec12015-04-14 08:13:48 -0400645 setAttachment(GL_BACK, new FramebufferAttachment(GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex::MakeInvalid(), surface));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000646
Jamie Madillc46f45d2015-03-31 13:20:55 -0400647 if (config->depthSize > 0)
Jamie Madille92a3542014-07-03 10:38:58 -0400648 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400649 setAttachment(GL_DEPTH, new FramebufferAttachment(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex::MakeInvalid(), surface));
Jamie Madille92a3542014-07-03 10:38:58 -0400650 }
Jamie Madillc46f45d2015-03-31 13:20:55 -0400651 if (config->stencilSize > 0)
Geoff Lang528ce3c2014-12-01 10:44:07 -0500652 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400653 setAttachment(GL_STENCIL, new FramebufferAttachment(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex::MakeInvalid(), surface));
Geoff Lang528ce3c2014-12-01 10:44:07 -0500654 }
655
Geoff Lang9dd95802014-12-01 11:12:59 -0500656 GLenum drawBufferState = GL_BACK;
657 setDrawBuffers(1, &drawBufferState);
658
659 setReadBuffer(GL_BACK);
Jamie Madille92a3542014-07-03 10:38:58 -0400660}
661
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000662}