Skip to content

Commit 452c789

Browse files
authored
Merge pull request #208 from ZehMatt/gc-optimizations
Eliminate some allocations per frame/tick
2 parents 377cf62 + b630fa5 commit 452c789

21 files changed

Lines changed: 294 additions & 245 deletions

‎Game.Client/GarrysMod/LuaCam.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static int Start(ILuaInterface lua) {
4242

4343
if (data.GetMemberStr("type", "3D")!.StartsWith('2')) {
4444
using MatRenderContextPtr renderContext = new(materials);
45-
ClientModeShared.SetupVGuiMatrices(true, renderContext);
45+
ClientModeShared.SetupVGuiMatrices(true, renderContext.Context);
4646
((ClientModeShared)clientMode).SetupGModSurface(true);
4747
renderContext.OverrideAlphaWriteEnable(true, true);
4848
Start2DCount++;
@@ -140,7 +140,7 @@ static int End2D(ILuaInterface lua) {
140140
using MatRenderContextPtr renderContext = new(materials);
141141
renderContext.OverrideAlphaWriteEnable(false, false);
142142
((ClientModeShared)clientMode).SetupGModSurface(false);
143-
ClientModeShared.SetupVGuiMatrices(false, renderContext);
143+
ClientModeShared.SetupVGuiMatrices(false, renderContext.Context);
144144
return 0;
145145
}
146146

‎Game.Client/GarrysMod/SpawnIcon.cs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,15 +333,15 @@ void Render() {
333333

334334
renderContext.ClearColor4ub(255, 0, 0, 0);
335335
renderContext.ClearBuffers(true, true);
336-
RenderPass(red, ent, renderContext, viewSetup.Width, viewSetup.Height);
336+
RenderPass(red, ent, renderContext.Context, viewSetup.Width, viewSetup.Height);
337337

338338
renderContext.ClearColor4ub(0, 255, 0, 0);
339339
renderContext.ClearBuffers(true, true);
340-
RenderPass(green, ent, renderContext, viewSetup.Width, viewSetup.Height);
340+
RenderPass(green, ent, renderContext.Context, viewSetup.Width, viewSetup.Height);
341341

342342
renderContext.ClearColor4ub(0, 0, 255, 0);
343343
renderContext.ClearBuffers(true, true);
344-
RenderPass(blue, ent, renderContext, viewSetup.Width, viewSetup.Height);
344+
RenderPass(blue, ent, renderContext.Context, viewSetup.Width, viewSetup.Height);
345345

346346
CombinePasses(red, green, blue, viewSetup.Width, viewSetup.Height);
347347

‎Game.Client/HLClient.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ public void HudUpdate(bool active) {
503503

504504
gHUD.UpdateHud(active);
505505

506-
BaseAnimating.AutoAllowBoneAccess boneAccess = new(true, true);
506+
using BaseAnimating.AutoAllowBoneAccess boneAccess = new(true, true);
507507
IGameSystem.UpdateAllSystems(frameTime);
508508

509509
vgui!.GetAnimationController().UpdateAnimations(gpGlobals.CurTime);

‎Game.Client/View.cs‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -418,10 +418,11 @@ public void RenderView(in ViewSetup viewRender, ClearFlags clearFlags, RenderVie
418418
SkyboxVisibility skyboxVisible = SkyboxVisibility.NotVisible;
419419

420420
{
421-
SkyboxView skyView = new SkyboxView(this);
421+
SkyboxView skyView = FreeSkyboxViews.Count > 0 ? FreeSkyboxViews.Pop() : new SkyboxView(this);
422422
if ((drew3dSkybox = skyView.Setup(in viewRender, ref clearFlags, ref skyboxVisible)) != false)
423423
AddViewToScene(skyView);
424424
skyView.ReleaseLists();
425+
FreeSkyboxViews.Push(skyView);
425426
}
426427

427428
if ((clearFlags & ClearFlags.ClearColor) == 0) {
@@ -515,7 +516,7 @@ public void RenderView(in ViewSetup viewRender, ClearFlags clearFlags, RenderVie
515516
// VGui_PostRender();
516517
using (renderContext = new MatRenderContextPtr(materials)) {
517518
#if GMOD_DLL
518-
((ClientModeShared)clientMode).PostRenderVGui(renderContext);
519+
((ClientModeShared)clientMode).PostRenderVGui(renderContext.Context);
519520
#endif
520521
if (pTexture != null) {
521522
// renderContext.OverrideAlphaWriteEnable(false, true);
@@ -743,30 +744,38 @@ private void DrawWorldAndEntities(bool drawSkybox, in ViewSetup viewIn, ClearFla
743744
DetermineWaterRenderInfo(in fogVolumeInfo, out WaterRenderInfo info);
744745

745746
if (info.CheapWater) {
746-
SimpleWorldView noWaterView = new SimpleWorldView(this);
747+
SimpleWorldView noWaterView = FreeSimpleWorldViews.Count > 0 ? FreeSimpleWorldViews.Pop() : new SimpleWorldView(this);
747748
noWaterView.Setup(in viewIn, clearFlags, drawSkybox, in fogVolumeInfo, in info);
748749
AddViewToScene(noWaterView);
749750
noWaterView.ReleaseLists();
751+
FreeSimpleWorldViews.Push(noWaterView);
750752
return;
751753
}
752754

753755
if (!r_ForceWaterLeaf.GetBool())
754756
fogVolumeInfo.VisibleFogVolumeLeaf = -1;
755757

756758
if (!fogVolumeInfo.EyeInFogVolume) {
757-
AboveWaterView aboveWaterView = new AboveWaterView(this);
759+
AboveWaterView aboveWaterView = FreeAboveWaterViews.Count > 0 ? FreeAboveWaterViews.Pop() : new AboveWaterView(this);
758760
aboveWaterView.Setup(in viewIn, drawSkybox, in fogVolumeInfo, in info);
759761
AddViewToScene(aboveWaterView);
760762
aboveWaterView.ReleaseLists();
763+
FreeAboveWaterViews.Push(aboveWaterView);
761764
}
762765
else {
763-
UnderWaterView underWaterView = new UnderWaterView(this);
766+
UnderWaterView underWaterView = FreeUnderWaterViews.Count > 0 ? FreeUnderWaterViews.Pop() : new UnderWaterView(this);
764767
underWaterView.Setup(in viewIn, drawSkybox, in fogVolumeInfo, in info);
765768
AddViewToScene(underWaterView);
766769
underWaterView.ReleaseLists();
770+
FreeUnderWaterViews.Push(underWaterView);
767771
}
768772
}
769773

774+
readonly Stack<SkyboxView> FreeSkyboxViews = [];
775+
readonly Stack<SimpleWorldView> FreeSimpleWorldViews = [];
776+
readonly Stack<AboveWaterView> FreeAboveWaterViews = [];
777+
readonly Stack<UnderWaterView> FreeUnderWaterViews = [];
778+
770779
public static bool DoesViewPlaneIntersectWater(float waterZ, int leafWaterDataID) {
771780
if (leafWaterDataID == -1)
772781
return false;

‎Game.Client/ViewBeams.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,7 @@ private void DrawSegs(int noise_divisions, ReadOnlySpan<float> noise, Model spri
875875
// Specify all the segments.
876876
using MatRenderContextPtr renderContext = new(materials);
877877
BeamSegDraw segDraw = new();
878-
segDraw.Start(renderContext, segments, null);
878+
segDraw.Start(renderContext.Context, segments, null);
879879

880880
for (i = 0; i < segments; i++) {
881881
Assert(noiseIndex < (noise_divisions << 16));

‎Game.Client/ViewRender.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ public virtual void ReleaseLists() {
794794
WorldRenderList?.Release();
795795
WorldRenderList = null;
796796
ClientRenderablesList.Shared.Free(RenderablesList);
797+
RenderablesList = null!;
797798
}
798799
public override DrawFlags GetDrawFlags() {
799800
return DrawFlags;

‎Game.Server/Player.cs‎

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Diagnostics;
1919
using System.Numerics;
2020
using System.Runtime.CompilerServices;
21+
using System.Runtime.InteropServices;
2122

2223
namespace Game.Server;
2324

@@ -426,6 +427,7 @@ public void SetPhysicsFlag(PlayerPhysFlag flag, bool set) {
426427
public TimeUnit_t LerpTime;
427428
public bool LagCompensation;
428429
public bool PredictWeapons;
430+
readonly List<UserCmd> AvailableCommandsBuf = [];
429431

430432
public static void SendProxy_CropFlagsToPlayerFlagBitsLength(SendProp prop, object instance, IFieldAccessor field, ref DVariant outData, int element, int objectID) {
431433
int mask = (1 << Constants.PLAYER_FLAG_BITS) - 1;
@@ -943,7 +945,7 @@ public virtual void ImpulseCommands() {
943945
}
944946

945947
if (tr.Fraction != 1.0) { // line hit something, so paint a decal
946-
// todo
948+
// todo
947949
}
948950

949951
break;
@@ -1219,7 +1221,7 @@ CommandContext RemoveAllCommandContextsExceptNewest() {
12191221

12201222
void RemoveAllCommandContexts() => CommandContext.Clear();
12211223

1222-
void ReplaceContextCommands(CommandContext ctx, UserCmd[] cmds, int commands) {
1224+
void ReplaceContextCommands(CommandContext ctx, ReadOnlySpan<UserCmd> cmds, int commands) {
12231225
ctx.Cmds.Clear();
12241226

12251227
ctx.NumCmds = commands;
@@ -1386,7 +1388,7 @@ public override void PhysicsSimulate() {
13861388

13871389
int command_context_count = GetCommandContextCount();
13881390

1389-
List<UserCmd> vecAvailCommands = [];
1391+
AvailableCommandsBuf.Clear();
13901392

13911393
for (int context_number = 0; context_number < command_context_count; context_number++) {
13921394
CommandContext ctx = GetCommandContext(context_number);
@@ -1404,32 +1406,32 @@ public override void PhysicsSimulate() {
14041406
while (droppedcmds > numbackup) {
14051407
UserCmd lastCmd = GetLastUserCommand();
14061408
lastCmd.CommandNumber++;
1407-
vecAvailCommands.Add(lastCmd);
1409+
AvailableCommandsBuf.Add(lastCmd);
14081410
droppedcmds--;
14091411
}
14101412

14111413
while (droppedcmds > 0) {
14121414
int cmdnum = ctx.NumCmds + droppedcmds - 1;
1413-
vecAvailCommands.Add(ctx.Cmds[cmdnum]);
1415+
AvailableCommandsBuf.Add(ctx.Cmds[cmdnum]);
14141416
droppedcmds--;
14151417
}
14161418
}
14171419

14181420
for (int i = ctx.NumCmds - 1; i >= 0; i--)
1419-
vecAvailCommands.Add(ctx.Cmds[i]);
1421+
AvailableCommandsBuf.Add(ctx.Cmds[i]);
14201422

14211423
LastCmd = ctx.Cmds[ctx.Cmds.Count - 1];
14221424
}
14231425

14241426
int commandLimit = IsSimulatingOnAlternateTicks() ? 2 : 1;
1425-
int commandsToRun = vecAvailCommands.Count;
1426-
if (gpGlobals.SimTicksThisFrame >= commandLimit && vecAvailCommands.Count > commandLimit) {
1427-
int commandsToRollOver = Math.Min(vecAvailCommands.Count, (gpGlobals.SimTicksThisFrame - 1));
1428-
commandsToRun = vecAvailCommands.Count - commandsToRollOver;
1427+
int commandsToRun = AvailableCommandsBuf.Count;
1428+
if (gpGlobals.SimTicksThisFrame >= commandLimit && AvailableCommandsBuf.Count > commandLimit) {
1429+
int commandsToRollOver = Math.Min(AvailableCommandsBuf.Count, (gpGlobals.SimTicksThisFrame - 1));
1430+
commandsToRun = AvailableCommandsBuf.Count - commandsToRollOver;
14291431
Assert(commandsToRun >= 0);
14301432
if (commandsToRollOver > 0) {
14311433
CommandContext ctx = RemoveAllCommandContextsExceptNewest();
1432-
ReplaceContextCommands(ctx, [.. vecAvailCommands.GetRange(vecAvailCommands.Count - commandsToRollOver, commandsToRollOver)], commandsToRollOver);
1434+
ReplaceContextCommands(ctx, CollectionsMarshal.AsSpan(AvailableCommandsBuf).Slice(AvailableCommandsBuf.Count - commandsToRollOver, commandsToRollOver), commandsToRollOver);
14331435
}
14341436
else
14351437
RemoveAllCommandContexts();
@@ -1458,7 +1460,7 @@ public override void PhysicsSimulate() {
14581460
IPredictionSystem.SuppressHostEvents(this);
14591461

14601462
for (int i = 0; i < commandsToRun; ++i) {
1461-
PlayerRunCommand(vecAvailCommands[i], MoveHelperServer.s_MoveHelperServer);
1463+
PlayerRunCommand(AvailableCommandsBuf[i], MoveHelperServer.s_MoveHelperServer);
14621464

14631465
if (PhysicsController != null) {
14641466
UpdateVPhysicsPosition(NewVPhysicsPosition, NewVPhysicsVelocity, (float)vphysicsArrivalTime);

‎Source.Common/MaterialSystem/IMaterialSystem.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ void DrawScreenSpaceRectangle(
12861286
#endif
12871287
}
12881288

1289-
public readonly struct MatRenderContextPtr : IDisposable, IMatRenderContext
1289+
public readonly ref struct MatRenderContextPtr : IDisposable
12901290
{
12911291
public readonly IMatRenderContext Context;
12921292

‎Source.Engine/DtLocalTransfer.cs‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ public static class LocalTransfer
3131
"(SP only) - show entities that were copied using small optimized lists (FL_EDICT_PARTIAL_CHANGE)."
3232
);
3333

34+
static ServerDatatableStack? s_ServerStack;
35+
static ClientDatatableStack? s_ClientStack;
36+
3437
public static void TransferEntity(BaseEdict edict, SendTable sendTable, object srcEnt, RecvTable recvTable, object destEnt, bool newlyCreated, bool justEnteredPVS, int objectID) {
3538
TotalEntChanges++;
3639
EdictChangeInfo changeInfo = g_SharedChangeInfo!.ChangeInfos[edict.GetChangeInfo()];
@@ -49,14 +52,18 @@ public static void TransferEntity(BaseEdict edict, SendTable sendTable, object s
4952
FastSortList(propIndices, changeOffsets);
5053

5154
// Setup the structure to traverse the source tree.
52-
ErrorIfNot(precalc != null, ($"SendTable_Encode: Missing precalc for SendTable {sendTable.NetTableName}."));
53-
ServerDatatableStack serverStack = new(precalc, srcEnt, objectID);
55+
if (precalc == null)
56+
Error($"SendTable_Encode: Missing precalc for SendTable {sendTable.NetTableName}.");
57+
ServerDatatableStack serverStack = s_ServerStack ??= new(precalc, srcEnt, objectID);
58+
serverStack.Reset(precalc, srcEnt, objectID);
5459
serverStack.Init(true);
5560

5661
// Setup the structure to traverse the dest tree.
5762
RecvDecoder? decoder = recvTable.Decoder;
58-
ErrorIfNot(decoder != null, ($"RecvTable_Decode: table '{recvTable.GetName()}' missing a decoder."));
59-
ClientDatatableStack clientStack = new(decoder, destEnt, objectID);
63+
if (decoder == null)
64+
Error($"RecvTable_Decode: table '{recvTable.GetName()}' missing a decoder.");
65+
ClientDatatableStack clientStack = s_ClientStack ??= new(decoder, destEnt, objectID);
66+
clientStack.Reset(decoder, destEnt, objectID);
6067
clientStack.Init(true);
6168

6269
// Cool. We can get away with just transferring a few.
@@ -86,14 +93,18 @@ public static void TransferEntity(BaseEdict edict, SendTable sendTable, object s
8693
else {
8794
// Setup the structure to traverse the source tree.
8895
SendTablePrecalc precalc = sendTable.Precalc!;
89-
ErrorIfNot(precalc != null, ($"SendTable_Encode: Missing precalc for SendTable {sendTable.NetTableName}."));
90-
ServerDatatableStack serverStack = new(precalc, srcEnt, objectID);
96+
if (precalc == null)
97+
Error($"SendTable_Encode: Missing precalc for SendTable {sendTable.NetTableName}.");
98+
ServerDatatableStack serverStack = s_ServerStack ??= new(precalc, srcEnt, objectID);
99+
serverStack.Reset(precalc, srcEnt, objectID);
91100
serverStack.Init();
92101

93102
// Setup the structure to traverse the dest tree.
94103
RecvDecoder? decoder = recvTable.Decoder;
95-
ErrorIfNot(decoder != null, ($"RecvTable_Decode: table '{recvTable.GetName()}' missing a decoder."));
96-
ClientDatatableStack clientStack = new(decoder, destEnt, objectID);
104+
if (decoder == null)
105+
Error($"RecvTable_Decode: table '{recvTable.GetName()}' missing a decoder.");
106+
ClientDatatableStack clientStack = s_ClientStack ??= new(decoder, destEnt, objectID);
107+
clientStack.Reset(decoder, destEnt, objectID);
97108
clientStack.Init();
98109

99110
AddToPartialChangeEntsList(Array.IndexOf(sv.Edicts, edict), false);

‎Source.Engine/EngineRecvTable.cs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ public DatatableStack(SendTablePrecalc precalc, object instance, int objectID) {
133133
ObjectID = objectID;
134134
}
135135

136+
public void Reset(SendTablePrecalc precalc, object instance, int objectID) {
137+
Precalc = precalc;
138+
Instance = instance;
139+
ObjectID = objectID;
140+
CurPropIndex = 0;
141+
CurProp = null;
142+
Initted = false;
143+
}
144+
136145
protected static readonly object Uncomputed = new();
137146

138147
public void Init(bool explicitRoutes = false) {
@@ -227,12 +236,17 @@ public int GetObjectID() {
227236

228237
public class ClientDatatableStack : DatatableStack
229238
{
230-
readonly RecvDecoder Decoder;
239+
RecvDecoder Decoder;
231240

232241
public ClientDatatableStack(RecvDecoder decoder, object instance, int objectID) : base(decoder.Precalc, instance, objectID) {
233242
Decoder = decoder;
234243
}
235244

245+
public void Reset(RecvDecoder decoder, object instance, int objectID) {
246+
Decoder = decoder;
247+
Reset(decoder.Precalc, instance, objectID);
248+
}
249+
236250
public override void RecurseAndCallProxies(SendNode node, object? instance) {
237251
Proxies[node.GetRecursiveProxyIndex()] = instance;
238252

0 commit comments

Comments
 (0)