blob: 78a06a8676f32ef57087bc6d0c2def045016d651 [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 Madillb6bda4a2015-04-20 12:53:26 -040059const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050060{
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
Jamie Madillb6bda4a2015-04-20 12:53:26 -040067const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050068{
69 for (FramebufferAttachment *colorAttachment : mColorAttachments)
70 {
71 if (colorAttachment != nullptr)
72 {
73 return colorAttachment;
74 }
75 }
76
77 return nullptr;
78}
79
Jamie Madillb6bda4a2015-04-20 12:53:26 -040080const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
Jamie Madill7147f012015-03-05 15:41:40 -050081{
82 return (mDepthAttachment != nullptr ? mDepthAttachment : mStencilAttachment);
83}
84
Jamie Madillb6bda4a2015-04-20 12:53:26 -040085FramebufferAttachment *Framebuffer::Data::getColorAttachment(unsigned int colorAttachment)
86{
87 ASSERT(colorAttachment < mColorAttachments.size());
88 return mColorAttachments[colorAttachment];
89}
90
91const FramebufferAttachment *Framebuffer::Data::getColorAttachment(unsigned int colorAttachment) const
92{
93 return const_cast<Framebuffer::Data *>(this)->getColorAttachment(colorAttachment);
94}
95
96FramebufferAttachment *Framebuffer::Data::getDepthAttachment()
97{
98 return mDepthAttachment;
99}
100
101const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const
102{
103 return const_cast<Framebuffer::Data *>(this)->getDepthAttachment();
104}
105
106FramebufferAttachment *Framebuffer::Data::getStencilAttachment()
107{
108 return mStencilAttachment;
109}
110
111const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const
112{
113 return const_cast<Framebuffer::Data *>(this)->getStencilAttachment();
114}
115
116FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment()
117{
118 // A valid depth-stencil attachment has the same resource bound to both the
119 // depth and stencil attachment points.
120 if (mDepthAttachment && mStencilAttachment &&
121 mDepthAttachment->type() == mStencilAttachment->type() &&
122 mDepthAttachment->id() == mStencilAttachment->id())
123 {
124 return mDepthAttachment;
125 }
126
127 return nullptr;
128}
129
130const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const
131{
132 return const_cast<Framebuffer::Data *>(this)->getDepthStencilAttachment();
133}
134
Jamie Madill48115b62015-03-16 10:46:57 -0400135Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
Jamie Madilld1405e52015-03-05 15:41:39 -0500136 : mData(caps),
Geoff Lang4ad17092015-03-10 16:47:44 -0400137 mImpl(nullptr),
Jamie Madilld1405e52015-03-05 15:41:39 -0500138 mId(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139{
Geoff Lang4ad17092015-03-10 16:47:44 -0400140 if (mId == 0)
141 {
142 mImpl = factory->createDefaultFramebuffer(mData);
143 }
144 else
145 {
146 mImpl = factory->createFramebuffer(mData);
147 }
Geoff Langda88add2014-12-01 10:22:01 -0500148 ASSERT(mImpl != nullptr);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149}
150
151Framebuffer::~Framebuffer()
152{
Geoff Langda88add2014-12-01 10:22:01 -0500153 SafeDelete(mImpl);
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000154}
155
Jamie Madille261b442014-06-25 12:42:21 -0400156void Framebuffer::detachTexture(GLuint textureId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157{
Jamie Madilld1405e52015-03-05 15:41:39 -0500158 detachResourceById(GL_TEXTURE, textureId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159}
160
Jamie Madille261b442014-06-25 12:42:21 -0400161void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162{
Jamie Madilld1405e52015-03-05 15:41:39 -0500163 detachResourceById(GL_RENDERBUFFER, renderbufferId);
164}
Jamie Madille261b442014-06-25 12:42:21 -0400165
Jamie Madilld1405e52015-03-05 15:41:39 -0500166void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
167{
168 for (auto &colorAttachment : mData.mColorAttachments)
169 {
170 DeleteMatchingAttachment(colorAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 }
172
Jamie Madilld1405e52015-03-05 15:41:39 -0500173 DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId);
174 DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175}
176
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400177FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000178{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400179 return mData.getColorAttachment(colorAttachment);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000180}
181
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400182const FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400184 return mData.getColorAttachment(colorAttachment);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185}
186
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400187FramebufferAttachment *Framebuffer::getDepthbuffer()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400189 return mData.getDepthAttachment();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000190}
191
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400192const FramebufferAttachment *Framebuffer::getDepthbuffer() const
Geoff Lang646559f2013-08-15 11:08:15 -0400193{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400194 return mData.getDepthAttachment();
Geoff Lang646559f2013-08-15 11:08:15 -0400195}
196
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400197FramebufferAttachment *Framebuffer::getStencilbuffer()
198{
199 return mData.getStencilAttachment();
200}
201
202const FramebufferAttachment *Framebuffer::getStencilbuffer() const
203{
204 return mData.getStencilAttachment();
205}
206
207FramebufferAttachment *Framebuffer::getDepthStencilBuffer()
208{
209 return mData.getDepthStencilAttachment();
210}
211
212const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
213{
214 return mData.getDepthStencilAttachment();
215}
216
217const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000218{
Jamie Madill7147f012015-03-05 15:41:40 -0500219 return mData.getDepthOrStencilAttachment();
daniel@transgaming.comd2b47022012-11-28 19:40:10 +0000220}
221
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400222const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000223{
Jamie Madill7147f012015-03-05 15:41:40 -0500224 return mData.getReadAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000225}
226
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000227GLenum Framebuffer::getReadColorbufferType() const
228{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400229 const FramebufferAttachment *readAttachment = mData.getReadAttachment();
230 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comf6863e02013-04-13 03:34:00 +0000231}
232
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400233const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000234{
Jamie Madill7147f012015-03-05 15:41:40 -0500235 return mData.getFirstColorAttachment();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000236}
237
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400238FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000239{
Jamie Madille92a3542014-07-03 10:38:58 -0400240 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
241 {
242 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
243 }
244 else
245 {
246 switch (attachment)
247 {
Geoff Lang528ce3c2014-12-01 10:44:07 -0500248 case GL_COLOR:
249 case GL_BACK:
250 return getColorbuffer(0);
251 case GL_DEPTH:
Jamie Madille92a3542014-07-03 10:38:58 -0400252 case GL_DEPTH_ATTACHMENT:
253 return getDepthbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500254 case GL_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400255 case GL_STENCIL_ATTACHMENT:
256 return getStencilbuffer();
Geoff Lang528ce3c2014-12-01 10:44:07 -0500257 case GL_DEPTH_STENCIL:
Jamie Madille92a3542014-07-03 10:38:58 -0400258 case GL_DEPTH_STENCIL_ATTACHMENT:
259 return getDepthStencilBuffer();
260 default:
261 UNREACHABLE();
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400262 return nullptr;
Jamie Madille92a3542014-07-03 10:38:58 -0400263 }
264 }
Geoff Lang55ba29c2013-07-11 16:57:53 -0400265}
266
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400267const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
268{
269 return const_cast<Framebuffer*>(this)->getAttachment(attachment);
270}
271
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000272GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
273{
Jamie Madilld1405e52015-03-05 15:41:39 -0500274 ASSERT(colorAttachment < mData.mDrawBufferStates.size());
275 return mData.mDrawBufferStates[colorAttachment];
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000276}
277
Geoff Lang164d54e2014-12-01 10:55:33 -0500278void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000279{
Jamie Madilld1405e52015-03-05 15:41:39 -0500280 auto &drawStates = mData.mDrawBufferStates;
281
282 ASSERT(count <= drawStates.size());
283 std::copy(buffers, buffers + count, drawStates.begin());
284 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
Geoff Lang9dd95802014-12-01 11:12:59 -0500285 mImpl->setDrawBuffers(count, buffers);
286}
287
288GLenum Framebuffer::getReadBufferState() const
289{
Jamie Madilld1405e52015-03-05 15:41:39 -0500290 return mData.mReadBufferState;
Geoff Lang9dd95802014-12-01 11:12:59 -0500291}
292
293void Framebuffer::setReadBuffer(GLenum buffer)
294{
Jamie Madillb885e572015-02-03 16:16:04 -0500295 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
296 (buffer >= GL_COLOR_ATTACHMENT0 &&
Jamie Madilld1405e52015-03-05 15:41:39 -0500297 (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
298 mData.mReadBufferState = buffer;
Geoff Lang9dd95802014-12-01 11:12:59 -0500299 mImpl->setReadBuffer(buffer);
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000300}
301
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000302bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
303{
Jamie Madilld1405e52015-03-05 15:41:39 -0500304 ASSERT(colorAttachment < mData.mColorAttachments.size());
305 return (mData.mColorAttachments[colorAttachment] &&
306 mData.mDrawBufferStates[colorAttachment] != GL_NONE);
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000307}
308
309bool Framebuffer::hasEnabledColorAttachment() const
310{
Jamie Madilld1405e52015-03-05 15:41:39 -0500311 for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannon.woods%transgaming.com@gtempaccount.comdae24092013-04-13 03:31:31 +0000312 {
313 if (isEnabledColorAttachment(colorAttachment))
314 {
315 return true;
316 }
317 }
318
319 return false;
320}
321
shannon.woods%transgaming.com@gtempaccount.com3b57b4f2013-04-13 03:28:29 +0000322bool Framebuffer::hasStencil() const
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000323{
Jamie Madilld1405e52015-03-05 15:41:39 -0500324 return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0);
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000325}
326
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000327bool Framebuffer::usingExtendedDrawBuffers() const
328{
Jamie Madilld1405e52015-03-05 15:41:39 -0500329 for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
shannonwoods@chromium.org24ac8502013-05-30 00:01:37 +0000330 {
331 if (isEnabledColorAttachment(colorAttachment))
332 {
333 return true;
334 }
335 }
336
337 return false;
338}
339
Geoff Lang748f74e2014-12-01 11:25:34 -0500340GLenum Framebuffer::checkStatus(const gl::Data &data) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341{
Geoff Lang528ce3c2014-12-01 10:44:07 -0500342 // The default framebuffer *must* always be complete, though it may not be
343 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
344 if (mId == 0)
345 {
346 return GL_FRAMEBUFFER_COMPLETE;
347 }
348
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349 int width = 0;
350 int height = 0;
shannonwoods@chromium.orgf6fb9592013-05-30 00:09:40 +0000351 unsigned int colorbufferSize = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000352 int samples = -1;
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000353 bool missingAttachment = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354
Jamie Madilld1405e52015-03-05 15:41:39 -0500355 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000356 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500357 if (colorAttachment != nullptr)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000358 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500359 if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000360 {
361 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
362 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000363
Jamie Madilld1405e52015-03-05 15:41:39 -0500364 GLenum internalformat = colorAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500365 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400366 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500367 if (colorAttachment->type() == GL_TEXTURE)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000368 {
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400369 if (!formatCaps.renderable)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000370 {
371 return GL_FRAMEBUFFER_UNSUPPORTED;
372 }
373
Geoff Lang5d601382014-07-22 15:14:06 -0400374 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000375 {
376 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
377 }
378 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500379 else if (colorAttachment->type() == GL_RENDERBUFFER)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000380 {
Geoff Lang5d601382014-07-22 15:14:06 -0400381 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400382 {
383 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
384 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000385 }
386
387 if (!missingAttachment)
388 {
389 // all color attachments must have the same width and height
Jamie Madilld1405e52015-03-05 15:41:39 -0500390 if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000391 {
392 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
393 }
394
395 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
396 // all color attachments have the same number of samples for the FBO to be complete.
Jamie Madilld1405e52015-03-05 15:41:39 -0500397 if (colorAttachment->getSamples() != samples)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000398 {
399 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
400 }
401
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000402 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
403 // in GLES 3.0, there is no such restriction
Jamie Madill48faf802014-11-06 15:27:22 -0500404 if (data.clientVersion < 3)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000405 {
Geoff Lang5d601382014-07-22 15:14:06 -0400406 if (formatInfo.pixelBytes != colorbufferSize)
shannon.woods%transgaming.com@gtempaccount.comc3471522013-04-13 03:34:52 +0000407 {
408 return GL_FRAMEBUFFER_UNSUPPORTED;
409 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000410 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000411 }
412 else
413 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500414 width = colorAttachment->getWidth();
415 height = colorAttachment->getHeight();
416 samples = colorAttachment->getSamples();
Geoff Lang5d601382014-07-22 15:14:06 -0400417 colorbufferSize = formatInfo.pixelBytes;
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000418 missingAttachment = false;
419 }
420 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000421 }
422
Jamie Madilld1405e52015-03-05 15:41:39 -0500423 const FramebufferAttachment *depthAttachment = mData.mDepthAttachment;
424 if (depthAttachment != nullptr)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000425 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500426 if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000428 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000429 }
430
Jamie Madilld1405e52015-03-05 15:41:39 -0500431 GLenum internalformat = depthAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500432 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400433 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500434 if (depthAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000435 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000436 // depth texture attachments require OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500437 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000438 {
439 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
440 }
441
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400442 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400443 {
444 return GL_FRAMEBUFFER_UNSUPPORTED;
445 }
446
Geoff Lang5d601382014-07-22 15:14:06 -0400447 if (formatInfo.depthBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000448 {
449 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
450 }
451 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500452 else if (depthAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000453 {
Geoff Lang5d601382014-07-22 15:14:06 -0400454 if (!formatCaps.renderable || formatInfo.depthBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400455 {
456 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
457 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000458 }
459
460 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000461 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500462 width = depthAttachment->getWidth();
463 height = depthAttachment->getHeight();
464 samples = depthAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000465 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000466 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500467 else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000468 {
469 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
470 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500471 else if (samples != depthAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000472 {
473 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
474 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000475 }
476
Jamie Madilld1405e52015-03-05 15:41:39 -0500477 const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment;
478 if (stencilAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000479 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500480 if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000481 {
482 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
483 }
484
Jamie Madilld1405e52015-03-05 15:41:39 -0500485 GLenum internalformat = stencilAttachment->getInternalFormat();
Jamie Madill48faf802014-11-06 15:27:22 -0500486 const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400487 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
Jamie Madilld1405e52015-03-05 15:41:39 -0500488 if (stencilAttachment->type() == GL_TEXTURE)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000489 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000490 // texture stencil attachments come along as part
491 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
Jamie Madill48faf802014-11-06 15:27:22 -0500492 if (!data.extensions->depthTextures)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000493 {
494 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
495 }
496
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400497 if (!formatCaps.renderable)
Geoff Langcec35902014-04-16 10:52:36 -0400498 {
499 return GL_FRAMEBUFFER_UNSUPPORTED;
500 }
501
Geoff Lang5d601382014-07-22 15:14:06 -0400502 if (formatInfo.stencilBits == 0)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000503 {
504 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
505 }
506 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500507 else if (stencilAttachment->type() == GL_RENDERBUFFER)
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000508 {
Geoff Lang5d601382014-07-22 15:14:06 -0400509 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
Jamie Madillbb94f342014-06-23 15:23:02 -0400510 {
511 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
512 }
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000513 }
514
515 if (missingAttachment)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000516 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500517 width = stencilAttachment->getWidth();
518 height = stencilAttachment->getHeight();
519 samples = stencilAttachment->getSamples();
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000520 missingAttachment = false;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000521 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500522 else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000523 {
524 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
525 }
Jamie Madilld1405e52015-03-05 15:41:39 -0500526 else if (samples != stencilAttachment->getSamples())
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000527 {
528 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
529 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000530 }
531
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000532 // if we have both a depth and stencil buffer, they must refer to the same object
533 // since we only support packed_depth_stencil and not separate depth and stencil
Jamie Madilld1405e52015-03-05 15:41:39 -0500534 if (depthAttachment && stencilAttachment && !hasValidDepthStencil())
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000535 {
daniel@transgaming.com6b7c84c2012-05-31 01:14:39 +0000536 return GL_FRAMEBUFFER_UNSUPPORTED;
537 }
538
539 // we need to have at least one attachment to be complete
540 if (missingAttachment)
541 {
542 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000543 }
544
Geoff Lang748f74e2014-12-01 11:25:34 -0500545 return mImpl->checkStatus();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000546}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000547
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500548Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400549{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500550 return mImpl->invalidate(count, attachments);
Jamie Madill2d96b9e2014-08-29 15:46:47 -0400551}
552
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500553Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
Jamie Madill400a4412014-08-29 15:46:45 -0400554{
Geoff Lang9ad4bda2014-12-01 11:03:09 -0500555 return mImpl->invalidateSub(count, attachments, area);
Jamie Madill400a4412014-08-29 15:46:45 -0400556}
557
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400558Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
Geoff Langb04dc822014-12-01 12:02:02 -0500559{
Jamie Madilld1f5ef22015-04-01 14:17:06 -0400560 return mImpl->clear(data, mask);
Geoff Langb04dc822014-12-01 12:02:02 -0500561}
562
563Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
564{
565 return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
566}
567
568Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
569{
570 return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
571}
572
573Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
574{
575 return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
576}
577
578Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
579{
580 return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
581}
582
Geoff Langbce529e2014-12-01 12:48:41 -0500583GLenum Framebuffer::getImplementationColorReadFormat() const
584{
585 return mImpl->getImplementationColorReadFormat();
586}
587
588GLenum Framebuffer::getImplementationColorReadType() const
589{
590 return mImpl->getImplementationColorReadType();
591}
592
593Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
594{
595 return mImpl->readPixels(state, area, format, type, pixels);
596}
597
Geoff Lang54bd5a42014-12-01 12:51:04 -0500598Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
599 GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
600{
601 return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
602}
603
Jamie Madill48faf802014-11-06 15:27:22 -0500604int Framebuffer::getSamples(const gl::Data &data) const
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000605{
Geoff Lang748f74e2014-12-01 11:25:34 -0500606 if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000607 {
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000608 // for a complete framebuffer, all attachments must have the same sample count
609 // in this case return the first nonzero sample size
Jamie Madilld1405e52015-03-05 15:41:39 -0500610 for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000611 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500612 if (colorAttachment != nullptr)
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000613 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500614 return colorAttachment->getSamples();
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000615 }
616 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000617 }
shannon.woods%transgaming.com@gtempaccount.comf30ccc22013-04-13 03:28:36 +0000618
619 return 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000620}
621
Jamie Madille261b442014-06-25 12:42:21 -0400622bool Framebuffer::hasValidDepthStencil() const
623{
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400624 return mData.getDepthStencilAttachment() != nullptr;
Jamie Madille261b442014-06-25 12:42:21 -0400625}
626
Geoff Langab75a052014-10-15 12:56:37 -0400627void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
628{
Jamie Madill5160ec12015-04-14 08:13:48 -0400629 setAttachment(attachment, new FramebufferAttachment(GL_TEXTURE, attachment, imageIndex, texture));
Geoff Langab75a052014-10-15 12:56:37 -0400630}
631
632void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
633{
Jamie Madill5160ec12015-04-14 08:13:48 -0400634 setAttachment(attachment, new FramebufferAttachment(GL_RENDERBUFFER, attachment, ImageIndex::MakeInvalid(), renderbuffer));
Geoff Langab75a052014-10-15 12:56:37 -0400635}
636
637void Framebuffer::setNULLAttachment(GLenum attachment)
638{
639 setAttachment(attachment, NULL);
640}
641
642void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
643{
Jamie Madilld1405e52015-03-05 15:41:39 -0500644 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size()))
Geoff Langab75a052014-10-15 12:56:37 -0400645 {
646 size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
Jamie Madilld1405e52015-03-05 15:41:39 -0500647 SafeDelete(mData.mColorAttachments[colorAttachment]);
648 mData.mColorAttachments[colorAttachment] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500649 mImpl->setColorAttachment(colorAttachment, attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400650 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500651 else if (attachment == GL_BACK)
652 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500653 SafeDelete(mData.mColorAttachments[0]);
654 mData.mColorAttachments[0] = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500655 mImpl->setColorAttachment(0, attachmentObj);
Geoff Lang528ce3c2014-12-01 10:44:07 -0500656 }
657 else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
Geoff Langab75a052014-10-15 12:56:37 -0400658 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500659 SafeDelete(mData.mDepthAttachment);
660 mData.mDepthAttachment = attachmentObj;
Jamie Madillf90353e2015-03-05 19:37:58 -0500661 mImpl->setDepthAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400662 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500663 else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400664 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500665 SafeDelete(mData.mStencilAttachment);
666 mData.mStencilAttachment = attachmentObj;
Geoff Lang9dd95802014-12-01 11:12:59 -0500667 mImpl->setStencilAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400668 }
Geoff Lang528ce3c2014-12-01 10:44:07 -0500669 else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
Geoff Langab75a052014-10-15 12:56:37 -0400670 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500671 SafeDelete(mData.mDepthAttachment);
672 SafeDelete(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400673
674 // ensure this is a legitimate depth+stencil format
675 if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
676 {
Jamie Madilld1405e52015-03-05 15:41:39 -0500677 mData.mDepthAttachment = attachmentObj;
Jamie Madillf90353e2015-03-05 19:37:58 -0500678 mImpl->setDepthAttachment(attachmentObj);
Geoff Langab75a052014-10-15 12:56:37 -0400679
680 // Make a new attachment object to ensure we do not double-delete
681 // See angle issue 686
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500682 if (attachmentObj->type() == GL_TEXTURE)
Geoff Langab75a052014-10-15 12:56:37 -0400683 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400684 mData.mStencilAttachment = new FramebufferAttachment(GL_TEXTURE,
685 GL_DEPTH_STENCIL_ATTACHMENT,
686 attachmentObj->getTextureImageIndex(),
687 attachmentObj->getTexture());
Jamie Madilld1405e52015-03-05 15:41:39 -0500688 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400689 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500690 else if (attachmentObj->type() == GL_RENDERBUFFER)
Geoff Langab75a052014-10-15 12:56:37 -0400691 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400692 mData.mStencilAttachment = new FramebufferAttachment(GL_RENDERBUFFER,
693 GL_DEPTH_STENCIL_ATTACHMENT,
694 ImageIndex::MakeInvalid(),
695 attachmentObj->getRenderbuffer());
Jamie Madilld1405e52015-03-05 15:41:39 -0500696 mImpl->setStencilAttachment(mData.mStencilAttachment);
Geoff Langab75a052014-10-15 12:56:37 -0400697 }
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500698 else
699 {
700 UNREACHABLE();
701 }
Geoff Langab75a052014-10-15 12:56:37 -0400702 }
703 }
704 else
705 {
706 UNREACHABLE();
707 }
708}
709
Jamie Madill48115b62015-03-16 10:46:57 -0400710DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface)
711 : Framebuffer(caps, factory, 0)
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000712{
Jamie Madillc46f45d2015-03-31 13:20:55 -0400713 const egl::Config *config = surface->getConfig();
Jamie Madilld1405e52015-03-05 15:41:39 -0500714
Jamie Madill5160ec12015-04-14 08:13:48 -0400715 setAttachment(GL_BACK, new FramebufferAttachment(GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex::MakeInvalid(), surface));
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000716
Jamie Madillc46f45d2015-03-31 13:20:55 -0400717 if (config->depthSize > 0)
Jamie Madille92a3542014-07-03 10:38:58 -0400718 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400719 setAttachment(GL_DEPTH, new FramebufferAttachment(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex::MakeInvalid(), surface));
Jamie Madille92a3542014-07-03 10:38:58 -0400720 }
Jamie Madillc46f45d2015-03-31 13:20:55 -0400721 if (config->stencilSize > 0)
Geoff Lang528ce3c2014-12-01 10:44:07 -0500722 {
Jamie Madill5160ec12015-04-14 08:13:48 -0400723 setAttachment(GL_STENCIL, new FramebufferAttachment(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex::MakeInvalid(), surface));
Geoff Lang528ce3c2014-12-01 10:44:07 -0500724 }
725
Geoff Lang9dd95802014-12-01 11:12:59 -0500726 GLenum drawBufferState = GL_BACK;
727 setDrawBuffers(1, &drawBufferState);
728
729 setReadBuffer(GL_BACK);
Jamie Madille92a3542014-07-03 10:38:58 -0400730}
731
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000732}