Workaround for NVidia flicker bug. (#5669)

Somehow, accessing IN.m_uv before the later calculations use it seems to make the values become stable and stop flickering.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2021-11-16 17:06:27 -06:00
committed by GitHub
parent fc805594d0
commit a74fa5c5b8
@@ -80,26 +80,38 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN)
// ------- Macro Color / Normal -------
float3 macroColor = TerrainMaterialSrg::m_baseColor.rgb;
[unroll] for (uint i = 0; i < 4 && (i < ObjectSrg::m_macroMaterialCount); ++i)
// There's a bug that shows up with an NVidia GTX 1660 Super card happening on driver versions as recent as 496.49 (10/26/21) in which
// the IN.m_uv values will intermittently "flicker" to 0.0 after entering and exiting game mode.
// (See https://github.com/o3de/o3de/issues/5014)
// This bug has only shown up on PCs when using the DX12 RHI. It doesn't show up with Vulkan or when capturing frames with PIX or
// RenderDoc. Our best guess is that it is a driver bug. The workaround is to use the IN.m_uv values in a calculation prior to the
// point that we actually use them for macroUv below. The "if(any(!isnan(IN.m_uv)))" seems to be sufficient for the workaround. The
// if statement will always be true, but just the act of reading these values in the if statement makes the values stable. Removing
// the if statement causes the flickering to occur using the steps documented in the bug.
if (any(!isnan(IN.m_uv)))
{
float2 macroUvMin = ObjectSrg::m_macroMaterialData[i].m_uvMin;
float2 macroUvMax = ObjectSrg::m_macroMaterialData[i].m_uvMax;
float2 macroUv = lerp(macroUvMin, macroUvMax, IN.m_uv);
if (macroUv.x >= 0.0 && macroUv.x <= 1.0 && macroUv.y >= 0.0 && macroUv.y <= 1.0)
[unroll] for (uint i = 0; i < 4 && (i < ObjectSrg::m_macroMaterialCount); ++i)
{
if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 1) > 0)
float2 macroUvMin = ObjectSrg::m_macroMaterialData[i].m_uvMin;
float2 macroUvMax = ObjectSrg::m_macroMaterialData[i].m_uvMax;
float2 macroUv = lerp(macroUvMin, macroUvMax, IN.m_uv);
if (macroUv.x >= 0.0 && macroUv.x <= 1.0 && macroUv.y >= 0.0 && macroUv.y <= 1.0)
{
macroColor = GetBaseColorInput(ObjectSrg::m_macroColorMap[i], TerrainMaterialSrg::m_sampler, macroUv, macroColor, true);
if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 1) > 0)
{
macroColor = GetBaseColorInput(ObjectSrg::m_macroColorMap[i], TerrainMaterialSrg::m_sampler, macroUv, macroColor, true);
}
if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 2) > 0)
{
bool flipX = ObjectSrg::m_macroMaterialData[i].m_flipNormalX;
bool flipY = ObjectSrg::m_macroMaterialData[i].m_flipNormalY;
bool factor = ObjectSrg::m_macroMaterialData[i].m_normalFactor;
macroNormal = GetNormalInputTS(ObjectSrg::m_macroNormalMap[i], TerrainMaterialSrg::m_sampler,
macroUv, flipX, flipY, CreateIdentity3x3(), true, factor);
}
break;
}
if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 2) > 0)
{
bool flipX = ObjectSrg::m_macroMaterialData[i].m_flipNormalX;
bool flipY = ObjectSrg::m_macroMaterialData[i].m_flipNormalY;
bool factor = ObjectSrg::m_macroMaterialData[i].m_normalFactor;
macroNormal = GetNormalInputTS(ObjectSrg::m_macroNormalMap[i], TerrainMaterialSrg::m_sampler,
macroUv, flipX, flipY, CreateIdentity3x3(), true, factor);
}
break;
}
}