|  | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | // Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer | 
|  | // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. | 
|  |  | 
|  | #include "Framebuffer.h" | 
|  |  | 
|  | #include "main.h" | 
|  | #include "Renderbuffer.h" | 
|  | #include "Texture.h" | 
|  | #include "utilities.h" | 
|  |  | 
|  | namespace es1 | 
|  | { | 
|  |  | 
|  | Framebuffer::Framebuffer() | 
|  | { | 
|  | mColorbufferType = GL_NONE_OES; | 
|  | mDepthbufferType = GL_NONE_OES; | 
|  | mStencilbufferType = GL_NONE_OES; | 
|  | } | 
|  |  | 
|  | Framebuffer::~Framebuffer() | 
|  | { | 
|  | mColorbufferPointer = nullptr; | 
|  | mDepthbufferPointer = nullptr; | 
|  | mStencilbufferPointer = nullptr; | 
|  | } | 
|  |  | 
|  | Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle, GLint level) const | 
|  | { | 
|  | Context *context = getContext(); | 
|  | Renderbuffer *buffer = nullptr; | 
|  |  | 
|  | if(type == GL_NONE_OES) | 
|  | { | 
|  | buffer = nullptr; | 
|  | } | 
|  | else if(type == GL_RENDERBUFFER_OES) | 
|  | { | 
|  | buffer = context->getRenderbuffer(handle); | 
|  | } | 
|  | else if(IsTextureTarget(type)) | 
|  | { | 
|  | buffer = context->getTexture(handle)->getRenderbuffer(type, level); | 
|  | } | 
|  | else UNREACHABLE(type); | 
|  |  | 
|  | return buffer; | 
|  | } | 
|  |  | 
|  | void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer, GLint level) | 
|  | { | 
|  | mColorbufferType = (colorbuffer != 0) ? type : GL_NONE_OES; | 
|  | mColorbufferPointer = lookupRenderbuffer(type, colorbuffer, level); | 
|  | } | 
|  |  | 
|  | void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level) | 
|  | { | 
|  | mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE_OES; | 
|  | mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer, level); | 
|  | } | 
|  |  | 
|  | void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level) | 
|  | { | 
|  | mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE_OES; | 
|  | mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer, level); | 
|  | } | 
|  |  | 
|  | void Framebuffer::detachTexture(GLuint texture) | 
|  | { | 
|  | if(mColorbufferPointer.name() == texture && IsTextureTarget(mColorbufferType)) | 
|  | { | 
|  | mColorbufferType = GL_NONE_OES; | 
|  | mColorbufferPointer = nullptr; | 
|  | } | 
|  |  | 
|  | if(mDepthbufferPointer.name() == texture && IsTextureTarget(mDepthbufferType)) | 
|  | { | 
|  | mDepthbufferType = GL_NONE_OES; | 
|  | mDepthbufferPointer = nullptr; | 
|  | } | 
|  |  | 
|  | if(mStencilbufferPointer.name() == texture && IsTextureTarget(mStencilbufferType)) | 
|  | { | 
|  | mStencilbufferType = GL_NONE_OES; | 
|  | mStencilbufferPointer = nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | void Framebuffer::detachRenderbuffer(GLuint renderbuffer) | 
|  | { | 
|  | if(mColorbufferPointer.name() == renderbuffer && mColorbufferType == GL_RENDERBUFFER_OES) | 
|  | { | 
|  | mColorbufferType = GL_NONE_OES; | 
|  | mColorbufferPointer = nullptr; | 
|  | } | 
|  |  | 
|  | if(mDepthbufferPointer.name() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER_OES) | 
|  | { | 
|  | mDepthbufferType = GL_NONE_OES; | 
|  | mDepthbufferPointer = nullptr; | 
|  | } | 
|  |  | 
|  | if(mStencilbufferPointer.name() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER_OES) | 
|  | { | 
|  | mStencilbufferType = GL_NONE_OES; | 
|  | mStencilbufferPointer = nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Increments refcount on surface. | 
|  | // caller must Release() the returned surface | 
|  | egl::Image *Framebuffer::getRenderTarget() | 
|  | { | 
|  | Renderbuffer *colorbuffer = mColorbufferPointer; | 
|  |  | 
|  | if(colorbuffer) | 
|  | { | 
|  | return colorbuffer->getRenderTarget(); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Increments refcount on surface. | 
|  | // caller must Release() the returned surface | 
|  | egl::Image *Framebuffer::getDepthBuffer() | 
|  | { | 
|  | Renderbuffer *depthbuffer = mDepthbufferPointer; | 
|  |  | 
|  | if(depthbuffer) | 
|  | { | 
|  | return depthbuffer->getRenderTarget(); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Increments refcount on surface. | 
|  | // caller must Release() the returned surface | 
|  | egl::Image *Framebuffer::getStencilBuffer() | 
|  | { | 
|  | Renderbuffer *stencilbuffer = mStencilbufferPointer; | 
|  |  | 
|  | if(stencilbuffer) | 
|  | { | 
|  | return stencilbuffer->getRenderTarget(); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | Renderbuffer *Framebuffer::getColorbuffer() | 
|  | { | 
|  | return mColorbufferPointer; | 
|  | } | 
|  |  | 
|  | Renderbuffer *Framebuffer::getDepthbuffer() | 
|  | { | 
|  | return mDepthbufferPointer; | 
|  | } | 
|  |  | 
|  | Renderbuffer *Framebuffer::getStencilbuffer() | 
|  | { | 
|  | return mStencilbufferPointer; | 
|  | } | 
|  |  | 
|  | GLenum Framebuffer::getColorbufferType() | 
|  | { | 
|  | return mColorbufferType; | 
|  | } | 
|  |  | 
|  | GLenum Framebuffer::getDepthbufferType() | 
|  | { | 
|  | return mDepthbufferType; | 
|  | } | 
|  |  | 
|  | GLenum Framebuffer::getStencilbufferType() | 
|  | { | 
|  | return mStencilbufferType; | 
|  | } | 
|  |  | 
|  | GLuint Framebuffer::getColorbufferName() | 
|  | { | 
|  | return mColorbufferPointer.name(); | 
|  | } | 
|  |  | 
|  | GLuint Framebuffer::getDepthbufferName() | 
|  | { | 
|  | return mDepthbufferPointer.name(); | 
|  | } | 
|  |  | 
|  | GLuint Framebuffer::getStencilbufferName() | 
|  | { | 
|  | return mStencilbufferPointer.name(); | 
|  | } | 
|  |  | 
|  | bool Framebuffer::hasStencil() | 
|  | { | 
|  | if(mStencilbufferType != GL_NONE_OES) | 
|  | { | 
|  | Renderbuffer *stencilbufferObject = getStencilbuffer(); | 
|  |  | 
|  | if(stencilbufferObject) | 
|  | { | 
|  | return stencilbufferObject->getStencilSize() > 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GLenum Framebuffer::completeness() | 
|  | { | 
|  | int width; | 
|  | int height; | 
|  | int samples; | 
|  |  | 
|  | return completeness(width, height, samples); | 
|  | } | 
|  |  | 
|  | GLenum Framebuffer::completeness(int &width, int &height, int &samples) | 
|  | { | 
|  | width = -1; | 
|  | height = -1; | 
|  | samples = -1; | 
|  |  | 
|  | if(mColorbufferType != GL_NONE_OES) | 
|  | { | 
|  | Renderbuffer *colorbuffer = getColorbuffer(); | 
|  |  | 
|  | if(!colorbuffer) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(mColorbufferType == GL_RENDERBUFFER_OES) | 
|  | { | 
|  | if(!IsColorRenderable(colorbuffer->getFormat())) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  | } | 
|  | else if(IsTextureTarget(mColorbufferType)) | 
|  | { | 
|  | GLenum format = colorbuffer->getFormat(); | 
|  |  | 
|  | if(!IsColorRenderable(format)) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(IsDepthTexture(format) || IsStencilTexture(format)) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | UNREACHABLE(mColorbufferType); | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | width = colorbuffer->getWidth(); | 
|  | height = colorbuffer->getHeight(); | 
|  | samples = colorbuffer->getSamples(); | 
|  | } | 
|  |  | 
|  | Renderbuffer *depthbuffer = nullptr; | 
|  | Renderbuffer *stencilbuffer = nullptr; | 
|  |  | 
|  | if(mDepthbufferType != GL_NONE_OES) | 
|  | { | 
|  | depthbuffer = getDepthbuffer(); | 
|  |  | 
|  | if(!depthbuffer) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(mDepthbufferType == GL_RENDERBUFFER_OES) | 
|  | { | 
|  | if(!es1::IsDepthRenderable(depthbuffer->getFormat())) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  | } | 
|  | else if(IsTextureTarget(mDepthbufferType)) | 
|  | { | 
|  | if(!es1::IsDepthTexture(depthbuffer->getFormat())) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | UNREACHABLE(mDepthbufferType); | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(width == -1 || height == -1) | 
|  | { | 
|  | width = depthbuffer->getWidth(); | 
|  | height = depthbuffer->getHeight(); | 
|  | samples = depthbuffer->getSamples(); | 
|  | } | 
|  | else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES; | 
|  | } | 
|  | else if(samples != depthbuffer->getSamples()) | 
|  | { | 
|  | UNREACHABLE(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | if(mStencilbufferType != GL_NONE_OES) | 
|  | { | 
|  | stencilbuffer = getStencilbuffer(); | 
|  |  | 
|  | if(!stencilbuffer) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(mStencilbufferType == GL_RENDERBUFFER_OES) | 
|  | { | 
|  | if(!es1::IsStencilRenderable(stencilbuffer->getFormat())) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  | } | 
|  | else if(IsTextureTarget(mStencilbufferType)) | 
|  | { | 
|  | GLenum internalformat = stencilbuffer->getFormat(); | 
|  |  | 
|  | if(!es1::IsStencilTexture(internalformat)) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | UNREACHABLE(mStencilbufferType); | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | if(width == -1 || height == -1) | 
|  | { | 
|  | width = stencilbuffer->getWidth(); | 
|  | height = stencilbuffer->getHeight(); | 
|  | samples = stencilbuffer->getSamples(); | 
|  | } | 
|  | else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES; | 
|  | } | 
|  | else if(samples != stencilbuffer->getSamples()) | 
|  | { | 
|  | UNREACHABLE(0); | 
|  | return GL_FRAMEBUFFER_UNSUPPORTED_OES;   // GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_OES; | 
|  | } | 
|  | } | 
|  |  | 
|  | // We need to have at least one attachment to be complete | 
|  | if(width == -1 || height == -1) | 
|  | { | 
|  | return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES; | 
|  | } | 
|  |  | 
|  | return GL_FRAMEBUFFER_COMPLETE_OES; | 
|  | } | 
|  |  | 
|  | GLenum Framebuffer::getImplementationColorReadFormat() | 
|  | { | 
|  | Renderbuffer *colorbuffer = mColorbufferPointer; | 
|  |  | 
|  | if(colorbuffer) | 
|  | { | 
|  | switch(colorbuffer->getFormat()) | 
|  | { | 
|  | case GL_BGRA8_EXT:   return GL_BGRA_EXT; | 
|  | case GL_RGBA4_OES:   return GL_RGBA; | 
|  | case GL_RGB5_A1_OES: return GL_RGBA; | 
|  | case GL_RGBA8_OES:   return GL_RGBA; | 
|  | case GL_RGB565_OES:  return GL_RGBA; | 
|  | case GL_RGB8_OES:    return GL_RGB; | 
|  | default: | 
|  | UNREACHABLE(colorbuffer->getFormat()); | 
|  | } | 
|  | } | 
|  |  | 
|  | return GL_RGBA; | 
|  | } | 
|  |  | 
|  | GLenum Framebuffer::getImplementationColorReadType() | 
|  | { | 
|  | Renderbuffer *colorbuffer = mColorbufferPointer; | 
|  |  | 
|  | if(colorbuffer) | 
|  | { | 
|  | switch(colorbuffer->getFormat()) | 
|  | { | 
|  | case GL_BGRA8_EXT:   return GL_UNSIGNED_BYTE; | 
|  | case GL_RGBA4_OES:   return GL_UNSIGNED_SHORT_4_4_4_4; | 
|  | case GL_RGB5_A1_OES: return GL_UNSIGNED_SHORT_5_5_5_1; | 
|  | case GL_RGBA8_OES:   return GL_UNSIGNED_BYTE; | 
|  | case GL_RGB565_OES:  return GL_UNSIGNED_SHORT_5_6_5; | 
|  | case GL_RGB8_OES:    return GL_UNSIGNED_BYTE; | 
|  | default: | 
|  | UNREACHABLE(colorbuffer->getFormat()); | 
|  | } | 
|  | } | 
|  |  | 
|  | return GL_UNSIGNED_BYTE; | 
|  | } | 
|  |  | 
|  | DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) | 
|  | { | 
|  | mColorbufferPointer = new Renderbuffer(0, colorbuffer); | 
|  |  | 
|  | Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); | 
|  | mDepthbufferPointer = depthStencilRenderbuffer; | 
|  | mStencilbufferPointer = depthStencilRenderbuffer; | 
|  |  | 
|  | mColorbufferType = GL_RENDERBUFFER_OES; | 
|  | mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES; | 
|  | mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES; | 
|  | } | 
|  |  | 
|  | } |