1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer
16 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
18 #include "Framebuffer.h"
21 #include "Renderbuffer.h"
23 #include "utilities.h"
28 Framebuffer::Framebuffer()
30 mColorbufferType = GL_NONE_OES;
31 mDepthbufferType = GL_NONE_OES;
32 mStencilbufferType = GL_NONE_OES;
35 Framebuffer::~Framebuffer()
37 mColorbufferPointer = nullptr;
38 mDepthbufferPointer = nullptr;
39 mStencilbufferPointer = nullptr;
42 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
44 Context *context = getContext();
45 Renderbuffer *buffer = nullptr;
47 if(type == GL_NONE_OES)
51 else if(type == GL_RENDERBUFFER_OES)
53 buffer = context->getRenderbuffer(handle);
55 else if(IsTextureTarget(type))
57 buffer = context->getTexture(handle)->getRenderbuffer(type);
59 else UNREACHABLE(type);
64 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
66 mColorbufferType = (colorbuffer != 0) ? type : GL_NONE_OES;
67 mColorbufferPointer = lookupRenderbuffer(type, colorbuffer);
70 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
72 mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE_OES;
73 mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer);
76 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
78 mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE_OES;
79 mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer);
82 void Framebuffer::detachTexture(GLuint texture)
84 if(mColorbufferPointer.name() == texture && IsTextureTarget(mColorbufferType))
86 mColorbufferType = GL_NONE_OES;
87 mColorbufferPointer = nullptr;
90 if(mDepthbufferPointer.name() == texture && IsTextureTarget(mDepthbufferType))
92 mDepthbufferType = GL_NONE_OES;
93 mDepthbufferPointer = nullptr;
96 if(mStencilbufferPointer.name() == texture && IsTextureTarget(mStencilbufferType))
98 mStencilbufferType = GL_NONE_OES;
99 mStencilbufferPointer = nullptr;
103 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
105 if(mColorbufferPointer.name() == renderbuffer && mColorbufferType == GL_RENDERBUFFER_OES)
107 mColorbufferType = GL_NONE_OES;
108 mColorbufferPointer = nullptr;
111 if(mDepthbufferPointer.name() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER_OES)
113 mDepthbufferType = GL_NONE_OES;
114 mDepthbufferPointer = nullptr;
117 if(mStencilbufferPointer.name() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER_OES)
119 mStencilbufferType = GL_NONE_OES;
120 mStencilbufferPointer = nullptr;
124 // Increments refcount on surface.
125 // caller must Release() the returned surface
126 egl::Image *Framebuffer::getRenderTarget()
128 Renderbuffer *colorbuffer = mColorbufferPointer;
132 return colorbuffer->getRenderTarget();
138 // Increments refcount on surface.
139 // caller must Release() the returned surface
140 egl::Image *Framebuffer::getDepthBuffer()
142 Renderbuffer *depthbuffer = mDepthbufferPointer;
146 return depthbuffer->getRenderTarget();
152 // Increments refcount on surface.
153 // caller must Release() the returned surface
154 egl::Image *Framebuffer::getStencilBuffer()
156 Renderbuffer *stencilbuffer = mStencilbufferPointer;
160 return stencilbuffer->getRenderTarget();
166 Renderbuffer *Framebuffer::getColorbuffer()
168 return mColorbufferPointer;
171 Renderbuffer *Framebuffer::getDepthbuffer()
173 return mDepthbufferPointer;
176 Renderbuffer *Framebuffer::getStencilbuffer()
178 return mStencilbufferPointer;
181 GLenum Framebuffer::getColorbufferType()
183 return mColorbufferType;
186 GLenum Framebuffer::getDepthbufferType()
188 return mDepthbufferType;
191 GLenum Framebuffer::getStencilbufferType()
193 return mStencilbufferType;
196 GLuint Framebuffer::getColorbufferName()
198 return mColorbufferPointer.name();
201 GLuint Framebuffer::getDepthbufferName()
203 return mDepthbufferPointer.name();
206 GLuint Framebuffer::getStencilbufferName()
208 return mStencilbufferPointer.name();
211 bool Framebuffer::hasStencil()
213 if(mStencilbufferType != GL_NONE_OES)
215 Renderbuffer *stencilbufferObject = getStencilbuffer();
217 if(stencilbufferObject)
219 return stencilbufferObject->getStencilSize() > 0;
226 GLenum Framebuffer::completeness()
232 return completeness(width, height, samples);
235 GLenum Framebuffer::completeness(int &width, int &height, int &samples)
241 if(mColorbufferType != GL_NONE_OES)
243 Renderbuffer *colorbuffer = getColorbuffer();
247 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
250 if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
252 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
255 if(mColorbufferType == GL_RENDERBUFFER_OES)
257 if(!IsColorRenderable(colorbuffer->getFormat()))
259 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
262 else if(IsTextureTarget(mColorbufferType))
264 GLenum format = colorbuffer->getFormat();
266 if(!IsColorRenderable(format))
268 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
271 if(IsDepthTexture(format) || IsStencilTexture(format))
273 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
278 UNREACHABLE(mColorbufferType);
279 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
282 width = colorbuffer->getWidth();
283 height = colorbuffer->getHeight();
284 samples = colorbuffer->getSamples();
287 Renderbuffer *depthbuffer = nullptr;
288 Renderbuffer *stencilbuffer = nullptr;
290 if(mDepthbufferType != GL_NONE_OES)
292 depthbuffer = getDepthbuffer();
296 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
299 if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
301 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
304 if(mDepthbufferType == GL_RENDERBUFFER_OES)
306 if(!es1::IsDepthRenderable(depthbuffer->getFormat()))
308 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
311 else if(IsTextureTarget(mDepthbufferType))
313 if(!es1::IsDepthTexture(depthbuffer->getFormat()))
315 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
320 UNREACHABLE(mDepthbufferType);
321 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
324 if(width == -1 || height == -1)
326 width = depthbuffer->getWidth();
327 height = depthbuffer->getHeight();
328 samples = depthbuffer->getSamples();
330 else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
332 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES;
334 else if(samples != depthbuffer->getSamples())
340 if(mStencilbufferType != GL_NONE_OES)
342 stencilbuffer = getStencilbuffer();
346 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
349 if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
351 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
354 if(mStencilbufferType == GL_RENDERBUFFER_OES)
356 if(!es1::IsStencilRenderable(stencilbuffer->getFormat()))
358 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
361 else if(IsTextureTarget(mStencilbufferType))
363 GLenum internalformat = stencilbuffer->getFormat();
365 if(!es1::IsStencilTexture(internalformat))
367 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
372 UNREACHABLE(mStencilbufferType);
373 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
376 if(width == -1 || height == -1)
378 width = stencilbuffer->getWidth();
379 height = stencilbuffer->getHeight();
380 samples = stencilbuffer->getSamples();
382 else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
384 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES;
386 else if(samples != stencilbuffer->getSamples())
389 return GL_FRAMEBUFFER_UNSUPPORTED_OES; // GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_OES;
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_OES;
399 return GL_FRAMEBUFFER_COMPLETE_OES;
402 GLenum Framebuffer::getImplementationColorReadFormat()
404 Renderbuffer *colorbuffer = mColorbufferPointer;
408 // Don't return GL_RGBA since that's always supported. Provide a second option here.
409 switch(colorbuffer->getInternalFormat())
411 case sw::FORMAT_A8R8G8B8: return GL_BGRA_EXT;
412 case sw::FORMAT_A8B8G8R8: return GL_BGRA_EXT;
413 case sw::FORMAT_X8R8G8B8: return 0x80E0; // GL_BGR_EXT
414 case sw::FORMAT_X8B8G8R8: return 0x80E0; // GL_BGR_EXT
415 case sw::FORMAT_A1R5G5B5: return GL_BGRA_EXT;
416 case sw::FORMAT_R5G6B5: return 0x80E0; // GL_BGR_EXT
418 UNREACHABLE(colorbuffer->getInternalFormat());
425 GLenum Framebuffer::getImplementationColorReadType()
427 Renderbuffer *colorbuffer = mColorbufferPointer;
431 switch(colorbuffer->getInternalFormat())
433 case sw::FORMAT_A8R8G8B8: return GL_UNSIGNED_BYTE;
434 case sw::FORMAT_A8B8G8R8: return GL_UNSIGNED_BYTE;
435 case sw::FORMAT_X8R8G8B8: return GL_UNSIGNED_BYTE;
436 case sw::FORMAT_X8B8G8R8: return GL_UNSIGNED_BYTE;
437 case sw::FORMAT_A1R5G5B5: return GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT;
438 case sw::FORMAT_R5G6B5: return GL_UNSIGNED_SHORT_5_6_5;
440 UNREACHABLE(colorbuffer->getInternalFormat());
444 return GL_UNSIGNED_BYTE;
447 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
449 mColorbufferPointer = new Renderbuffer(0, colorbuffer);
451 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
452 mDepthbufferPointer = depthStencilRenderbuffer;
453 mStencilbufferPointer = depthStencilRenderbuffer;
455 mColorbufferType = GL_RENDERBUFFER_OES;
456 mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES;
457 mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES;