mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-23 08:59:17 +01:00
Add ForwardingTextureWrap
This commit is contained in:
parent
6c8c42ca05
commit
5fd7457df4
5 changed files with 120 additions and 77 deletions
81
Dalamud/Interface/Textures/ForwardingTextureWrap.cs
Normal file
81
Dalamud/Interface/Textures/ForwardingTextureWrap.cs
Normal file
|
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>Base class for implementations of <see cref="IDalamudTextureWrap"/> that forwards to another.</summary>
|
||||||
|
public abstract class ForwardingTextureWrap : IDalamudTextureWrap
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IntPtr ImGuiHandle
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.GetWrap().ImGuiHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int Width
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.GetWrap().Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int Height
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.GetWrap().Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Vector2 Size
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => new(this.Width, this.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() => $"{this.GetType()}({(this.TryGetWrap(out var wrap) ? wrap : null)})";
|
||||||
|
|
||||||
|
/// <summary>Called on <see cref="IDisposable.Dispose"/>.</summary>
|
||||||
|
/// <param name="disposing"><c>true</c> if called from <see cref="IDisposable.Dispose"/>.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>Base implementation will not dispose the result of <see cref="TryGetWrap"/>.</para>
|
||||||
|
/// <para>If you need to implement a finalizer, then make it call this function with <c>false</c>.</para>
|
||||||
|
/// </remarks>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the inner wrap.</summary>
|
||||||
|
/// <param name="wrap">The inner wrap.</param>
|
||||||
|
/// <returns><c>true</c> if not disposed and <paramref name="wrap"/> is available.</returns>
|
||||||
|
protected abstract bool TryGetWrap([NotNullWhen(true)] out IDalamudTextureWrap? wrap);
|
||||||
|
|
||||||
|
/// <summary>Gets the inner wrap.</summary>
|
||||||
|
/// <returns>The inner wrap.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected IDalamudTextureWrap GetWrap() =>
|
||||||
|
this.TryGetWrap(out var wrap) ? wrap : throw new ObjectDisposedException(this.GetType().Name);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
|
using Dalamud.Interface.Textures;
|
||||||
using Dalamud.Interface.Textures.Internal;
|
using Dalamud.Interface.Textures.Internal;
|
||||||
|
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
|
|
@ -12,6 +13,8 @@ namespace Dalamud.Interface.Internal;
|
||||||
/// Base TextureWrap interface for all Dalamud-owned texture wraps.
|
/// Base TextureWrap interface for all Dalamud-owned texture wraps.
|
||||||
/// Used to avoid referencing ImGuiScene.
|
/// Used to avoid referencing ImGuiScene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>If you want to implement this, see if you're actually wrapping an existing instance of
|
||||||
|
/// <see cref="IDalamudTextureWrap"/>; if you are, then use <see cref="ForwardingTextureWrap"/>.</remarks>
|
||||||
public interface IDalamudTextureWrap : IDisposable
|
public interface IDalamudTextureWrap : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>Gets a texture handle suitable for direct use with ImGui functions.</summary>
|
/// <summary>Gets a texture handle suitable for direct use with ImGui functions.</summary>
|
||||||
|
|
|
||||||
|
|
@ -2,31 +2,19 @@ using Dalamud.Interface.Internal;
|
||||||
|
|
||||||
namespace Dalamud.Interface.Textures.Internal;
|
namespace Dalamud.Interface.Textures.Internal;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>A texture wrap that ignores <see cref="IDisposable.Dispose"/> calls.</summary>
|
||||||
/// A texture wrap that ignores <see cref="IDisposable.Dispose"/> calls.
|
internal class DisposeSuppressingTextureWrap : ForwardingTextureWrap
|
||||||
/// </summary>
|
|
||||||
internal sealed class DisposeSuppressingTextureWrap : IDalamudTextureWrap
|
|
||||||
{
|
{
|
||||||
private readonly IDalamudTextureWrap innerWrap;
|
private readonly IDalamudTextureWrap innerWrap;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>Initializes a new instance of the <see cref="DisposeSuppressingTextureWrap"/> class.</summary>
|
||||||
/// Initializes a new instance of the <see cref="DisposeSuppressingTextureWrap"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="wrap">The inner wrap.</param>
|
/// <param name="wrap">The inner wrap.</param>
|
||||||
public DisposeSuppressingTextureWrap(IDalamudTextureWrap wrap) => this.innerWrap = wrap;
|
public DisposeSuppressingTextureWrap(IDalamudTextureWrap wrap) => this.innerWrap = wrap;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr ImGuiHandle => this.innerWrap.ImGuiHandle;
|
protected override bool TryGetWrap(out IDalamudTextureWrap? wrap)
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Width => this.innerWrap.Width;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Height => this.innerWrap.Height;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
// suppressed
|
wrap = this.innerWrap;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,46 +363,35 @@ internal abstract class SharedImmediateTexture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class NotOwnedTextureWrap : IDalamudTextureWrap
|
/// <summary>Same with <see cref="DisposeSuppressingTextureWrap"/>, but with a custom implementation of
|
||||||
|
/// <see cref="CreateWrapSharingLowLevelResource"/>.</summary>
|
||||||
|
private sealed class NotOwnedTextureWrap : DisposeSuppressingTextureWrap
|
||||||
{
|
{
|
||||||
private readonly IDalamudTextureWrap innerWrap;
|
|
||||||
private readonly IRefCountable owner;
|
private readonly IRefCountable owner;
|
||||||
|
|
||||||
/// <summary>Initializes a new instance of the <see cref="NotOwnedTextureWrap"/> class.</summary>
|
/// <summary>Initializes a new instance of the <see cref="NotOwnedTextureWrap"/> class.</summary>
|
||||||
/// <param name="wrap">The inner wrap.</param>
|
/// <param name="wrap">The inner wrap.</param>
|
||||||
/// <param name="owner">The reference counting owner.</param>
|
/// <param name="owner">The reference counting owner.</param>
|
||||||
public NotOwnedTextureWrap(IDalamudTextureWrap wrap, IRefCountable owner)
|
public NotOwnedTextureWrap(IDalamudTextureWrap wrap, IRefCountable owner)
|
||||||
|
: base(wrap)
|
||||||
{
|
{
|
||||||
this.innerWrap = wrap;
|
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr ImGuiHandle => this.innerWrap.ImGuiHandle;
|
public override IDalamudTextureWrap CreateWrapSharingLowLevelResource()
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Width => this.innerWrap.Width;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Height => this.innerWrap.Height;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IDalamudTextureWrap CreateWrapSharingLowLevelResource()
|
|
||||||
{
|
{
|
||||||
|
var wrap = this.GetWrap();
|
||||||
this.owner.AddRef();
|
this.owner.AddRef();
|
||||||
return new RefCountableWrappingTextureWrap(this.innerWrap, this.owner);
|
return new RefCountableWrappingTextureWrap(wrap, this.owner);
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string ToString() => $"{nameof(NotOwnedTextureWrap)}({this.owner})";
|
public override string ToString() => $"{nameof(NotOwnedTextureWrap)}({this.owner})";
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class RefCountableWrappingTextureWrap : IDalamudTextureWrap
|
/// <summary>Reference counting texture wrap, to be used with <see cref="RentAsync"/>.</summary>
|
||||||
|
private sealed class RefCountableWrappingTextureWrap : ForwardingTextureWrap
|
||||||
{
|
{
|
||||||
private IDalamudTextureWrap? innerWrap;
|
private IDalamudTextureWrap? innerWrap;
|
||||||
private IRefCountable? owner;
|
private IRefCountable? owner;
|
||||||
|
|
@ -416,22 +405,11 @@ internal abstract class SharedImmediateTexture
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
~RefCountableWrappingTextureWrap() => this.Dispose();
|
/// <summary>Finalizes an instance of the <see cref="RefCountableWrappingTextureWrap"/> class.</summary>
|
||||||
|
~RefCountableWrappingTextureWrap() => this.Dispose(false);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr ImGuiHandle => this.InnerWrapNonDisposed.ImGuiHandle;
|
public override IDalamudTextureWrap CreateWrapSharingLowLevelResource()
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Width => this.InnerWrapNonDisposed.Width;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Height => this.InnerWrapNonDisposed.Height;
|
|
||||||
|
|
||||||
private IDalamudTextureWrap InnerWrapNonDisposed =>
|
|
||||||
this.innerWrap ?? throw new ObjectDisposedException(nameof(RefCountableWrappingTextureWrap));
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IDalamudTextureWrap CreateWrapSharingLowLevelResource()
|
|
||||||
{
|
{
|
||||||
var ownerCopy = this.owner;
|
var ownerCopy = this.owner;
|
||||||
var wrapCopy = this.innerWrap;
|
var wrapCopy = this.innerWrap;
|
||||||
|
|
@ -443,7 +421,13 @@ internal abstract class SharedImmediateTexture
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public override string ToString() => $"{nameof(RefCountableWrappingTextureWrap)}({this.owner})";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override bool TryGetWrap(out IDalamudTextureWrap? wrap) => (wrap = this.innerWrap) is not null;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
@ -455,32 +439,22 @@ internal abstract class SharedImmediateTexture
|
||||||
// Note: do not dispose this; life of the wrap is managed by the owner.
|
// Note: do not dispose this; life of the wrap is managed by the owner.
|
||||||
this.innerWrap = null;
|
this.innerWrap = null;
|
||||||
ownerCopy.Release();
|
ownerCopy.Release();
|
||||||
GC.SuppressFinalize(this);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>A texture wrap that revives and waits for the underlying texture as needed on every access.</summary>
|
||||||
public override string ToString() => $"{nameof(RefCountableWrappingTextureWrap)}({this.owner})";
|
|
||||||
}
|
|
||||||
|
|
||||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||||
private sealed class AvailableOnAccessTextureWrap : IDalamudTextureWrap
|
private sealed class AvailableOnAccessTextureWrap : ForwardingTextureWrap
|
||||||
{
|
{
|
||||||
private readonly SharedImmediateTexture inner;
|
private readonly SharedImmediateTexture inner;
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="AvailableOnAccessTextureWrap"/> class.</summary>
|
||||||
|
/// <param name="inner">The shared texture.</param>
|
||||||
public AvailableOnAccessTextureWrap(SharedImmediateTexture inner) => this.inner = inner;
|
public AvailableOnAccessTextureWrap(SharedImmediateTexture inner) => this.inner = inner;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr ImGuiHandle => this.WaitGet().ImGuiHandle;
|
public override IDalamudTextureWrap CreateWrapSharingLowLevelResource()
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Width => this.WaitGet().Width;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Height => this.WaitGet().Height;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IDalamudTextureWrap CreateWrapSharingLowLevelResource()
|
|
||||||
{
|
{
|
||||||
this.inner.AddRef();
|
this.inner.AddRef();
|
||||||
try
|
try
|
||||||
|
|
@ -506,22 +480,18 @@ internal abstract class SharedImmediateTexture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string ToString() => $"{nameof(AvailableOnAccessTextureWrap)}({this.inner})";
|
public override string ToString() => $"{nameof(AvailableOnAccessTextureWrap)}({this.inner})";
|
||||||
|
|
||||||
private IDalamudTextureWrap WaitGet()
|
/// <inheritdoc/>
|
||||||
|
protected override bool TryGetWrap(out IDalamudTextureWrap? wrap)
|
||||||
{
|
{
|
||||||
if (this.inner.TryGetWrapCore(out var t, out _))
|
if (this.inner.TryGetWrapCore(out var t, out _))
|
||||||
return t;
|
wrap = t;
|
||||||
|
|
||||||
this.inner.UnderlyingWrap?.Wait();
|
this.inner.UnderlyingWrap?.Wait();
|
||||||
return this.inner.nonOwningWrap ?? Service<DalamudAssetManager>.Get().Empty4X4;
|
wrap = this.inner.nonOwningWrap ?? Service<DalamudAssetManager>.Get().Empty4X4;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ internal sealed class ViewportTextureWrap : IDalamudTextureWrap, IDeferredDispos
|
||||||
_ = this.FirstUpdateTask.Exception;
|
_ = this.FirstUpdateTask.Exception;
|
||||||
this.tex.Reset();
|
this.tex.Reset();
|
||||||
this.srv.Reset();
|
this.srv.Reset();
|
||||||
|
this.rtv.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe ComPtr<ID3D11Texture2D> GetImGuiViewportBackBuffer(uint viewportId)
|
private static unsafe ComPtr<ID3D11Texture2D> GetImGuiViewportBackBuffer(uint viewportId)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue