1 // SwiftShader Software Renderer
3 // Copyright(c) 2005-2013 TransGaming Inc.
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,
6 // transcribed, stored in a retrieval system, translated into any human or computer
7 // language by any means, or disclosed to third parties without the explicit written
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9 // or implied, including but not limited to any patent rights, are granted to you.
12 // Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer
13 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
15 #include "Framebuffer.h"
18 #include "Renderbuffer.h"
20 #include "utilities.h"
25 Framebuffer::Framebuffer()
27 mColorbufferType = GL_NONE;
28 mDepthbufferType = GL_NONE;
29 mStencilbufferType = GL_NONE;
32 Framebuffer::~Framebuffer()
34 mColorbufferPointer.set(NULL);
35 mDepthbufferPointer.set(NULL);
36 mStencilbufferPointer.set(NULL);
39 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
41 Context *context = getContext();
42 Renderbuffer *buffer = NULL;
48 else if(type == GL_RENDERBUFFER)
50 buffer = context->getRenderbuffer(handle);
52 else if(IsTextureTarget(type))
54 buffer = context->getTexture(handle)->getRenderbuffer(type);
64 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
66 mColorbufferType = (colorbuffer != 0) ? type : GL_NONE;
67 mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
70 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
72 mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
73 mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
76 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
78 mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
79 mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
82 void Framebuffer::detachTexture(GLuint texture)
84 if(mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
86 mColorbufferType = GL_NONE;
87 mColorbufferPointer.set(NULL);
90 if(mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
92 mDepthbufferType = GL_NONE;
93 mDepthbufferPointer.set(NULL);
96 if(mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
98 mStencilbufferType = GL_NONE;
99 mStencilbufferPointer.set(NULL);
103 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
105 if(mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
107 mColorbufferType = GL_NONE;
108 mColorbufferPointer.set(NULL);
111 if(mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
113 mDepthbufferType = GL_NONE;
114 mDepthbufferPointer.set(NULL);
117 if(mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
119 mStencilbufferType = GL_NONE;
120 mStencilbufferPointer.set(NULL);
124 // Increments refcount on surface.
125 // caller must Release() the returned surface
126 egl::Image *Framebuffer::getRenderTarget()
128 Renderbuffer *colorbuffer = mColorbufferPointer.get();
132 return colorbuffer->getRenderTarget();
138 // Increments refcount on surface.
139 // caller must Release() the returned surface
140 egl::Image *Framebuffer::getDepthStencil()
142 Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
144 if(!depthstencilbuffer)
146 depthstencilbuffer = mStencilbufferPointer.get();
149 if(depthstencilbuffer)
151 return depthstencilbuffer->getRenderTarget();
157 Renderbuffer *Framebuffer::getColorbuffer()
159 return mColorbufferPointer.get();
162 Renderbuffer *Framebuffer::getDepthbuffer()
164 return mDepthbufferPointer.get();
167 Renderbuffer *Framebuffer::getStencilbuffer()
169 return mStencilbufferPointer.get();
172 GLenum Framebuffer::getColorbufferType()
174 return mColorbufferType;
177 GLenum Framebuffer::getDepthbufferType()
179 return mDepthbufferType;
182 GLenum Framebuffer::getStencilbufferType()
184 return mStencilbufferType;
187 GLuint Framebuffer::getColorbufferHandle()
189 return mColorbufferPointer.id();
192 GLuint Framebuffer::getDepthbufferHandle()
194 return mDepthbufferPointer.id();
197 GLuint Framebuffer::getStencilbufferHandle()
199 return mStencilbufferPointer.id();
202 bool Framebuffer::hasStencil()
204 if(mStencilbufferType != GL_NONE)
206 Renderbuffer *stencilbufferObject = getStencilbuffer();
208 if(stencilbufferObject)
210 return stencilbufferObject->getStencilSize() > 0;
217 GLenum Framebuffer::completeness()
223 return completeness(width, height, samples);
226 GLenum Framebuffer::completeness(int &width, int &height, int &samples)
232 if(mColorbufferType != GL_NONE)
234 Renderbuffer *colorbuffer = getColorbuffer();
238 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
241 if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
243 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
246 if(mColorbufferType == GL_RENDERBUFFER)
248 if(!es2::IsColorRenderable(colorbuffer->getFormat()))
250 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
253 else if(IsTextureTarget(mColorbufferType))
255 GLenum format = colorbuffer->getFormat();
257 if(IsCompressed(format) ||
258 format == GL_ALPHA ||
259 format == GL_LUMINANCE ||
260 format == GL_LUMINANCE_ALPHA)
262 return GL_FRAMEBUFFER_UNSUPPORTED;
265 if(es2::IsDepthTexture(format) || es2::IsStencilTexture(format))
267 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
273 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
276 width = colorbuffer->getWidth();
277 height = colorbuffer->getHeight();
278 samples = colorbuffer->getSamples();
281 Renderbuffer *depthbuffer = NULL;
282 Renderbuffer *stencilbuffer = NULL;
284 if(mDepthbufferType != GL_NONE)
286 depthbuffer = getDepthbuffer();
290 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
293 if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
295 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
298 if(mDepthbufferType == GL_RENDERBUFFER)
300 if(!es2::IsDepthRenderable(depthbuffer->getFormat()))
302 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
305 else if(IsTextureTarget(mDepthbufferType))
307 if(!es2::IsDepthTexture(depthbuffer->getFormat()))
309 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
315 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
318 if(width == -1 || height == -1)
320 width = depthbuffer->getWidth();
321 height = depthbuffer->getHeight();
322 samples = depthbuffer->getSamples();
324 else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
326 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
328 else if(samples != depthbuffer->getSamples())
330 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
334 if(mStencilbufferType != GL_NONE)
336 stencilbuffer = getStencilbuffer();
340 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
343 if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
345 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
348 if(mStencilbufferType == GL_RENDERBUFFER)
350 if(!es2::IsStencilRenderable(stencilbuffer->getFormat()))
352 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
355 else if(IsTextureTarget(mStencilbufferType))
357 GLenum internalformat = stencilbuffer->getFormat();
359 if(!es2::IsStencilTexture(internalformat))
361 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
367 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
370 if(width == -1 || height == -1)
372 width = stencilbuffer->getWidth();
373 height = stencilbuffer->getHeight();
374 samples = stencilbuffer->getSamples();
376 else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
378 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
380 else if(samples != stencilbuffer->getSamples())
382 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
386 // If we have both a depth and stencil buffer, they must refer to the same object
387 // since we only support packed_depth_stencil and not separate depth and stencil
388 if(depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
390 return GL_FRAMEBUFFER_UNSUPPORTED;
393 // We need to have at least one attachment to be complete
394 if(width == -1 || height == -1)
396 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
399 return GL_FRAMEBUFFER_COMPLETE;
402 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
404 mColorbufferPointer.set(new Renderbuffer(0, colorbuffer));
406 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
407 mDepthbufferPointer.set(depthStencilRenderbuffer);
408 mStencilbufferPointer.set(depthStencilRenderbuffer);
410 mColorbufferType = GL_RENDERBUFFER;
411 mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
412 mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
415 GLenum DefaultFramebuffer::completeness()
417 // The default framebuffer should always be complete
418 ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
420 return GL_FRAMEBUFFER_COMPLETE;