diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/angle/src/libANGLE/renderer/gl/FramebufferGL.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/FramebufferGL.cpp')
-rwxr-xr-x | gfx/angle/src/libANGLE/renderer/gl/FramebufferGL.cpp | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/FramebufferGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/FramebufferGL.cpp new file mode 100755 index 000000000..0a058f8ba --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/FramebufferGL.cpp @@ -0,0 +1,553 @@ +// +// 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/BitSetIterator.h" +#include "common/debug.h" +#include "libANGLE/ContextState.h" +#include "libANGLE/State.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/gl/BlitGL.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" +#include "libANGLE/renderer/gl/WorkaroundsGL.h" +#include "libANGLE/renderer/gl/formatutilsgl.h" +#include "libANGLE/renderer/gl/renderergl_utils.h" +#include "platform/Platform.h" + +using namespace gl; +using angle::CheckedNumeric; + +namespace rx +{ + +FramebufferGL::FramebufferGL(const FramebufferState &state, + const FunctionsGL *functions, + StateManagerGL *stateManager, + const WorkaroundsGL &workarounds, + BlitGL *blitter, + bool isDefault) + : FramebufferImpl(state), + mFunctions(functions), + mStateManager(stateManager), + mWorkarounds(workarounds), + mBlitter(blitter), + mFramebufferID(0), + mIsDefault(isDefault) +{ + if (!mIsDefault) + { + mFunctions->genFramebuffers(1, &mFramebufferID); + } +} + +FramebufferGL::FramebufferGL(GLuint id, + const FramebufferState &state, + const FunctionsGL *functions, + const WorkaroundsGL &workarounds, + BlitGL *blitter, + StateManagerGL *stateManager) + : FramebufferImpl(state), + mFunctions(functions), + mStateManager(stateManager), + mWorkarounds(workarounds), + mBlitter(blitter), + mFramebufferID(id), + mIsDefault(true) +{ +} + +FramebufferGL::~FramebufferGL() +{ + mStateManager->deleteFramebuffer(mFramebufferID); + mFramebufferID = 0; +} + +static void BindFramebufferAttachment(const FunctionsGL *functions, + GLenum attachmentPoint, + const FramebufferAttachment *attachment) +{ + if (attachment) + { + if (attachment->type() == GL_TEXTURE) + { + const 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 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); + } +} + +Error FramebufferGL::discard(size_t count, const GLenum *attachments) +{ + UNIMPLEMENTED(); + return Error(GL_INVALID_OPERATION); +} + +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 Error(GL_NO_ERROR); +} + +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 Error(GL_NO_ERROR); +} + +Error FramebufferGL::clear(ContextImpl *context, GLbitfield mask) +{ + syncClearState(mask); + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + mFunctions->clear(mask); + + return Error(GL_NO_ERROR); +} + +Error FramebufferGL::clearBufferfv(ContextImpl *context, + GLenum buffer, + GLint drawbuffer, + const GLfloat *values) +{ + syncClearBufferState(buffer, drawbuffer); + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + mFunctions->clearBufferfv(buffer, drawbuffer, values); + + return Error(GL_NO_ERROR); +} + +Error FramebufferGL::clearBufferuiv(ContextImpl *context, + GLenum buffer, + GLint drawbuffer, + const GLuint *values) +{ + syncClearBufferState(buffer, drawbuffer); + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + mFunctions->clearBufferuiv(buffer, drawbuffer, values); + + return Error(GL_NO_ERROR); +} + +Error FramebufferGL::clearBufferiv(ContextImpl *context, + GLenum buffer, + GLint drawbuffer, + const GLint *values) +{ + syncClearBufferState(buffer, drawbuffer); + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + mFunctions->clearBufferiv(buffer, drawbuffer, values); + + return Error(GL_NO_ERROR); +} + +Error FramebufferGL::clearBufferfi(ContextImpl *context, + GLenum buffer, + GLint drawbuffer, + GLfloat depth, + GLint stencil) +{ + syncClearBufferState(buffer, drawbuffer); + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil); + + return Error(GL_NO_ERROR); +} + +GLenum FramebufferGL::getImplementationColorReadFormat() const +{ + const auto *readAttachment = mState.getReadAttachment(); + const Format &format = readAttachment->getFormat(); + return format.info->getReadPixelsFormat(); +} + +GLenum FramebufferGL::getImplementationColorReadType() const +{ + const auto *readAttachment = mState.getReadAttachment(); + const Format &format = readAttachment->getFormat(); + return format.info->getReadPixelsType(); +} + +Error FramebufferGL::readPixels(ContextImpl *context, + 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 PixelPackState &packState = context->getGLState().getPackState(); + mStateManager->setPixelPackState(packState); + + nativegl::ReadPixelsFormat readPixelsFormat = + nativegl::GetReadPixelsFormat(mFunctions, mWorkarounds, format, type); + GLenum readFormat = readPixelsFormat.format; + GLenum readType = readPixelsFormat.type; + + mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID); + + if (mWorkarounds.packOverlappingRowsSeparatelyPackBuffer && packState.pixelBuffer.get() && + packState.rowLength != 0 && packState.rowLength < area.width) + { + return readPixelsRowByRowWorkaround(area, readFormat, readType, packState, pixels); + } + + if (mWorkarounds.packLastRowSeparatelyForPaddingInclusion) + { + gl::Extents size(area.width, area.height, 1); + + bool apply; + ANGLE_TRY_RESULT(ShouldApplyLastRowPaddingWorkaround(size, packState, readFormat, readType, + false, pixels), + apply); + + if (apply) + { + return readPixelsPaddingWorkaround(area, readFormat, readType, packState, pixels); + } + } + + mFunctions->readPixels(area.x, area.y, area.width, area.height, readFormat, readType, pixels); + + return gl::NoError(); +} + +Error FramebufferGL::blit(ContextImpl *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + GLbitfield mask, + GLenum filter) +{ + const Framebuffer *sourceFramebuffer = context->getGLState().getReadFramebuffer(); + const Framebuffer *destFramebuffer = context->getGLState().getDrawFramebuffer(); + + const FramebufferAttachment *colorReadAttachment = sourceFramebuffer->getReadColorbuffer(); + GLsizei readAttachmentSamples = colorReadAttachment->getSamples(); + + bool needManualColorBlit = false; + + // TODO(cwallez) when the filter is LINEAR and both source and destination are SRGB, we + // could avoid doing a manual blit. + + // Prior to OpenGL 4.4 BlitFramebuffer (section 18.3.1 of GL 4.3 core profile) reads: + // When values are taken from the read buffer, no linearization is performed, even + // if the format of the buffer is SRGB. + // Starting from OpenGL 4.4 (section 18.3.1) it reads: + // When values are taken from the read buffer, if FRAMEBUFFER_SRGB is enabled and the + // value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the framebuffer attachment + // corresponding to the read buffer is SRGB, the red, green, and blue components are + // converted from the non-linear sRGB color space according [...]. + { + bool sourceSRGB = colorReadAttachment != nullptr && + colorReadAttachment->getColorEncoding() == GL_SRGB; + needManualColorBlit = + needManualColorBlit || (sourceSRGB && mFunctions->isAtMostGL(gl::Version(4, 3))); + } + + // Prior to OpenGL 4.2 BlitFramebuffer (section 4.3.2 of GL 4.1 core profile) reads: + // Blit operations bypass the fragment pipeline. The only fragment operations which + // affect a blit are the pixel ownership test and scissor test. + // Starting from OpenGL 4.2 (section 4.3.2) it reads: + // When values are written to the draw buffers, blit operations bypass the fragment + // pipeline. The only fragment operations which affect a blit are the pixel ownership + // test, the scissor test and sRGB conversion. + if (!needManualColorBlit) + { + bool destSRGB = false; + for (size_t i = 0; i < destFramebuffer->getDrawbufferStateCount(); ++i) + { + const FramebufferAttachment *attachment = destFramebuffer->getDrawBuffer(i); + if (attachment && attachment->getColorEncoding() == GL_SRGB) + { + destSRGB = true; + break; + } + } + + needManualColorBlit = + needManualColorBlit || (destSRGB && mFunctions->isAtMostGL(gl::Version(4, 1))); + } + + // Enable FRAMEBUFFER_SRGB if needed + mStateManager->setFramebufferSRGBEnabledForFramebuffer(true, this); + + GLenum blitMask = mask; + if (needManualColorBlit && (mask & GL_COLOR_BUFFER_BIT) && readAttachmentSamples <= 1) + { + ANGLE_TRY(mBlitter->blitColorBufferWithShader(sourceFramebuffer, destFramebuffer, + sourceArea, destArea, filter)); + blitMask &= ~GL_COLOR_BUFFER_BIT; + } + + if (blitMask == 0) + { + return gl::NoError(); + } + + 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.x1(), sourceArea.y1(), + destArea.x, destArea.y, destArea.x1(), destArea.y1(), blitMask, + filter); + + return gl::NoError(); +} + +bool FramebufferGL::checkStatus() const +{ + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + GLenum status = mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + { + ANGLEPlatformCurrent()->logWarning("GL framebuffer returned incomplete."); + } + return (status == GL_FRAMEBUFFER_COMPLETE); +} + +void FramebufferGL::syncState(const Framebuffer::DirtyBits &dirtyBits) +{ + // Don't need to sync state for the default FBO. + if (mIsDefault) + { + return; + } + + mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + + for (auto dirtyBit : angle::IterateBitSet(dirtyBits)) + { + switch (dirtyBit) + { + case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT: + BindFramebufferAttachment(mFunctions, GL_DEPTH_ATTACHMENT, + mState.getDepthAttachment()); + break; + case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: + BindFramebufferAttachment(mFunctions, GL_STENCIL_ATTACHMENT, + mState.getStencilAttachment()); + break; + case Framebuffer::DIRTY_BIT_DRAW_BUFFERS: + { + const auto &drawBuffers = mState.getDrawBufferStates(); + mFunctions->drawBuffers(static_cast<GLsizei>(drawBuffers.size()), + drawBuffers.data()); + break; + } + case Framebuffer::DIRTY_BIT_READ_BUFFER: + mFunctions->readBuffer(mState.getReadBufferState()); + break; + default: + { + ASSERT(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 && + dirtyBit < Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX); + size_t index = + static_cast<size_t>(dirtyBit - Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); + BindFramebufferAttachment(mFunctions, + static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index), + mState.getColorAttachment(index)); + break; + } + } + } +} + +GLuint FramebufferGL::getFramebufferID() const +{ + return mFramebufferID; +} + +bool FramebufferGL::isDefault() const +{ + return mIsDefault; +} + +void FramebufferGL::syncClearState(GLbitfield mask) +{ + if (mFunctions->standard == STANDARD_GL_DESKTOP) + { + if (mWorkarounds.doesSRGBClearsOnLinearFramebufferAttachments && + (mask & GL_COLOR_BUFFER_BIT) != 0 && !mIsDefault) + { + bool hasSRGBAttachment = false; + for (const auto &attachment : mState.getColorAttachments()) + { + if (attachment.isAttached() && attachment.getColorEncoding() == GL_SRGB) + { + hasSRGBAttachment = true; + break; + } + } + + mStateManager->setFramebufferSRGBEnabled(hasSRGBAttachment); + } + else + { + mStateManager->setFramebufferSRGBEnabled(!mIsDefault); + } + } +} + +void FramebufferGL::syncClearBufferState(GLenum buffer, GLint drawBuffer) +{ + if (mFunctions->standard == STANDARD_GL_DESKTOP) + { + if (mWorkarounds.doesSRGBClearsOnLinearFramebufferAttachments && buffer == GL_COLOR && + !mIsDefault) + { + // If doing a clear on a color buffer, set SRGB blend enabled only if the color buffer + // is an SRGB format. + const auto &drawbufferState = mState.getDrawBufferStates(); + const auto &colorAttachments = mState.getColorAttachments(); + + const FramebufferAttachment *attachment = nullptr; + if (drawbufferState[drawBuffer] >= GL_COLOR_ATTACHMENT0 && + drawbufferState[drawBuffer] < GL_COLOR_ATTACHMENT0 + colorAttachments.size()) + { + size_t attachmentIdx = + static_cast<size_t>(drawbufferState[drawBuffer] - GL_COLOR_ATTACHMENT0); + attachment = &colorAttachments[attachmentIdx]; + } + + if (attachment != nullptr) + { + mStateManager->setFramebufferSRGBEnabled(attachment->getColorEncoding() == GL_SRGB); + } + } + else + { + mStateManager->setFramebufferSRGBEnabled(!mIsDefault); + } + } +} +gl::Error FramebufferGL::readPixelsRowByRowWorkaround(const gl::Rectangle &area, + GLenum format, + GLenum type, + const gl::PixelPackState &pack, + GLvoid *pixels) const +{ + intptr_t offset = reinterpret_cast<intptr_t>(pixels); + + const gl::InternalFormat &glFormat = + gl::GetInternalFormatInfo(gl::GetSizedInternalFormat(format, type)); + GLuint rowBytes = 0; + ANGLE_TRY_RESULT(glFormat.computeRowPitch(area.width, pack.alignment, pack.rowLength), + rowBytes); + GLuint skipBytes = 0; + ANGLE_TRY_RESULT(glFormat.computeSkipBytes(rowBytes, 0, pack, false), skipBytes); + + gl::PixelPackState directPack; + directPack.pixelBuffer = pack.pixelBuffer; + directPack.alignment = 1; + mStateManager->setPixelPackState(directPack); + directPack.pixelBuffer.set(nullptr); + + offset += skipBytes; + for (GLint row = 0; row < area.height; ++row) + { + mFunctions->readPixels(area.x, row + area.y, area.width, 1, format, type, + reinterpret_cast<GLvoid *>(offset)); + offset += row * rowBytes; + } + + return gl::NoError(); +} + +gl::Error FramebufferGL::readPixelsPaddingWorkaround(const gl::Rectangle &area, + GLenum format, + GLenum type, + const gl::PixelPackState &pack, + GLvoid *pixels) const +{ + const gl::InternalFormat &glFormat = + gl::GetInternalFormatInfo(gl::GetSizedInternalFormat(format, type)); + GLuint rowBytes = 0; + ANGLE_TRY_RESULT(glFormat.computeRowPitch(area.width, pack.alignment, pack.rowLength), + rowBytes); + GLuint skipBytes = 0; + ANGLE_TRY_RESULT(glFormat.computeSkipBytes(rowBytes, 0, pack, false), skipBytes); + + // Get all by the last row + if (area.height > 1) + { + mFunctions->readPixels(area.x, area.y, area.width, area.height - 1, format, type, pixels); + } + + // Get the last row manually + gl::PixelPackState directPack; + directPack.pixelBuffer = pack.pixelBuffer; + directPack.alignment = 1; + mStateManager->setPixelPackState(directPack); + directPack.pixelBuffer.set(nullptr); + + intptr_t lastRowOffset = + reinterpret_cast<intptr_t>(pixels) + skipBytes + (area.height - 1) * rowBytes; + mFunctions->readPixels(area.x, area.y + area.height - 1, area.width, 1, format, type, + reinterpret_cast<GLvoid *>(lastRowOffset)); + + return gl::NoError(); +} +} // namespace rx |