From 5161053cb34d9a8299beb982c703fe1782f7a55f Mon Sep 17 00:00:00 2001 From: Soreepeong Date: Wed, 24 Jan 2024 00:19:27 +0900 Subject: [PATCH] Move `IFontHandle.ImFontLocked` to `ILockedImFont`+impl --- Dalamud/Interface/GameFonts/GameFontHandle.cs | 2 +- .../Interface/Internal/InterfaceManager.cs | 10 +- .../Widgets/GamePrebakedFontsTestWidget.cs | 2 +- .../Interface/ManagedFontAtlas/IFontHandle.cs | 96 +------------------ .../ManagedFontAtlas/ILockedImFont.cs | 21 ++++ .../FontAtlasFactory.Implementation.cs | 4 +- .../ManagedFontAtlas/Internals/FontHandle.cs | 14 +-- .../Internals/LockedImFont.cs | 62 ++++++++++++ Dalamud/Interface/UiBuilder.cs | 4 +- 9 files changed, 105 insertions(+), 110 deletions(-) create mode 100644 Dalamud/Interface/ManagedFontAtlas/ILockedImFont.cs create mode 100644 Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs diff --git a/Dalamud/Interface/GameFonts/GameFontHandle.cs b/Dalamud/Interface/GameFonts/GameFontHandle.cs index 679452ba4..2594eea0e 100644 --- a/Dalamud/Interface/GameFonts/GameFontHandle.cs +++ b/Dalamud/Interface/GameFonts/GameFontHandle.cs @@ -71,7 +71,7 @@ public sealed class GameFontHandle : IFontHandle public void Dispose() => this.fontHandle.Dispose(); /// - public IFontHandle.ImFontLocked Lock() => this.fontHandle.Lock(); + public ILockedImFont Lock() => this.fontHandle.Lock(); /// public IDisposable Push() => this.fontHandle.Push(); diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 82299a136..6cf4a8b90 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -63,7 +63,7 @@ internal class InterfaceManager : IDisposable, IServiceType public const float DefaultFontSizePx = (DefaultFontSizePt * 4.0f) / 3.0f; private readonly ConcurrentBag deferredDisposeTextures = new(); - private readonly ConcurrentBag deferredDisposeImFontLockeds = new(); + private readonly ConcurrentBag deferredDisposeImFontLockeds = new(); [ServiceManager.ServiceDependency] private readonly WndProcHookManager wndProcHookManager = Service.Get(); @@ -79,7 +79,7 @@ internal class InterfaceManager : IDisposable, IServiceType private Hook? resizeBuffersHook; private IFontAtlas? dalamudAtlas; - private IFontHandle.ImFontLocked? defaultFontResourceLock; + private ILockedImFont? defaultFontResourceLock; // can't access imgui IO before first present call private bool lastWantCapture = false; @@ -408,10 +408,10 @@ internal class InterfaceManager : IDisposable, IServiceType } /// - /// Enqueue an to be disposed at the end of the frame. + /// Enqueue an to be disposed at the end of the frame. /// /// The disposable. - public void EnqueueDeferredDispose(in IFontHandle.ImFontLocked locked) + public void EnqueueDeferredDispose(in ILockedImFont locked) { this.deferredDisposeImFontLockeds.Add(locked); } @@ -738,7 +738,7 @@ internal class InterfaceManager : IDisposable, IServiceType // Update the ImGui default font. unsafe { - ImGui.GetIO().NativePtr->FontDefault = fontLocked; + ImGui.GetIO().NativePtr->FontDefault = fontLocked.ImFont; } // Update the reference to the resources of the default font. diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs index 7b649a895..b486cc7d9 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs @@ -249,7 +249,7 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable await handle.WaitAsync(); var locked = handle.Lock(); garbage.Add(locked); - fonts.Add(locked); + fonts.Add(locked.ImFont); } } catch (ObjectDisposedException) diff --git a/Dalamud/Interface/ManagedFontAtlas/IFontHandle.cs b/Dalamud/Interface/ManagedFontAtlas/IFontHandle.cs index dd3775236..11c26616b 100644 --- a/Dalamud/Interface/ManagedFontAtlas/IFontHandle.cs +++ b/Dalamud/Interface/ManagedFontAtlas/IFontHandle.cs @@ -1,14 +1,7 @@ -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; - -using Dalamud.Interface.Utility; -using Dalamud.Utility; +using System.Threading.Tasks; using ImGuiNET; -using Microsoft.Extensions.ObjectPool; - namespace Dalamud.Interface.ManagedFontAtlas; /// @@ -21,7 +14,7 @@ public interface IFontHandle : IDisposable /// /// The relevant font handle. /// The locked font for this font handle, locked during the call of this delegate. - public delegate void ImFontChangedDelegate(IFontHandle fontHandle, ImFontLocked lockedFont); + public delegate void ImFontChangedDelegate(IFontHandle fontHandle, ILockedImFont lockedFont); /// /// Called when the built instance of has been changed.
@@ -48,13 +41,13 @@ public interface IFontHandle : IDisposable /// , for use in any thread.
/// Modification of the font will exhibit undefined behavior if some other thread also uses the font. ///
- /// An instance of that must be disposed after use. + /// An instance of that must be disposed after use. /// /// Calling . will not unlock the /// locked by this function. /// /// If is false. - ImFontLocked Lock(); + ILockedImFont Lock(); /// /// Pushes the current font into ImGui font stack, if available.
@@ -80,85 +73,4 @@ public interface IFontHandle : IDisposable ///
/// A task containing this . Task WaitAsync(); - - /// - /// The wrapper for , guaranteeing that the associated data will be available as long as - /// this struct is not disposed. - /// - public class ImFontLocked : IDisposable - { - // Using constructor instead of DefaultObjectPoolProvider, since we do not want the pool to call Dispose. - private static readonly ObjectPool Pool = - new DefaultObjectPool(new DefaultPooledObjectPolicy()); - - private IRefCountable? owner; - - /// - /// Finalizes an instance of the class. - /// - ~ImFontLocked() => this.FreeOwner(); - - /// - /// Gets the associated . - /// - public ImFontPtr ImFont { get; private set; } - - public static implicit operator ImFontPtr(ImFontLocked l) => l.ImFont; - - public static unsafe implicit operator ImFont*(ImFontLocked l) => l.ImFont.NativePtr; - - /// - /// Creates a new instance of with an additional reference to the owner. - /// - /// The new locked instance. - public ImFontLocked NewRef() - { - if (this.owner is null) - throw new ObjectDisposedException(nameof(ImFontLocked)); - - var rented = Pool.Get(); - rented.owner = this.owner; - rented.ImFont = this.ImFont; - - this.owner.AddRef(); - return rented; - } - - /// - [SuppressMessage( - "Usage", - "CA1816:Dispose methods should call SuppressFinalize", - Justification = "Dispose returns this object to the pool.")] - public void Dispose() - { - this.FreeOwner(); - Pool.Return(this); - } - - /// - /// Initializes a new instance of the class. - /// Ownership of reference of is transferred. - /// - /// The contained font. - /// The owner. - /// The rented instance of . - internal static ImFontLocked Rent(ImFontPtr font, IRefCountable owner) - { - var rented = Pool.Get(); - Debug.Assert(rented.ImFont.IsNull(), "Rented object must not have its font set"); - rented.ImFont = font; - rented.owner = owner; - return rented; - } - - private void FreeOwner() - { - if (this.owner is null) - return; - - this.owner.Release(); - this.owner = null; - this.ImFont = default; - } - } } diff --git a/Dalamud/Interface/ManagedFontAtlas/ILockedImFont.cs b/Dalamud/Interface/ManagedFontAtlas/ILockedImFont.cs new file mode 100644 index 000000000..9136d2723 --- /dev/null +++ b/Dalamud/Interface/ManagedFontAtlas/ILockedImFont.cs @@ -0,0 +1,21 @@ +using ImGuiNET; + +namespace Dalamud.Interface.ManagedFontAtlas; + +/// +/// The wrapper for , guaranteeing that the associated data will be available as long as +/// this struct is not disposed. +/// +public interface ILockedImFont : IDisposable +{ + /// + /// Gets the associated . + /// + ImFontPtr ImFont { get; } + + /// + /// Creates a new instance of with an additional reference to the owner. + /// + /// The new locked instance. + ILockedImFont NewRef(); +} diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs index 06bc5b7ab..4d636b8cf 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs @@ -534,7 +534,7 @@ internal sealed partial class FontAtlasFactory private void PromoteBuiltData(int rebuildIndex, FontAtlasBuiltData data, [UsedImplicitly] string source) { // Capture the locks inside the lock block, so that the fonts are guaranteed to be the ones just built. - var fontsAndLocks = new List<(FontHandle FontHandle, IFontHandle.ImFontLocked Lock)>(); + var fontsAndLocks = new List<(FontHandle FontHandle, ILockedImFont Lock)>(); using var garbage = new DisposeSafety.ScopedFinalizer(); lock (this.syncRoot) @@ -557,7 +557,7 @@ internal sealed partial class FontAtlasFactory foreach (var fontHandle in substance.RelevantHandles) { substance.DataRoot.AddRef(); - var locked = IFontHandle.ImFontLocked.Rent( + var locked = new LockedImFont( substance.GetFontPtr(fontHandle), substance.DataRoot); fontsAndLocks.Add((fontHandle, garbage.Add(locked))); diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs index f8291cc51..47254a5c9 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs @@ -74,7 +74,7 @@ internal abstract class FontHandle : IFontHandle /// Invokes . /// /// The font, locked during the call of . - public void InvokeImFontChanged(IFontHandle.ImFontLocked font) + public void InvokeImFontChanged(ILockedImFont font) { try { @@ -133,11 +133,11 @@ internal abstract class FontHandle : IFontHandle /// /// The error message, if any. /// - /// An instance of that must be disposed after use on success; + /// An instance of that must be disposed after use on success; /// null with populated on failure. /// /// Still may be thrown. - public IFontHandle.ImFontLocked? TryLock(out string? errorMessage) + public ILockedImFont? TryLock(out string? errorMessage) { IFontHandleSubstance? prevSubstance = default; while (true) @@ -182,12 +182,12 @@ internal abstract class FontHandle : IFontHandle // Transfer the ownership of reference. errorMessage = null; - return IFontHandle.ImFontLocked.Rent(fontPtr, substance.DataRoot); + return new LockedImFont(fontPtr, substance.DataRoot); } } /// - public IFontHandle.ImFontLocked Lock() => + public ILockedImFont Lock() => this.TryLock(out var errorMessage) ?? throw new InvalidOperationException(errorMessage); /// @@ -238,10 +238,10 @@ internal abstract class FontHandle : IFontHandle this.ImFontChanged += OnImFontChanged; this.Disposed += OnDisposed; if (this.Available) - OnImFontChanged(this, default); + OnImFontChanged(this, null); return tcs.Task; - void OnImFontChanged(IFontHandle unused, IFontHandle.ImFontLocked unused2) + void OnImFontChanged(IFontHandle unused, ILockedImFont? unused2) { if (tcs.Task.IsCompletedSuccessfully) return; diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs new file mode 100644 index 000000000..bd50502c8 --- /dev/null +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs @@ -0,0 +1,62 @@ +using Dalamud.Utility; + +using ImGuiNET; + +namespace Dalamud.Interface.ManagedFontAtlas.Internals; + +/// +/// The implementation for . +/// +internal class LockedImFont : ILockedImFont +{ + private IRefCountable? owner; + + /// + /// Initializes a new instance of the class. + /// Ownership of reference of is transferred. + /// + /// The contained font. + /// The owner. + /// The rented instance of . + internal LockedImFont(ImFontPtr font, IRefCountable owner) + { + this.ImFont = font; + this.owner = owner; + } + + /// + /// Finalizes an instance of the class. + /// + ~LockedImFont() => this.FreeOwner(); + + /// + public ImFontPtr ImFont { get; private set; } + + /// + public ILockedImFont NewRef() + { + if (this.owner is null) + throw new ObjectDisposedException(nameof(LockedImFont)); + + var newRef = new LockedImFont(this.ImFont, this.owner); + this.owner.AddRef(); + return newRef; + } + + /// + public void Dispose() + { + this.FreeOwner(); + GC.SuppressFinalize(this); + } + + private void FreeOwner() + { + if (this.owner is null) + return; + + this.owner.Release(); + this.owner = null; + this.ImFont = default; + } +} diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs index b038d44ba..ce5a09b22 100644 --- a/Dalamud/Interface/UiBuilder.cs +++ b/Dalamud/Interface/UiBuilder.cs @@ -761,7 +761,7 @@ public sealed class UiBuilder : IDisposable // Note: do not dispose w; we do not own it } - public IFontHandle.ImFontLocked Lock() => + public ILockedImFont Lock() => this.wrapped?.Lock() ?? throw new ObjectDisposedException(nameof(FontHandleWrapper)); public IDisposable Push() => @@ -775,7 +775,7 @@ public sealed class UiBuilder : IDisposable public override string ToString() => $"{nameof(FontHandleWrapper)}({this.wrapped})"; - private void WrappedOnImFontChanged(IFontHandle obj, IFontHandle.ImFontLocked lockedFont) => + private void WrappedOnImFontChanged(IFontHandle obj, ILockedImFont lockedFont) => this.ImFontChanged?.Invoke(obj, lockedFont); } }