This commit is contained in:
Soreepeong 2024-02-28 20:10:31 +09:00
parent b16fa5cb46
commit 35f3802471
5 changed files with 47 additions and 104 deletions

View file

@ -6,16 +6,12 @@ using Dalamud.Utility;
namespace Dalamud.Interface.Internal.SharedImmediateTextures;
/// <summary>
/// Represents a sharable texture, based on a file on the system filesystem.
/// </summary>
/// <summary>Represents a sharable texture, based on a file on the system filesystem.</summary>
internal sealed class FileSystemSharedImmediateTexture : SharedImmediateTexture
{
private readonly string path;
/// <summary>
/// Initializes a new instance of the <see cref="FileSystemSharedImmediateTexture"/> class.
/// </summary>
/// <summary>Initializes a new instance of the <see cref="FileSystemSharedImmediateTexture"/> class.</summary>
/// <param name="path">The path.</param>
/// <param name="holdSelfReference">If set to <c>true</c>, this class will hold a reference to self.
/// Otherwise, it is expected that the caller to hold the reference.</param>
@ -30,18 +26,14 @@ internal sealed class FileSystemSharedImmediateTexture : SharedImmediateTexture
/// <inheritdoc/>
public override string SourcePathForDebug => this.path;
/// <summary>
/// Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The new instance will hold a reference to itself.
/// </summary>
/// <summary>Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The new instance will hold a reference to itself.</summary>
/// <param name="path">The path.</param>
/// <returns>The new instance.</returns>
public static SharedImmediateTexture CreateImmediate(string path) => new FileSystemSharedImmediateTexture(path, true);
/// <summary>
/// Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The caller is expected to manage ownership of the new instance.
/// </summary>
/// <summary>Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The caller is expected to manage ownership of the new instance.</summary>
/// <param name="path">The path.</param>
/// <returns>The new instance.</returns>
public static SharedImmediateTexture CreateAsync(string path) => new FileSystemSharedImmediateTexture(path, false);

View file

@ -9,16 +9,12 @@ using Lumina.Data.Files;
namespace Dalamud.Interface.Internal.SharedImmediateTextures;
/// <summary>
/// Represents a sharable texture, based on a file in game resources.
/// </summary>
/// <summary>Represents a sharable texture, based on a file in game resources.</summary>
internal sealed class GamePathSharedImmediateTexture : SharedImmediateTexture
{
private readonly string path;
/// <summary>
/// Initializes a new instance of the <see cref="GamePathSharedImmediateTexture"/> class.
/// </summary>
/// <summary>Initializes a new instance of the <see cref="GamePathSharedImmediateTexture"/> class.</summary>
/// <param name="path">The path.</param>
/// <param name="holdSelfReference">If set to <c>true</c>, this class will hold a reference to self.
/// Otherwise, it is expected that the caller to hold the reference.</param>
@ -33,18 +29,14 @@ internal sealed class GamePathSharedImmediateTexture : SharedImmediateTexture
/// <inheritdoc/>
public override string SourcePathForDebug => this.path;
/// <summary>
/// Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The new instance will hold a reference to itself.
/// </summary>
/// <summary>Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The new instance will hold a reference to itself.</summary>
/// <param name="path">The path.</param>
/// <returns>The new instance.</returns>
public static SharedImmediateTexture CreateImmediate(string path) => new GamePathSharedImmediateTexture(path, true);
/// <summary>
/// Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The caller is expected to manage ownership of the new instance.
/// </summary>
/// <summary>Creates a new instance of <see cref="GamePathSharedImmediateTexture"/>.
/// The caller is expected to manage ownership of the new instance.</summary>
/// <param name="path">The path.</param>
/// <returns>The new instance.</returns>
public static SharedImmediateTexture CreateAsync(string path) => new GamePathSharedImmediateTexture(path, false);

View file

@ -8,9 +8,7 @@ using Dalamud.Utility;
namespace Dalamud.Interface.Internal.SharedImmediateTextures;
/// <summary>
/// Represents a texture that may have multiple reference holders (owners).
/// </summary>
/// <summary>Represents a texture that may have multiple reference holders (owners).</summary>
internal abstract class SharedImmediateTexture
: ISharedImmediateTexture, IRefCountable, TextureLoadThrottler.IThrottleBasisProvider
{
@ -28,9 +26,7 @@ internal abstract class SharedImmediateTexture
private CancellationTokenSource? cancellationTokenSource;
private NotOwnedTextureWrap? nonOwningWrap;
/// <summary>
/// Initializes a new instance of the <see cref="SharedImmediateTexture"/> class.
/// </summary>
/// <summary>Initializes a new instance of the <see cref="SharedImmediateTexture"/> class.</summary>
/// <param name="holdSelfReference">If set to <c>true</c>, this class will hold a reference to self.
/// Otherwise, it is expected that the caller to hold the reference.</param>
protected SharedImmediateTexture(bool holdSelfReference)
@ -58,37 +54,26 @@ internal abstract class SharedImmediateTexture
this.FirstRequestedTick = this.LatestRequestedTick = Environment.TickCount64;
}
/// <summary>
/// Gets the instance ID. Debug use only.
/// </summary>
/// <summary>Gets the instance ID. Debug use only.</summary>
public long InstanceIdForDebug { get; }
/// <summary>
/// Gets the remaining time for self reference in milliseconds. Debug use only.
/// </summary>
/// <summary>Gets the remaining time for self reference in milliseconds. Debug use only.</summary>
public long SelfReferenceExpiresInForDebug =>
this.selfReferenceExpiry == SelfReferenceExpiryExpired
? 0
: Math.Max(0, this.selfReferenceExpiry - Environment.TickCount64);
/// <summary>
/// Gets the reference count. Debug use only.
/// </summary>
/// <summary>Gets the reference count. Debug use only.</summary>
public int RefCountForDebug => this.refCount;
/// <summary>
/// Gets the source path. Debug use only.
/// </summary>
/// <summary>Gets the source path. Debug use only.</summary>
public abstract string SourcePathForDebug { get; }
/// <summary>
/// Gets a value indicating whether this instance of <see cref="SharedImmediateTexture"/> supports revival.
/// <summary>Gets a value indicating whether this instance of <see cref="SharedImmediateTexture"/> supports revival.
/// </summary>
public bool HasRevivalPossibility => this.RevivalPossibility?.TryGetTarget(out _) is true;
/// <summary>
/// Gets or sets the underlying texture wrap.
/// </summary>
/// <summary>Gets or sets the underlying texture wrap.</summary>
public Task<IDalamudTextureWrap>? UnderlyingWrap { get; set; }
/// <inheritdoc/>
@ -100,21 +85,15 @@ internal abstract class SharedImmediateTexture
/// <inheritdoc/>
public long LatestRequestedTick { get; private set; }
/// <summary>
/// Gets a value indicating whether the content has been queried,
/// i.e. <see cref="TryGetWrap"/> or <see cref="RentAsync"/> is called.
/// </summary>
/// <summary>Gets a value indicating whether the content has been queried,
/// i.e. <see cref="TryGetWrap"/> or <see cref="RentAsync"/> is called.</summary>
public bool ContentQueried { get; private set; }
/// <summary>
/// Gets a cancellation token for cancelling load.
/// Intended to be called from implementors' constructors and <see cref="ReviveResources"/>.
/// </summary>
/// <summary>Gets a cancellation token for cancelling load.
/// Intended to be called from implementors' constructors and <see cref="ReviveResources"/>.</summary>
protected CancellationToken LoadCancellationToken => this.cancellationTokenSource?.Token ?? default;
/// <summary>
/// Gets or sets a weak reference to an object that demands this objects to be alive.
/// </summary>
/// <summary>Gets or sets a weak reference to an object that demands this objects to be alive.</summary>
/// <remarks>
/// TextureManager must keep references to all shared textures, regardless of whether textures' contents are
/// flushed, because API9 functions demand that the returned textures may be stored so that they can used anytime,
@ -184,9 +163,7 @@ internal abstract class SharedImmediateTexture
}
}
/// <summary>
/// Releases self-reference, if conditions are met.
/// </summary>
/// <summary>Releases self-reference, if conditions are met.</summary>
/// <param name="immediate">If set to <c>true</c>, the self-reference will be released immediately.</param>
/// <returns>Number of the new reference count that may or may not have changed.</returns>
public int ReleaseSelfReference(bool immediate)
@ -280,9 +257,7 @@ internal abstract class SharedImmediateTexture
return new RefCountableWrappingTextureWrap(dtw, this);
}
/// <summary>
/// Gets a texture wrap which ensures that the values will be populated on access.
/// </summary>
/// <summary>Gets a texture wrap which ensures that the values will be populated on access.</summary>
/// <returns>The texture wrap, or null if failed.</returns>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public IDalamudTextureWrap? GetAvailableOnAccessWrapForApi9()
@ -311,14 +286,10 @@ internal abstract class SharedImmediateTexture
return this.availableOnAccessWrapForApi9;
}
/// <summary>
/// Cleans up this instance of <see cref="SharedImmediateTexture"/>.
/// </summary>
/// <summary>Cleans up this instance of <see cref="SharedImmediateTexture"/>.</summary>
protected abstract void ReleaseResources();
/// <summary>
/// Attempts to restore the reference to this texture.
/// </summary>
/// <summary>Attempts to restore the reference to this texture.</summary>
protected abstract void ReviveResources();
private IRefCountable.RefCountResult TryAddRef(out int newRefCount)

View file

@ -26,9 +26,7 @@ using SharpDX.DXGI;
namespace Dalamud.Interface.Internal;
/// <summary>
/// Service responsible for loading and disposing ImGui texture wraps.
/// </summary>
/// <summary>Service responsible for loading and disposing ImGui texture wraps.</summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
@ -73,25 +71,19 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
/// <inheritdoc/>
public event ITextureSubstitutionProvider.TextureDataInterceptorDelegate? InterceptTexDataLoad;
/// <summary>
/// Gets all the loaded textures from the game resources. Debug use only.
/// </summary>
public ICollection<SharedImmediateTexture> GamePathTextures => this.gamePathTextures.Values;
/// <summary>Gets all the loaded textures from the game resources.</summary>
public ICollection<SharedImmediateTexture> GamePathTexturesForDebug => this.gamePathTextures.Values;
/// <summary>
/// Gets all the loaded textures from the game resources. Debug use only.
/// </summary>
public ICollection<SharedImmediateTexture> FileSystemTextures => this.fileSystemTextures.Values;
/// <summary>Gets all the loaded textures from the game resources.</summary>
public ICollection<SharedImmediateTexture> FileSystemTexturesForDebug => this.fileSystemTextures.Values;
/// <summary>
/// Gets all the loaded textures that are invalidated from <see cref="InvalidatePaths"/>. Debug use only.
/// </summary>
/// <summary>Gets all the loaded textures that are invalidated from <see cref="InvalidatePaths"/>.</summary>
/// <remarks><c>lock</c> on use of the value returned from this property.</remarks>
[SuppressMessage(
"ReSharper",
"InconsistentlySynchronizedField",
Justification = "Debug use only; users are expected to lock around this")]
public ICollection<SharedImmediateTexture> InvalidatedTextures => this.invalidatedTextures;
public ICollection<SharedImmediateTexture> InvalidatedTexturesForDebug => this.invalidatedTextures;
/// <inheritdoc/>
public void Dispose()
@ -435,10 +427,8 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
}
}
/// <summary>
/// Gets a texture from the given image. Skips the load throttler; intended to be used from implementation of
/// <see cref="SharedImmediateTexture"/>s.
/// </summary>
/// <summary>Gets a texture from the given image. Skips the load throttler; intended to be used from implementation
/// of <see cref="SharedImmediateTexture"/>s.</summary>
/// <param name="bytes">The data.</param>
/// <returns>The loaded texture.</returns>
internal IDalamudTextureWrap NoThrottleGetFromImage(ReadOnlyMemory<byte> bytes)
@ -454,10 +444,8 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
?? throw new("Failed to load image because of an unknown reason."));
}
/// <summary>
/// Gets a texture from the given <see cref="TexFile"/>. Skips the load throttler; intended to be used from
/// implementation of <see cref="SharedImmediateTexture"/>s.
/// </summary>
/// <summary>Gets a texture from the given <see cref="TexFile"/>. Skips the load throttler; intended to be used from
/// implementation of <see cref="SharedImmediateTexture"/>s.</summary>
/// <param name="file">The data.</param>
/// <returns>The loaded texture.</returns>
internal IDalamudTextureWrap NoThrottleGetFromTexFile(TexFile file)

View file

@ -65,21 +65,21 @@ internal class TexWidget : IDataWindowWidget
GC.Collect();
ImGui.PushID("loadedGameTextures");
if (ImGui.CollapsingHeader($"Loaded Game Textures: {this.textureManager.GamePathTextures.Count:g}###header"))
this.DrawLoadedTextures(this.textureManager.GamePathTextures);
if (ImGui.CollapsingHeader($"Loaded Game Textures: {this.textureManager.GamePathTexturesForDebug.Count:g}###header"))
this.DrawLoadedTextures(this.textureManager.GamePathTexturesForDebug);
ImGui.PopID();
ImGui.PushID("loadedFileTextures");
if (ImGui.CollapsingHeader($"Loaded File Textures: {this.textureManager.FileSystemTextures.Count:g}###header"))
this.DrawLoadedTextures(this.textureManager.FileSystemTextures);
if (ImGui.CollapsingHeader($"Loaded File Textures: {this.textureManager.FileSystemTexturesForDebug.Count:g}###header"))
this.DrawLoadedTextures(this.textureManager.FileSystemTexturesForDebug);
ImGui.PopID();
lock (this.textureManager.InvalidatedTextures)
lock (this.textureManager.InvalidatedTexturesForDebug)
{
ImGui.PushID("invalidatedTextures");
if (ImGui.CollapsingHeader($"Invalidated: {this.textureManager.InvalidatedTextures.Count:g}###header"))
if (ImGui.CollapsingHeader($"Invalidated: {this.textureManager.InvalidatedTexturesForDebug.Count:g}###header"))
{
this.DrawLoadedTextures(this.textureManager.InvalidatedTextures);
this.DrawLoadedTextures(this.textureManager.InvalidatedTexturesForDebug);
}
ImGui.PopID();