| // |
| // Copyright 2015 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. |
| // |
| |
| // FramebufferGL.cpp: Implements the class methods for FramebufferGL. |
| |
| #include "libANGLE/renderer/gl/FramebufferGL.h" |
| |
| #include "common/debug.h" |
| #include "libANGLE/Data.h" |
| #include "libANGLE/State.h" |
| #include "libANGLE/FramebufferAttachment.h" |
| #include "libANGLE/angletypes.h" |
| #include "libANGLE/formatutils.h" |
| #include "libANGLE/renderer/gl/FunctionsGL.h" |
| #include "libANGLE/renderer/gl/RenderbufferGL.h" |
| #include "libANGLE/renderer/gl/StateManagerGL.h" |
| #include "libANGLE/renderer/gl/TextureGL.h" |
| |
| namespace rx |
| { |
| |
| FramebufferGL::FramebufferGL(const gl::Framebuffer::Data &data, const FunctionsGL *functions, StateManagerGL *stateManager, bool isDefault) |
| : FramebufferImpl(data), |
| mFunctions(functions), |
| mStateManager(stateManager), |
| mFramebufferID(0), |
| mIsDefault(isDefault) |
| { |
| if (!mIsDefault) |
| { |
| mFunctions->genFramebuffers(1, &mFramebufferID); |
| } |
| } |
| |
| FramebufferGL::FramebufferGL(GLuint id, |
| const gl::Framebuffer::Data &data, |
| const FunctionsGL *functions, |
| StateManagerGL *stateManager) |
| : FramebufferImpl(data), |
| mFunctions(functions), |
| mStateManager(stateManager), |
| mFramebufferID(id), |
| mIsDefault(true) |
| { |
| } |
| |
| FramebufferGL::~FramebufferGL() |
| { |
| mStateManager->deleteFramebuffer(mFramebufferID); |
| mFramebufferID = 0; |
| } |
| |
| static void BindFramebufferAttachment(const FunctionsGL *functions, GLenum attachmentPoint, |
| const gl::FramebufferAttachment *attachment) |
| { |
| if (attachment) |
| { |
| if (attachment->type() == GL_TEXTURE) |
| { |
| const gl::Texture *texture = attachment->getTexture(); |
| const TextureGL *textureGL = GetImplAs<TextureGL>(texture); |
| |
| if (texture->getTarget() == GL_TEXTURE_2D) |
| { |
| functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D, |
| textureGL->getTextureID(), attachment->mipLevel()); |
| } |
| else if (texture->getTarget() == GL_TEXTURE_CUBE_MAP) |
| { |
| functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, attachment->cubeMapFace(), |
| textureGL->getTextureID(), attachment->mipLevel()); |
| } |
| else if (texture->getTarget() == GL_TEXTURE_2D_ARRAY || texture->getTarget() == GL_TEXTURE_3D) |
| { |
| functions->framebufferTextureLayer(GL_FRAMEBUFFER, attachmentPoint, textureGL->getTextureID(), |
| attachment->mipLevel(), attachment->layer()); |
| } |
| else |
| { |
| UNREACHABLE(); |
| } |
| } |
| else if (attachment->type() == GL_RENDERBUFFER) |
| { |
| const gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); |
| const RenderbufferGL *renderbufferGL = GetImplAs<RenderbufferGL>(renderbuffer); |
| |
| functions->framebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER, |
| renderbufferGL->getRenderbufferID()); |
| } |
| else |
| { |
| UNREACHABLE(); |
| } |
| } |
| else |
| { |
| // Unbind this attachment |
| functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D, 0, 0); |
| } |
| } |
| |
| void FramebufferGL::onUpdateColorAttachment(size_t index) |
| { |
| if (!mIsDefault) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| BindFramebufferAttachment(mFunctions, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), |
| mData.getColorAttachment(static_cast<unsigned int>(index))); |
| } |
| } |
| |
| void FramebufferGL::onUpdateDepthAttachment() |
| { |
| if (!mIsDefault) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| BindFramebufferAttachment(mFunctions, |
| GL_DEPTH_ATTACHMENT, |
| mData.getDepthAttachment()); |
| } |
| } |
| |
| void FramebufferGL::onUpdateStencilAttachment() |
| { |
| if (!mIsDefault) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| BindFramebufferAttachment(mFunctions, |
| GL_STENCIL_ATTACHMENT, |
| mData.getStencilAttachment()); |
| } |
| } |
| |
| void FramebufferGL::onUpdateDepthStencilAttachment() |
| { |
| if (!mIsDefault) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| BindFramebufferAttachment(mFunctions, |
| GL_DEPTH_STENCIL_ATTACHMENT, |
| mData.getDepthStencilAttachment()); |
| } |
| } |
| |
| void FramebufferGL::setDrawBuffers(size_t count, const GLenum *buffers) |
| { |
| if (!mIsDefault) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->drawBuffers(static_cast<GLsizei>(count), buffers); |
| } |
| } |
| |
| void FramebufferGL::setReadBuffer(GLenum buffer) |
| { |
| if (!mIsDefault) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->readBuffer(buffer); |
| } |
| } |
| |
| gl::Error FramebufferGL::discard(size_t count, const GLenum *attachments) |
| { |
| UNIMPLEMENTED(); |
| return gl::Error(GL_INVALID_OPERATION); |
| } |
| |
| gl::Error FramebufferGL::invalidate(size_t count, const GLenum *attachments) |
| { |
| // Since this function is just a hint and not available until OpenGL 4.3, only call it if it is available. |
| if (mFunctions->invalidateFramebuffer) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->invalidateFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count), attachments); |
| } |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| gl::Error FramebufferGL::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) |
| { |
| // Since this function is just a hint and not available until OpenGL 4.3, only call it if it is available. |
| if (mFunctions->invalidateSubFramebuffer) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->invalidateSubFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count), |
| attachments, area.x, area.y, area.width, area.height); |
| } |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| gl::Error FramebufferGL::clear(const gl::Data &data, GLbitfield mask) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->clear(mask); |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| gl::Error FramebufferGL::clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->clearBufferfv(buffer, drawbuffer, values); |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| gl::Error FramebufferGL::clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->clearBufferuiv(buffer, drawbuffer, values); |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| gl::Error FramebufferGL::clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->clearBufferiv(buffer, drawbuffer, values); |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| gl::Error FramebufferGL::clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil); |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| GLenum FramebufferGL::getImplementationColorReadFormat() const |
| { |
| const gl::FramebufferAttachment *readAttachment = getData().getReadAttachment(); |
| GLenum internalFormat = readAttachment->getInternalFormat(); |
| const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); |
| return internalFormatInfo.format; |
| } |
| |
| GLenum FramebufferGL::getImplementationColorReadType() const |
| { |
| const gl::FramebufferAttachment *readAttachment = getData().getReadAttachment(); |
| GLenum internalFormat = readAttachment->getInternalFormat(); |
| const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); |
| return internalFormatInfo.type; |
| } |
| |
| gl::Error FramebufferGL::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const |
| { |
| // TODO: don't sync the pixel pack state here once the dirty bits contain the pixel pack buffer |
| // binding |
| const gl::PixelPackState &packState = state.getPackState(); |
| mStateManager->setPixelPackState(packState); |
| |
| mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID); |
| mFunctions->readPixels(area.x, area.y, area.width, area.height, format, type, pixels); |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| gl::Error FramebufferGL::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, |
| GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) |
| { |
| const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(sourceFramebuffer); |
| |
| mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID()); |
| mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferID); |
| |
| mFunctions->blitFramebuffer(sourceArea.x, sourceArea.y, sourceArea.x + sourceArea.width, sourceArea.y + sourceArea.height, |
| destArea.x, destArea.y, destArea.x + destArea.width, destArea.y + destArea.height, |
| mask, filter); |
| |
| return gl::Error(GL_NO_ERROR); |
| } |
| |
| GLenum FramebufferGL::checkStatus() const |
| { |
| mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); |
| return mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER); |
| } |
| |
| GLuint FramebufferGL::getFramebufferID() const |
| { |
| return mFramebufferID; |
| } |
| |
| } |