Fix blend mode options for LyShine's image component (#2377)

* Fix blend mode options for LyShine's image component
* Fix Lighten blend mode
* Fix errors from last merge

Signed-off-by: abrmich <abrmich@amazon.com>
monroegm-disable-blank-issue-2
michabr 4 years ago committed by GitHub
parent a54fceccc6
commit f58b51b8ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -38,7 +38,7 @@ namespace LyShine
////////////////////////////////////////////////////////////////////////////////////////////////////
PrimitiveListRenderNode::PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture,
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, int blendModeState)
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, const AZ::RHI::TargetBlendState& blendModeState)
: RenderNode(RenderNodeType::PrimitiveList)
, m_numTextures(1)
, m_isTextureSRGB(isTextureSRGB)
@ -55,7 +55,7 @@ namespace LyShine
////////////////////////////////////////////////////////////////////////////////////////////////////
PrimitiveListRenderNode::PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture,
const AZ::Data::Instance<AZ::RPI::Image>& maskTexture, bool isClampTextureMode, bool isTextureSRGB,
bool preMultiplyAlpha, AlphaMaskType alphaMaskType, int blendModeState)
bool preMultiplyAlpha, AlphaMaskType alphaMaskType, const AZ::RHI::TargetBlendState& blendModeState)
: RenderNode(RenderNodeType::PrimitiveList)
, m_numTextures(2)
, m_isTextureSRGB(isTextureSRGB)
@ -102,9 +102,16 @@ namespace LyShine
const UiRenderer::UiShaderData& uiShaderData = uiRenderer->GetUiShaderData();
// Set render state
dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState);
dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState);
// The blend factor and op is stored in m_blendModeState when the primitive is added to the graph.
// That is also when the graph determines whether a new primitive list node is needed.
// The rest of the blend properties are assigned during the render calls, so they get merged here
// and all are passed to the dynamic draw context
AZ::RHI::TargetBlendState targetBlendState = m_blendModeState;
targetBlendState.m_enable = uiRenderer->GetBaseState().m_blendStateEnabled;
targetBlendState.m_writeMask = uiRenderer->GetBaseState().m_blendStateWriteMask;
dynamicDraw->SetTarget0BlendState(targetBlendState);
dynamicDraw->SetShaderVariant(uiRenderer->GetCurrentShaderVariant());
@ -354,13 +361,13 @@ namespace LyShine
// 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
curBaseState.m_blendState.m_enable = false;
curBaseState.m_blendState.m_writeMask = 0x0;
curBaseState.m_blendStateEnabled = false;
curBaseState.m_blendStateWriteMask = 0x0;
if ((m_drawBehind && firstPass) ||
(m_drawInFront && !firstPass))
{
curBaseState.m_blendState.m_enable = true;
curBaseState.m_blendState.m_writeMask = 0xF;
curBaseState.m_blendStateEnabled = true;
curBaseState.m_blendStateWriteMask = 0xF;
}
if (m_isMaskingEnabled)
@ -507,19 +514,10 @@ namespace LyShine
if (m_dynamicDraw)
{
UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState();
UiRenderer::BaseState curBaseState = priorBaseState;
curBaseState.m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
curBaseState.m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::AlphaSource1Inverse;
uiRenderer->SetBaseState(curBaseState);
for (RenderNode* renderNode : m_childRenderNodes)
{
renderNode->Render(uiRenderer, m_modelViewProjMat, m_dynamicDraw);
}
uiRenderer->SetBaseState(priorBaseState);
}
else
{
@ -722,7 +720,7 @@ namespace LyShine
// The shader can be outputing premultiplied alpha EITHER if the input texture is premultiplied alpha OR if the
// shader is doing the premultiply of the output color
bool isShaderOutputPremultAlpha = isPreMultiplyAlpha || isTexturePremultipliedAlpha;
int blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
AZ::RHI::TargetBlendState blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
PrimitiveListRenderNode* renderNodeToAddTo = nullptr;
if (!renderNodeList->empty())
@ -801,7 +799,7 @@ namespace LyShine
// The shader can be outputing premultiplied alpha EITHER if the input texture is premultiplied alpha OR if the
// shader is doing the premultiply of the output color
bool isShaderOutputPremultAlpha = isPreMultiplyAlpha || isTexturePremultipliedAlpha;
int blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
AZ::RHI::TargetBlendState blendModeState = GetBlendModeState(blendMode, isShaderOutputPremultAlpha);
AlphaMaskType alphaMaskType = isShaderOutputPremultAlpha ? AlphaMaskType::ModulateAlphaAndColor : AlphaMaskType::ModulateAlpha;
PrimitiveListRenderNode* renderNodeToAddTo = nullptr;
@ -947,9 +945,12 @@ namespace LyShine
{
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = uiRenderer->GetDynamicDrawContext();
// Disable stencil and enable blend/color write
// Reset stencil and blend mode to defaults (disable stencil and enable blend/color write)
dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState);
dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState);
AZ::RHI::TargetBlendState defaultBlendModeState = GetBlendModeState(LyShine::BlendMode::Normal, false);
defaultBlendModeState.m_enable = uiRenderer->GetBaseState().m_blendStateEnabled;
defaultBlendModeState.m_writeMask = uiRenderer->GetBaseState().m_blendStateWriteMask;
dynamicDraw->SetTarget0BlendState(defaultBlendModeState);
// First render the render targets, they are sorted so that more deeply nested ones are rendered first.
// They only need to be rendered the first time that a render graph is rendered after it has been built.
@ -1169,7 +1170,7 @@ namespace LyShine
if (prevPrimListNode)
{
if (prevPrimListNode->GetBlendModeState() != primListRenderNode->GetBlendModeState())
if (!(prevPrimListNode->GetBlendModeState() == primListRenderNode->GetBlendModeState()))
{
++info.m_numNodesDueToBlendMode;
}
@ -1346,8 +1347,9 @@ namespace LyShine
}
// Write heading to logfile for this render node
logLine = AZStd::string::format("%sPrimitive render node (Blend mode=%d, SRGB=%d). NumPrims=%d, NumTris=%d. Using textures:\r\n",
indent.c_str(), primListRenderNode->GetBlendModeState(),
AZ::RHI::TargetBlendState blendMode = primListRenderNode->GetBlendModeState();
logLine = AZStd::string::format("%sPrimitive render node (Blend mode=%s, SRGB=%d). NumPrims=%d, NumTris=%d. Using textures:\r\n",
indent.c_str(), blendMode.m_enable ? "enabled" : "disabled",
static_cast<int>(primListRenderNode->GetIsTextureSRGB()),
numPrimitives, numTriangles);
AZ::IO::LocalFileIO::GetInstance()->Write(fileHandle, logLine.c_str(), logLine.size());
@ -1415,8 +1417,9 @@ namespace LyShine
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
int RenderGraph::GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const
{
AZ::RHI::TargetBlendState RenderGraph::GetBlendModeState(LyShine::BlendMode blendMode, [[maybe_unused]] bool isShaderOutputPremultAlpha) const
{
// LYSHINE_ATOM_TODO - remove "premultiplyAlpha" parameter and clean up related comments as I think it's no longer needed
// Our blend modes are complicated by the fact we want to be able to render to a render target and then
// render from that render target texture to the back buffer and get the same result as if we rendered
// directly to the back buffer. This should be true even if the render target texture does not end up
@ -1443,72 +1446,47 @@ namespace LyShine
// properly might require shader changes also. For the moment using the blend modes Screen, Darken, Lighten
// is not encouraged, especially when rendering to a render target.
int flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA; // the default
AZ::RHI::TargetBlendState blendState;
blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::AlphaSourceInverse;
switch (blendMode)
{
case LyShine::BlendMode::Normal:
// This is the default mode that does an alpha blend by interpolating based on src alpha
if (isShaderOutputPremultAlpha)
{
flags = GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA;
}
else
{
flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
}
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
blendState.m_blendDest = AZ::RHI::BlendFactor::AlphaSourceInverse;
break;
case LyShine::BlendMode::Add:
// This works well, the amount of the src color added is controlled by src alpha
if (isShaderOutputPremultAlpha)
{
flags = GS_BLSRC_ONE | GS_BLDST_ONE;
}
else
{
flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONE;
}
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
blendState.m_blendDest = AZ::RHI::BlendFactor::One;
break;
case LyShine::BlendMode::Screen:
// This is a poor approximation of the PhotoShop Screen mode but trying to take some account of src alpha
// In Photoshop this would be 1 - ( (1-SrcColor) * (1-DstColor) )
// So we should use a blend op of multiply but the IRenderer interface doesn't support that. We get some multiply
// from GS_BLDST_ONEMINUSSRCCOL which multiplies the DstColor by (1-SrcColor)
if (isShaderOutputPremultAlpha)
{
flags = GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCCOL;
}
else
{
flags = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCCOL;
}
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
blendState.m_blendDest = AZ::RHI::BlendFactor::ColorSourceInverse;
break;
case LyShine::BlendMode::Darken:
// This is a poor approximation of the PhotoShop Darken mode but trying to take some account of src alpha
// In Photoshop Darken means min(SrcColor, DstColor)
if (isShaderOutputPremultAlpha)
{
flags = GS_BLOP_MIN | GS_BLSRC_ONE | GS_BLDST_ONE | GS_BLALPHA_MAX;
}
else
{
flags = GS_BLOP_MIN | GS_BLSRC_ONEMINUSSRCALPHA | GS_BLDST_ONE;
}
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSourceInverse;
blendState.m_blendDest = AZ::RHI::BlendFactor::One;
blendState.m_blendOp = AZ::RHI::BlendOp::Minimum;
break;
case LyShine::BlendMode::Lighten:
// This is a pretty good an approximation of the PhotoShop Lighten mode but trying to take some account of src alpha
// In PhotoShop Lighten means max(SrcColor, DstColor)
if (isShaderOutputPremultAlpha)
{
flags = GS_BLOP_MAX | GS_BLSRC_ONE| GS_BLDST_ONE;
}
else
{
flags = GS_BLOP_MAX | GS_BLSRC_SRCALPHA | GS_BLDST_ONE;
}
blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
blendState.m_blendDest = AZ::RHI::BlendFactor::One;
blendState.m_blendOp = AZ::RHI::BlendOp::Maximum;
break;
}
return flags;
return blendState;
}
void RenderGraph::SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled)

@ -71,9 +71,9 @@ namespace LyShine
// We use a pool allocator to keep these allocations fast.
AZ_CLASS_ALLOCATOR(PrimitiveListRenderNode, AZ::PoolAllocator, 0);
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, int blendModeState);
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, const AZ::RHI::TargetBlendState& blendModeState);
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, const AZ::Data::Instance<AZ::RPI::Image>& maskTexture,
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, int blendModeState);
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, const AZ::RHI::TargetBlendState& blendModeState);
~PrimitiveListRenderNode() override;
void Render(UiRenderer* uiRenderer
, const AZ::Matrix4x4& modelViewProjMat
@ -88,7 +88,7 @@ namespace LyShine
bool GetTextureIsClampMode(int texIndex) const { return m_textures[texIndex].m_isClampTextureMode; }
bool GetIsTextureSRGB() const { return m_isTextureSRGB; }
int GetBlendModeState() const { return m_blendModeState; }
AZ::RHI::TargetBlendState GetBlendModeState() const { return m_blendModeState; }
bool GetIsPremultiplyAlpha() const { return m_preMultiplyAlpha; }
AlphaMaskType GetAlphaMaskType() const { return m_alphaMaskType; }
@ -118,7 +118,7 @@ namespace LyShine
bool m_isTextureSRGB;
bool m_preMultiplyAlpha;
AlphaMaskType m_alphaMaskType;
int m_blendModeState;
AZ::RHI::TargetBlendState m_blendModeState;
int m_totalNumVertices;
int m_totalNumIndices;
@ -340,7 +340,7 @@ namespace LyShine
protected: // member functions
//! Given a blend mode and whether the shader will be outputing premultiplied alpha, return state flags
int GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const;
AZ::RHI::TargetBlendState GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const;
void SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled);

@ -53,14 +53,8 @@ public: // types
void ResetToDefault()
{
// Enable blend/color write
m_blendState.m_enable = true;
m_blendState.m_writeMask = 0xF;
m_blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource;
m_blendState.m_blendDest = AZ::RHI::BlendFactor::AlphaSourceInverse;
m_blendState.m_blendOp = AZ::RHI::BlendOp::Add;
m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One;
m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::Zero;
m_blendState.m_blendAlphaOp = AZ::RHI::BlendOp::Add;
m_blendStateEnabled = true;
m_blendStateWriteMask = 0xF;
// Disable stencil
m_stencilState = AZ::RHI::StencilState();
@ -70,7 +64,8 @@ public: // types
m_modulateAlpha = false;
}
AZ::RHI::TargetBlendState m_blendState;
uint32_t m_blendStateEnabled = true;
uint32_t m_blendStateWriteMask = 0xF;
AZ::RHI::StencilState m_stencilState;
bool m_useAlphaTest = false;
bool m_modulateAlpha = false;

Loading…
Cancel
Save