summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/Framebuffer.cpp')
-rw-r--r--src/3rdparty/angle/src/libANGLE/Framebuffer.cpp658
1 files changed, 658 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
new file mode 100644
index 0000000000..b1dd4a1b0f
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
@@ -0,0 +1,658 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
+
+#include "libANGLE/Framebuffer.h"
+
+#include "common/utilities.h"
+#include "libANGLE/Config.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Renderbuffer.h"
+#include "libANGLE/Surface.h"
+#include "libANGLE/Texture.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/FramebufferImpl.h"
+#include "libANGLE/renderer/ImplFactory.h"
+#include "libANGLE/renderer/RenderbufferImpl.h"
+#include "libANGLE/renderer/Workarounds.h"
+
+namespace gl
+{
+
+namespace
+{
+void DeleteMatchingAttachment(FramebufferAttachment *&attachment, GLenum matchType, GLuint matchId)
+{
+ if (attachment && attachment->type() == matchType && attachment->id() == matchId)
+ {
+ SafeDelete(attachment);
+ }
+}
+}
+
+Framebuffer::Data::Data(const Caps &caps)
+ : mColorAttachments(caps.maxColorAttachments, nullptr),
+ mDepthAttachment(nullptr),
+ mStencilAttachment(nullptr),
+ mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
+ mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
+{
+ mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
+}
+
+Framebuffer::Data::~Data()
+{
+ for (auto it = mColorAttachments.begin(); it != mColorAttachments.end(); ++it)
+ {
+ SafeDelete(*it);
+ }
+ SafeDelete(mDepthAttachment);
+ SafeDelete(mStencilAttachment);
+}
+
+FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
+{
+ ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
+ size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
+ ASSERT(readIndex < mColorAttachments.size());
+ return mColorAttachments[readIndex];
+}
+
+FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
+{
+ for (auto it = mColorAttachments.cbegin(); it != mColorAttachments.cend(); ++it)
+ {
+ if (*it != nullptr)
+ {
+ return *it;
+ }
+ }
+
+ return nullptr;
+}
+
+FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
+{
+ return (mDepthAttachment != nullptr ? mDepthAttachment : mStencilAttachment);
+}
+
+Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
+ : mData(caps),
+ mImpl(nullptr),
+ mId(id)
+{
+ if (mId == 0)
+ {
+ mImpl = factory->createDefaultFramebuffer(mData);
+ }
+ else
+ {
+ mImpl = factory->createFramebuffer(mData);
+ }
+ ASSERT(mImpl != nullptr);
+}
+
+Framebuffer::~Framebuffer()
+{
+ SafeDelete(mImpl);
+}
+
+void Framebuffer::detachTexture(GLuint textureId)
+{
+ detachResourceById(GL_TEXTURE, textureId);
+}
+
+void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
+{
+ detachResourceById(GL_RENDERBUFFER, renderbufferId);
+}
+
+void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
+{
+ for (auto it = mData.mColorAttachments.begin(); it != mData.mColorAttachments.end(); ++it)
+ {
+ DeleteMatchingAttachment(*it, resourceType, resourceId);
+ }
+
+ DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId);
+ DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId);
+}
+
+FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
+{
+ ASSERT(colorAttachment < mData.mColorAttachments.size());
+ return mData.mColorAttachments[colorAttachment];
+}
+
+FramebufferAttachment *Framebuffer::getDepthbuffer() const
+{
+ return mData.mDepthAttachment;
+}
+
+FramebufferAttachment *Framebuffer::getStencilbuffer() const
+{
+ return mData.mStencilAttachment;
+}
+
+FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
+{
+ return (hasValidDepthStencil() ? mData.mDepthAttachment : NULL);
+}
+
+FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
+{
+ return mData.getDepthOrStencilAttachment();
+}
+
+FramebufferAttachment *Framebuffer::getReadColorbuffer() const
+{
+ return mData.getReadAttachment();
+}
+
+GLenum Framebuffer::getReadColorbufferType() const
+{
+ FramebufferAttachment *readAttachment = mData.getReadAttachment();
+ return (readAttachment ? readAttachment->type() : GL_NONE);
+}
+
+FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
+{
+ return mData.getFirstColorAttachment();
+}
+
+FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
+{
+ if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
+ {
+ return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
+ }
+ else
+ {
+ switch (attachment)
+ {
+ case GL_COLOR:
+ case GL_BACK:
+ return getColorbuffer(0);
+ case GL_DEPTH:
+ case GL_DEPTH_ATTACHMENT:
+ return getDepthbuffer();
+ case GL_STENCIL:
+ case GL_STENCIL_ATTACHMENT:
+ return getStencilbuffer();
+ case GL_DEPTH_STENCIL:
+ case GL_DEPTH_STENCIL_ATTACHMENT:
+ return getDepthStencilBuffer();
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+ }
+}
+
+GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
+{
+ ASSERT(colorAttachment < mData.mDrawBufferStates.size());
+ return mData.mDrawBufferStates[colorAttachment];
+}
+
+void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
+{
+ auto &drawStates = mData.mDrawBufferStates;
+
+ ASSERT(count <= drawStates.size());
+ std::copy(buffers, buffers + count, drawStates.begin());
+ std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
+ mImpl->setDrawBuffers(count, buffers);
+}
+
+GLenum Framebuffer::getReadBufferState() const
+{
+ return mData.mReadBufferState;
+}
+
+void Framebuffer::setReadBuffer(GLenum buffer)
+{
+ ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
+ (buffer >= GL_COLOR_ATTACHMENT0 &&
+ (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
+ mData.mReadBufferState = buffer;
+ mImpl->setReadBuffer(buffer);
+}
+
+bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
+{
+ ASSERT(colorAttachment < mData.mColorAttachments.size());
+ return (mData.mColorAttachments[colorAttachment] &&
+ mData.mDrawBufferStates[colorAttachment] != GL_NONE);
+}
+
+bool Framebuffer::hasEnabledColorAttachment() const
+{
+ for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
+ {
+ if (isEnabledColorAttachment(colorAttachment))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Framebuffer::hasStencil() const
+{
+ return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0);
+}
+
+bool Framebuffer::usingExtendedDrawBuffers() const
+{
+ for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
+ {
+ if (isEnabledColorAttachment(colorAttachment))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+GLenum Framebuffer::checkStatus(const gl::Data &data) const
+{
+ // The default framebuffer *must* always be complete, though it may not be
+ // subject to the same rules as application FBOs. ie, it could have 0x0 size.
+ if (mId == 0)
+ {
+ return GL_FRAMEBUFFER_COMPLETE;
+ }
+
+ int width = 0;
+ int height = 0;
+ unsigned int colorbufferSize = 0;
+ int samples = -1;
+ bool missingAttachment = true;
+
+ for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it)
+ {
+ const auto &colorAttachment = *it;
+ if (colorAttachment != nullptr)
+ {
+ if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ GLenum internalformat = colorAttachment->getInternalFormat();
+ const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
+ const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
+ if (colorAttachment->type() == GL_TEXTURE)
+ {
+ if (!formatCaps.renderable)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if (colorAttachment->type() == GL_RENDERBUFFER)
+ {
+ if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+
+ if (!missingAttachment)
+ {
+ // all color attachments must have the same width and height
+ if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+
+ // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
+ // all color attachments have the same number of samples for the FBO to be complete.
+ if (colorAttachment->getSamples() != samples)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
+ }
+
+ // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
+ // in GLES 3.0, there is no such restriction
+ if (data.clientVersion < 3)
+ {
+ if (formatInfo.pixelBytes != colorbufferSize)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+ }
+ }
+ else
+ {
+ width = colorAttachment->getWidth();
+ height = colorAttachment->getHeight();
+ samples = colorAttachment->getSamples();
+ colorbufferSize = formatInfo.pixelBytes;
+ missingAttachment = false;
+ }
+ }
+ }
+
+ const FramebufferAttachment *depthAttachment = mData.mDepthAttachment;
+ if (depthAttachment != nullptr)
+ {
+ if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ GLenum internalformat = depthAttachment->getInternalFormat();
+ const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
+ const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
+ if (depthAttachment->type() == GL_TEXTURE)
+ {
+ // depth texture attachments require OES/ANGLE_depth_texture
+ if (!data.extensions->depthTextures)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (!formatCaps.renderable)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if (formatInfo.depthBits == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if (depthAttachment->type() == GL_RENDERBUFFER)
+ {
+ if (!formatCaps.renderable || formatInfo.depthBits == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+
+ if (missingAttachment)
+ {
+ width = depthAttachment->getWidth();
+ height = depthAttachment->getHeight();
+ samples = depthAttachment->getSamples();
+ missingAttachment = false;
+ }
+ else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+ else if (samples != depthAttachment->getSamples())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+ }
+ }
+
+ const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment;
+ if (stencilAttachment)
+ {
+ if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ GLenum internalformat = stencilAttachment->getInternalFormat();
+ const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
+ const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
+ if (stencilAttachment->type() == GL_TEXTURE)
+ {
+ // texture stencil attachments come along as part
+ // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
+ if (!data.extensions->depthTextures)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (!formatCaps.renderable)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if (formatInfo.stencilBits == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if (stencilAttachment->type() == GL_RENDERBUFFER)
+ {
+ if (!formatCaps.renderable || formatInfo.stencilBits == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+
+ if (missingAttachment)
+ {
+ width = stencilAttachment->getWidth();
+ height = stencilAttachment->getHeight();
+ samples = stencilAttachment->getSamples();
+ missingAttachment = false;
+ }
+ else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+ else if (samples != stencilAttachment->getSamples())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+ }
+ }
+
+ // if we have both a depth and stencil buffer, they must refer to the same object
+ // since we only support packed_depth_stencil and not separate depth and stencil
+ if (depthAttachment && stencilAttachment && !hasValidDepthStencil())
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ // we need to have at least one attachment to be complete
+ if (missingAttachment)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ }
+
+ return mImpl->checkStatus();
+}
+
+Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
+{
+ return mImpl->invalidate(count, attachments);
+}
+
+Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
+{
+ return mImpl->invalidateSub(count, attachments, area);
+}
+
+Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
+{
+ return mImpl->clear(data, mask);
+}
+
+Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
+{
+ return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
+}
+
+Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
+{
+ return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
+}
+
+Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
+{
+ return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
+}
+
+Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+{
+ return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
+}
+
+GLenum Framebuffer::getImplementationColorReadFormat() const
+{
+ return mImpl->getImplementationColorReadFormat();
+}
+
+GLenum Framebuffer::getImplementationColorReadType() const
+{
+ return mImpl->getImplementationColorReadType();
+}
+
+Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
+{
+ return mImpl->readPixels(state, area, format, type, pixels);
+}
+
+Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
+ GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
+{
+ return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
+}
+
+int Framebuffer::getSamples(const gl::Data &data) const
+{
+ if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE)
+ {
+ // for a complete framebuffer, all attachments must have the same sample count
+ // in this case return the first nonzero sample size
+ for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it)
+ {
+ if (*it != nullptr)
+ {
+ return (*it)->getSamples();
+ }
+ }
+ }
+
+ return 0;
+}
+
+bool Framebuffer::hasValidDepthStencil() const
+{
+ // A valid depth-stencil attachment has the same resource bound to both the
+ // depth and stencil attachment points.
+ return (mData.mDepthAttachment && mData.mStencilAttachment &&
+ mData.mDepthAttachment->type() == mData.mStencilAttachment->type() &&
+ mData.mDepthAttachment->id() == mData.mStencilAttachment->id());
+}
+
+void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
+{
+ setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
+}
+
+void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
+{
+ setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
+}
+
+void Framebuffer::setNULLAttachment(GLenum attachment)
+{
+ setAttachment(attachment, NULL);
+}
+
+void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
+{
+ if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size()))
+ {
+ size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
+ SafeDelete(mData.mColorAttachments[colorAttachment]);
+ mData.mColorAttachments[colorAttachment] = attachmentObj;
+ mImpl->setColorAttachment(colorAttachment, attachmentObj);
+ }
+ else if (attachment == GL_BACK)
+ {
+ SafeDelete(mData.mColorAttachments[0]);
+ mData.mColorAttachments[0] = attachmentObj;
+ mImpl->setColorAttachment(0, attachmentObj);
+ }
+ else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
+ {
+ SafeDelete(mData.mDepthAttachment);
+ mData.mDepthAttachment = attachmentObj;
+ mImpl->setDepthAttachment(attachmentObj);
+ }
+ else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
+ {
+ SafeDelete(mData.mStencilAttachment);
+ mData.mStencilAttachment = attachmentObj;
+ mImpl->setStencilAttachment(attachmentObj);
+ }
+ else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
+ {
+ SafeDelete(mData.mDepthAttachment);
+ SafeDelete(mData.mStencilAttachment);
+
+ // ensure this is a legitimate depth+stencil format
+ if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
+ {
+ mData.mDepthAttachment = attachmentObj;
+ mImpl->setDepthAttachment(attachmentObj);
+
+ // Make a new attachment object to ensure we do not double-delete
+ // See angle issue 686
+ if (attachmentObj->type() == GL_TEXTURE)
+ {
+ mData.mStencilAttachment = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
+ *attachmentObj->getTextureImageIndex());
+ mImpl->setStencilAttachment(mData.mStencilAttachment);
+ }
+ else if (attachmentObj->type() == GL_RENDERBUFFER)
+ {
+ mData.mStencilAttachment = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
+ mImpl->setStencilAttachment(mData.mStencilAttachment);
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+}
+
+DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface)
+ : Framebuffer(caps, factory, 0)
+{
+ const egl::Config *config = surface->getConfig();
+
+ setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, surface));
+
+ if (config->depthSize > 0)
+ {
+ setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, surface));
+ }
+ if (config->stencilSize > 0)
+ {
+ setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, surface));
+ }
+
+ GLenum drawBufferState = GL_BACK;
+ setDrawBuffers(1, &drawBufferState);
+
+ setReadBuffer(GL_BACK);
+}
+
+}