mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Make IDalamudTextureWrap ICloneable
This commit is contained in:
parent
c1c85e5236
commit
f6be80a5fb
6 changed files with 145 additions and 32 deletions
|
|
@ -1,41 +1,14 @@
|
||||||
using System.Numerics;
|
using Dalamud.Utility;
|
||||||
|
|
||||||
using ImGuiScene;
|
using ImGuiScene;
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal;
|
namespace Dalamud.Interface.Internal;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base TextureWrap interface for all Dalamud-owned texture wraps.
|
|
||||||
/// Used to avoid referencing ImGuiScene.
|
|
||||||
/// </summary>
|
|
||||||
public interface IDalamudTextureWrap : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a texture handle suitable for direct use with ImGui functions.
|
|
||||||
/// </summary>
|
|
||||||
IntPtr ImGuiHandle { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the width of the texture.
|
|
||||||
/// </summary>
|
|
||||||
int Width { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the height of the texture.
|
|
||||||
/// </summary>
|
|
||||||
int Height { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the size vector of the texture using Width, Height.
|
|
||||||
/// </summary>
|
|
||||||
Vector2 Size => new(this.Width, this.Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Safety harness for ImGuiScene textures that will defer destruction until
|
/// Safety harness for ImGuiScene textures that will defer destruction until
|
||||||
/// the end of the frame.
|
/// the end of the frame.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DalamudTextureWrap : IDalamudTextureWrap
|
public class DalamudTextureWrap : IDalamudTextureWrap, IDeferredDisposable
|
||||||
{
|
{
|
||||||
private readonly TextureWrap wrappedWrap;
|
private readonly TextureWrap wrappedWrap;
|
||||||
|
|
||||||
|
|
@ -83,7 +56,7 @@ public class DalamudTextureWrap : IDalamudTextureWrap
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Actually dispose the wrapped texture.
|
/// Actually dispose the wrapped texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void RealDispose()
|
void IDeferredDisposable.RealDispose()
|
||||||
{
|
{
|
||||||
this.wrappedWrap.Dispose();
|
this.wrappedWrap.Dispose();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
47
Dalamud/Interface/Internal/IDalamudTextureWrap.cs
Normal file
47
Dalamud/Interface/Internal/IDalamudTextureWrap.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.Internal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base TextureWrap interface for all Dalamud-owned texture wraps.
|
||||||
|
/// Used to avoid referencing ImGuiScene.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDalamudTextureWrap : IDisposable, ICloneable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a texture handle suitable for direct use with ImGui functions.
|
||||||
|
/// </summary>
|
||||||
|
IntPtr ImGuiHandle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width of the texture.
|
||||||
|
/// </summary>
|
||||||
|
int Width { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height of the texture.
|
||||||
|
/// </summary>
|
||||||
|
int Height { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size vector of the texture using Width, Height.
|
||||||
|
/// </summary>
|
||||||
|
Vector2 Size => new(this.Width, this.Height);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new reference to this texture wrap.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The new reference to this texture wrap.</returns>
|
||||||
|
/// <remarks>The default implementation will treat <see cref="ImGuiHandle"/> as an <see cref="IUnknown"/>.</remarks>
|
||||||
|
new unsafe IDalamudTextureWrap Clone()
|
||||||
|
{
|
||||||
|
// Dalamud specific: IDalamudTextureWrap always points to an ID3D11ShaderResourceView.
|
||||||
|
var handle = (IUnknown*)this.ImGuiHandle;
|
||||||
|
return new UnknownTextureWrap(handle, this.Width, this.Height, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
object ICloneable.Clone() => this.Clone();
|
||||||
|
}
|
||||||
|
|
@ -62,7 +62,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const float DefaultFontSizePx = (DefaultFontSizePt * 4.0f) / 3.0f;
|
public const float DefaultFontSizePx = (DefaultFontSizePt * 4.0f) / 3.0f;
|
||||||
|
|
||||||
private readonly ConcurrentBag<DalamudTextureWrap> deferredDisposeTextures = new();
|
private readonly ConcurrentBag<IDeferredDisposable> deferredDisposeTextures = new();
|
||||||
private readonly ConcurrentBag<ILockedImFont> deferredDisposeImFontLockeds = new();
|
private readonly ConcurrentBag<ILockedImFont> deferredDisposeImFontLockeds = new();
|
||||||
|
|
||||||
[ServiceManager.ServiceDependency]
|
[ServiceManager.ServiceDependency]
|
||||||
|
|
@ -402,7 +402,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
/// Enqueue a texture to be disposed at the end of the frame.
|
/// Enqueue a texture to be disposed at the end of the frame.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="wrap">The texture.</param>
|
/// <param name="wrap">The texture.</param>
|
||||||
public void EnqueueDeferredDispose(DalamudTextureWrap wrap)
|
public void EnqueueDeferredDispose(IDeferredDisposable wrap)
|
||||||
{
|
{
|
||||||
this.deferredDisposeTextures.Add(wrap);
|
this.deferredDisposeTextures.Add(wrap);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
77
Dalamud/Interface/Internal/UnknownTextureWrap.cs
Normal file
77
Dalamud/Interface/Internal/UnknownTextureWrap.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.Internal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A texture wrap that is created by cloning the underlying <see cref="IDalamudTextureWrap.ImGuiHandle"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed unsafe class UnknownTextureWrap : IDalamudTextureWrap, IDeferredDisposable
|
||||||
|
{
|
||||||
|
private IntPtr imGuiHandle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UnknownTextureWrap"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="unknown">The pointer to <see cref="IUnknown"/> that is suitable for use with
|
||||||
|
/// <see cref="IDalamudTextureWrap.ImGuiHandle"/>.</param>
|
||||||
|
/// <param name="width">The width of the texture.</param>
|
||||||
|
/// <param name="height">The height of the texture.</param>
|
||||||
|
/// <param name="callAddRef">If <c>true</c>, call <see cref="IUnknown.AddRef"/>.</param>
|
||||||
|
public UnknownTextureWrap(IUnknown* unknown, int width, int height, bool callAddRef)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(unknown is null, typeof(IUnknown));
|
||||||
|
this.imGuiHandle = (nint)unknown;
|
||||||
|
this.Width = width;
|
||||||
|
this.Height = height;
|
||||||
|
if (callAddRef)
|
||||||
|
unknown->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finalizes an instance of the <see cref="UnknownTextureWrap"/> class.
|
||||||
|
/// </summary>
|
||||||
|
~UnknownTextureWrap() => this.Dispose(false);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint ImGuiHandle =>
|
||||||
|
this.imGuiHandle == nint.Zero
|
||||||
|
? throw new ObjectDisposedException(nameof(UnknownTextureWrap))
|
||||||
|
: this.imGuiHandle;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int Width { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int Height { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue the texture to be disposed once the frame ends.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Actually dispose the wrapped texture.
|
||||||
|
/// </summary>
|
||||||
|
void IDeferredDisposable.RealDispose()
|
||||||
|
{
|
||||||
|
var handle = Interlocked.Exchange(ref this.imGuiHandle, nint.Zero);
|
||||||
|
if (handle != nint.Zero)
|
||||||
|
((IUnknown*)handle)->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
Service<InterfaceManager>.GetNullable()?.EnqueueDeferredDispose(this);
|
||||||
|
else
|
||||||
|
((IDeferredDisposable)this).RealDispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -119,6 +119,10 @@ internal class TexWidget : IDataWindowWidget
|
||||||
|
|
||||||
if (ImGui.Button($"X##{i}"))
|
if (ImGui.Button($"X##{i}"))
|
||||||
toRemove = tex;
|
toRemove = tex;
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button($"Clone##{i}"))
|
||||||
|
this.addedTextures.Add(tex.Clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
Dalamud/Utility/IDeferredDisposable.cs
Normal file
12
Dalamud/Utility/IDeferredDisposable.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Dalamud.Utility;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An extension of <see cref="IDisposable"/> which makes <see cref="IDisposable.Dispose"/> queue
|
||||||
|
/// <see cref="RealDispose"/> to be called at a later time.
|
||||||
|
/// </summary>
|
||||||
|
internal interface IDeferredDisposable : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>Actually dispose the object.</summary>
|
||||||
|
/// <remarks>Not to be called from the code that uses the end object.</remarks>
|
||||||
|
void RealDispose();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue