mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-01 05:13:40 +01:00
Move PostPromotion modification functions to PostBuild
These changes are done to ensure that `IFontHandle.Lock` will be guaranteed to obtain a fully built font that will not be modified any further (unless `PostPromotion` is being used for modifying fonts, which should not be done by clients.)
* Moved `CopyGlyphsAcrossFonts` and `BuildLookupTable` from `PostPromotion` to `PostBuild` build toolkit.
* `IFontAtlasBuildToolkit`: Added `GetFont` to enable retrieving font corresponding to a handle being built.
* `InterfaceManager`: Use `OnPostBuild` for copying glyphs from Mono to Default.
* `FontAtlasBuildStep`:
* Removed `Invalid` to prevent an unnecessary switch-case warnings.
* Added contracts on when `IFontAtlas.BuildStepChanged` will be called.
This commit is contained in:
parent
5479149e79
commit
fb8beb9370
8 changed files with 180 additions and 136 deletions
|
|
@ -135,6 +135,19 @@ internal sealed partial class FontAtlasFactory
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr GetFont(IFontHandle fontHandle)
|
||||
{
|
||||
foreach (var s in this.data.Substances)
|
||||
{
|
||||
var f = s.GetFontPtr(fontHandle);
|
||||
if (!f.IsNull())
|
||||
return f;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr IgnoreGlobalScale(ImFontPtr fontPtr)
|
||||
{
|
||||
|
|
@ -608,49 +621,6 @@ internal sealed partial class FontAtlasFactory
|
|||
ArrayPool<byte>.Shared.Return(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementations for <see cref="IFontAtlasBuildToolkitPostPromotion"/>.
|
||||
/// </summary>
|
||||
private class BuildToolkitPostPromotion : IFontAtlasBuildToolkitPostPromotion
|
||||
{
|
||||
private readonly FontAtlasBuiltData builtData;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuildToolkitPostPromotion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="builtData">The built data.</param>
|
||||
public BuildToolkitPostPromotion(FontAtlasBuiltData builtData) => this.builtData = builtData;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr Font { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Scale => this.builtData.Scale;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsAsyncBuildOperation => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FontAtlasBuildStep BuildStep => FontAtlasBuildStep.PostPromotion;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontAtlasPtr NewImAtlas => this.builtData.Atlas;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe ImVectorWrapper<ImFontPtr> Fonts => new(
|
||||
&this.NewImAtlas.NativePtr->Fonts,
|
||||
x => ImGuiNative.ImFont_destroy(x->NativePtr));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T DisposeWithAtlas<T>(T disposable) where T : IDisposable => this.builtData.Garbage.Add(disposable);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GCHandle DisposeWithAtlas(GCHandle gcHandle) => this.builtData.Garbage.Add(gcHandle);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DisposeWithAtlas(Action action) => this.builtData.Garbage.Add(action);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe void CopyGlyphsAcrossFonts(
|
||||
|
|
@ -707,4 +677,60 @@ internal sealed partial class FontAtlasFactory
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementations for <see cref="IFontAtlasBuildToolkitPostPromotion"/>.
|
||||
/// </summary>
|
||||
private class BuildToolkitPostPromotion : IFontAtlasBuildToolkitPostPromotion
|
||||
{
|
||||
private readonly FontAtlasBuiltData builtData;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuildToolkitPostPromotion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="builtData">The built data.</param>
|
||||
public BuildToolkitPostPromotion(FontAtlasBuiltData builtData) => this.builtData = builtData;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr Font { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Scale => this.builtData.Scale;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsAsyncBuildOperation => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FontAtlasBuildStep BuildStep => FontAtlasBuildStep.PostPromotion;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontAtlasPtr NewImAtlas => this.builtData.Atlas;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe ImVectorWrapper<ImFontPtr> Fonts => new(
|
||||
&this.NewImAtlas.NativePtr->Fonts,
|
||||
x => ImGuiNative.ImFont_destroy(x->NativePtr));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T DisposeWithAtlas<T>(T disposable) where T : IDisposable => this.builtData.Garbage.Add(disposable);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GCHandle DisposeWithAtlas(GCHandle gcHandle) => this.builtData.Garbage.Add(gcHandle);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DisposeWithAtlas(Action action) => this.builtData.Garbage.Add(action);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr GetFont(IFontHandle fontHandle)
|
||||
{
|
||||
foreach (var s in this.builtData.Substances)
|
||||
{
|
||||
var f = s.GetFontPtr(fontHandle);
|
||||
if (!f.IsNull())
|
||||
return f;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Interface.GameFonts;
|
||||
|
|
@ -168,7 +167,7 @@ internal sealed partial class FontAtlasFactory
|
|||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
|
||||
public unsafe int Release()
|
||||
public int Release()
|
||||
{
|
||||
switch (IRefCountable.AlterRefCount(-1, ref this.refCount, out var newRefCount))
|
||||
{
|
||||
|
|
@ -176,22 +175,35 @@ internal sealed partial class FontAtlasFactory
|
|||
return newRefCount;
|
||||
|
||||
case IRefCountable.RefCountResult.FinalRelease:
|
||||
if (this.IsBuildInProgress)
|
||||
{
|
||||
Log.Error(
|
||||
"[{name}] 0x{ptr:X}: Trying to dispose while build is in progress; waiting for build.\n" +
|
||||
"Stack:\n{trace}",
|
||||
this.Owner?.Name ?? "<?>",
|
||||
(nint)this.Atlas.NativePtr,
|
||||
new StackTrace());
|
||||
while (this.IsBuildInProgress)
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
#if VeryVerboseLog
|
||||
Log.Verbose("[{name}] 0x{ptr:X}: Disposing", this.Owner?.Name ?? "<?>", (nint)this.Atlas.NativePtr);
|
||||
#endif
|
||||
this.Garbage.Dispose();
|
||||
|
||||
if (this.IsBuildInProgress)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
Log.Error(
|
||||
"[{name}] 0x{ptr:X}: Trying to dispose while build is in progress; disposing later.\n" +
|
||||
"Stack:\n{trace}",
|
||||
this.Owner?.Name ?? "<?>",
|
||||
(nint)this.Atlas.NativePtr,
|
||||
new StackTrace());
|
||||
}
|
||||
|
||||
Task.Run(
|
||||
async () =>
|
||||
{
|
||||
while (this.IsBuildInProgress)
|
||||
await Task.Delay(100);
|
||||
this.Garbage.Dispose();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Garbage.Dispose();
|
||||
}
|
||||
|
||||
return newRefCount;
|
||||
|
||||
case IRefCountable.RefCountResult.AlreadyDisposed:
|
||||
|
|
@ -549,20 +561,10 @@ internal sealed partial class FontAtlasFactory
|
|||
return;
|
||||
}
|
||||
|
||||
var toolkit = new BuildToolkitPostPromotion(data);
|
||||
foreach (var substance in data.Substances)
|
||||
substance.Manager.InvokeFontHandleImFontChanged();
|
||||
|
||||
try
|
||||
{
|
||||
this.BuildStepChange?.Invoke(toolkit);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
"[{name}] {delegateName} PostPromotion error",
|
||||
this.Name,
|
||||
nameof(FontAtlasBuildStepDelegate));
|
||||
}
|
||||
var toolkit = new BuildToolkitPostPromotion(data);
|
||||
|
||||
foreach (var substance in data.Substances)
|
||||
{
|
||||
|
|
@ -580,20 +582,18 @@ internal sealed partial class FontAtlasFactory
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var font in toolkit.Fonts)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
toolkit.BuildLookupTable(font);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "[{name}] BuildLookupTable error", this.Name);
|
||||
}
|
||||
this.BuildStepChange?.Invoke(toolkit);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
"[{name}] {delegateName} PostPromotion error",
|
||||
this.Name,
|
||||
nameof(FontAtlasBuildStepDelegate));
|
||||
}
|
||||
|
||||
foreach (var substance in data.Substances)
|
||||
substance.Manager.InvokeFontHandleImFontChanged();
|
||||
|
||||
#if VeryVerboseLog
|
||||
Log.Verbose("[{name}] Built from {source}.", this.Name, source);
|
||||
|
|
@ -709,6 +709,9 @@ internal sealed partial class FontAtlasFactory
|
|||
toolkit.PostBuildSubstances();
|
||||
this.BuildStepChange?.Invoke(toolkit);
|
||||
|
||||
foreach (var font in toolkit.Fonts)
|
||||
toolkit.BuildLookupTable(font);
|
||||
|
||||
if (this.factory.SceneTask is { IsCompleted: false } sceneTask)
|
||||
{
|
||||
Log.Verbose(
|
||||
|
|
@ -754,6 +757,8 @@ internal sealed partial class FontAtlasFactory
|
|||
}
|
||||
finally
|
||||
{
|
||||
// RS is being dumb
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
toolkit?.Dispose();
|
||||
this.buildQueued = false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue