Reenable LyShine mask support now using Atom (#1218)

* Add option to set stencil ref in Dynamic Draw Context

* Add depth/stencil attachment slot to UI pass

* Rework mask rendering to use Atom

* Add missing circle mask image
This commit is contained in:
michabr
2021-06-11 10:03:06 -07:00
committed by GitHub
parent 0c7605c9b6
commit 6584e1290b
12 changed files with 196 additions and 94 deletions
+51 -58
View File
@@ -137,7 +137,11 @@ namespace LyShine
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
const UiRenderer::UiShaderData& uiShaderData = uiRenderer->GetUiShaderData();
dynamicDraw->SetShaderVariant(uiShaderData.m_shaderVariantDefault);
// Set render state
dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState);
dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState);
dynamicDraw->SetShaderVariant(uiRenderer->GetCurrentShaderVariant());
// Set up per draw SRG
AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> drawSrg = dynamicDraw->NewDrawSrg();
@@ -307,7 +311,7 @@ namespace LyShine
////////////////////////////////////////////////////////////////////////////////////////////////////
void MaskRenderNode::Render(UiRenderer* uiRenderer)
{
int priorBaseState = uiRenderer->GetBaseState();
UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState();
if (m_isMaskingEnabled || m_drawBehind)
{
@@ -369,68 +373,61 @@ namespace LyShine
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, int priorBaseState)
void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState)
{
UiRenderer::BaseState curBaseState = priorBaseState;
// If using alpha test for drawing the renderable components on this element then we turn on
// alpha test as a pre-render step
int alphaTest = 0;
if (m_useAlphaTest)
{
alphaTest = GS_ALPHATEST_GREATER;
}
curBaseState.m_useAlphaTest = m_useAlphaTest;
// if either of the draw flags are checked then we may want to draw the renderable component(s)
// on this element, otherwise use the color mask to stop them rendering
int colorMask = GS_COLMASK_NONE;
curBaseState.m_blendState.m_enable = false;
curBaseState.m_blendState.m_writeMask = 0x0;
if ((m_drawBehind && firstPass) ||
(m_drawInFront && !firstPass))
{
colorMask = 0; // mask everything, don't write color or alpha, we just write to stencil buffer
curBaseState.m_blendState.m_enable = true;
curBaseState.m_blendState.m_writeMask = 0xF;
}
if (m_isMaskingEnabled)
if (m_isMaskingEnabled)
{
AZ::RHI::StencilOpState stencilOpState;
stencilOpState.m_func = AZ::RHI::ComparisonFunc::Equal;
// masking is enabled so we want to setup to increment (first pass) or decrement (second pass)
// the stencil buff when rendering the renderable component(s) on this element
int passOp = 0;
if (firstPass)
{
passOp = STENCOP_PASS(FSS_STENCOP_INCR);
gEnv->pRenderer->PushProfileMarker(s_maskIncrProfileMarker);
stencilOpState.m_passOp = AZ::RHI::StencilOp::Increment;
}
else
{
passOp = STENCOP_PASS(FSS_STENCOP_DECR);
gEnv->pRenderer->PushProfileMarker(s_maskDecrProfileMarker);
stencilOpState.m_passOp = AZ::RHI::StencilOp::Decrement;
}
// set up for stencil write
const uint32 stencilRef = uiRenderer->GetStencilRef();
const uint32 stencilMask = 0xFF;
const uint32 stencilWriteMask = 0xFF;
const int32 stencilState = STENC_FUNC(FSS_STENCFUNC_EQUAL)
| STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | passOp;
gEnv->pRenderer->SetStencilState(stencilState, stencilRef, stencilMask, stencilWriteMask);
curBaseState.m_stencilState.m_frontFace = stencilOpState;
curBaseState.m_stencilState.m_backFace = stencilOpState;
// Set the base state that should be used when rendering the renderable component(s) on this
// element
uiRenderer->SetBaseState(priorBaseState | GS_STENCIL | alphaTest | colorMask);
// set up for stencil write
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef());
curBaseState.m_stencilState.m_enable = true;
curBaseState.m_stencilState.m_writeMask = 0xFF;
}
else
{
// masking is not enabled
// Even if not masking we still use alpha test (if checked). This is primarily to help the user to
// visualize what their alpha tested mask looks like.
if (colorMask || alphaTest)
{
uiRenderer->SetBaseState(priorBaseState | colorMask | alphaTest);
}
curBaseState.m_stencilState.m_enable = false;
}
uiRenderer->SetBaseState(curBaseState);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, int priorBaseState)
void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState)
{
if (m_isMaskingEnabled)
{
@@ -442,26 +439,29 @@ namespace LyShine
if (firstPass)
{
uiRenderer->IncrementStencilRef();
gEnv->pRenderer->PopProfileMarker(s_maskIncrProfileMarker);
}
else
{
uiRenderer->DecrementStencilRef();
gEnv->pRenderer->PopProfileMarker(s_maskDecrProfileMarker);
}
// turn off stencil write and turn on stencil test
const uint32 stencilRef = uiRenderer->GetStencilRef();
const uint32 stencilMask = 0xFF;
const uint32 stencilWriteMask = 0x00;
const int32 stencilState = STENC_FUNC(FSS_STENCFUNC_EQUAL)
| STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | STENCOP_PASS(FSS_STENCOP_KEEP);
gEnv->pRenderer->SetStencilState(stencilState, stencilRef, stencilMask, stencilWriteMask);
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef());
if (firstPass)
{
// first pass, turn on stencil test for drawing children
uiRenderer->SetBaseState(priorBaseState | GS_STENCIL);
UiRenderer::BaseState curBaseState = priorBaseState;
// turn off stencil write and turn on stencil test
curBaseState.m_stencilState.m_enable = true;
curBaseState.m_stencilState.m_writeMask = 0x00;
AZ::RHI::StencilOpState stencilOpState;
stencilOpState.m_func = AZ::RHI::ComparisonFunc::Equal;
curBaseState.m_stencilState.m_frontFace = stencilOpState;
curBaseState.m_stencilState.m_backFace = stencilOpState;
uiRenderer->SetBaseState(curBaseState);
}
else
{
@@ -475,7 +475,6 @@ namespace LyShine
// remove any color mask or alpha test that we set in pre-render
uiRenderer->SetBaseState(priorBaseState);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -637,35 +636,24 @@ namespace LyShine
////////////////////////////////////////////////////////////////////////////////////////////////////
void RenderGraph::BeginMask(bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront)
{
#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets)
// this uses pool allocator
MaskRenderNode* maskRenderNode = new MaskRenderNode(m_currentMask, isMaskingEnabled, useAlphaTest, drawBehind, drawInFront);
m_currentMask = maskRenderNode;
m_renderNodeListStack.push(&maskRenderNode->GetMaskRenderNodeList());
#else
AZ_UNUSED(drawInFront);
AZ_UNUSED(drawBehind);
AZ_UNUSED(useAlphaTest);
AZ_UNUSED(isMaskingEnabled);
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void RenderGraph::StartChildrenForMask()
{
#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets)
AZ_Assert(m_currentMask, "Calling StartChildrenForMask while not defining a mask");
m_renderNodeListStack.pop();
m_renderNodeListStack.push(&m_currentMask->GetContentRenderNodeList());
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void RenderGraph::EndMask()
{
#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets)
AZ_Assert(m_currentMask, "Calling EndMask while not defining a mask");
if (m_currentMask)
{
@@ -686,7 +674,6 @@ namespace LyShine
m_renderNodeListStack.top()->push_back(newMaskRenderNode);
}
}
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -996,6 +983,12 @@ namespace LyShine
// LYSHINE_ATOM_TODO - will probably need to support this when converting UI Editor to use Atom
AZ_UNUSED(viewportSize);
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
// Disable stencil and enable blend/color write
dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState);
dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState);
// First render the render targets, they are sorted so that more deeply nested ones are rendered first.
#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (render targets)