Skip to content

Commit 8b20012

Browse files
author
Evergreen
committed
2022.3: Fix for editor crash with multiple stack traces when playing video on a render texture with low end graphics devices
1 parent 2050134 commit 8b20012

File tree

1 file changed

+42
-28
lines changed
  • Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop

1 file changed

+42
-28
lines changed

Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS
643643
#if SHADEROPTIONS_AREA_LIGHTS
644644
if (featureFlags & LIGHTFEATUREFLAGS_AREA)
645645
{
646-
uint lightCount, lightStart;
646+
uint lightCount, lightStart; // Start is the offset specific to the tile (or cluster)
647647

648648
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
649649
GetCountAndStart(posInput, LIGHTCATEGORY_AREA, lightStart, lightCount);
@@ -652,43 +652,57 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS
652652
lightStart = _PunctualLightCount;
653653
#endif
654654

655-
// COMPILER BEHAVIOR WARNING!
656-
// If rectangle lights are before line lights, the compiler will duplicate light matrices in VGPR because they are used differently between the two types of lights.
657-
// By keeping line lights first we avoid this behavior and save substantial register pressure.
658-
// TODO: This is based on the current Lit.shader and can be different for any other way of implementing area lights, how to be generic and ensure performance ?
655+
bool fastPath = false;
656+
#if SCALARIZE_LIGHT_LOOP
657+
uint lightStartLane0;
658+
fastPath = IsFastPath(lightStart, lightStartLane0); // True if all pixels belong to the same tile (or cluster)
659659

660-
if (lightCount > 0)
660+
if (fastPath)
661661
{
662-
i = 0;
663-
664-
uint last = lightCount - 1;
665-
LightData lightData = FetchLight(lightStart, i);
662+
lightStart = lightStartLane0;
663+
}
664+
#endif
666665

667-
while (i <= last && lightData.lightType == GPULIGHTTYPE_TUBE)
668-
{
669-
lightData.lightType = GPULIGHTTYPE_TUBE; // Enforce constant propagation
670-
lightData.cookieMode = COOKIEMODE_NONE; // Enforce constant propagation
666+
// Scalarized loop. All lights that are in a tile/cluster touched by any pixel in the wave are loaded (scalar load), only the one relevant to current thread/pixel are processed.
667+
// For clarity, the following code will follow the convention: variables starting with s_ are meant to be wave uniform (meant for scalar register),
668+
// v_ are variables that might have different value for each thread in the wave (meant for vector registers).
669+
// This will perform more loads than it is supposed to, however, the benefits should offset the downside, especially given that light data accessed should be largely coherent.
670+
// Note that the above is valid only if wave intriniscs are supported.
671+
uint v_lightListOffset = 0;
672+
uint v_lightIdx = lightStart;
671673

672-
if (IsMatchingLightLayer(lightData.lightLayers, builtinData.renderingLayers))
673-
{
674-
DirectLighting lighting = EvaluateBSDF_Area(context, V, posInput, preLightData, lightData, bsdfData, builtinData);
675-
AccumulateDirectLighting(lighting, aggregateLighting);
676-
}
674+
#if NEED_TO_CHECK_HELPER_LANE
675+
// On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether.
676+
// IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be
677+
// sure it will not happen.
678+
bool isHelperLane = WaveIsHelperLane();
679+
while (!isHelperLane && v_lightListOffset < lightCount)
680+
#else
681+
while (v_lightListOffset < lightCount)
682+
#endif
683+
{
684+
v_lightIdx = FetchIndex(lightStart, v_lightListOffset);
685+
#if SCALARIZE_LIGHT_LOOP
686+
uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath);
687+
#else
688+
uint s_lightIdx = v_lightIdx;
689+
#endif
690+
if (s_lightIdx == -1)
691+
break;
677692

678-
lightData = FetchLight(lightStart, min(++i, last));
679-
}
693+
LightData s_lightData = FetchLight(s_lightIdx);
680694

681-
while (i <= last) // GPULIGHTTYPE_RECTANGLE
695+
// If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased.
696+
// Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
697+
// end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem.
698+
if (s_lightIdx >= v_lightIdx)
682699
{
683-
lightData.lightType = GPULIGHTTYPE_RECTANGLE; // Enforce constant propagation
684-
685-
if (IsMatchingLightLayer(lightData.lightLayers, builtinData.renderingLayers))
700+
v_lightListOffset++;
701+
if (IsMatchingLightLayer(s_lightData.lightLayers, builtinData.renderingLayers))
686702
{
687-
DirectLighting lighting = EvaluateBSDF_Area(context, V, posInput, preLightData, lightData, bsdfData, builtinData);
703+
DirectLighting lighting = EvaluateBSDF_Area(context, V, posInput, preLightData, s_lightData, bsdfData, builtinData);
688704
AccumulateDirectLighting(lighting, aggregateLighting);
689705
}
690-
691-
lightData = FetchLight(lightStart, min(++i, last));
692706
}
693707
}
694708
}

0 commit comments

Comments
 (0)