diff --git a/Dalamud/Interface/Internal/TextureManager.cs b/Dalamud/Interface/Internal/TextureManager.cs
index 66a2cf731..905cac55a 100644
--- a/Dalamud/Interface/Internal/TextureManager.cs
+++ b/Dalamud/Interface/Internal/TextureManager.cs
@@ -233,13 +233,12 @@ internal class TextureManager : IDisposable, IServiceType, ITextureSubstitutionP
/// Get texture info.
///
/// Path to the texture.
- /// Whether or not the texture should be reloaded if it was unloaded.
///
/// If true, exceptions caused by texture load will not be caught.
/// 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 rethrow = false)
{
TextureInfo? info;
lock (this.activeTextures)
@@ -248,106 +247,94 @@ internal class TextureManager : IDisposable, IServiceType, ITextureSubstitutionP
{
Debug.Assert(rethrow, "This should never run when getting outside of creator");
- if (!refresh)
- return null;
-
info = new TextureInfo();
this.activeTextures.Add(path, info);
}
if (info == null)
throw new Exception("null info in activeTextures");
-
- // NOTE: We need to increase 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.RefCount++;
}
- if (refresh && info.KeepAliveCount == 0)
+ if (info.KeepAliveCount == 0)
info.LastAccess = DateTime.UtcNow;
if (info is { Wrap: not null })
return info;
- if (refresh)
- {
- if (!this.im.IsReady)
+ if (!this.im.IsReady)
throw new InvalidOperationException("Cannot create textures before scene is ready");
- string? interceptPath = null;
- this.InterceptTexDataLoad?.Invoke(path, ref interceptPath);
+ string? interceptPath = null;
+ this.InterceptTexDataLoad?.Invoke(path, ref interceptPath);
- if (interceptPath != null)
- {
- Log.Verbose("Intercept: {OriginalPath} => {ReplacePath}", path, interceptPath);
- path = interceptPath;
- }
+ if (interceptPath != null)
+ {
+ Log.Verbose("Intercept: {OriginalPath} => {ReplacePath}", path, interceptPath);
+ path = interceptPath;
+ }
- TextureWrap? wrap;
- try
+ TextureWrap? wrap;
+ try
+ {
+ // We want to load this from the disk, probably, if the path has a root
+ // Not sure if this can cause issues with e.g. network drives, might have to rethink
+ // and add a flag instead if it does.
+ if (Path.IsPathRooted(path))
{
- // We want to load this from the disk, probably, if the path has a root
- // Not sure if this can cause issues with e.g. network drives, might have to rethink
- // and add a flag instead if it does.
- if (Path.IsPathRooted(path))
+ if (Path.GetExtension(path) == ".tex")
{
- if (Path.GetExtension(path) == ".tex")
- {
- // Attempt to load via Lumina
- var file = this.dataManager.GameData.GetFileFromDisk(path);
- wrap = this.GetTexture(file);
- Log.Verbose("Texture {Path} loaded FS via Lumina", path);
- }
- else
- {
- // Attempt to load image
- wrap = this.im.LoadImage(path);
- Log.Verbose("Texture {Path} loaded FS via LoadImage", path);
- }
+ // Attempt to load via Lumina
+ var file = this.dataManager.GameData.GetFileFromDisk(path);
+ wrap = this.GetTexture(file);
+ Log.Verbose("Texture {Path} loaded FS via Lumina", path);
}
else
{
- // Load regularly from dats
- var file = this.dataManager.GetFile(path);
- if (file == null)
- throw new Exception("Could not load TexFile from dat.");
-
- wrap = this.GetTexture(file);
- Log.Verbose("Texture {Path} loaded from SqPack", path);
+ // Attempt to load image
+ wrap = this.im.LoadImage(path);
+ Log.Verbose("Texture {Path} loaded FS via LoadImage", path);
}
-
- if (wrap == null)
- throw new Exception("Could not create texture");
-
- // TODO: We could support this, but I don't think it's worth it at the moment.
- var extents = new Vector2(wrap.Width, wrap.Height);
- if (info.Extents != Vector2.Zero && info.Extents != extents)
- Log.Warning("Texture at {Path} changed size between reloads, this is currently not supported.", path);
-
- info.Extents = extents;
}
- catch (Exception e)
+ else
{
- Log.Error(e, "Could not load texture from {Path}", path);
-
- // When creating the texture initially, we want to be able to pass errors back to the plugin
- if (rethrow)
- throw;
-
- // This means that the load failed due to circumstances outside of our control,
- // and we can't do anything about it. Return a dummy texture so that the plugin still
- // has something to draw.
- wrap = this.fallbackTextureWrap;
-
- // Prevent divide-by-zero
- if (info.Extents == Vector2.Zero)
- info.Extents = Vector2.One;
+ // Load regularly from dats
+ var file = this.dataManager.GetFile(path);
+ if (file == null)
+ throw new Exception("Could not load TexFile from dat.");
+
+ wrap = this.GetTexture(file);
+ Log.Verbose("Texture {Path} loaded from SqPack", path);
}
+
+ if (wrap == null)
+ throw new Exception("Could not create texture");
- info.Wrap = wrap;
+ // TODO: We could support this, but I don't think it's worth it at the moment.
+ var extents = new Vector2(wrap.Width, wrap.Height);
+ if (info.Extents != Vector2.Zero && info.Extents != extents)
+ Log.Warning("Texture at {Path} changed size between reloads, this is currently not supported.", path);
+
+ info.Extents = extents;
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Could not load texture from {Path}", path);
+
+ // When creating the texture initially, we want to be able to pass errors back to the plugin
+ if (rethrow)
+ throw;
+
+ // This means that the load failed due to circumstances outside of our control,
+ // and we can't do anything about it. Return a dummy texture so that the plugin still
+ // has something to draw.
+ wrap = this.fallbackTextureWrap;
+
+ // Prevent divide-by-zero
+ if (info.Extents == Vector2.Zero)
+ info.Extents = Vector2.One;
}
+ info.Wrap = wrap;
return info;
}
@@ -359,23 +346,23 @@ internal class TextureManager : IDisposable, IServiceType, ITextureSubstitutionP
/// Whether or not this handle was created in keep-alive mode.
internal void NotifyTextureDisposed(string path, bool keepAlive)
{
- var info = this.GetInfo(path, false);
-
- // This texture was already disposed
- if (info == null)
+ lock (this.activeTextures)
{
- Log.Warning("Disposing unknown texture {Path}", path);
- return;
+ if (!this.activeTextures.TryGetValue(path, out var info))
+ {
+ Log.Warning("Disposing texture that didn't exist: {Path}", path);
+ return;
+ }
+
+ info.RefCount--;
+
+ if (keepAlive)
+ info.KeepAliveCount--;
+
+ // Clean it up by the next update. If it's re-requested in-between, we don't reload it.
+ if (info.RefCount <= 0)
+ info.LastAccess = default;
}
-
- info.RefCount--;
-
- if (keepAlive)
- info.KeepAliveCount--;
-
- // Clean it up by the next update. If it's re-requested in-between, we don't reload it.
- if (info.RefCount <= 0)
- info.LastAccess = default;
}
private static string FormatIconPath(uint iconId, string? type, bool highResolution)
@@ -391,14 +378,22 @@ internal class TextureManager : IDisposable, IServiceType, ITextureSubstitutionP
private TextureManagerTextureWrap? CreateWrap(string path, bool keepAlive)
{
- // 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)!;
+ lock (this.activeTextures)
+ {
+ // 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);
- if (keepAlive)
- info.KeepAliveCount++;
+ // We need to increase the refcounts 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.RefCount++;
- return new TextureManagerTextureWrap(path, info.Extents, keepAlive, this);
+ if (keepAlive)
+ info.KeepAliveCount++;
+
+ return new TextureManagerTextureWrap(path, info.Extents, keepAlive, this);
+ }
}
private void FrameworkOnUpdate(Framework fw)
@@ -589,7 +584,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.");
///