// 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. // Renderbuffer.cpp: the Renderbuffer class and its derived classes // Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer // objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. #include "Renderbuffer.h" #include "main.h" #include "Texture.h" #include "utilities.h" namespace es2 { RenderbufferInterface::RenderbufferInterface() { } // The default case for classes inherited from RenderbufferInterface is not to // need to do anything upon the reference count to the parent Renderbuffer incrementing // or decrementing. void RenderbufferInterface::addProxyRef(const Renderbuffer *proxy) { } void RenderbufferInterface::releaseProxy(const Renderbuffer *proxy) { } GLuint RenderbufferInterface::getRedSize() const { return GetRedSize(getFormat()); } GLuint RenderbufferInterface::getGreenSize() const { return GetGreenSize(getFormat()); } GLuint RenderbufferInterface::getBlueSize() const { return GetBlueSize(getFormat()); } GLuint RenderbufferInterface::getAlphaSize() const { return GetAlphaSize(getFormat()); } GLuint RenderbufferInterface::getDepthSize() const { return GetDepthSize(getFormat()); } GLuint RenderbufferInterface::getStencilSize() const { return GetStencilSize(getFormat()); } ///// RenderbufferTexture2D Implementation //////// RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture, GLint level) : mLevel(level) { mTexture2D = texture; } RenderbufferTexture2D::~RenderbufferTexture2D() { mTexture2D = nullptr; } // Textures need to maintain their own reference count for references via // Renderbuffers acting as proxies. Here, we notify the texture of a reference. void RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy) { mTexture2D->addProxyRef(proxy); } void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy) { mTexture2D->releaseProxy(proxy); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTexture2D::getRenderTarget() { return mTexture2D->getRenderTarget(GL_TEXTURE_2D, mLevel); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTexture2D::createSharedImage() { return mTexture2D->createSharedImage(GL_TEXTURE_2D, mLevel); } bool RenderbufferTexture2D::isShared() const { return mTexture2D->isShared(GL_TEXTURE_2D, mLevel); } GLsizei RenderbufferTexture2D::getWidth() const { return mTexture2D->getWidth(GL_TEXTURE_2D, mLevel); } GLsizei RenderbufferTexture2D::getHeight() const { return mTexture2D->getHeight(GL_TEXTURE_2D, mLevel); } GLint RenderbufferTexture2D::getFormat() const { return mTexture2D->getFormat(GL_TEXTURE_2D, mLevel); } GLsizei RenderbufferTexture2D::getSamples() const { return 0; // Core OpenGL ES 3.0 does not support multisample textures. } ///// RenderbufferTexture2DRect Implementation //////// RenderbufferTexture2DRect::RenderbufferTexture2DRect(Texture2DRect *texture) { mTexture2DRect = texture; } RenderbufferTexture2DRect::~RenderbufferTexture2DRect() { mTexture2DRect = NULL; } // Textures need to maintain their own reference count for references via // Renderbuffers acting as proxies. Here, we notify the texture of a reference. void RenderbufferTexture2DRect::addProxyRef(const Renderbuffer *proxy) { mTexture2DRect->addProxyRef(proxy); } void RenderbufferTexture2DRect::releaseProxy(const Renderbuffer *proxy) { mTexture2DRect->releaseProxy(proxy); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTexture2DRect::getRenderTarget() { return mTexture2DRect->getRenderTarget(GL_TEXTURE_RECTANGLE_ARB, 0); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTexture2DRect::createSharedImage() { return mTexture2DRect->createSharedImage(GL_TEXTURE_RECTANGLE_ARB, 0); } bool RenderbufferTexture2DRect::isShared() const { return mTexture2DRect->isShared(GL_TEXTURE_RECTANGLE_ARB, 0); } GLsizei RenderbufferTexture2DRect::getWidth() const { return mTexture2DRect->getWidth(GL_TEXTURE_RECTANGLE_ARB, 0); } GLsizei RenderbufferTexture2DRect::getHeight() const { return mTexture2DRect->getHeight(GL_TEXTURE_RECTANGLE_ARB, 0); } GLint RenderbufferTexture2DRect::getFormat() const { return mTexture2DRect->getFormat(GL_TEXTURE_RECTANGLE_ARB, 0); } GLsizei RenderbufferTexture2DRect::getSamples() const { return 0; // Core OpenGL ES 3.0 does not support multisample textures. } ///// RenderbufferTexture3D Implementation //////// RenderbufferTexture3D::RenderbufferTexture3D(Texture3D *texture, GLint level) : mLevel(level) { mTexture3D = texture; } RenderbufferTexture3D::~RenderbufferTexture3D() { mTexture3D = NULL; } // Textures need to maintain their own reference count for references via // Renderbuffers acting as proxies. Here, we notify the texture of a reference. void RenderbufferTexture3D::addProxyRef(const Renderbuffer *proxy) { mTexture3D->addProxyRef(proxy); } void RenderbufferTexture3D::releaseProxy(const Renderbuffer *proxy) { mTexture3D->releaseProxy(proxy); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTexture3D::getRenderTarget() { return mTexture3D->getRenderTarget(mTexture3D->getTarget(), mLevel); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTexture3D::createSharedImage() { return mTexture3D->createSharedImage(mTexture3D->getTarget(), mLevel); } bool RenderbufferTexture3D::isShared() const { return mTexture3D->isShared(mTexture3D->getTarget(), mLevel); } GLsizei RenderbufferTexture3D::getWidth() const { return mTexture3D->getWidth(mTexture3D->getTarget(), mLevel); } GLsizei RenderbufferTexture3D::getHeight() const { return mTexture3D->getHeight(mTexture3D->getTarget(), mLevel); } GLsizei RenderbufferTexture3D::getDepth() const { return mTexture3D->getDepth(mTexture3D->getTarget(), mLevel); } GLint RenderbufferTexture3D::getFormat() const { return mTexture3D->getFormat(mTexture3D->getTarget(), mLevel); } GLsizei RenderbufferTexture3D::getSamples() const { return 0; // Core OpenGL ES 3.0 does not support multisample textures. } ///// RenderbufferTextureCubeMap Implementation //////// RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target, GLint level) : mTarget(target), mLevel(level) { mTextureCubeMap = texture; } RenderbufferTextureCubeMap::~RenderbufferTextureCubeMap() { mTextureCubeMap = NULL; } // Textures need to maintain their own reference count for references via // Renderbuffers acting as proxies. Here, we notify the texture of a reference. void RenderbufferTextureCubeMap::addProxyRef(const Renderbuffer *proxy) { mTextureCubeMap->addProxyRef(proxy); } void RenderbufferTextureCubeMap::releaseProxy(const Renderbuffer *proxy) { mTextureCubeMap->releaseProxy(proxy); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTextureCubeMap::getRenderTarget() { return mTextureCubeMap->getRenderTarget(mTarget, mLevel); } // Increments refcount on image. // caller must release() the returned image egl::Image *RenderbufferTextureCubeMap::createSharedImage() { return mTextureCubeMap->createSharedImage(mTarget, mLevel); } bool RenderbufferTextureCubeMap::isShared() const { return mTextureCubeMap->isShared(mTarget, mLevel); } GLsizei RenderbufferTextureCubeMap::getWidth() const { return mTextureCubeMap->getWidth(mTarget, mLevel); } GLsizei RenderbufferTextureCubeMap::getHeight() const { return mTextureCubeMap->getHeight(mTarget, mLevel); } GLint RenderbufferTextureCubeMap::getFormat() const { return mTextureCubeMap->getFormat(mTarget, mLevel); } GLsizei RenderbufferTextureCubeMap::getSamples() const { return 0; // Core OpenGL ES 3.0 does not support multisample textures. } ////// Renderbuffer Implementation ////// Renderbuffer::Renderbuffer(GLuint name, RenderbufferInterface *instance) : NamedObject(name) { ASSERT(instance); mInstance = instance; } Renderbuffer::~Renderbuffer() { delete mInstance; } // The RenderbufferInterface contained in this Renderbuffer may need to maintain // its own reference count, so we pass it on here. void Renderbuffer::addRef() { mInstance->addProxyRef(this); Object::addRef(); } void Renderbuffer::release() { mInstance->releaseProxy(this); Object::release(); } // Increments refcount on image. // caller must Release() the returned image egl::Image *Renderbuffer::getRenderTarget() { return mInstance->getRenderTarget(); } // Increments refcount on image. // caller must Release() the returned image egl::Image *Renderbuffer::createSharedImage() { return mInstance->createSharedImage(); } bool Renderbuffer::isShared() const { return mInstance->isShared(); } GLsizei Renderbuffer::getWidth() const { return mInstance->getWidth(); } GLsizei Renderbuffer::getHeight() const { return mInstance->getHeight(); } GLsizei Renderbuffer::getDepth() const { return mInstance->getDepth(); } GLint Renderbuffer::getLevel() const { return mInstance->getLevel(); } GLint Renderbuffer::getFormat() const { return mInstance->getFormat(); } GLuint Renderbuffer::getRedSize() const { return mInstance->getRedSize(); } GLuint Renderbuffer::getGreenSize() const { return mInstance->getGreenSize(); } GLuint Renderbuffer::getBlueSize() const { return mInstance->getBlueSize(); } GLuint Renderbuffer::getAlphaSize() const { return mInstance->getAlphaSize(); } GLuint Renderbuffer::getDepthSize() const { return mInstance->getDepthSize(); } GLuint Renderbuffer::getStencilSize() const { return mInstance->getStencilSize(); } GLsizei Renderbuffer::getSamples() const { return mInstance->getSamples(); } void Renderbuffer::setLevel(GLint level) { return mInstance->setLevel(level); } void Renderbuffer::setStorage(RenderbufferStorage *newStorage) { ASSERT(newStorage); delete mInstance; mInstance = newStorage; } RenderbufferStorage::RenderbufferStorage() { mWidth = 0; mHeight = 0; format = GL_NONE; mSamples = 0; } RenderbufferStorage::~RenderbufferStorage() { } GLsizei RenderbufferStorage::getWidth() const { return mWidth; } GLsizei RenderbufferStorage::getHeight() const { return mHeight; } GLint RenderbufferStorage::getFormat() const { return format; } GLsizei RenderbufferStorage::getSamples() const { return mSamples; } Colorbuffer::Colorbuffer(egl::Image *renderTarget) : mRenderTarget(renderTarget) { if(renderTarget) { renderTarget->addRef(); mWidth = renderTarget->getWidth(); mHeight = renderTarget->getHeight(); format = renderTarget->getFormat(); mSamples = renderTarget->getDepth() & ~1; } } Colorbuffer::Colorbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mRenderTarget(nullptr) { int supportedSamples = Context::getSupportedMultisampleCount(samples); if(width > 0 && height > 0) { if(height > sw::OUTLINE_RESOLUTION) { error(GL_OUT_OF_MEMORY); return; } mRenderTarget = egl::Image::create(width, height, internalformat, supportedSamples, false); if(!mRenderTarget) { error(GL_OUT_OF_MEMORY); return; } } mWidth = width; mHeight = height; format = internalformat; mSamples = supportedSamples; } Colorbuffer::~Colorbuffer() { if(mRenderTarget) { mRenderTarget->release(); } } // Increments refcount on image. // caller must release() the returned image egl::Image *Colorbuffer::getRenderTarget() { if(mRenderTarget) { mRenderTarget->addRef(); } return mRenderTarget; } // Increments refcount on image. // caller must release() the returned image egl::Image *Colorbuffer::createSharedImage() { if(mRenderTarget) { mRenderTarget->addRef(); mRenderTarget->markShared(); } return mRenderTarget; } bool Colorbuffer::isShared() const { return mRenderTarget->isShared(); } DepthStencilbuffer::DepthStencilbuffer(egl::Image *depthStencil) : mDepthStencil(depthStencil) { if(depthStencil) { depthStencil->addRef(); mWidth = depthStencil->getWidth(); mHeight = depthStencil->getHeight(); format = depthStencil->getFormat(); mSamples = depthStencil->getDepth() & ~1; } } DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLenum internalformat, GLsizei samples) : mDepthStencil(nullptr) { int supportedSamples = Context::getSupportedMultisampleCount(samples); if(width > 0 && height > 0) { if(height > sw::OUTLINE_RESOLUTION) { error(GL_OUT_OF_MEMORY); return; } mDepthStencil = egl::Image::create(width, height, internalformat, supportedSamples, false); if(!mDepthStencil) { error(GL_OUT_OF_MEMORY); return; } } mWidth = width; mHeight = height; format = internalformat; mSamples = supportedSamples; } DepthStencilbuffer::~DepthStencilbuffer() { if(mDepthStencil) { mDepthStencil->release(); } } // Increments refcount on image. // caller must release() the returned image egl::Image *DepthStencilbuffer::getRenderTarget() { if(mDepthStencil) { mDepthStencil->addRef(); } return mDepthStencil; } // Increments refcount on image. // caller must release() the returned image egl::Image *DepthStencilbuffer::createSharedImage() { if(mDepthStencil) { mDepthStencil->addRef(); mDepthStencil->markShared(); } return mDepthStencil; } bool DepthStencilbuffer::isShared() const { return mDepthStencil->isShared(); } Depthbuffer::Depthbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil) { } Depthbuffer::Depthbuffer(int width, int height, GLenum internalformat, GLsizei samples) : DepthStencilbuffer(width, height, internalformat, samples) { } Depthbuffer::~Depthbuffer() { } Stencilbuffer::Stencilbuffer(egl::Image *depthStencil) : DepthStencilbuffer(depthStencil) { } Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, GL_STENCIL_INDEX8, samples) { } Stencilbuffer::~Stencilbuffer() { } }