Reduce and pad IMC allocations and log allocations.

This commit is contained in:
Ottermandias 2025-01-20 17:14:13 +01:00
parent 8779f4b689
commit 0c8571fba9
6 changed files with 29 additions and 14 deletions

@ -1 +1 @@
Subproject commit 5bac66e5ad73e57919aff7f8b046606b75e191a2
Subproject commit ebeea67c17f6bf4ce7e635041b2138e835d31262

View file

@ -51,7 +51,6 @@ public sealed class ImcCache(MetaFileManager manager, ModCollection collection)
if (!_imcFiles.TryGetValue(path, out var pair))
pair = (new ImcFile(Manager, identifier), []);
if (!Apply(pair.Item1, identifier, entry))
return;

View file

@ -10,9 +10,9 @@ public struct ModCollectionIdentity(Guid id, LocalCollectionId localId)
public static readonly ModCollectionIdentity Empty = new(Guid.Empty, LocalCollectionId.Zero, EmptyCollectionName, 0);
public string Name { get; set; }
public Guid Id { get; } = id;
public LocalCollectionId LocalId { get; } = localId;
public string Name { get; set; } = string.Empty;
public Guid Id { get; } = id;
public LocalCollectionId LocalId { get; } = localId;
/// <summary> The index of the collection is set and kept up-to-date by the CollectionManager. </summary>
public int Index { get; internal set; }

View file

@ -11,8 +11,8 @@ public class GameState : IService
{
#region Last Game Object
private readonly ThreadLocal<Queue<nint>> _lastGameObject = new(() => new Queue<nint>());
public readonly ThreadLocal<bool> CharacterAssociated = new(() => false);
private readonly ThreadLocal<Queue<nint>> _lastGameObject = new(() => new Queue<nint>());
public readonly ThreadLocal<bool> CharacterAssociated = new(() => false);
public nint LastGameObject
=> _lastGameObject.IsValueCreated && _lastGameObject.Value!.Count > 0 ? _lastGameObject.Value.Peek() : nint.Zero;

View file

@ -1,3 +1,4 @@
using Penumbra.GameData;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.Structs;
@ -192,22 +193,26 @@ public unsafe class ImcFile : MetaBaseFile
public void Replace(ResourceHandle* resource)
{
var (data, length) = resource->GetData();
if (length == ActualLength)
var actualLength = ActualLength;
if (length >= actualLength)
{
MemoryUtility.MemCpyUnchecked((byte*)data, Data, ActualLength);
MemoryUtility.MemCpyUnchecked((byte*)data, Data, actualLength);
MemoryUtility.MemSet((byte*)data + actualLength, 0, length - actualLength);
return;
}
var newData = Manager.XivAllocator.Allocate(ActualLength, 8);
var paddedLength = actualLength.PadToMultiple(128);
var newData = Manager.XivAllocator.Allocate(paddedLength, 8);
if (newData == null)
{
Penumbra.Log.Error($"Could not replace loaded IMC data at 0x{(ulong)resource:X}, allocation failed.");
return;
}
MemoryUtility.MemCpyUnchecked(newData, Data, ActualLength);
MemoryUtility.MemCpyUnchecked(newData, Data, actualLength);
MemoryUtility.MemSet((byte*)data + actualLength, 0, paddedLength - actualLength);
Manager.XivAllocator.Release((void*)data, length);
resource->SetData((nint)newData, ActualLength);
resource->SetData((nint)newData, paddedLength);
}
}

View file

@ -28,11 +28,16 @@ public unsafe interface IFileAllocator
public sealed class MarshalAllocator : IFileAllocator
{
public unsafe T* Allocate<T>(int length, int alignment = 1) where T : unmanaged
=> (T*)Marshal.AllocHGlobal(length * sizeof(T));
{
var ret = (T*)Marshal.AllocHGlobal(length * sizeof(T));
Penumbra.Log.Verbose($"Allocating {length * sizeof(T)} bytes via Marshal Allocator to 0x{(nint)ret:X}.");
return ret;
}
public unsafe void Release<T>(ref T* pointer, int length) where T : unmanaged
{
Marshal.FreeHGlobal((nint)pointer);
Penumbra.Log.Verbose($"Freeing {length * sizeof(T)} bytes from 0x{(nint)pointer:X} via Marshal Allocator.");
pointer = null;
}
}
@ -53,11 +58,17 @@ public sealed unsafe class XivFileAllocator : IFileAllocator, IService
=> ((delegate* unmanaged<IMemorySpace*>)_getFileSpaceAddress)();
public T* Allocate<T>(int length, int alignment = 1) where T : unmanaged
=> (T*)GetFileSpace()->Malloc((ulong)(length * sizeof(T)), (ulong)alignment);
{
var ret = (T*)GetFileSpace()->Malloc((ulong)(length * sizeof(T)), (ulong)alignment);
Penumbra.Log.Verbose($"Allocating {length * sizeof(T)} bytes via FFXIV File Allocator to 0x{(nint)ret:X}.");
return ret;
}
public void Release<T>(ref T* pointer, int length) where T : unmanaged
{
IMemorySpace.Free(pointer, (ulong)(length * sizeof(T)));
Penumbra.Log.Verbose($"Freeing {length * sizeof(T)} bytes from 0x{(nint)pointer:X} via FFXIV File Allocator.");
pointer = null;
}
}