Add mechanism to handle completion of async res loads

This commit is contained in:
Exter-N 2025-01-24 02:50:02 +01:00
parent dcab443b2f
commit a3ddce0ef5
11 changed files with 303 additions and 58 deletions

View file

@ -10,10 +10,11 @@ namespace Penumbra.UI.ResourceWatcher;
[Flags]
public enum RecordType : byte
{
Request = 0x01,
ResourceLoad = 0x02,
FileLoad = 0x04,
Destruction = 0x08,
Request = 0x01,
ResourceLoad = 0x02,
FileLoad = 0x04,
Destruction = 0x08,
ResourceComplete = 0x10,
}
internal unsafe struct Record
@ -141,4 +142,24 @@ internal unsafe struct Record
LoadState = handle->LoadState,
Crc64 = 0,
};
public static Record CreateResourceComplete(CiByteString path, ResourceHandle* handle, Utf8GamePath originalPath)
=> new()
{
Time = DateTime.UtcNow,
Path = path.IsOwned ? path : path.Clone(),
OriginalPath = originalPath.Path.IsOwned ? originalPath.Path : originalPath.Path.Clone(),
Collection = null,
Handle = handle,
ResourceType = handle->FileType.ToFlag(),
Category = handle->Category.ToFlag(),
RefCount = handle->RefCount,
RecordType = RecordType.ResourceComplete,
Synchronously = false,
ReturnValue = OptionalBool.Null,
CustomLoad = OptionalBool.Null,
AssociatedGameObject = string.Empty,
LoadState = handle->LoadState,
Crc64 = 0,
};
}

View file

@ -47,9 +47,10 @@ public sealed class ResourceWatcher : IDisposable, ITab, IUiService
_table = new ResourceWatcherTable(config.Ephemeral, _records);
_resources.ResourceRequested += OnResourceRequested;
_destructor.Subscribe(OnResourceDestroyed, ResourceHandleDestructor.Priority.ResourceWatcher);
_loader.ResourceLoaded += OnResourceLoaded;
_loader.FileLoaded += OnFileLoaded;
_loader.PapRequested += OnPapRequested;
_loader.ResourceLoaded += OnResourceLoaded;
_loader.ResourceComplete += OnResourceComplete;
_loader.FileLoaded += OnFileLoaded;
_loader.PapRequested += OnPapRequested;
UpdateFilter(_ephemeral.ResourceLoggingFilter, false);
_newMaxEntries = _config.MaxResourceWatcherRecords;
}
@ -73,9 +74,10 @@ public sealed class ResourceWatcher : IDisposable, ITab, IUiService
_records.TrimExcess();
_resources.ResourceRequested -= OnResourceRequested;
_destructor.Unsubscribe(OnResourceDestroyed);
_loader.ResourceLoaded -= OnResourceLoaded;
_loader.FileLoaded -= OnFileLoaded;
_loader.PapRequested -= OnPapRequested;
_loader.ResourceLoaded -= OnResourceLoaded;
_loader.ResourceComplete -= OnResourceComplete;
_loader.FileLoaded -= OnFileLoaded;
_loader.PapRequested -= OnPapRequested;
}
private void Clear()
@ -255,6 +257,23 @@ public sealed class ResourceWatcher : IDisposable, ITab, IUiService
_newRecords.Enqueue(record);
}
private unsafe void OnResourceComplete(ResourceHandle* resource, CiByteString path, Utf8GamePath original, ReadOnlySpan<byte> _, bool isAsync)
{
if (!isAsync)
return;
if (_ephemeral.EnableResourceLogging && FilterMatch(path, out var match))
Penumbra.Log.Information(
$"[ResourceLoader] [DONE] [{resource->FileType}] Finished loading {match} into 0x{(ulong)resource:X}, state {resource->LoadState}.");
if (!_ephemeral.EnableResourceWatcher)
return;
var record = Record.CreateResourceComplete(path, resource, original);
if (!_ephemeral.OnlyAddMatchingResources || _table.WouldBeVisible(record))
_newRecords.Enqueue(record);
}
private unsafe void OnFileLoaded(ResourceHandle* resource, CiByteString path, bool success, bool custom, ReadOnlySpan<byte> _)
{
if (_ephemeral.EnableResourceLogging && FilterMatch(path, out var match))

View file

@ -124,11 +124,12 @@ internal sealed class ResourceWatcherTable : Table<Record>
{
ImGui.TextUnformatted(item.RecordType switch
{
RecordType.Request => "REQ",
RecordType.ResourceLoad => "LOAD",
RecordType.FileLoad => "FILE",
RecordType.Destruction => "DEST",
_ => string.Empty,
RecordType.Request => "REQ",
RecordType.ResourceLoad => "LOAD",
RecordType.FileLoad => "FILE",
RecordType.Destruction => "DEST",
RecordType.ResourceComplete => "DONE",
_ => string.Empty,
});
}
}
@ -317,10 +318,10 @@ internal sealed class ResourceWatcherTable : Table<Record>
{
LoadState.None => FilterValue.HasFlag(LoadStateFlag.None),
LoadState.Success => FilterValue.HasFlag(LoadStateFlag.Success),
LoadState.Async => FilterValue.HasFlag(LoadStateFlag.Async),
LoadState.Failure => FilterValue.HasFlag(LoadStateFlag.Failed),
LoadState.FailedSubResource => FilterValue.HasFlag(LoadStateFlag.FailedSub),
_ => FilterValue.HasFlag(LoadStateFlag.Unknown),
<= LoadState.Constructed => FilterValue.HasFlag(LoadStateFlag.Unknown),
< LoadState.Success => FilterValue.HasFlag(LoadStateFlag.Async),
> LoadState.Success => FilterValue.HasFlag(LoadStateFlag.Failed),
};
public override void DrawColumn(Record item, int _)
@ -332,12 +333,12 @@ internal sealed class ResourceWatcherTable : Table<Record>
{
LoadState.Success => (FontAwesomeIcon.CheckCircle, ColorId.IncreasedMetaValue.Value(),
$"Successfully loaded ({(byte)item.LoadState})."),
LoadState.Async => (FontAwesomeIcon.Clock, ColorId.FolderLine.Value(), $"Loading asynchronously ({(byte)item.LoadState})."),
LoadState.Failure => (FontAwesomeIcon.Times, ColorId.DecreasedMetaValue.Value(),
$"Failed to load ({(byte)item.LoadState})."),
LoadState.FailedSubResource => (FontAwesomeIcon.ExclamationCircle, ColorId.DecreasedMetaValue.Value(),
$"Dependencies failed to load ({(byte)item.LoadState})."),
_ => (FontAwesomeIcon.QuestionCircle, ColorId.UndefinedMod.Value(), $"Unknown state ({(byte)item.LoadState})."),
<= LoadState.Constructed => (FontAwesomeIcon.QuestionCircle, ColorId.UndefinedMod.Value(), $"Not yet loaded ({(byte)item.LoadState})."),
< LoadState.Success => (FontAwesomeIcon.Clock, ColorId.FolderLine.Value(), $"Loading asynchronously ({(byte)item.LoadState})."),
> LoadState.Success => (FontAwesomeIcon.Times, ColorId.DecreasedMetaValue.Value(),
$"Failed to load ({(byte)item.LoadState})."),
};
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
{