Correct Async refcount handling

This commit is contained in:
Soreepeong 2024-02-22 16:52:07 +09:00
parent ba51ec52f5
commit 80875247b6
4 changed files with 41 additions and 21 deletions

View file

@ -23,12 +23,7 @@ internal sealed class FileSystemSharableTexture : SharableTexture
{ {
this.path = path; this.path = path;
if (holdSelfReference) if (holdSelfReference)
{ this.ReviveResources();
this.UnderlyingWrap = Service<TextureLoadThrottler>.Get().CreateLoader(
this,
this.CreateTextureAsync,
this.LoadCancellationToken);
}
} }
/// <inheritdoc/> /// <inheritdoc/>

View file

@ -27,12 +27,7 @@ internal sealed class GamePathSharableTexture : SharableTexture
{ {
this.path = path; this.path = path;
if (holdSelfReference) if (holdSelfReference)
{ this.ReviveResources();
this.UnderlyingWrap = Service<TextureLoadThrottler>.Get().CreateLoader(
this,
this.CreateTextureAsync,
this.LoadCancellationToken);
}
} }
/// <inheritdoc/> /// <inheritdoc/>

View file

@ -32,14 +32,26 @@ internal abstract class SharableTexture : IRefCountable, TextureLoadThrottler.IT
protected SharableTexture(bool holdSelfReference) protected SharableTexture(bool holdSelfReference)
{ {
this.InstanceIdForDebug = Interlocked.Increment(ref instanceCounter); this.InstanceIdForDebug = Interlocked.Increment(ref instanceCounter);
this.refCount = 1;
this.selfReferenceExpiry = if (holdSelfReference)
holdSelfReference {
? Environment.TickCount64 + SelfReferenceDurationTicks this.refCount = 1;
: SelfReferenceExpiryExpired; this.selfReferenceExpiry = Environment.TickCount64 + SelfReferenceDurationTicks;
this.IsOpportunistic = true; this.ContentQueried = true;
this.IsOpportunistic = true;
this.resourceReleased = false;
this.cancellationTokenSource = new();
}
else
{
this.refCount = 0;
this.selfReferenceExpiry = SelfReferenceExpiryExpired;
this.ContentQueried = false;
this.IsOpportunistic = false;
this.resourceReleased = true;
}
this.FirstRequestedTick = this.LatestRequestedTick = Environment.TickCount64; this.FirstRequestedTick = this.LatestRequestedTick = Environment.TickCount64;
this.cancellationTokenSource = new();
} }
/// <summary> /// <summary>
@ -84,6 +96,12 @@ internal abstract class SharableTexture : IRefCountable, TextureLoadThrottler.IT
/// <inheritdoc/> /// <inheritdoc/>
public long LatestRequestedTick { get; private set; } public long LatestRequestedTick { get; private set; }
/// <summary>
/// Gets a value indicating whether the content has been queried,
/// i.e. <see cref="CreateNewReference"/> or <see cref="GetImmediate"/> is called.
/// </summary>
public bool ContentQueried { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the dispose-suppressing wrap for <see cref="UnderlyingWrap"/>. /// Gets or sets the dispose-suppressing wrap for <see cref="UnderlyingWrap"/>.
/// </summary> /// </summary>
@ -199,8 +217,12 @@ internal abstract class SharableTexture : IRefCountable, TextureLoadThrottler.IT
public IDalamudTextureWrap? GetImmediate() public IDalamudTextureWrap? GetImmediate()
{ {
if (this.TryAddRef(out _) != IRefCountable.RefCountResult.StillAlive) if (this.TryAddRef(out _) != IRefCountable.RefCountResult.StillAlive)
{
this.ContentQueried = true;
return null; return null;
}
this.ContentQueried = true;
this.LatestRequestedTick = Environment.TickCount64; this.LatestRequestedTick = Environment.TickCount64;
var nexp = Environment.TickCount64 + SelfReferenceDurationTicks; var nexp = Environment.TickCount64 + SelfReferenceDurationTicks;
while (true) while (true)
@ -230,7 +252,15 @@ internal abstract class SharableTexture : IRefCountable, TextureLoadThrottler.IT
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
this.AddRef(); try
{
this.AddRef();
}
finally
{
this.ContentQueried = true;
}
if (this.UnderlyingWrap is null) if (this.UnderlyingWrap is null)
throw new InvalidOperationException("AddRef returned but UnderlyingWrap is null?"); throw new InvalidOperationException("AddRef returned but UnderlyingWrap is null?");

View file

@ -469,7 +469,7 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
return; return;
static bool TextureFinalReleasePredicate(SharableTexture v) => static bool TextureFinalReleasePredicate(SharableTexture v) =>
v.ReleaseSelfReference(false) == 0 && !v.HasRevivalPossibility; v.ContentQueried && v.ReleaseSelfReference(false) == 0 && !v.HasRevivalPossibility;
} }
private string GetIconPathByValue(GameIconLookup lookup) => private string GetIconPathByValue(GameIconLookup lookup) =>