Skip to content

Commit 017ad84

Browse files
authored
Merge pull request #201 from ZehMatt/map-data-arrays
Replace some Lists that used Base() with raw arrays
2 parents b484657 + 1ec9986 commit 017ad84

18 files changed

Lines changed: 207 additions & 260 deletions

File tree

‎Game.Client/C_BaseAnimating.cs‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ public void Dispose() {
283283
Vector3 BonePosition;
284284
QAngle BoneAngles;
285285
Handle<C_BaseAnimating> AttachedTo = new();
286-
readonly List<Matrix3x4> CachedBoneData = [];
286+
Matrix3x4[] CachedBoneData = [];
287287

288288
public void InvalidateBoneCache() {
289289
MostRecentModelBoneCounter = ModelBoneCounter - 1;
@@ -533,7 +533,7 @@ public override bool SetupBones(Span<Matrix3x4> boneToWorldOut, int maxBones, in
533533
AccumulatedBoneMask = 0;
534534
}
535535

536-
int nBoneCount = CachedBoneData.Count;
536+
int nBoneCount = CachedBoneData.Length;
537537

538538
AccumulatedBoneMask |= boneMask;
539539

@@ -597,11 +597,11 @@ public override bool SetupBones(Span<Matrix3x4> boneToWorldOut, int maxBones, in
597597
}
598598

599599
if (!boneToWorldOut.IsEmpty) {
600-
if (maxBones >= CachedBoneData.Count) {
600+
if (maxBones >= CachedBoneData.Length) {
601601
memcpy(boneToWorldOut, CachedBoneData.AsSpan());
602602
}
603603
else {
604-
Warning($"SetupBones: invalid bone array size ({maxBones} - needs {CachedBoneData.Count})\n");
604+
Warning($"SetupBones: invalid bone array size ({maxBones} - needs {CachedBoneData.Length})\n");
605605
return false;
606606
}
607607
}
@@ -992,12 +992,12 @@ private static void RecvProxy_Sequence(ref readonly RecvProxyData data, object i
992992
Studio.DestroyBoneCache(HitboxBoneCacheHandle);
993993
HitboxBoneCacheHandle = 0;
994994

995-
if (CachedBoneData.Count != hdr.NumBones()) {
996-
CachedBoneData.SetSize(hdr.NumBones());
995+
if (CachedBoneData.Length != hdr.NumBones()) {
996+
CachedBoneData = new Matrix3x4[hdr.NumBones()];
997997
for (i = 0; i < hdr.NumBones(); i++)
998-
MathLib.SetIdentityMatrix(out CachedBoneData.AsSpan()[i]);
998+
MathLib.SetIdentityMatrix(out CachedBoneData[i]);
999999
}
1000-
BoneAccessor.Init(CachedBoneData.Base());
1000+
BoneAccessor.Init(CachedBoneData);
10011001

10021002
Ik = null;
10031003

‎Source.Common/BoneSetup.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@ public void CalcAutoplaySequences(Span<Vector3> pos, Span<Quaternion> q, TimeUni
15451545

15461546
ikContext?.AddAutoplayLocks(pos, q);
15471547

1548-
int count = studioHdr.GetAutoplayList(out Span<short> pList);
1548+
int count = studioHdr.GetAutoplayList(out ReadOnlySpan<short> pList);
15491549
for (int i = 0; i < count; i++) {
15501550
int sequenceIndex = pList[i];
15511551
MStudioSeqDesc seqdesc = studioHdr.Seqdesc(sequenceIndex);

‎Source.Common/DataCache/IMDLCache.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public interface IMDLCache
5151
VCollide? GetVCollide(MDLHandle_t handle);
5252
Memory<byte> GetAnimBlock(MDLHandle_t handle, int block);
5353
VirtualModel? GetVirtualModel(MDLHandle_t handle);
54-
Memory<short> GetAutoplayList(MDLHandle_t handle);
54+
ReadOnlySpan<short> GetAutoplayList(MDLHandle_t handle);
5555
VertexFileHeader? GetVertexData(MDLHandle_t handle);
5656

5757
void TouchAllData(MDLHandle_t handle);

‎Source.Common/Engine/IModelInfo.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public interface IVModelInfo
6161
byte ComputeViewScreenFade(in Vector3 absOrigin, float radius, float fadeScale);
6262

6363
// both client and server
64-
int GetAutoplayList(StudioHeader studioHdr, out Span<short> autoplayList);
64+
int GetAutoplayList(StudioHeader studioHdr, out ReadOnlySpan<short> autoplayList);
6565

6666
// Gets a terrain collision model (creates if necessary)
6767
// NOTE: This may return NULL if the terrain model cannot be ized

‎Source.Common/Exts.cs‎

Lines changed: 1 addition & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -650,51 +650,7 @@ public static class BitVecExts
650650
public static void Clear(this bool[] bools, int bit) => bools[bit] = false;
651651
}
652652
public static class ListExtensions
653-
{ // Thanks JamesHoux: https://stackoverflow.com/questions/4972951/listt-to-t-without-copying
654-
delegate ref TField RefAccessor<TObj, TField>(TObj obj);
655-
static class ArrayAccessor<T>
656-
{
657-
public static Func<List<T>, T[]> Getter;
658-
public static RefAccessor<List<T>, int> GetCount;
659-
660-
static ArrayAccessor() {
661-
var dm = new DynamicMethod("get", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(T[]), [typeof(List<T>)], typeof(ArrayAccessor<T>), true);
662-
var il = dm.GetILGenerator();
663-
il.Emit(OpCodes.Ldarg_0); // Load List<T> argument
664-
il.Emit(OpCodes.Ldfld, typeof(List<T>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance)!); // Replace argument by field
665-
il.Emit(OpCodes.Ret); // Return field
666-
Getter = (Func<List<T>, T[]>)dm.CreateDelegate(typeof(Func<List<T>, T[]>));
667-
668-
dm = new DynamicMethod("getSize", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(int).MakeByRefType(), [typeof(List<T>)], typeof(ArrayAccessor<T>), true);
669-
il = dm.GetILGenerator();
670-
il.Emit(OpCodes.Ldarg_0);
671-
il.Emit(OpCodes.Ldflda, typeof(List<T>).GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance)!);
672-
il.Emit(OpCodes.Ret);
673-
GetCount = (RefAccessor<List<T>, int>)dm.CreateDelegate(typeof(RefAccessor<List<T>, int>));
674-
}
675-
}
676-
677-
static class TempSwap<T>
678-
{
679-
public static readonly ThreadLocal<List<T>> List = new(() => []);
680-
}
681-
682-
public static void Swap<T>(this List<T> a, List<T> b) {
683-
var swap = TempSwap<T>.List.Value!;
684-
swap.Clear();
685-
swap.EnsureCapacity(a.Count);
686-
687-
a.Clear();
688-
a.EnsureCapacity(b.Count);
689-
b.Base().AsSpan()[..b.Count].CopyTo(a.Base());
690-
a.CountForEdit() = b.Count;
691-
692-
b.Clear();
693-
b.EnsureCapacity(swap.Count);
694-
swap.Base().AsSpan()[..swap.Count].CopyTo(b.Base());
695-
b.CountForEdit() = swap.Count;
696-
}
697-
653+
{
698654
public static nint Find<T>(this List<T> list, T? value) {
699655
for (int i = 0, c = list.Count; i < c; i++) {
700656
T? at = list[i];
@@ -710,14 +666,6 @@ public static nint Find<T>(this List<T> list, T? value) {
710666
}
711667
return -1;
712668
}
713-
714-
public static T[] Base<T>(this List<T> list) {
715-
return ArrayAccessor<T>.Getter(list);
716-
}
717-
718-
public static ref int CountForEdit<T>(this List<T> list) {
719-
return ref ArrayAccessor<T>.GetCount(list);
720-
}
721669
}
722670
public static class ClassUtils
723671
{

‎Source.Common/IStudioRender.cs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Source.Common.Engine;
33
using Source.Common.MaterialSystem;
44
using Source.Common.Mathematics;
5+
using Source.Common.Utilities;
56

67
using System.Numerics;
78

@@ -100,8 +101,8 @@ public interface IStudioRender {
100101
bool LoadModel(StudioHeader studioHDR, Memory<byte> vtxData, StudioHWData hardwareData);
101102
void UnloadModel(StudioHWData hardwareData);
102103

103-
int GetMaterialList(StudioHeader studioHDR, Span<IMaterial> materials);
104-
int GetMaterialListFromBodyAndSkin(MDLHandle_t studio, int skin, int body, Span<IMaterial> outputMaterials);
104+
void GetMaterialList(StudioHeader studioHDR, ref SpanList<IMaterial> materials);
105+
void GetMaterialListFromBodyAndSkin(MDLHandle_t studio, int skin, int body, ref SpanList<IMaterial> outputMaterials);
105106
Span<Matrix3x4> LockBoneMatrices(int boneCount);
106107
void UnlockBoneMatrices();
107108
void LockFlexWeights(int weightCount, out Span<float> flexWeights);

‎Source.Common/Studio.cs‎

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -343,14 +343,14 @@ public VirtualGroup AnimGroup(int animation) {
343343

344344
public readonly object Lock = new();
345345

346-
public readonly List<VirtualSequence> Seq = [];
347-
public readonly List<VirtualGeneric> Anim = [];
348-
public readonly List<VirtualGeneric> Attachment = [];
349-
public readonly List<VirtualGeneric> Pose = [];
346+
public List<VirtualSequence> Seq = [];
347+
public List<VirtualGeneric> Anim = [];
348+
public List<VirtualGeneric> Attachment = [];
349+
public List<VirtualGeneric> Pose = [];
350350
public readonly List<VirtualGroup> Group = [];
351-
public readonly List<VirtualGeneric> Node = [];
352-
public readonly List<VirtualGeneric> IKLock = [];
353-
public readonly List<short> AutoplaySequences = [];
351+
public List<VirtualGeneric> Node = [];
352+
public List<VirtualGeneric> IKLock = [];
353+
public short[] AutoplaySequences = [];
354354
}
355355

356356
public enum StudioMeshGroupFlags
@@ -2038,7 +2038,7 @@ public class StudioHdr
20382038
public Span<MStudioBone> Bones() => studioHdr.Bones();
20392039

20402040

2041-
readonly List<StudioHeader?> StudioHdrCache = [];
2041+
StudioHeader?[] StudioHdrCache = [];
20422042

20432043
public StudioHdrFlags Flags() => studioHdr!.Flags;
20442044
public AnonymousSafeFieldPointer<int> FrameUnlockCounterPtr;
@@ -2048,7 +2048,7 @@ public void Init(StudioHeader? studioHdr, IMDLCache mdlcache) {
20482048
this.studioHdr = studioHdr;
20492049

20502050
this.vModel = null;
2051-
StudioHdrCache.Clear();
2051+
StudioHdrCache = [];
20522052

20532053
if (this.studioHdr == null)
20542054
return;
@@ -2088,10 +2088,7 @@ public bool SequencesAvailable() {
20882088
private VirtualModel? ResetVModel(VirtualModel? virtualModel) {
20892089
if (virtualModel != null) {
20902090
vModel = virtualModel;
2091-
StudioHdrCache!.EnsureCountDefault(vModel.Group.Count());
2092-
2093-
for (int i = 0; i < StudioHdrCache.Count; i++)
2094-
StudioHdrCache[i] = null!;
2091+
StudioHdrCache = new StudioHeader?[vModel.Group.Count()];
20952092

20962093
return vModel;
20972094
}
@@ -2120,13 +2117,13 @@ public int RemapSeqBone(int sequence, int localBone) {
21202117
lock (FrameUnlockCounterMutex) {
21212118
if (FrameUnlockCounterPtr.Get() != FrameUnlockCounter) // i.e., this thread got the mutex
21222119
{
2123-
memcreset(StudioHdrCache.Base());
2120+
memcreset<StudioHeader>(StudioHdrCache);
21242121
FrameUnlockCounter = FrameUnlockCounterPtr.Get();
21252122
}
21262123
}
21272124
}
21282125

2129-
if (!StudioHdrCache.IsValidIndex(i)) {
2126+
if ((uint)i >= (uint)StudioHdrCache.Length) {
21302127
ReadOnlySpan<char> name = (this.studioHdr != null) ? this.studioHdr.GetName() : "<<null>>";
21312128
Debugger.Break();
21322129
return this.studioHdr; // return something known to probably exist, certainly things will be messed up, but hopefully not crash before the warning is noticed
@@ -2674,7 +2671,7 @@ internal int RelativeSeq(int baseseq, int relseq) {
26742671
return group.MasterSeq[relseq];
26752672
}
26762673

2677-
public int GetAutoplayList(out Span<short> pList) {
2674+
public int GetAutoplayList(out ReadOnlySpan<short> pList) {
26782675
return studioHdr!.GetAutoplayList(out pList);
26792676
}
26802677

@@ -3181,7 +3178,7 @@ public ref byte LocalTransition(int i) {
31813178
}
31823179

31833180

3184-
public int GetAutoplayList(out Span<short> pList) {
3181+
public int GetAutoplayList(out ReadOnlySpan<short> pList) {
31853182
return modelinfo.GetAutoplayList(this, out pList);
31863183
}
31873184

@@ -3221,18 +3218,6 @@ public int CountAutoplaySequences() {
32213218
return count;
32223219
}
32233220

3224-
public void CopyAutoplaySequences(ref Memory<short> autoplaySequenceList, int outCount) {
3225-
int outIndex = 0;
3226-
for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++) {
3227-
MStudioSeqDesc seqdesc = Seqdesc(i);
3228-
if ((seqdesc.Flags & StudioAnimSeqFlags.Autoplay) != 0) {
3229-
autoplaySequenceList.Span[outIndex] = (short)i;
3230-
outIndex++;
3231-
}
3232-
}
3233-
autoplaySequenceList = autoplaySequenceList[..outIndex];
3234-
}
3235-
32363221
public int CopyAutoplaySequences(Span<short> autoplaySequenceList, int outCount) {
32373222
int outIndex = 0;
32383223
for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++) {

‎Source.Common/StudioVirtualModel.cs‎

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,8 @@ public void Dispose() {
5656
private int LookupIndex;
5757
}
5858

59-
void BeginTemporaryCopyList<T>(List<T> source, out List<T> dest) {
60-
dest = ListPool<T>.Shared.Alloc();
61-
dest.Clear();
62-
dest.CountForEdit() = source.Count;
63-
source.AsSpan().CopyTo(dest.AsSpan());
64-
}
65-
void EndTemporaryCopyList<T>(List<T> source, List<T> dest) {
66-
source.Swap(dest);
67-
ListPool<T>.Shared.Free(dest);
68-
}
59+
void BeginTemporaryCopyList<T>(List<T> source, out List<T> dest) => dest = new List<T>(source);
60+
void EndTemporaryCopyList<T>(ref List<T> source, List<T> dest) => source = dest;
6961

7062
public void AppendSequences(int group, StudioHeader studioHdr) {
7163
lock (Lock) {
@@ -123,7 +115,7 @@ public void AppendSequences(int group, StudioHeader studioHdr) {
123115
GetSeqTable()[s1.Hash(invariant: false)] = (short)j;
124116
}
125117
}
126-
EndTemporaryCopyList(Seq, seq);
118+
EndTemporaryCopyList(ref Seq, seq);
127119
}
128120
}
129121
}
@@ -171,7 +163,7 @@ public void AppendAnimations(int group, StudioHeader studioHdr) {
171163
}
172164
}
173165

174-
EndTemporaryCopyList(Anim, anim);
166+
EndTemporaryCopyList(ref Anim, anim);
175167
}
176168
}
177169
}
@@ -224,7 +216,7 @@ public void AppendAttachments(int group, StudioHeader studioHdr) {
224216
Group[group].MasterAttachment[j] = k;
225217
}
226218

227-
EndTemporaryCopyList(Attachment, attachment);
219+
EndTemporaryCopyList(ref Attachment, attachment);
228220
}
229221
}
230222
public void AppendPoseParameters(int group, StudioHeader studioHdr) {
@@ -264,7 +256,7 @@ public void AppendPoseParameters(int group, StudioHeader studioHdr) {
264256
Group[group].MasterPose[j] = k;
265257
}
266258

267-
EndTemporaryCopyList(Pose, pose);
259+
EndTemporaryCopyList(ref Pose, pose);
268260
}
269261
}
270262
public void AppendBonemap(int group, StudioHeader studioHdr) {
@@ -339,7 +331,7 @@ public void AppendNodes(int group, StudioHeader studioHdr) {
339331
Group[group].MasterNode[j] = k;
340332
}
341333

342-
EndTemporaryCopyList(Node, node);
334+
EndTemporaryCopyList(ref Node, node);
343335
}
344336
}
345337

@@ -367,7 +359,7 @@ public void AppendIKLocks(int group, StudioHeader studioHDR) {
367359
}
368360
}
369361

370-
EndTemporaryCopyList(IKLock, iklock);
362+
EndTemporaryCopyList(ref IKLock, iklock);
371363
}
372364
}
373365

@@ -426,7 +418,8 @@ public void AppendModels(int group, StudioHeader studioHdr) {
426418
}
427419
public void UpdateAutoplaySequences(StudioHeader studioHdr) {
428420
int autoplayCount = studioHdr.CountAutoplaySequences();
429-
AutoplaySequences.SetCount(autoplayCount);
430-
studioHdr.CopyAutoplaySequences(AutoplaySequences.Base().AsSpan(), autoplayCount);
421+
if (AutoplaySequences.Length != autoplayCount)
422+
AutoplaySequences = new short[autoplayCount];
423+
studioHdr.CopyAutoplaySequences(AutoplaySequences, autoplayCount);
431424
}
432425
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace Source.Common.Utilities;
2+
3+
/// <summary>
4+
/// <see cref="List{T}"/> style of operations on fixed/pre-allocated arrays.
5+
/// </summary>
6+
public ref struct SpanList<T>(Span<T> items)
7+
{
8+
readonly Span<T> Items = items;
9+
int Used;
10+
11+
public readonly int Count => Used;
12+
public readonly int Capacity => Items.Length;
13+
14+
public readonly ref T this[int index] => ref Items[..Used][index];
15+
16+
public void Add(in T value) => Items[Used++] = value;
17+
18+
public void RemoveAt(int index) {
19+
Items[(index + 1)..Used].CopyTo(Items[index..]);
20+
Used--;
21+
}
22+
23+
public void Clear() => Used = 0;
24+
25+
public readonly Span<T> AsSpan() => Items[..Used];
26+
}

0 commit comments

Comments
 (0)