Skip to content

Commit 87a00e6

Browse files
GL: reworked color write masks handling
1 parent 2fde5b5 commit 87a00e6

File tree

3 files changed

+117
-71
lines changed

3 files changed

+117
-71
lines changed

Graphics/GraphicsEngineOpenGL/include/GLContextState.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2024 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -78,12 +78,14 @@ class GLContextState
7878
void EnableScissorTest (bool bEnableScissorTest);
7979

8080
void SetBlendFactors(const float* BlendFactors);
81-
void SetBlendState(const BlendStateDesc& BSDsc, Uint32 SampleMask);
81+
void SetBlendState(const BlendStateDesc& BSDsc, Uint32 RenderTargetMask, Uint32 SampleMask);
8282

8383
Bool GetDepthWritesEnabled(){ return m_DSState.m_DepthWritesEnableState; }
8484
Bool GetScissorTestEnabled(){ return m_RSState.ScissorTestEnable; }
85-
void GetColorWriteMask(Uint32 RTIndex, Uint32& WriteMask, Bool& bIsIndependent);
86-
void SetColorWriteMask(Uint32 RTIndex, Uint32 WriteMask, Bool bIsIndependent);
85+
void GetColorWriteMask(Uint32 RTIndex, Uint32& WriteMask, Bool& bIsIndexed);
86+
void SetColorWriteMask(Uint32 WriteMask);
87+
void SetColorWriteMaskIndexed(Uint32 RTIndex, Uint32 WriteMask);
88+
8789
Uint8 GetStencilWriteMask(){ return static_cast<Uint8>(m_DSState.m_StencilWriteMask); }
8890

8991
void GetBoundImage(Uint32 Index, GLuint& GLHandle, GLint& MipLevel, GLboolean& IsLayered, GLint& Layer, GLenum& Access, GLenum& Format) const;
@@ -307,7 +309,7 @@ class GLContextState
307309
ContextCaps m_Caps;
308310

309311
Uint32 m_ColorWriteMasks[MAX_RENDER_TARGETS] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
310-
EnableStateHelper m_bIndependentWriteMasks;
312+
EnableStateHelper m_bIndexedWriteMasks;
311313
Int32 m_iActiveTexture = -1;
312314
Int32 m_NumPatchVertices = -1;
313315

Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void DeviceContextGLImpl::SetPipelineState(IPipelineState* pPipelineState)
121121
// Set blend state
122122
{
123123
const BlendStateDesc& BSDsc = GraphicsPipeline.BlendDesc;
124-
m_ContextState.SetBlendState(BSDsc, GraphicsPipeline.SampleMask);
124+
m_ContextState.SetBlendState(BSDsc, m_pPipelineState->GetRenderTargetMask(), GraphicsPipeline.SampleMask);
125125
}
126126

127127
// Set depth-stencil state
@@ -1466,10 +1466,17 @@ void DeviceContextGLImpl::ClearRenderTarget(ITextureView* pView, const void* RGB
14661466
m_ContextState.EnableScissorTest(False);
14671467

14681468
// Set write mask
1469-
Uint32 WriteMask = 0;
1470-
Bool bIndependentBlend = False;
1471-
m_ContextState.GetColorWriteMask(RTIndex, WriteMask, bIndependentBlend);
1472-
m_ContextState.SetColorWriteMask(RTIndex, COLOR_MASK_ALL, bIndependentBlend);
1469+
Uint32 WriteMask = 0;
1470+
Bool bIndexedMasks = False;
1471+
m_ContextState.GetColorWriteMask(RTIndex, WriteMask, bIndexedMasks);
1472+
if (bIndexedMasks)
1473+
{
1474+
m_ContextState.SetColorWriteMaskIndexed(RTIndex, COLOR_MASK_ALL);
1475+
}
1476+
else
1477+
{
1478+
m_ContextState.SetColorWriteMask(COLOR_MASK_ALL);
1479+
}
14731480

14741481
const TEXTURE_FORMAT RTVFormat = m_pBoundRenderTargets[RTIndex]->GetDesc().Format;
14751482
const TextureFormatAttribs& FmtAttribs = GetTextureFormatAttribs(RTVFormat);
@@ -1489,7 +1496,15 @@ void DeviceContextGLImpl::ClearRenderTarget(ITextureView* pView, const void* RGB
14891496
DEV_CHECK_GL_ERROR("glClearBufferfv() failed");
14901497
}
14911498

1492-
m_ContextState.SetColorWriteMask(RTIndex, WriteMask, bIndependentBlend);
1499+
if (bIndexedMasks)
1500+
{
1501+
m_ContextState.SetColorWriteMaskIndexed(RTIndex, WriteMask);
1502+
}
1503+
else
1504+
{
1505+
m_ContextState.SetColorWriteMask(WriteMask);
1506+
}
1507+
14931508
m_ContextState.EnableScissorTest(ScissorTestEnabled);
14941509
}
14951510

Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp

Lines changed: 89 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ void GLContextState::Invalidate()
115115
for (Uint32 rt = 0; rt < _countof(m_ColorWriteMasks); ++rt)
116116
m_ColorWriteMasks[rt] = 0xFF;
117117

118-
m_bIndependentWriteMasks = EnableStateHelper();
118+
m_bIndexedWriteMasks = EnableStateHelper();
119119

120120
m_iActiveTexture = -1;
121121
m_NumPatchVertices = -1;
@@ -717,35 +717,62 @@ void GLContextState::SetBlendFactors(const float* BlendFactors)
717717
DEV_CHECK_GL_ERROR("Failed to set blend color");
718718
}
719719

720-
void GLContextState::SetBlendState(const BlendStateDesc& BSDsc, Uint32 SampleMask)
720+
void GLContextState::SetBlendState(const BlendStateDesc& BSDsc, Uint32 RenderTargetMask, Uint32 SampleMask)
721721
{
722722
if (SampleMask != 0xFFFFFFFF)
723723
LOG_ERROR_MESSAGE("Sample mask is not currently implemented in GL backend");
724724

725-
bool bEnableBlend = false;
726-
if (BSDsc.IndependentBlendEnable)
725+
bool bEnableBlend = BSDsc.RenderTargets[0].BlendEnable;
726+
bool bUseIndexedColorWriteMasks = false;
727+
COLOR_MASK NonIndexedColorMask = COLOR_MASK_NONE;
728+
729+
if (RenderTargetMask & ~((1u << MAX_RENDER_TARGETS) - 1u))
730+
{
731+
UNEXPECTED("Render target mask (", RenderTargetMask, ") contains bits that correspond to non-existent render targets");
732+
RenderTargetMask &= (1u << MAX_RENDER_TARGETS) - 1u;
733+
}
734+
735+
if (RenderTargetMask & ~((1u << m_Caps.MaxDrawBuffers) - 1u))
736+
{
737+
LOG_ERROR_MESSAGE("Render target mask (", RenderTargetMask, ") contains buffer ", PlatformMisc::GetLSB(RenderTargetMask), " but this device only supports ", m_Caps.MaxDrawBuffers, " draw buffers");
738+
RenderTargetMask &= (1u << m_Caps.MaxDrawBuffers) - 1u;
739+
}
740+
741+
for (Uint32 Mask = RenderTargetMask; Mask != 0;)
727742
{
728-
for (int i = 0; i < static_cast<int>(MAX_RENDER_TARGETS); ++i)
743+
Uint32 rt = PlatformMisc::GetLSB(Mask);
744+
Mask &= ~(1u << rt);
745+
VERIFY_EXPR(rt < MAX_RENDER_TARGETS && static_cast<int>(rt) < m_Caps.MaxDrawBuffers);
746+
747+
const RenderTargetBlendDesc& RT = BSDsc.RenderTargets[rt];
748+
VERIFY(RT.RenderTargetWriteMask != COLOR_MASK_NONE, "Render target write mask should not be COLOR_MASK_NONE if corresponding bit is set in RenderTargetMask");
749+
if (NonIndexedColorMask == COLOR_MASK_NONE)
750+
{
751+
NonIndexedColorMask = RT.RenderTargetWriteMask;
752+
}
753+
else if (NonIndexedColorMask != RT.RenderTargetWriteMask)
729754
{
730-
const RenderTargetBlendDesc& RT = BSDsc.RenderTargets[i];
731-
if (RT.BlendEnable)
732-
bEnableBlend = true;
755+
bUseIndexedColorWriteMasks = true;
756+
}
733757

734-
if (i < m_Caps.MaxDrawBuffers)
735-
{
736-
SetColorWriteMask(i, RT.RenderTargetWriteMask, True);
737-
}
738-
else
739-
{
740-
VERIFY(RT.RenderTargetWriteMask == RenderTargetBlendDesc().RenderTargetWriteMask, "Render target write mask is specified for buffer ", i, " but this device only supports ", m_Caps.MaxDrawBuffers, " draw buffers");
741-
}
758+
if (BSDsc.IndependentBlendEnable && RT.BlendEnable)
759+
bEnableBlend = true;
760+
}
761+
762+
if (bUseIndexedColorWriteMasks)
763+
{
764+
for (Uint32 Mask = RenderTargetMask; Mask != 0;)
765+
{
766+
Uint32 rt = PlatformMisc::GetLSB(Mask);
767+
Mask &= ~(1u << rt);
768+
VERIFY_EXPR(rt < MAX_RENDER_TARGETS && static_cast<int>(rt) < m_Caps.MaxDrawBuffers);
769+
SetColorWriteMaskIndexed(rt, BSDsc.RenderTargets[rt].RenderTargetWriteMask);
742770
}
743771
}
744-
else
772+
else if (NonIndexedColorMask != COLOR_MASK_NONE)
745773
{
746-
const RenderTargetBlendDesc& RT0 = BSDsc.RenderTargets[0];
747-
bEnableBlend = RT0.BlendEnable;
748-
SetColorWriteMask(0, RT0.RenderTargetWriteMask, False);
774+
// If the color write mask is COLOR_MASK_NONE, the draw buffer is disabled with glDrawBuffer.
775+
SetColorWriteMask(NonIndexedColorMask);
749776
}
750777

751778
if (bEnableBlend)
@@ -826,55 +853,57 @@ void GLContextState::SetBlendState(const BlendStateDesc& BSDsc, Uint32 SampleMas
826853
}
827854
}
828855

829-
void GLContextState::SetColorWriteMask(Uint32 RTIndex, Uint32 WriteMask, Bool bIsIndependent)
856+
void GLContextState::SetColorWriteMask(Uint32 WriteMask)
830857
{
831858
// Even though the write mask only applies to writes to a framebuffer, the mask state is NOT
832859
// Framebuffer state. So it is NOT part of a Framebuffer Object or the Default Framebuffer.
833860
// Binding a new framebuffer will NOT affect the mask.
861+
if (!m_bIndexedWriteMasks && m_ColorWriteMasks[0] == WriteMask)
862+
return;
834863

835-
if (!bIsIndependent)
836-
RTIndex = 0;
864+
// glColorMask() sets the mask for ALL draw buffers
865+
glColorMask(
866+
(WriteMask & COLOR_MASK_RED) ? GL_TRUE : GL_FALSE,
867+
(WriteMask & COLOR_MASK_GREEN) ? GL_TRUE : GL_FALSE,
868+
(WriteMask & COLOR_MASK_BLUE) ? GL_TRUE : GL_FALSE,
869+
(WriteMask & COLOR_MASK_ALPHA) ? GL_TRUE : GL_FALSE);
870+
DEV_CHECK_GL_ERROR("Failed to set GL color mask");
837871

838-
if (m_ColorWriteMasks[RTIndex] != WriteMask ||
839-
m_bIndependentWriteMasks != bIsIndependent)
840-
{
841-
if (bIsIndependent)
842-
{
843-
// Note that glColorMaski() does not set color mask for the framebuffer
844-
// attachment point RTIndex. Rather it sets the mask for what was set
845-
// by the glDrawBuffers() function for the i-th output
846-
glColorMaski(RTIndex,
847-
(WriteMask & COLOR_MASK_RED) ? GL_TRUE : GL_FALSE,
848-
(WriteMask & COLOR_MASK_GREEN) ? GL_TRUE : GL_FALSE,
849-
(WriteMask & COLOR_MASK_BLUE) ? GL_TRUE : GL_FALSE,
850-
(WriteMask & COLOR_MASK_ALPHA) ? GL_TRUE : GL_FALSE);
851-
DEV_CHECK_GL_ERROR("Failed to set GL color mask");
852-
853-
m_ColorWriteMasks[RTIndex] = WriteMask;
854-
}
855-
else
856-
{
857-
// glColorMask() sets the mask for ALL draw buffers
858-
glColorMask(
859-
(WriteMask & COLOR_MASK_RED) ? GL_TRUE : GL_FALSE,
860-
(WriteMask & COLOR_MASK_GREEN) ? GL_TRUE : GL_FALSE,
861-
(WriteMask & COLOR_MASK_BLUE) ? GL_TRUE : GL_FALSE,
862-
(WriteMask & COLOR_MASK_ALPHA) ? GL_TRUE : GL_FALSE);
863-
DEV_CHECK_GL_ERROR("Failed to set GL color mask");
864-
865-
for (size_t rt = 0; rt < _countof(m_ColorWriteMasks); ++rt)
866-
m_ColorWriteMasks[rt] = WriteMask;
867-
}
868-
m_bIndependentWriteMasks = bIsIndependent;
869-
}
872+
for (size_t rt = 0; rt < _countof(m_ColorWriteMasks); ++rt)
873+
m_ColorWriteMasks[rt] = WriteMask;
874+
875+
m_bIndexedWriteMasks = false;
876+
}
877+
878+
void GLContextState::SetColorWriteMaskIndexed(Uint32 RTIndex, Uint32 WriteMask)
879+
{
880+
// Even though the write mask only applies to writes to a framebuffer, the mask state is NOT
881+
// Framebuffer state. So it is NOT part of a Framebuffer Object or the Default Framebuffer.
882+
// Binding a new framebuffer will NOT affect the mask.
883+
if (m_ColorWriteMasks[RTIndex] == WriteMask)
884+
return;
885+
886+
// Note that glColorMaski() does not set color mask for the framebuffer
887+
// attachment point RTIndex. Rather it sets the mask for what was set
888+
// by the glDrawBuffers() function for the i-th output
889+
glColorMaski(RTIndex,
890+
(WriteMask & COLOR_MASK_RED) ? GL_TRUE : GL_FALSE,
891+
(WriteMask & COLOR_MASK_GREEN) ? GL_TRUE : GL_FALSE,
892+
(WriteMask & COLOR_MASK_BLUE) ? GL_TRUE : GL_FALSE,
893+
(WriteMask & COLOR_MASK_ALPHA) ? GL_TRUE : GL_FALSE);
894+
DEV_CHECK_GL_ERROR("Failed to set GL color mask");
895+
896+
m_ColorWriteMasks[RTIndex] = WriteMask;
897+
898+
m_bIndexedWriteMasks = true;
870899
}
871900

872-
void GLContextState::GetColorWriteMask(Uint32 RTIndex, Uint32& WriteMask, Bool& bIsIndependent)
901+
void GLContextState::GetColorWriteMask(Uint32 RTIndex, Uint32& WriteMask, Bool& bIsIndexed)
873902
{
874-
if (!m_bIndependentWriteMasks)
875-
RTIndex = 0;
876-
WriteMask = m_ColorWriteMasks[RTIndex];
877-
bIsIndependent = m_bIndependentWriteMasks;
903+
WriteMask = m_ColorWriteMasks[RTIndex];
904+
if (WriteMask == 0xFF)
905+
WriteMask = 0xF;
906+
bIsIndexed = m_bIndexedWriteMasks;
878907
}
879908

880909
void GLContextState::SetNumPatchVertices(Int32 NumVertices)

0 commit comments

Comments
 (0)