Commit 26a717b0 by Corentin Wallez Committed by Commit Bot

GL: Emulate SRGB blits where needed.

Desktop OpenGL before 4.4 doesn't handle SRGB blits the same way OpenGL ES does. Emulate them by drawing a quad. BUG=angleproject:1492 BUG=chromium:634525 Change-Id: I9f2992d9b373941b10f19f8a51564f0f756cc4df Reviewed-on: https://chromium-review.googlesource.com/389853Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent b80a5e9c
......@@ -44,6 +44,15 @@ struct Vector4
float w;
};
struct Vector2
{
Vector2() {}
Vector2(float x, float y) : x(x), y(y) {}
float x;
float y;
};
inline bool isPow2(int x)
{
return (x & (x - 1)) == 0 && (x != 0);
......
......@@ -52,14 +52,26 @@ class BlitGL : public angle::NonCopyable
const gl::Rectangle &sourceArea,
const gl::Framebuffer *source);
gl::Error blitColorBufferWithShader(const gl::Framebuffer *source,
const gl::Framebuffer *dest,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
GLenum filter);
gl::Error initializeResources();
private:
void orphanScratchTextures();
void setScratchTextureParameter(GLenum param, GLenum value);
const FunctionsGL *mFunctions;
const WorkaroundsGL &mWorkarounds;
StateManagerGL *mStateManager;
GLuint mBlitProgram;
GLint mSourceTextureLocation;
GLint mScaleLocation;
GLint mOffsetLocation;
GLuint mScratchTextures[2];
GLuint mScratchFBO;
......
......@@ -62,7 +62,8 @@ ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data)
{
return new FramebufferGL(data, getFunctions(), getStateManager(), getWorkaroundsGL(), false);
return new FramebufferGL(data, getFunctions(), getStateManager(), getWorkaroundsGL(),
mRenderer->getBlitter(), false);
}
TextureImpl *ContextGL::createTexture(const gl::TextureState &state)
......
......@@ -16,6 +16,7 @@
#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"
......@@ -35,11 +36,13 @@ 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)
{
......@@ -53,11 +56,13 @@ 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)
{
......@@ -276,15 +281,81 @@ Error FramebufferGL::blit(ContextImpl *context,
GLenum filter)
{
const Framebuffer *sourceFramebuffer = context->getGLState().getReadFramebuffer();
const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(sourceFramebuffer);
const Framebuffer *destFramebuffer = context->getGLState().getDrawFramebuffer();
bool needManualColorBlit = false;
// The manual SRGB blit is only needed to perform correct linear interpolation. We don't
// need to make sure there is SRGB conversion for NEAREST as the values will be copied.
if (filter != GL_NEAREST)
{
// 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 [...].
{
const FramebufferAttachment *readAttachment = sourceFramebuffer->getReadColorbuffer();
bool sourceSRGB =
readAttachment != nullptr && readAttachment->getColorEncoding() == GL_SRGB;
needManualColorBlit =
needManualColorBlit || (sourceSRGB && !mFunctions->isAtLeastGL(gl::Version(4, 4)));
}
// 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->isAtLeastGL(gl::Version(4, 2)));
}
}
// Enable FRAMEBUFFER_SRGB if needed
syncDrawState();
GLenum blitMask = mask;
if (needManualColorBlit && (mask & GL_COLOR_BUFFER_BIT))
{
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(), mask, filter);
destArea.x, destArea.y, destArea.x1(), destArea.y1(), blitMask,
filter);
return Error(GL_NO_ERROR);
return gl::NoError();
}
bool FramebufferGL::checkStatus() const
......@@ -370,17 +441,17 @@ void FramebufferGL::syncClearState(GLbitfield mask)
if (mWorkarounds.doesSRGBClearsOnLinearFramebufferAttachments &&
(mask & GL_COLOR_BUFFER_BIT) != 0 && !mIsDefault)
{
bool hasSRBAttachment = false;
bool hasSRGBAttachment = false;
for (const auto &attachment : mState.getColorAttachments())
{
if (attachment.isAttached() && attachment.getColorEncoding() == GL_SRGB)
{
hasSRBAttachment = true;
hasSRGBAttachment = true;
break;
}
}
mStateManager->setFramebufferSRGBEnabled(hasSRBAttachment);
mStateManager->setFramebufferSRGBEnabled(hasSRGBAttachment);
}
else
{
......
......@@ -14,6 +14,7 @@
namespace rx
{
class BlitGL;
class FunctionsGL;
class StateManagerGL;
struct WorkaroundsGL;
......@@ -25,6 +26,7 @@ class FramebufferGL : public FramebufferImpl
const FunctionsGL *functions,
StateManagerGL *stateManager,
const WorkaroundsGL &workarounds,
BlitGL *blitter,
bool isDefault);
// Constructor called when we need to create a FramebufferGL from an
// existing framebuffer name, for example for the default framebuffer
......@@ -33,6 +35,7 @@ class FramebufferGL : public FramebufferImpl
const gl::FramebufferState &data,
const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
BlitGL *blitter,
StateManagerGL *stateManager);
~FramebufferGL() override;
......@@ -100,6 +103,7 @@ class FramebufferGL : public FramebufferImpl
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds;
BlitGL *mBlitter;
GLuint mFramebufferID;
bool mIsDefault;
......
......@@ -26,6 +26,6 @@ SurfaceGL::~SurfaceGL()
FramebufferImpl *SurfaceGL::createDefaultFramebuffer(const gl::FramebufferState &data)
{
return new FramebufferGL(data, mRenderer->getFunctions(), mRenderer->getStateManager(),
mRenderer->getWorkarounds(), true);
mRenderer->getWorkarounds(), mRenderer->getBlitter(), true);
}
}
......@@ -53,7 +53,7 @@ class PbufferSurfaceCGL : public SurfaceGL
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds;
RendererGL *mRenderer;
GLuint mFramebuffer;
GLuint mColorRenderbuffer;
......
......@@ -28,7 +28,7 @@ PbufferSurfaceCGL::PbufferSurfaceCGL(const egl::SurfaceState &state,
mHeight(height),
mFunctions(functions),
mStateManager(renderer->getStateManager()),
mWorkarounds(renderer->getWorkarounds()),
mRenderer(renderer),
mFramebuffer(0),
mColorRenderbuffer(0),
mDSRenderbuffer(0)
......@@ -136,7 +136,8 @@ EGLint PbufferSurfaceCGL::getSwapBehavior() const
FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state)
{
// TODO(cwallez) assert it happens only once?
return new FramebufferGL(mFramebuffer, state, mFunctions, mWorkarounds, mStateManager);
return new FramebufferGL(mFramebuffer, state, mFunctions, mRenderer->getWorkarounds(),
mRenderer->getBlitter(), mStateManager);
}
}
......@@ -88,6 +88,7 @@ class WindowSurfaceCGL : public SurfaceGL
CGLContextObj mContext;
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
RendererGL *mRenderer;
const WorkaroundsGL &mWorkarounds;
GLuint mFramebuffer;
......
......@@ -154,11 +154,12 @@
mContext(context),
mFunctions(functions),
mStateManager(renderer->getStateManager()),
mRenderer(renderer),
mWorkarounds(renderer->getWorkarounds()),
mFramebuffer(0),
mDSRenderbuffer(0)
{
pthread_mutex_init(&mSwapState.mutex, nullptr);
{
pthread_mutex_init(&mSwapState.mutex, nullptr);
}
WindowSurfaceCGL::~WindowSurfaceCGL()
......@@ -324,7 +325,8 @@ EGLint WindowSurfaceCGL::getSwapBehavior() const
FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state)
{
// TODO(cwallez) assert it happens only once?
return new FramebufferGL(mFramebuffer, state, mFunctions, mWorkarounds, mStateManager);
return new FramebufferGL(mFramebuffer, state, mFunctions, mWorkarounds, mRenderer->getBlitter(),
mStateManager);
}
}
......@@ -308,9 +308,9 @@ uint32_t DisplayOzone::Buffer::getDRMFB()
FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::FramebufferState &state)
{
return new FramebufferGL(mGLFB, state, mDisplay->mFunctionsGL,
mDisplay->getRenderer()->getWorkarounds(),
mDisplay->getRenderer()->getStateManager());
return new FramebufferGL(
mGLFB, state, mDisplay->mFunctionsGL, mDisplay->getRenderer()->getWorkarounds(),
mDisplay->getRenderer()->getBlitter(), mDisplay->getRenderer()->getStateManager());
}
void DisplayOzone::Buffer::present()
......
......@@ -36,6 +36,7 @@ DXGISwapChainWindowSurfaceWGL::DXGISwapChainWindowSurfaceWGL(const egl::SurfaceS
mWindow(window),
mStateManager(renderer->getStateManager()),
mWorkarounds(renderer->getWorkarounds()),
mRenderer(renderer),
mFunctionsGL(functionsGL),
mFunctionsWGL(functionsWGL),
mDevice(device),
......@@ -292,7 +293,8 @@ EGLint DXGISwapChainWindowSurfaceWGL::getSwapBehavior() const
FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer(
const gl::FramebufferState &data)
{
return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds, mStateManager);
return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds,
mRenderer->getBlitter(), mStateManager);
}
egl::Error DXGISwapChainWindowSurfaceWGL::setObjectsLocked(bool locked)
......
......@@ -66,6 +66,7 @@ class DXGISwapChainWindowSurfaceWGL : public SurfaceGL
StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds;
RendererGL *mRenderer;
const FunctionsGL *mFunctionsGL;
const FunctionsWGL *mFunctionsWGL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment