diff --git a/Dalamud/Interface/Textures/ForwardingTextureWrap.cs b/Dalamud/Interface/Textures/ForwardingTextureWrap.cs
new file mode 100644
index 000000000..c398fc55c
--- /dev/null
+++ b/Dalamud/Interface/Textures/ForwardingTextureWrap.cs
@@ -0,0 +1,81 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+using Dalamud.Interface.Internal;
+using Dalamud.Interface.Textures.Internal;
+
+using TerraFX.Interop.Windows;
+
+namespace Dalamud.Interface.Textures;
+
+/// Base class for implementations of that forwards to another.
+public abstract class ForwardingTextureWrap : IDalamudTextureWrap
+{
+ ///
+ public IntPtr ImGuiHandle
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => this.GetWrap().ImGuiHandle;
+ }
+
+ ///
+ public int Width
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => this.GetWrap().Width;
+ }
+
+ ///
+ public int Height
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => this.GetWrap().Height;
+ }
+
+ ///
+ public Vector2 Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => new(this.Width, this.Height);
+ }
+
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ public virtual unsafe IDalamudTextureWrap CreateWrapSharingLowLevelResource()
+ {
+ // Dalamud specific: IDalamudTextureWrap always points to an ID3D11ShaderResourceView.
+ var handle = (IUnknown*)this.ImGuiHandle;
+ return new UnknownTextureWrap(handle, this.Width, this.Height, true);
+ }
+
+ ///
+ public override string ToString() => $"{this.GetType()}({(this.TryGetWrap(out var wrap) ? wrap : null)})";
+
+ /// Called on .
+ /// true if called from .
+ ///
+ /// Base implementation will not dispose the result of .
+ /// If you need to implement a finalizer, then make it call this function with false.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ }
+
+ /// Gets the inner wrap.
+ /// The inner wrap.
+ /// true if not disposed and is available.
+ protected abstract bool TryGetWrap([NotNullWhen(true)] out IDalamudTextureWrap? wrap);
+
+ /// Gets the inner wrap.
+ /// The inner wrap.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected IDalamudTextureWrap GetWrap() =>
+ this.TryGetWrap(out var wrap) ? wrap : throw new ObjectDisposedException(this.GetType().Name);
+}
diff --git a/Dalamud/Interface/Textures/IDalamudTextureWrap.cs b/Dalamud/Interface/Textures/IDalamudTextureWrap.cs
index dad453cb9..c51a69f06 100644
--- a/Dalamud/Interface/Textures/IDalamudTextureWrap.cs
+++ b/Dalamud/Interface/Textures/IDalamudTextureWrap.cs
@@ -1,5 +1,6 @@
using System.Numerics;
+using Dalamud.Interface.Textures;
using Dalamud.Interface.Textures.Internal;
using TerraFX.Interop.Windows;
@@ -12,6 +13,8 @@ namespace Dalamud.Interface.Internal;
/// Base TextureWrap interface for all Dalamud-owned texture wraps.
/// Used to avoid referencing ImGuiScene.
///
+/// If you want to implement this, see if you're actually wrapping an existing instance of
+/// ; if you are, then use .
public interface IDalamudTextureWrap : IDisposable
{
/// Gets a texture handle suitable for direct use with ImGui functions.
diff --git a/Dalamud/Interface/Textures/Internal/DisposeSuppressingTextureWrap.cs b/Dalamud/Interface/Textures/Internal/DisposeSuppressingTextureWrap.cs
index 17a88e270..88d8d9ca0 100644
--- a/Dalamud/Interface/Textures/Internal/DisposeSuppressingTextureWrap.cs
+++ b/Dalamud/Interface/Textures/Internal/DisposeSuppressingTextureWrap.cs
@@ -2,31 +2,19 @@ using Dalamud.Interface.Internal;
namespace Dalamud.Interface.Textures.Internal;
-///
-/// A texture wrap that ignores calls.
-///
-internal sealed class DisposeSuppressingTextureWrap : IDalamudTextureWrap
+/// A texture wrap that ignores calls.
+internal class DisposeSuppressingTextureWrap : ForwardingTextureWrap
{
private readonly IDalamudTextureWrap innerWrap;
- ///
- /// Initializes a new instance of the class.
- ///
+ /// Initializes a new instance of the class.
/// The inner wrap.
public DisposeSuppressingTextureWrap(IDalamudTextureWrap wrap) => this.innerWrap = wrap;
///
- public IntPtr ImGuiHandle => this.innerWrap.ImGuiHandle;
-
- ///
- public int Width => this.innerWrap.Width;
-
- ///
- public int Height => this.innerWrap.Height;
-
- ///
- public void Dispose()
+ protected override bool TryGetWrap(out IDalamudTextureWrap? wrap)
{
- // suppressed
+ wrap = this.innerWrap;
+ return true;
}
}
diff --git a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs
index f730637e4..4a6289ceb 100644
--- a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs
+++ b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs
@@ -363,46 +363,35 @@ internal abstract class SharedImmediateTexture
}
}
- private sealed class NotOwnedTextureWrap : IDalamudTextureWrap
+ /// Same with , but with a custom implementation of
+ /// .
+ private sealed class NotOwnedTextureWrap : DisposeSuppressingTextureWrap
{
- private readonly IDalamudTextureWrap innerWrap;
private readonly IRefCountable owner;
/// Initializes a new instance of the class.
/// The inner wrap.
/// The reference counting owner.
public NotOwnedTextureWrap(IDalamudTextureWrap wrap, IRefCountable owner)
+ : base(wrap)
{
- this.innerWrap = wrap;
this.owner = owner;
}
///
- public IntPtr ImGuiHandle => this.innerWrap.ImGuiHandle;
-
- ///
- public int Width => this.innerWrap.Width;
-
- ///
- public int Height => this.innerWrap.Height;
-
- ///
- public IDalamudTextureWrap CreateWrapSharingLowLevelResource()
+ public override IDalamudTextureWrap CreateWrapSharingLowLevelResource()
{
+ var wrap = this.GetWrap();
this.owner.AddRef();
- return new RefCountableWrappingTextureWrap(this.innerWrap, this.owner);
- }
-
- ///
- public void Dispose()
- {
+ return new RefCountableWrappingTextureWrap(wrap, this.owner);
}
///
public override string ToString() => $"{nameof(NotOwnedTextureWrap)}({this.owner})";
}
- private sealed class RefCountableWrappingTextureWrap : IDalamudTextureWrap
+ /// Reference counting texture wrap, to be used with .
+ private sealed class RefCountableWrappingTextureWrap : ForwardingTextureWrap
{
private IDalamudTextureWrap? innerWrap;
private IRefCountable? owner;
@@ -416,22 +405,11 @@ internal abstract class SharedImmediateTexture
this.owner = owner;
}
- ~RefCountableWrappingTextureWrap() => this.Dispose();
+ /// Finalizes an instance of the class.
+ ~RefCountableWrappingTextureWrap() => this.Dispose(false);
///
- public IntPtr ImGuiHandle => this.InnerWrapNonDisposed.ImGuiHandle;
-
- ///
- public int Width => this.InnerWrapNonDisposed.Width;
-
- ///
- public int Height => this.InnerWrapNonDisposed.Height;
-
- private IDalamudTextureWrap InnerWrapNonDisposed =>
- this.innerWrap ?? throw new ObjectDisposedException(nameof(RefCountableWrappingTextureWrap));
-
- ///
- public IDalamudTextureWrap CreateWrapSharingLowLevelResource()
+ public override IDalamudTextureWrap CreateWrapSharingLowLevelResource()
{
var ownerCopy = this.owner;
var wrapCopy = this.innerWrap;
@@ -443,7 +421,13 @@ internal abstract class SharedImmediateTexture
}
///
- public void Dispose()
+ public override string ToString() => $"{nameof(RefCountableWrappingTextureWrap)}({this.owner})";
+
+ ///
+ protected override bool TryGetWrap(out IDalamudTextureWrap? wrap) => (wrap = this.innerWrap) is not null;
+
+ ///
+ protected override void Dispose(bool disposing)
{
while (true)
{
@@ -455,32 +439,22 @@ internal abstract class SharedImmediateTexture
// Note: do not dispose this; life of the wrap is managed by the owner.
this.innerWrap = null;
ownerCopy.Release();
- GC.SuppressFinalize(this);
}
}
-
- ///
- public override string ToString() => $"{nameof(RefCountableWrappingTextureWrap)}({this.owner})";
}
+ /// A texture wrap that revives and waits for the underlying texture as needed on every access.
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
- private sealed class AvailableOnAccessTextureWrap : IDalamudTextureWrap
+ private sealed class AvailableOnAccessTextureWrap : ForwardingTextureWrap
{
private readonly SharedImmediateTexture inner;
+ /// Initializes a new instance of the class.
+ /// The shared texture.
public AvailableOnAccessTextureWrap(SharedImmediateTexture inner) => this.inner = inner;
///
- public IntPtr ImGuiHandle => this.WaitGet().ImGuiHandle;
-
- ///
- public int Width => this.WaitGet().Width;
-
- ///
- public int Height => this.WaitGet().Height;
-
- ///
- public IDalamudTextureWrap CreateWrapSharingLowLevelResource()
+ public override IDalamudTextureWrap CreateWrapSharingLowLevelResource()
{
this.inner.AddRef();
try
@@ -506,22 +480,18 @@ internal abstract class SharedImmediateTexture
}
}
- ///
- public void Dispose()
- {
- // ignore
- }
-
///
public override string ToString() => $"{nameof(AvailableOnAccessTextureWrap)}({this.inner})";
- private IDalamudTextureWrap WaitGet()
+ ///
+ protected override bool TryGetWrap(out IDalamudTextureWrap? wrap)
{
if (this.inner.TryGetWrapCore(out var t, out _))
- return t;
+ wrap = t;
this.inner.UnderlyingWrap?.Wait();
- return this.inner.nonOwningWrap ?? Service.Get().Empty4X4;
+ wrap = this.inner.nonOwningWrap ?? Service.Get().Empty4X4;
+ return true;
}
}
}
diff --git a/Dalamud/Interface/Textures/Internal/ViewportTextureWrap.cs b/Dalamud/Interface/Textures/Internal/ViewportTextureWrap.cs
index ca914a234..272a2d8ee 100644
--- a/Dalamud/Interface/Textures/Internal/ViewportTextureWrap.cs
+++ b/Dalamud/Interface/Textures/Internal/ViewportTextureWrap.cs
@@ -195,6 +195,7 @@ internal sealed class ViewportTextureWrap : IDalamudTextureWrap, IDeferredDispos
_ = this.FirstUpdateTask.Exception;
this.tex.Reset();
this.srv.Reset();
+ this.rtv.Reset();
}
private static unsafe ComPtr GetImGuiViewportBackBuffer(uint viewportId)