mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Merge pull request #1684 from Soreepeong/feature/idtw-cloneable
Add IDalamudTextureWrap.CreateWrapSharingLowLevelResource
This commit is contained in:
commit
8e5a84792e
6 changed files with 153 additions and 32 deletions
|
|
@ -1,41 +1,14 @@
|
|||
using System.Numerics;
|
||||
using Dalamud.Utility;
|
||||
|
||||
using ImGuiScene;
|
||||
|
||||
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>
|
||||
/// Safety harness for ImGuiScene textures that will defer destruction until
|
||||
/// the end of the frame.
|
||||
/// </summary>
|
||||
public class DalamudTextureWrap : IDalamudTextureWrap
|
||||
public class DalamudTextureWrap : IDalamudTextureWrap, IDeferredDisposable
|
||||
{
|
||||
private readonly TextureWrap wrappedWrap;
|
||||
|
||||
|
|
@ -83,7 +56,7 @@ public class DalamudTextureWrap : IDalamudTextureWrap
|
|||
/// <summary>
|
||||
/// Actually dispose the wrapped texture.
|
||||
/// </summary>
|
||||
internal void RealDispose()
|
||||
void IDeferredDisposable.RealDispose()
|
||||
{
|
||||
this.wrappedWrap.Dispose();
|
||||
}
|
||||
|
|
|
|||
55
Dalamud/Interface/Internal/IDalamudTextureWrap.cs
Normal file
55
Dalamud/Interface/Internal/IDalamudTextureWrap.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
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
|
||||
{
|
||||
/// <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 the resource being pointed by this instance of <see cref="IDalamudTextureWrap"/>.
|
||||
/// </summary>
|
||||
/// <returns>The new reference to this texture wrap.</returns>
|
||||
/// <remarks>
|
||||
/// On calling this function, a new instance of <see cref="IDalamudTextureWrap"/> will be returned, but with
|
||||
/// the same <see cref="ImGuiHandle"/>. The new instance must be <see cref="IDisposable.Dispose"/>d, as the backing
|
||||
/// resource will stay alive until all the references are released. The old instance may be disposed as needed,
|
||||
/// once this function returns; the new instance will stay alive regardless of whether the old instance has been
|
||||
/// disposed.<br />
|
||||
/// Primary purpose of this function is to share textures across plugin boundaries. When texture wraps get passed
|
||||
/// across plugin boundaries for use for an indeterminate duration, the receiver should call this function to
|
||||
/// obtain a new reference to the texture received, so that it gets its own "copy" of the texture and the caller
|
||||
/// may dispose the texture anytime without any care for the receiver.<br />
|
||||
/// The default implementation will treat <see cref="ImGuiHandle"/> as an <see cref="IUnknown"/>.
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
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();
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
|
|
@ -402,7 +402,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
/// Enqueue a texture to be disposed at the end of the frame.
|
||||
/// </summary>
|
||||
/// <param name="wrap">The texture.</param>
|
||||
public void EnqueueDeferredDispose(DalamudTextureWrap wrap)
|
||||
public void EnqueueDeferredDispose(IDeferredDisposable 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}"))
|
||||
toRemove = tex;
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button($"Clone##{i}"))
|
||||
this.addedTextures.Add(tex.CreateWrapSharingLowLevelResource());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
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