Proper SRGB handling in opengl. See gl-320-fbo-srgb

* We create fake backbuffer as SRGB if the original default backbuffer was
  SRGB in the program.
* All of our output backbuffers are also SRGB, and we enable
  GL_FRAMEBUFFER_SRGB when writing to them.
* Add the 'fake' srgb curve applied to linear data to display it as if it
  were srgb, which tends to look intuitively correct even if it's not 100%
  accurate. See the behaviour existing in D3D11 already.
This commit is contained in:
baldurk
2014-12-01 17:13:30 +00:00
parent 962ac749bc
commit 50d6b62adf
12 changed files with 122 additions and 19 deletions
+1
View File
@@ -111,6 +111,7 @@ BINDING(0) uniform HistogramCBufferData
#define TEXDISPLAY_DEPTH_TEX 0x20
#define TEXDISPLAY_NANS 0x40
#define TEXDISPLAY_CLIPPING 0x80
#define TEXDISPLAY_GAMMA_CURVE 0x100
#ifndef FLT_EPSILON
#define FLT_EPSILON 1.192092896e-07f
+5 -3
View File
@@ -154,9 +154,11 @@ void main(void)
col = vec4(dot(col.rgb, 1.0f.xxx).xxx, 1.0f);
}
}
// TODO: Check OutputDisplayFormat for SRGB handling
// TODO: Figure out SRGB in opengl at all :)
if((OutputDisplayFormat & TEXDISPLAY_GAMMA_CURVE) > 0)
{
col.rgb = pow(clamp(col.rgb, 0.0f.xxx, 1.0f.xxx), 2.2f.xxx);
}
color_out = col;
}
+6 -1
View File
@@ -759,6 +759,9 @@ bool GLReplay::RenderTexture(TextureDisplay cfg)
if(cfg.overlay == eTexOverlay_Clipping)
ubo->OutputDisplayFormat |= TEXDISPLAY_CLIPPING;
if(!IsSRGBFormat(texDetails.internalFormat) && cfg.linearDisplayAsGamma)
ubo->OutputDisplayFormat |= TEXDISPLAY_GAMMA_CURVE;
ubo->RawOutput = cfg.rawoutput ? 1 : 0;
@@ -788,6 +791,8 @@ bool GLReplay::RenderTexture(TextureDisplay cfg)
gl.glBlendFunc(eGL_SRC_ALPHA, eGL_ONE_MINUS_SRC_ALPHA);
}
gl.glEnable(eGL_FRAMEBUFFER_SRGB);
gl.glBindVertexArray(DebugData.emptyVAO);
gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4);
@@ -933,7 +938,7 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overl
DebugData.overlayTexWidth = texDetails.width;
DebugData.overlayTexHeight = texDetails.height;
gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_RGBA8, texDetails.width, texDetails.height);
gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_SRGB8_ALPHA8, texDetails.width, texDetails.height);
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
+9 -7
View File
@@ -294,6 +294,7 @@ GLInitParams::GLInitParams()
colorBits = 32;
depthBits = 32;
stencilBits = 8;
isSRGB = 1;
width = 32;
height = 32;
}
@@ -308,11 +309,12 @@ ReplayCreateStatus GLInitParams::Serialise()
return eReplayCreate_APIIncompatibleVersion;
}
SERIALISE_ELEMENT(uint32_t, col, colorBits); colorBits = col;
SERIALISE_ELEMENT(uint32_t, dpth, depthBits); depthBits = dpth;
SERIALISE_ELEMENT(uint32_t, stenc, stencilBits); stencilBits = stenc;
SERIALISE_ELEMENT(uint32_t, w, width); width = w;
SERIALISE_ELEMENT(uint32_t, h, height); height = h;
m_pSerialiser->Serialise("Color bits", colorBits);
m_pSerialiser->Serialise("Depth bits", depthBits);
m_pSerialiser->Serialise("Stencil bits", stencilBits);
m_pSerialiser->Serialise("Is SRGB", isSRGB);
m_pSerialiser->Serialise("Width", width);
m_pSerialiser->Serialise("Height", height);
return eReplayCreate_Success;
}
@@ -466,9 +468,9 @@ void WrappedOpenGL::Initialise(GLInitParams &params)
GLenum colfmt = eGL_RGBA8;
if(params.colorBits == 32)
colfmt = eGL_RGBA8;
colfmt = params.isSRGB ? eGL_SRGB8_ALPHA8 : eGL_RGBA8;
else if(params.colorBits == 24)
colfmt = eGL_RGB8;
colfmt = params.isSRGB ? eGL_SRGB8 : eGL_RGB8;
else
RDCERR("Unexpected # colour bits: %d", params.colorBits);
+2 -1
View File
@@ -50,10 +50,11 @@ struct GLInitParams : public RDCInitParams
uint32_t colorBits;
uint32_t depthBits;
uint32_t stencilBits;
uint32_t isSRGB;
uint32_t width;
uint32_t height;
static const uint32_t GL_SERIALISE_VERSION = 0x0000002;
static const uint32_t GL_SERIALISE_VERSION = 0x0000003;
// version number internal to opengl stream
uint32_t SerialiseVersion;
+2 -1
View File
@@ -151,7 +151,7 @@ void GLReplay::CreateOutputWindowBackbuffer(OutputWindow &outwin)
gl.glGenTextures(1, &outwin.BlitData.backbuffer);
gl.glBindTexture(eGL_TEXTURE_2D, outwin.BlitData.backbuffer);
gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_RGB8, outwin.width, outwin.height);
gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_SRGB8, outwin.width, outwin.height);
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST);
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST);
gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE);
@@ -264,6 +264,7 @@ void GLReplay::FlipOutputWindow(uint64_t id)
gl.glActiveTexture(eGL_TEXTURE0);
gl.glBindTexture(eGL_TEXTURE_2D, outw.BlitData.backbuffer);
gl.glEnable(eGL_FRAMEBUFFER_SRGB);
gl.glBindVertexArray(outw.BlitData.emptyVAO);
gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4);
+1
View File
@@ -98,6 +98,7 @@ uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth)
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DOUBLEBUFFER, True,
GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True,
0
};
int numCfgs = 0;
+66 -6
View File
@@ -27,8 +27,8 @@
#include "gl_driver.h"
#include "gl_resources.h"
PIXELFORMATDESCRIPTOR pfd = { 0 };
PFNWGLCREATECONTEXTATTRIBSARBPROC createContextAttribs = NULL;
PFNWGLGETPIXELFORMATATTRIBIVARBPROC getPixelFormatAttrib = NULL;
typedef PROC (WINAPI *WGLGETPROCADDRESSPROC)(const char*);
typedef HGLRC (WINAPI *WGLCREATECONTEXTPROC)(HDC);
@@ -77,8 +77,57 @@ uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth)
NULL, NULL, GetModuleHandle(NULL), NULL);
HDC DC = GetDC(w);
PIXELFORMATDESCRIPTOR pfd = { 0 };
int attrib = eWGL_NUMBER_PIXEL_FORMATS_ARB;
int value = 1;
getPixelFormatAttrib(DC, 1, 0, 1, &attrib, &value);
int pf = 0;
int numpfs = value;
for(int i=1; i <= numpfs; i++)
{
// verify that we have the properties we want
attrib = eWGL_DRAW_TO_WINDOW_ARB;
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
if(value == 0) continue;
attrib = eWGL_ACCELERATION_ARB;
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
if(value == eWGL_NO_ACCELERATION_ARB) continue;
attrib = eWGL_SUPPORT_OPENGL_ARB;
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
if(value == 0) continue;
attrib = eWGL_DOUBLE_BUFFER_ARB;
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
if(value == 0) continue;
attrib = eWGL_PIXEL_TYPE_ARB;
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
if(value != eWGL_TYPE_RGBA_ARB) continue;
// we have an opengl-capable accelerated RGBA context.
// we use internal framebuffers to do almost all rendering, so we just need
// RGB (color bits > 24) and SRGB buffer.
attrib = eWGL_COLOR_BITS_ARB;
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
if(value < 24) continue;
attrib = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
if(value == 0) continue;
// this one suits our needs, choose it
pf = i;
break;
}
int pf = ChoosePixelFormat(DC, &pfd);
if(pf == 0)
{
ReleaseDC(w, DC);
@@ -86,7 +135,15 @@ uint64_t GLReplay::MakeOutputWindow(void *wn, bool depth)
return NULL;
}
BOOL res = SetPixelFormat(DC, pf, &pfd);
BOOL res = DescribePixelFormat(DC, pf, sizeof(pfd), &pfd);
if(res == FALSE)
{
ReleaseDC(w, DC);
RDCERR("Couldn't describe pixel format");
return NULL;
}
res = SetPixelFormat(DC, pf, &pfd);
if(res == FALSE)
{
ReleaseDC(w, DC);
@@ -193,6 +250,8 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
return eReplayCreate_APIIncompatibleVersion;
}
PIXELFORMATDESCRIPTOR pfd = { 0 };
if(wglGetProc == NULL)
{
wglGetProc = (WGLGETPROCADDRESSPROC)GetProcAddress(lib, "wglGetProcAddress");
@@ -267,11 +326,12 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
return eReplayCreate_APIInitFailed;
}
createContextAttribs = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProc( "wglCreateContextAttribsARB" );
createContextAttribs = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProc("wglCreateContextAttribsARB");
getPixelFormatAttrib = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProc("wglGetPixelFormatAttribivARB");
if(createContextAttribs == NULL)
if(createContextAttribs == NULL || getPixelFormatAttrib == NULL)
{
RDCERR("RenderDoc requires WGL_ARB_create_context");
RDCERR("RenderDoc requires WGL_ARB_create_context and WGL_ARB_pixel_format");
return eReplayCreate_APIHardwareUnsupported;
}
+14
View File
@@ -532,6 +532,20 @@ bool IsSIntFormat(GLenum internalFormat)
return false;
}
bool IsSRGBFormat(GLenum internalFormat)
{
switch(internalFormat)
{
case eGL_SRGB8:
case eGL_SRGB8_ALPHA8:
return true;
default:
break;
}
return false;
}
GLenum TextureBinding(GLenum target)
{
switch(target)
+1
View File
@@ -42,6 +42,7 @@ bool IsCompressedFormat(GLenum internalFormat);
bool IsDepthStencilFormat(GLenum internalFormat);
bool IsUIntFormat(GLenum internalFormat);
bool IsSIntFormat(GLenum internalFormat);
bool IsSRGBFormat(GLenum internalFormat);
GLenum TextureBinding(GLenum target);
GLenum TextureTarget(GLenum target);
+2
View File
@@ -344,6 +344,8 @@ GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList
OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_BUFFER_SIZE, &value); init.colorBits = value;
OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_DEPTH_SIZE, &value); init.depthBits = value;
OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_STENCIL_SIZE, &value); init.stencilBits = value;
value = 1; // default to srgb
OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &value); init.isSRGB = value;
OpenGLHook::glhooks.GetDriver()->CreateContext(NULL, ret, shareList, init);
+13
View File
@@ -298,6 +298,19 @@ class OpenGLHook : LibraryHook
ret.width = (r.right-r.left);
ret.height = (r.bottom-r.top);
ret.isSRGB = true;
if(glhooks.wglGetPixelFormatAttribivARB_realfunc == NULL)
glhooks.wglGetProcAddress_hooked("wglGetPixelFormatAttribivARB");
if(glhooks.wglGetPixelFormatAttribivARB_realfunc)
{
int attrname = eWGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
int srgb = 1;
glhooks.wglGetPixelFormatAttribivARB_realfunc(dc, pf, 0, 1, &attrname, &srgb);
ret.isSRGB = srgb;
}
if(pfd.iPixelType != PFD_TYPE_RGBA)
{
RDCERR("Unsupported OpenGL pixel type");