diff --git a/Dalamud/Interface/Internal/TextureManager.cs b/Dalamud/Interface/Internal/TextureManager.cs
index 717bd8081..294edbb0a 100644
--- a/Dalamud/Interface/Internal/TextureManager.cs
+++ b/Dalamud/Interface/Internal/TextureManager.cs
@@ -239,24 +239,33 @@ internal class TextureManager : IDisposable, IServiceType, ITextureSubstitutionP
/// If false, exceptions will be caught and a dummy texture will be returned to prevent plugins from using invalid texture handles.
///
/// Info object storing texture metadata.
- internal TextureInfo GetInfo(string path, bool refresh = true, bool rethrow = false)
+ internal TextureInfo? GetInfo(string path, bool refresh = true, bool rethrow = false)
{
TextureInfo? info;
lock (this.activeTextures)
{
- this.activeTextures.TryGetValue(path, out info);
+ if (!this.activeTextures.TryGetValue(path, out info))
+ {
+ Debug.Assert(rethrow, "This should never run when getting outside of creator");
+
+ if (!refresh)
+ return null;
+
+ // NOTE: We need to init the refcount here while locking the collection!
+ // Otherwise, if this is loaded from a task, cleanup might already try to delete it
+ // before it can be increased.
+ info = new TextureInfo
+ {
+ RefCount = 1,
+ };
+
+ this.activeTextures.Add(path, info);
+ }
+
+ if (info == null)
+ throw new Exception("null info in activeTextures");
}
- if (info == null)
- {
- info = new TextureInfo();
- lock (this.activeTextures)
- {
- if (!this.activeTextures.TryAdd(path, info))
- Log.Warning("Texture {Path} tracked twice", path);
- }
- }
-
if (refresh && info.KeepAliveCount == 0)
info.LastAccess = DateTime.UtcNow;
@@ -353,6 +362,14 @@ internal class TextureManager : IDisposable, IServiceType, ITextureSubstitutionP
internal void NotifyTextureDisposed(string path, bool keepAlive)
{
var info = this.GetInfo(path, false);
+
+ // This texture was already disposed
+ if (info == null)
+ {
+ Log.Warning("Disposing unknown texture {Path}", path);
+ return;
+ }
+
info.RefCount--;
if (keepAlive)
@@ -378,8 +395,7 @@ internal class TextureManager : IDisposable, IServiceType, ITextureSubstitutionP
{
// This will create the texture.
// That's fine, it's probably used immediately and this will let the plugin catch load errors.
- var info = this.GetInfo(path, rethrow: true);
- info.RefCount++;
+ var info = this.GetInfo(path, rethrow: true)!;
if (keepAlive)
info.KeepAliveCount++;
@@ -575,7 +591,7 @@ internal class TextureManagerTextureWrap : IDalamudTextureWrap
///
public IntPtr ImGuiHandle => !this.IsDisposed ?
- this.manager.GetInfo(this.path).Wrap!.ImGuiHandle :
+ this.manager.GetInfo(this.path)!.Wrap!.ImGuiHandle :
throw new InvalidOperationException("Texture already disposed. You may not render it.");
///