Files
Performance-Fish/Source/PerformanceFish/Rendering/DynamicDrawManagerPatches.cs
T
bbradson d34bc77869 1.5, added stuff, fixed stuff
- mod icon
- fixes for new vanilla clipping issues
- GenClosest optimization improving repairing, wardening, tending jobs
- caching for new ListerBuildings methods
- DynamicDrawManager single threading
- Type.GetFields caching
- StatParts analyzer category
- removed duplicate steam warning and optionally window
- added exception handling for debug menu, incidentworker, Graphic_Multi, InitializeComps, making all those now log what mod broke and not cause black screens or whatever
2024-04-27 22:31:07 +02:00

188 lines
5.8 KiB
C#

// Copyright (c) 2023 bradson
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
#if !V1_4
using Gilzoide.ManagedJobs;
using Mono.Cecil;
using Mono.Cecil.Cil;
using PerformanceFish.Prepatching;
using Unity.Jobs;
namespace PerformanceFish.Rendering;
public sealed class DynamicDrawManagerPatches : ClassWithFishPrepatches
{
public sealed class DrawDynamicThingsPatch : FishPrepatch
{
public override string? Description { get; }
= "Optimizes rendering by reverting most of the threading added in 1.5, making 5 of the 6 parallel loops "
+ "in DrawDynamicThings run on the main thread again. This generally improves rendering performance by "
+ "about 10% or so";
public override MethodBase TargetMethodBase { get; }
= AccessTools.DeclaredMethod(typeof(DynamicDrawManager), nameof(DynamicDrawManager.DrawDynamicThings));
public override void Transpiler(ILProcessor ilProcessor, ModuleDefinition module)
=> ilProcessor.ReplaceBodyWith(ReplacementBody);
public static void ReplacementBody(DynamicDrawManager instance)
{
if (!DebugViewSettings.drawThingsDynamic || instance.map.Disposed)
return;
instance.drawingNow = true;
try
{
CullAndInitializeThings(instance);
var hasAnyThingsToDraw = ThingsToDraw.Count > 0;
if (hasAnyThingsToDraw)
{
if (!DebugViewSettings.singleThreadedDrawing)
DoPreDrawThings();
DrawThingsNow();
}
if (PawnShadowsToDraw.Count > 0)
DrawShadowsNow();
if (SilhouetteUtility.CanHighlightAny() && hasAnyThingsToDraw)
DrawSilhouettes(instance);
}
catch (Exception ex)
{
Log.Error("Exception drawing dynamic things: " + ex);
}
finally
{
ThingsToDraw.Clear();
PawnShadowsToDraw.Clear();
instance.drawingNow = false;
}
}
public static void CullAndInitializeThings(DynamicDrawManager instance)
{
var map = instance.map;
var mapSizeX = map.SizeX();
var fogGrid = map.fogGrid.fogGrid;
var snowGrid = map.snowGrid.depthGrid;
var checkShadows = MatBases.SunShadow.shader.isSupported;
var currentViewRect = Find.CameraDriver.CurrentViewRect.ClipInsideMap(map).ExpandedBy(1);
var shadowViewRect = SectionLayer_SunShadows.GetSunShadowsViewRect(map, currentViewRect);
instance.drawThings.UnwrapArray(out var drawThings, out var drawThingsCount);
for (var i = 0; i < drawThingsCount; i++)
{
var drawThing = drawThings.UnsafeLoad(i);
var position = drawThing.Position;
var drawThingDef = drawThing.def;
var cellIndex = position.CellToIndex(mapSizeX);
if ((!fogGrid[cellIndex] || drawThingDef.seeThroughFog)
&& (drawThingDef.hideAtSnowDepth >= 1f
|| drawThingDef.hideAtSnowDepth >= snowGrid[cellIndex]))
{
if (currentViewRect.Contains(position)
|| currentViewRect.Overlaps(drawThing.OccupiedDrawRect()))
{
ThingsToDraw.Add(drawThing);
if (!DebugViewSettings.singleThreadedDrawing)
drawThing.DynamicDrawPhase(DrawPhase.EnsureInitialized);
}
else if (drawThing is Pawn pawn && checkShadows && shadowViewRect.Contains(drawThing.Position))
{
PawnShadowsToDraw.Add(pawn);
}
}
}
}
public static void DrawShadowsNow()
{
PawnShadowsToDraw.UnwrapArray(out var pawnShadowsToDraw, out var pawnShadowsToDrawCount);
for (var i = 0; i < pawnShadowsToDrawCount; i++)
{
var pawn = pawnShadowsToDraw.UnsafeLoad(i);
try
{
pawn.DrawShadowAt(pawn.DrawPos);
}
catch (Exception ex)
{
Log.Error($"Exception drawing shadow for '{pawn}': {ex}");
}
}
}
public static void DrawThingsNow()
{
ThingsToDraw.UnwrapArray(out var thingsToDraw, out var thingsToDrawCount);
for (var i = 0; i < thingsToDrawCount; i++)
{
var drawThing = thingsToDraw.UnsafeLoad(i);
try
{
drawThing.DynamicDrawPhase(DrawPhase.Draw);
}
catch (Exception ex)
{
Log.Error($"Exception drawing '{drawThing}': {ex}");
}
}
}
public static void DoPreDrawThings()
{
ThingsToDraw.UnwrapArray(out PreDrawThingsJob.thingsToDraw, out var thingsToDrawCount);
new ManagedJobParallelFor(PreDrawThingsJob)
.Schedule(thingsToDrawCount, UnityData.GetIdealBatchCount(thingsToDrawCount)).Complete();
}
public static readonly List<Thing> ThingsToDraw = [];
public static readonly List<Pawn> PawnShadowsToDraw = [];
public static readonly PreDrawThings PreDrawThingsJob = new();
[MethodImpl(MethodImplOptions.NoInlining)]
public static void DrawSilhouettes(DynamicDrawManager instance)
{
ThingsToDraw.UnwrapArray(out var thingsToDraw, out var thingsToDrawCount);
var inverseFovScale = Find.CameraDriver.InverseFovScale;
var altitude = AltitudeLayer.Silhouettes.AltitudeFor();
var angleAxis = Quaternion.AngleAxis(0f, Vector3.up);
for (var i = 0; i < thingsToDrawCount; i++)
{
if (thingsToDraw.UnsafeLoad(i) is not Pawn pawn || !SilhouetteUtility.ShouldDrawSilhouette(pawn))
continue;
var pawnRenderer = pawn.Drawer.renderer;
var drawSize = pawnRenderer.SilhouetteGraphic.drawSize;
drawSize.x = drawSize.x < 2.5f ? drawSize.x + SilhouetteUtility.AdjustScale(drawSize.x) : drawSize.x;
drawSize.y = drawSize.y < 2.5f ? drawSize.y + SilhouetteUtility.AdjustScale(drawSize.y) : drawSize.y;
var pos = pawnRenderer.SilhouettePos;
pos.y = altitude;
SilhouetteUtility.DrawSilhouetteJob(pawn, Matrix4x4.TRS(pos, angleAxis,
inverseFovScale with { x = inverseFovScale.x * drawSize.x, z = inverseFovScale.z * drawSize.y }));
}
}
public class PreDrawThings : IJobParallelFor
{
public Thing[] thingsToDraw = Array.Empty<Thing>();
public void Execute(int index) => thingsToDraw[index].DynamicDrawPhase(DrawPhase.ParallelPreDraw);
}
}
}
#endif