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))
{

View file

@ -80,6 +80,7 @@ public class DebugTab : Window, ITab, IUiService
private readonly StainService _stains;
private readonly GlobalVariablesDrawer _globalVariablesDrawer;
private readonly ResourceManagerService _resourceManager;
private readonly ResourceLoader _resourceLoader;
private readonly CollectionResolver _collectionResolver;
private readonly DrawObjectState _drawObjectState;
private readonly PathState _pathState;
@ -109,7 +110,7 @@ public class DebugTab : Window, ITab, IUiService
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
IClientState clientState, IDataManager dataManager,
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorManager actors, StainService stains,
ResourceManagerService resourceManager, CollectionResolver collectionResolver,
ResourceManagerService resourceManager, ResourceLoader resourceLoader, CollectionResolver collectionResolver,
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
TextureManager textureManager, ShaderReplacementFixer shaderReplacementFixer, RedrawService redraws, DictEmote emotes,
@ -133,6 +134,7 @@ public class DebugTab : Window, ITab, IUiService
_actors = actors;
_stains = stains;
_resourceManager = resourceManager;
_resourceLoader = resourceLoader;
_collectionResolver = collectionResolver;
_drawObjectState = drawObjectState;
_pathState = pathState;
@ -191,6 +193,7 @@ public class DebugTab : Window, ITab, IUiService
DrawShaderReplacementFixer();
DrawData();
DrawCrcCache();
DrawResourceLoader();
DrawResourceProblems();
_renderTargetDrawer.Draw();
_hookOverrides.Draw();
@ -1099,6 +1102,38 @@ public class DebugTab : Window, ITab, IUiService
}
}
private unsafe void DrawResourceLoader()
{
if (!ImGui.CollapsingHeader("Resource Loader"))
return;
var ongoingLoads = _resourceLoader.OngoingLoads;
var ongoingLoadCount = ongoingLoads.Count;
ImUtf8.Text($"Ongoing Loads: {ongoingLoadCount}");
if (ongoingLoadCount == 0)
return;
using var table = ImUtf8.Table("ongoingLoadTable"u8, 3);
if (!table)
return;
ImUtf8.TableSetupColumn("Resource Handle"u8, ImGuiTableColumnFlags.WidthStretch, 0.2f);
ImUtf8.TableSetupColumn("Actual Path"u8, ImGuiTableColumnFlags.WidthStretch, 0.4f);
ImUtf8.TableSetupColumn("Original Path"u8, ImGuiTableColumnFlags.WidthStretch, 0.4f);
ImGui.TableHeadersRow();
foreach (var (handle, original) in ongoingLoads)
{
ImGui.TableNextColumn();
ImUtf8.Text($"0x{handle:X}");
ImGui.TableNextColumn();
ImUtf8.Text(((ResourceHandle*)handle)->CsHandle.FileName);
ImGui.TableNextColumn();
ImUtf8.Text(original.Path.Span);
}
}
/// <summary> Draw resources with unusual reference count. </summary>
private unsafe void DrawResourceProblems()
{