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 ...@@ -44,6 +44,15 @@ struct Vector4
float w; float w;
}; };
struct Vector2
{
Vector2() {}
Vector2(float x, float y) : x(x), y(y) {}
float x;
float y;
};
inline bool isPow2(int x) inline bool isPow2(int x)
{ {
return (x & (x - 1)) == 0 && (x != 0); return (x & (x - 1)) == 0 && (x != 0);
......
...@@ -52,14 +52,26 @@ class BlitGL : public angle::NonCopyable ...@@ -52,14 +52,26 @@ class BlitGL : public angle::NonCopyable
const gl::Rectangle &sourceArea, const gl::Rectangle &sourceArea,
const gl::Framebuffer *source); 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(); gl::Error initializeResources();
private: private:
void orphanScratchTextures();
void setScratchTextureParameter(GLenum param, GLenum value);
const FunctionsGL *mFunctions; const FunctionsGL *mFunctions;
const WorkaroundsGL &mWorkarounds; const WorkaroundsGL &mWorkarounds;
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
GLuint mBlitProgram; GLuint mBlitProgram;
GLint mSourceTextureLocation;
GLint mScaleLocation;
GLint mOffsetLocation;
GLuint mScratchTextures[2]; GLuint mScratchTextures[2];
GLuint mScratchFBO; GLuint mScratchFBO;
......
...@@ -62,7 +62,8 @@ ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data) ...@@ -62,7 +62,8 @@ ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &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) TextureImpl *ContextGL::createTexture(const gl::TextureState &state)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/RenderbufferGL.h" #include "libANGLE/renderer/gl/RenderbufferGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h" #include "libANGLE/renderer/gl/StateManagerGL.h"
...@@ -35,11 +36,13 @@ FramebufferGL::FramebufferGL(const FramebufferState &state, ...@@ -35,11 +36,13 @@ FramebufferGL::FramebufferGL(const FramebufferState &state,
const FunctionsGL *functions, const FunctionsGL *functions,
StateManagerGL *stateManager, StateManagerGL *stateManager,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter,
bool isDefault) bool isDefault)
: FramebufferImpl(state), : FramebufferImpl(state),
mFunctions(functions), mFunctions(functions),
mStateManager(stateManager), mStateManager(stateManager),
mWorkarounds(workarounds), mWorkarounds(workarounds),
mBlitter(blitter),
mFramebufferID(0), mFramebufferID(0),
mIsDefault(isDefault) mIsDefault(isDefault)
{ {
...@@ -53,11 +56,13 @@ FramebufferGL::FramebufferGL(GLuint id, ...@@ -53,11 +56,13 @@ FramebufferGL::FramebufferGL(GLuint id,
const FramebufferState &state, const FramebufferState &state,
const FunctionsGL *functions, const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter,
StateManagerGL *stateManager) StateManagerGL *stateManager)
: FramebufferImpl(state), : FramebufferImpl(state),
mFunctions(functions), mFunctions(functions),
mStateManager(stateManager), mStateManager(stateManager),
mWorkarounds(workarounds), mWorkarounds(workarounds),
mBlitter(blitter),
mFramebufferID(id), mFramebufferID(id),
mIsDefault(true) mIsDefault(true)
{ {
...@@ -276,15 +281,81 @@ Error FramebufferGL::blit(ContextImpl *context, ...@@ -276,15 +281,81 @@ Error FramebufferGL::blit(ContextImpl *context,
GLenum filter) GLenum filter)
{ {
const Framebuffer *sourceFramebuffer = context->getGLState().getReadFramebuffer(); 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_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferID);
mFunctions->blitFramebuffer(sourceArea.x, sourceArea.y, sourceArea.x1(), sourceArea.y1(), 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 bool FramebufferGL::checkStatus() const
...@@ -370,17 +441,17 @@ void FramebufferGL::syncClearState(GLbitfield mask) ...@@ -370,17 +441,17 @@ void FramebufferGL::syncClearState(GLbitfield mask)
if (mWorkarounds.doesSRGBClearsOnLinearFramebufferAttachments && if (mWorkarounds.doesSRGBClearsOnLinearFramebufferAttachments &&
(mask & GL_COLOR_BUFFER_BIT) != 0 && !mIsDefault) (mask & GL_COLOR_BUFFER_BIT) != 0 && !mIsDefault)
{ {
bool hasSRBAttachment = false; bool hasSRGBAttachment = false;
for (const auto &attachment : mState.getColorAttachments()) for (const auto &attachment : mState.getColorAttachments())
{ {
if (attachment.isAttached() && attachment.getColorEncoding() == GL_SRGB) if (attachment.isAttached() && attachment.getColorEncoding() == GL_SRGB)
{ {
hasSRBAttachment = true; hasSRGBAttachment = true;
break; break;
} }
} }
mStateManager->setFramebufferSRGBEnabled(hasSRBAttachment); mStateManager->setFramebufferSRGBEnabled(hasSRGBAttachment);
} }
else else
{ {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
namespace rx namespace rx
{ {
class BlitGL;
class FunctionsGL; class FunctionsGL;
class StateManagerGL; class StateManagerGL;
struct WorkaroundsGL; struct WorkaroundsGL;
...@@ -25,6 +26,7 @@ class FramebufferGL : public FramebufferImpl ...@@ -25,6 +26,7 @@ class FramebufferGL : public FramebufferImpl
const FunctionsGL *functions, const FunctionsGL *functions,
StateManagerGL *stateManager, StateManagerGL *stateManager,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter,
bool isDefault); bool isDefault);
// Constructor called when we need to create a FramebufferGL from an // Constructor called when we need to create a FramebufferGL from an
// existing framebuffer name, for example for the default framebuffer // existing framebuffer name, for example for the default framebuffer
...@@ -33,6 +35,7 @@ class FramebufferGL : public FramebufferImpl ...@@ -33,6 +35,7 @@ class FramebufferGL : public FramebufferImpl
const gl::FramebufferState &data, const gl::FramebufferState &data,
const FunctionsGL *functions, const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter,
StateManagerGL *stateManager); StateManagerGL *stateManager);
~FramebufferGL() override; ~FramebufferGL() override;
...@@ -100,6 +103,7 @@ class FramebufferGL : public FramebufferImpl ...@@ -100,6 +103,7 @@ class FramebufferGL : public FramebufferImpl
const FunctionsGL *mFunctions; const FunctionsGL *mFunctions;
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds; const WorkaroundsGL &mWorkarounds;
BlitGL *mBlitter;
GLuint mFramebufferID; GLuint mFramebufferID;
bool mIsDefault; bool mIsDefault;
......
...@@ -26,6 +26,6 @@ SurfaceGL::~SurfaceGL() ...@@ -26,6 +26,6 @@ SurfaceGL::~SurfaceGL()
FramebufferImpl *SurfaceGL::createDefaultFramebuffer(const gl::FramebufferState &data) FramebufferImpl *SurfaceGL::createDefaultFramebuffer(const gl::FramebufferState &data)
{ {
return new FramebufferGL(data, mRenderer->getFunctions(), mRenderer->getStateManager(), return new FramebufferGL(data, mRenderer->getFunctions(), mRenderer->getStateManager(),
mRenderer->getWorkarounds(), true); mRenderer->getWorkarounds(), mRenderer->getBlitter(), true);
} }
} }
...@@ -53,7 +53,7 @@ class PbufferSurfaceCGL : public SurfaceGL ...@@ -53,7 +53,7 @@ class PbufferSurfaceCGL : public SurfaceGL
const FunctionsGL *mFunctions; const FunctionsGL *mFunctions;
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds; RendererGL *mRenderer;
GLuint mFramebuffer; GLuint mFramebuffer;
GLuint mColorRenderbuffer; GLuint mColorRenderbuffer;
......
...@@ -28,7 +28,7 @@ PbufferSurfaceCGL::PbufferSurfaceCGL(const egl::SurfaceState &state, ...@@ -28,7 +28,7 @@ PbufferSurfaceCGL::PbufferSurfaceCGL(const egl::SurfaceState &state,
mHeight(height), mHeight(height),
mFunctions(functions), mFunctions(functions),
mStateManager(renderer->getStateManager()), mStateManager(renderer->getStateManager()),
mWorkarounds(renderer->getWorkarounds()), mRenderer(renderer),
mFramebuffer(0), mFramebuffer(0),
mColorRenderbuffer(0), mColorRenderbuffer(0),
mDSRenderbuffer(0) mDSRenderbuffer(0)
...@@ -136,7 +136,8 @@ EGLint PbufferSurfaceCGL::getSwapBehavior() const ...@@ -136,7 +136,8 @@ EGLint PbufferSurfaceCGL::getSwapBehavior() const
FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state) FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state)
{ {
// TODO(cwallez) assert it happens only once? // 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 ...@@ -88,6 +88,7 @@ class WindowSurfaceCGL : public SurfaceGL
CGLContextObj mContext; CGLContextObj mContext;
const FunctionsGL *mFunctions; const FunctionsGL *mFunctions;
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
RendererGL *mRenderer;
const WorkaroundsGL &mWorkarounds; const WorkaroundsGL &mWorkarounds;
GLuint mFramebuffer; GLuint mFramebuffer;
......
...@@ -154,11 +154,12 @@ ...@@ -154,11 +154,12 @@
mContext(context), mContext(context),
mFunctions(functions), mFunctions(functions),
mStateManager(renderer->getStateManager()), mStateManager(renderer->getStateManager()),
mRenderer(renderer),
mWorkarounds(renderer->getWorkarounds()), mWorkarounds(renderer->getWorkarounds()),
mFramebuffer(0), mFramebuffer(0),
mDSRenderbuffer(0) mDSRenderbuffer(0)
{ {
pthread_mutex_init(&mSwapState.mutex, nullptr); pthread_mutex_init(&mSwapState.mutex, nullptr);
} }
WindowSurfaceCGL::~WindowSurfaceCGL() WindowSurfaceCGL::~WindowSurfaceCGL()
...@@ -324,7 +325,8 @@ EGLint WindowSurfaceCGL::getSwapBehavior() const ...@@ -324,7 +325,8 @@ EGLint WindowSurfaceCGL::getSwapBehavior() const
FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state) FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state)
{ {
// TODO(cwallez) assert it happens only once? // 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() ...@@ -308,9 +308,9 @@ uint32_t DisplayOzone::Buffer::getDRMFB()
FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::FramebufferState &state) FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::FramebufferState &state)
{ {
return new FramebufferGL(mGLFB, state, mDisplay->mFunctionsGL, return new FramebufferGL(
mDisplay->getRenderer()->getWorkarounds(), mGLFB, state, mDisplay->mFunctionsGL, mDisplay->getRenderer()->getWorkarounds(),
mDisplay->getRenderer()->getStateManager()); mDisplay->getRenderer()->getBlitter(), mDisplay->getRenderer()->getStateManager());
} }
void DisplayOzone::Buffer::present() void DisplayOzone::Buffer::present()
......
...@@ -36,6 +36,7 @@ DXGISwapChainWindowSurfaceWGL::DXGISwapChainWindowSurfaceWGL(const egl::SurfaceS ...@@ -36,6 +36,7 @@ DXGISwapChainWindowSurfaceWGL::DXGISwapChainWindowSurfaceWGL(const egl::SurfaceS
mWindow(window), mWindow(window),
mStateManager(renderer->getStateManager()), mStateManager(renderer->getStateManager()),
mWorkarounds(renderer->getWorkarounds()), mWorkarounds(renderer->getWorkarounds()),
mRenderer(renderer),
mFunctionsGL(functionsGL), mFunctionsGL(functionsGL),
mFunctionsWGL(functionsWGL), mFunctionsWGL(functionsWGL),
mDevice(device), mDevice(device),
...@@ -292,7 +293,8 @@ EGLint DXGISwapChainWindowSurfaceWGL::getSwapBehavior() const ...@@ -292,7 +293,8 @@ EGLint DXGISwapChainWindowSurfaceWGL::getSwapBehavior() const
FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer( FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer(
const gl::FramebufferState &data) 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) egl::Error DXGISwapChainWindowSurfaceWGL::setObjectsLocked(bool locked)
......
...@@ -66,6 +66,7 @@ class DXGISwapChainWindowSurfaceWGL : public SurfaceGL ...@@ -66,6 +66,7 @@ class DXGISwapChainWindowSurfaceWGL : public SurfaceGL
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds; const WorkaroundsGL &mWorkarounds;
RendererGL *mRenderer;
const FunctionsGL *mFunctionsGL; const FunctionsGL *mFunctionsGL;
const FunctionsWGL *mFunctionsWGL; 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