Skip to content

Commit d801f19

Browse files
Fixed non-sRGB default framebuffer in OpenGL (close #124)
1 parent de886df commit d801f19

File tree

5 files changed

+68
-19
lines changed

5 files changed

+68
-19
lines changed

Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ class DeviceContextGLImpl final : public DeviceContextBase<EngineGLImplTraits>
316316
GLContextState m_ContextState;
317317

318318
private:
319+
void CommitDefaultFramebuffer();
320+
319321
__forceinline void PrepareForDraw(DRAW_FLAGS Flags, bool IsIndexed, GLenum& GlTopology);
320322
__forceinline void PrepareForIndexedDraw(VALUE_TYPE IndexType, Uint32 FirstIndexLocation, GLenum& GLIndexType, size_t& FirstIndexByteOffset);
321323
__forceinline void PrepareForIndirectDraw(IBuffer* pAttribsBuffer);

Graphics/GraphicsEngineOpenGL/include/GLContextState.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class GLContextState
4949
void SetProgram (const GLObjectWrappers::GLProgramObj& GLProgram);
5050
void SetPipeline (const GLObjectWrappers::GLPipelineObj& GLPipeline);
5151
void BindVAO (const GLObjectWrappers::GLVertexArrayObj& VAO);
52-
void BindFBO (const GLObjectWrappers::GLFrameBufferObj& FBO);
52+
void BindFBO (const GLObjectWrappers::GLFrameBufferObj& FBO, bool DoEnableFramebufferSRGB = true);
5353
void SetActiveTexture (Int32 Index);
5454
void BindTexture (Int32 Index, GLenum BindTarget, const GLObjectWrappers::GLTextureObj& Tex);
5555
void BindUniformBuffer (Int32 Index, const GLObjectWrappers::GLBufferObj& Buff, GLintptr Offset, GLsizeiptr Size);
@@ -85,6 +85,7 @@ class GLContextState
8585
void GetColorWriteMask(Uint32 RTIndex, Uint32& WriteMask, Bool& bIsIndexed);
8686
void SetColorWriteMask(Uint32 WriteMask);
8787
void SetColorWriteMaskIndexed(Uint32 RTIndex, Uint32 WriteMask);
88+
void EnableFramebufferSRGB(Bool bEnable);
8889

8990
Uint8 GetStencilWriteMask() const { return static_cast<Uint8>(m_DSState.m_StencilWriteMask); }
9091

@@ -118,6 +119,7 @@ class GLContextState
118119
bool IsFillModeSelectionSupported = true;
119120
bool IsProgramPipelineSupported = true;
120121
bool IsDepthClampSupported = true;
122+
bool IsFramebufferSRGBSupported = false;
121123
GLint MaxCombinedTexUnits = 0;
122124
GLint MaxDrawBuffers = 0;
123125
GLint MaxUniformBufferBindings = 0;
@@ -310,6 +312,7 @@ class GLContextState
310312

311313
Uint32 m_ColorWriteMasks[MAX_RENDER_TARGETS] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
312314
EnableStateHelper m_bIndexedWriteMasks;
315+
EnableStateHelper m_bFramebufferSRGB;
313316
Int32 m_iActiveTexture = -1;
314317
Int32 m_NumPatchVertices = -1;
315318

Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,34 @@ GLuint DeviceContextGLImpl::GetDefaultFBO() const
366366
return m_pSwapChain ? m_pSwapChain->GetDefaultFBO() : 0;
367367
}
368368

369+
void DeviceContextGLImpl::CommitDefaultFramebuffer()
370+
{
371+
GLuint DefaultFBOHandle = m_pSwapChain->GetDefaultFBO();
372+
if (m_DefaultFBO != DefaultFBOHandle)
373+
{
374+
m_DefaultFBO = GLObjectWrappers::GLFrameBufferObj{true, GLObjectWrappers::GLFBOCreateReleaseHelper{DefaultFBOHandle}};
375+
}
376+
377+
// In theory, we should not be messing with GL_FRAMEBUFFER_SRGB, but sRGB conversion
378+
// control for default framebuffers is totally broken.
379+
// https://github.com/DiligentGraphics/DiligentCore/issues/124
380+
bool EnableFramebufferSRGB = true;
381+
if (m_ContextState.GetContextCaps().IsFramebufferSRGBSupported)
382+
{
383+
if (DefaultFBOHandle == 0 && m_NumBoundRenderTargets == 1)
384+
{
385+
if (const TextureViewGLImpl* pRT0 = m_pBoundRenderTargets[0])
386+
{
387+
const TEXTURE_FORMAT Fmt = pRT0->GetDesc().Format;
388+
EnableFramebufferSRGB = (Fmt == TEX_FORMAT_RGBA8_UNORM_SRGB || Fmt == TEX_FORMAT_BGRA8_UNORM_SRGB);
389+
}
390+
}
391+
}
392+
393+
m_ContextState.BindFBO(m_DefaultFBO, EnableFramebufferSRGB);
394+
m_DrawFBO = nullptr;
395+
}
396+
369397
void DeviceContextGLImpl::CommitRenderTargets()
370398
{
371399
DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "This method must not be called inside render pass");
@@ -375,13 +403,7 @@ void DeviceContextGLImpl::CommitRenderTargets()
375403

376404
if (m_IsDefaultFBOBound)
377405
{
378-
GLuint DefaultFBOHandle = m_pSwapChain->GetDefaultFBO();
379-
if (m_DefaultFBO != DefaultFBOHandle)
380-
{
381-
m_DefaultFBO = GLObjectWrappers::GLFrameBufferObj{true, GLObjectWrappers::GLFBOCreateReleaseHelper{DefaultFBOHandle}};
382-
}
383-
m_ContextState.BindFBO(m_DefaultFBO);
384-
m_DrawFBO = nullptr;
406+
CommitDefaultFramebuffer();
385407
}
386408
else
387409
{
@@ -475,13 +497,7 @@ void DeviceContextGLImpl::BeginSubpass()
475497
}
476498
else
477499
{
478-
GLuint DefaultFBOHandle = m_pSwapChain->GetDefaultFBO();
479-
if (m_DefaultFBO != DefaultFBOHandle)
480-
{
481-
m_DefaultFBO = GLObjectWrappers::GLFrameBufferObj{true, GLObjectWrappers::GLFBOCreateReleaseHelper{DefaultFBOHandle}};
482-
}
483-
m_ContextState.BindFBO(m_DefaultFBO);
484-
m_DrawFBO = nullptr;
500+
CommitDefaultFramebuffer();
485501
}
486502

487503

Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ GLContextState::GLContextState(RenderDeviceGLImpl* pDeviceGL)
4848
m_Caps.IsFillModeSelectionSupported = AdapterInfo.Features.WireframeFill;
4949
m_Caps.IsProgramPipelineSupported = AdapterInfo.Features.SeparablePrograms;
5050
m_Caps.IsDepthClampSupported = AdapterInfo.Features.DepthClamp;
51+
m_Caps.IsFramebufferSRGBSupported = pDeviceGL->GetGLCaps().FramebufferSRGB;
5152

5253
{
5354
m_Caps.MaxCombinedTexUnits = 0;
@@ -109,13 +110,14 @@ void GLContextState::Invalidate()
109110
m_BoundUniformBuffers.clear();
110111
m_BoundStorageBlocks.clear();
111112

112-
m_DSState = DepthStencilGLState();
113-
m_RSState = RasterizerGLState();
113+
m_DSState = DepthStencilGLState{};
114+
m_RSState = RasterizerGLState{};
114115

115116
for (Uint32 rt = 0; rt < _countof(m_ColorWriteMasks); ++rt)
116117
m_ColorWriteMasks[rt] = 0xFF;
117118

118-
m_bIndexedWriteMasks = EnableStateHelper();
119+
m_bIndexedWriteMasks = EnableStateHelper{};
120+
m_bFramebufferSRGB = EnableStateHelper{};
119121

120122
m_iActiveTexture = -1;
121123
m_NumPatchVertices = -1;
@@ -177,7 +179,7 @@ void GLContextState::BindVAO(const GLVertexArrayObj& VAO)
177179
}
178180
}
179181

180-
void GLContextState::BindFBO(const GLFrameBufferObj& FBO)
182+
void GLContextState::BindFBO(const GLFrameBufferObj& FBO, bool DoEnableFramebufferSRGB)
181183
{
182184
GLuint FBOHandle = 0;
183185
if (UpdateBoundObject(m_FBOId, FBO, FBOHandle))
@@ -193,6 +195,8 @@ void GLContextState::BindFBO(const GLFrameBufferObj& FBO)
193195
DEV_CHECK_GL_ERROR("Failed to bind FBO as draw framebuffer");
194196
glBindFramebuffer(GL_READ_FRAMEBUFFER, FBOHandle);
195197
DEV_CHECK_GL_ERROR("Failed to bind FBO as read framebuffer");
198+
199+
EnableFramebufferSRGB(DoEnableFramebufferSRGB);
196200
}
197201
}
198202

@@ -906,6 +910,27 @@ void GLContextState::GetColorWriteMask(Uint32 RTIndex, Uint32& WriteMask, Bool&
906910
bIsIndexed = m_bIndexedWriteMasks;
907911
}
908912

913+
void GLContextState::EnableFramebufferSRGB(Bool bEnable)
914+
{
915+
if (!m_Caps.IsFramebufferSRGBSupported)
916+
return;
917+
918+
if (m_bFramebufferSRGB != bEnable)
919+
{
920+
if (bEnable)
921+
{
922+
glEnable(GL_FRAMEBUFFER_SRGB);
923+
DEV_CHECK_GL_ERROR("Failed to enable framebuffer sRGB");
924+
}
925+
else
926+
{
927+
glDisable(GL_FRAMEBUFFER_SRGB);
928+
DEV_CHECK_GL_ERROR("Failed to disable framebuffer sRGB");
929+
}
930+
m_bFramebufferSRGB = bEnable;
931+
}
932+
}
933+
909934
void GLContextState::SetNumPatchVertices(Int32 NumVertices)
910935
{
911936
#if GL_ARB_tessellation_shader

Graphics/GraphicsEngineOpenGL/src/GLContextWindows.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ GLContext::GLContext(const EngineGLCreateInfo& InitAttribs,
127127
if (nPixelFormat == 0)
128128
LOG_ERROR_AND_THROW("Invalid Pixel Format");
129129

130+
// NB: An application can only set the pixel format of a window one time.
131+
// Once a window's pixel format is set, it cannot be changed.
132+
// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setpixelformat
130133
BOOL bResult = SetPixelFormat(m_WindowHandleToDeviceContext, nPixelFormat, &pfd);
131134
if (!bResult)
132135
LOG_ERROR_AND_THROW("Failed to set Pixel Format");

0 commit comments

Comments
 (0)