mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-26 18:39:20 +01:00
More cleanup
This commit is contained in:
parent
3415df5d40
commit
3853191c48
7 changed files with 226 additions and 196 deletions
|
|
@ -216,13 +216,37 @@ internal class TexWidget : IDataWindowWidget
|
|||
if (this.renderTargetChoiceInt < 0 || this.renderTargetChoiceInt >= supportedFormats.Length)
|
||||
return;
|
||||
var texTask = this.textureManager.CreateFromExistingTextureAsync(
|
||||
source,
|
||||
source.CreateWrapSharingLowLevelResource(),
|
||||
new(0.25f),
|
||||
new(0.75f),
|
||||
supportedFormats[this.renderTargetChoiceInt]);
|
||||
this.addedTextures.Add(new() { Api10 = texTask });
|
||||
};
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
unsafe
|
||||
{
|
||||
if (t.GetTexture(this.textureManager) is { } source)
|
||||
{
|
||||
var psrv = (ID3D11ShaderResourceView*)source.ImGuiHandle;
|
||||
var rcsrv = psrv->AddRef() - 1;
|
||||
psrv->Release();
|
||||
|
||||
var pres = default(ID3D11Resource*);
|
||||
psrv->GetResource(&pres);
|
||||
var rcres = pres->AddRef() - 1;
|
||||
pres->Release();
|
||||
pres->Release();
|
||||
|
||||
ImGui.TextUnformatted($"RC: Resource({rcres})/View({rcsrv})");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextUnformatted("RC: -");
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,10 +21,6 @@ using ImGuiScene;
|
|||
|
||||
using Lumina.Data.Files;
|
||||
|
||||
using SharpDX;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.DXGI;
|
||||
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||
|
|
@ -249,31 +245,12 @@ internal sealed partial class FontAtlasFactory
|
|||
var fileIndex = textureIndex / 4;
|
||||
var channelIndex = FdtReader.FontTableEntry.TextureChannelOrder[textureIndex % 4];
|
||||
wraps[textureIndex] ??= this.GetChannelTexture(texPathFormat, fileIndex, channelIndex);
|
||||
return CloneTextureWrap(wraps[textureIndex]);
|
||||
return wraps[textureIndex].CreateWrapSharingLowLevelResource();
|
||||
}
|
||||
}
|
||||
|
||||
private static T ExtractResult<T>(Task<T> t) => t.IsCompleted ? t.Result : t.GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Clones a texture wrap, by getting a new reference to the underlying <see cref="ShaderResourceView"/> and the
|
||||
/// texture behind.
|
||||
/// </summary>
|
||||
/// <param name="wrap">The <see cref="IDalamudTextureWrap"/> to clone from.</param>
|
||||
/// <returns>The cloned <see cref="IDalamudTextureWrap"/>.</returns>
|
||||
private static IDalamudTextureWrap CloneTextureWrap(IDalamudTextureWrap wrap)
|
||||
{
|
||||
var srv = CppObject.FromPointer<ShaderResourceView>(wrap.ImGuiHandle);
|
||||
using var res = srv.Resource;
|
||||
using var tex2D = res.QueryInterface<Texture2D>();
|
||||
var description = tex2D.Description;
|
||||
return new DalamudTextureWrap(
|
||||
new D3DTextureWrap(
|
||||
srv.QueryInterface<ShaderResourceView>(),
|
||||
description.Width,
|
||||
description.Height));
|
||||
}
|
||||
|
||||
private static unsafe void ExtractChannelFromB8G8R8A8(
|
||||
Span<byte> target,
|
||||
ReadOnlySpan<byte> source,
|
||||
|
|
@ -384,7 +361,9 @@ internal sealed partial class FontAtlasFactory
|
|||
texFile.Header.Width,
|
||||
texFile.Header.Height,
|
||||
texFile.Header.Width * bpp,
|
||||
(int)(targetIsB4G4R4A4 ? Format.B4G4R4A4_UNorm : Format.B8G8R8A8_UNorm)),
|
||||
(int)(targetIsB4G4R4A4
|
||||
? DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM
|
||||
: DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM)),
|
||||
buffer));
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -72,18 +72,21 @@ internal class TextureLoadThrottler : IServiceType, IDisposable
|
|||
/// <param name="basis">The throttle basis.</param>
|
||||
/// <param name="immediateLoadFunction">The immediate load function.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="disposables">Disposables to dispose when the task completes.</param>
|
||||
/// <returns>The task.</returns>
|
||||
public Task<IDalamudTextureWrap> LoadTextureAsync(
|
||||
IThrottleBasisProvider basis,
|
||||
Func<CancellationToken, Task<IDalamudTextureWrap>> immediateLoadFunction,
|
||||
CancellationToken cancellationToken)
|
||||
CancellationToken cancellationToken,
|
||||
params IDisposable?[] disposables)
|
||||
{
|
||||
var work = new WorkItem(basis, immediateLoadFunction, cancellationToken);
|
||||
var work = new WorkItem(basis, immediateLoadFunction, cancellationToken, disposables);
|
||||
|
||||
return
|
||||
this.newItemChannel.Writer.TryWrite(work)
|
||||
? work.Task
|
||||
: Task.FromException<IDalamudTextureWrap>(new ObjectDisposedException(nameof(TextureLoadThrottler)));
|
||||
if (this.newItemChannel.Writer.TryWrite(work))
|
||||
return work.Task;
|
||||
|
||||
work.Dispose();
|
||||
return Task.FromException<IDalamudTextureWrap>(new ObjectDisposedException(nameof(TextureLoadThrottler)));
|
||||
}
|
||||
|
||||
private async Task LoopAddWorkItemAsync()
|
||||
|
|
@ -118,6 +121,7 @@ internal class TextureLoadThrottler : IServiceType, IDisposable
|
|||
continue;
|
||||
|
||||
await work.Process(this.disposeCancellationTokenSource.Token);
|
||||
work.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +140,7 @@ internal class TextureLoadThrottler : IServiceType, IDisposable
|
|||
{
|
||||
if (itemRef.CancelAsRequested())
|
||||
{
|
||||
itemRef.Dispose();
|
||||
itemRef = lastRef;
|
||||
this.workItemPending.RemoveAt(this.workItemPending.Count - 1);
|
||||
break;
|
||||
|
|
@ -152,7 +157,13 @@ internal class TextureLoadThrottler : IServiceType, IDisposable
|
|||
|
||||
var last = this.workItemPending[^1];
|
||||
this.workItemPending.RemoveAt(this.workItemPending.Count - 1);
|
||||
return last.CancelAsRequested() ? null : last;
|
||||
if (last.CancelAsRequested())
|
||||
{
|
||||
last.Dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,26 +182,34 @@ internal class TextureLoadThrottler : IServiceType, IDisposable
|
|||
public long LatestRequestedTick { get; init; } = Environment.TickCount64;
|
||||
}
|
||||
|
||||
private class WorkItem : IComparable<WorkItem>
|
||||
private sealed class WorkItem : IComparable<WorkItem>, IDisposable
|
||||
{
|
||||
private readonly TaskCompletionSource<IDalamudTextureWrap> taskCompletionSource;
|
||||
private readonly IThrottleBasisProvider basis;
|
||||
private readonly CancellationToken cancellationToken;
|
||||
private readonly Func<CancellationToken, Task<IDalamudTextureWrap>> immediateLoadFunction;
|
||||
private readonly IDisposable?[] disposables;
|
||||
|
||||
public WorkItem(
|
||||
IThrottleBasisProvider basis,
|
||||
Func<CancellationToken, Task<IDalamudTextureWrap>> immediateLoadFunction,
|
||||
CancellationToken cancellationToken)
|
||||
CancellationToken cancellationToken, IDisposable?[] disposables)
|
||||
{
|
||||
this.taskCompletionSource = new();
|
||||
this.basis = basis;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.disposables = disposables;
|
||||
this.immediateLoadFunction = immediateLoadFunction;
|
||||
}
|
||||
|
||||
public Task<IDalamudTextureWrap> Task => this.taskCompletionSource.Task;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (ref var d in this.disposables.AsSpan())
|
||||
Interlocked.Exchange(ref d, null)?.Dispose();
|
||||
}
|
||||
|
||||
public int CompareTo(WorkItem other)
|
||||
{
|
||||
if (this.basis.IsOpportunistic != other.basis.IsOpportunistic)
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@ using Dalamud.Utility;
|
|||
|
||||
using ImGuiNET;
|
||||
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.DXGI;
|
||||
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
|
|
@ -28,14 +25,8 @@ internal sealed partial class TextureManager
|
|||
this.IsDxgiFormatSupportedForCreateFromExistingTextureAsync((DXGI_FORMAT)dxgiFormat);
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.IsDxgiFormatSupportedForCreateFromExistingTextureAsync"/>
|
||||
public bool IsDxgiFormatSupportedForCreateFromExistingTextureAsync(DXGI_FORMAT dxgiFormat)
|
||||
public unsafe bool IsDxgiFormatSupportedForCreateFromExistingTextureAsync(DXGI_FORMAT dxgiFormat)
|
||||
{
|
||||
if (this.interfaceManager.Scene is not { } scene)
|
||||
{
|
||||
_ = Service<InterfaceManager.InterfaceManagerWithScene>.Get();
|
||||
scene = this.interfaceManager.Scene ?? throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
switch (dxgiFormat)
|
||||
{
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
|
||||
|
|
@ -48,12 +39,14 @@ internal sealed partial class TextureManager
|
|||
return false;
|
||||
}
|
||||
|
||||
var format = (Format)dxgiFormat;
|
||||
var support = scene.Device.CheckFormatSupport(format);
|
||||
const FormatSupport required =
|
||||
FormatSupport.RenderTarget |
|
||||
FormatSupport.Texture2D;
|
||||
return (support & required) == required;
|
||||
D3D11_FORMAT_SUPPORT supported;
|
||||
if (this.Device.Get()->CheckFormatSupport(dxgiFormat, (uint*)&supported).FAILED)
|
||||
return false;
|
||||
|
||||
const D3D11_FORMAT_SUPPORT required =
|
||||
D3D11_FORMAT_SUPPORT.D3D11_FORMAT_SUPPORT_TEXTURE2D
|
||||
| D3D11_FORMAT_SUPPORT.D3D11_FORMAT_SUPPORT_RENDER_TARGET;
|
||||
return (supported & required) == required;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -62,61 +55,56 @@ internal sealed partial class TextureManager
|
|||
Vector2 uv0,
|
||||
Vector2 uv1,
|
||||
int dxgiFormat,
|
||||
bool leaveWrapOpen,
|
||||
CancellationToken cancellationToken) =>
|
||||
this.CreateFromExistingTextureAsync(wrap, uv0, uv1, (DXGI_FORMAT)dxgiFormat, cancellationToken);
|
||||
this.CreateFromExistingTextureAsync(
|
||||
wrap,
|
||||
uv0,
|
||||
uv1,
|
||||
(DXGI_FORMAT)dxgiFormat,
|
||||
leaveWrapOpen,
|
||||
cancellationToken);
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.CreateFromExistingTextureAsync"/>
|
||||
public Task<IDalamudTextureWrap> CreateFromExistingTextureAsync(
|
||||
IDalamudTextureWrap wrap,
|
||||
Vector2 uv0,
|
||||
Vector2 uv1,
|
||||
DXGI_FORMAT format,
|
||||
DXGI_FORMAT format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN,
|
||||
bool leaveWrapOpen = false,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var wrapCopy = wrap.CreateWrapSharingLowLevelResource();
|
||||
return this.textureLoadThrottler.LoadTextureAsync(
|
||||
new TextureLoadThrottler.ReadOnlyThrottleBasisProvider(),
|
||||
async _ =>
|
||||
{
|
||||
using var tex = await this.NoThrottleCreateFromExistingTextureAsync(
|
||||
wrapCopy,
|
||||
uv0,
|
||||
uv1,
|
||||
format);
|
||||
using var device = default(ComPtr<ID3D11Device>);
|
||||
using var srv = default(ComPtr<ID3D11ShaderResourceView>);
|
||||
var desc = default(D3D11_TEXTURE2D_DESC);
|
||||
unsafe
|
||||
{
|
||||
tex.Get()->GetDevice(device.GetAddressOf());
|
||||
new TextureLoadThrottler.ReadOnlyThrottleBasisProvider(),
|
||||
ImmediateLoadFunction,
|
||||
cancellationToken,
|
||||
leaveWrapOpen ? null : wrap);
|
||||
|
||||
var srvDesc = new D3D11_SHADER_RESOURCE_VIEW_DESC(
|
||||
tex,
|
||||
D3D_SRV_DIMENSION.D3D11_SRV_DIMENSION_TEXTURE2D);
|
||||
device.Get()->CreateShaderResourceView(
|
||||
(ID3D11Resource*)tex.Get(),
|
||||
&srvDesc,
|
||||
srv.GetAddressOf())
|
||||
.ThrowOnError();
|
||||
async Task<IDalamudTextureWrap> ImmediateLoadFunction(CancellationToken ct)
|
||||
{
|
||||
using var tex = await this.NoThrottleCreateFromExistingTextureAsync(wrap, uv0, uv1, format);
|
||||
|
||||
tex.Get()->GetDesc(&desc);
|
||||
unsafe
|
||||
{
|
||||
var srvDesc = new D3D11_SHADER_RESOURCE_VIEW_DESC(
|
||||
tex,
|
||||
D3D_SRV_DIMENSION.D3D11_SRV_DIMENSION_TEXTURE2D);
|
||||
using var srv = default(ComPtr<ID3D11ShaderResourceView>);
|
||||
this.Device.Get()->CreateShaderResourceView(
|
||||
(ID3D11Resource*)tex.Get(),
|
||||
&srvDesc,
|
||||
srv.GetAddressOf())
|
||||
.ThrowOnError();
|
||||
|
||||
return new UnknownTextureWrap(
|
||||
(IUnknown*)srv.Get(),
|
||||
(int)desc.Width,
|
||||
(int)desc.Height,
|
||||
true);
|
||||
}
|
||||
},
|
||||
cancellationToken)
|
||||
.ContinueWith(
|
||||
r =>
|
||||
{
|
||||
wrapCopy.Dispose();
|
||||
return r;
|
||||
},
|
||||
default(CancellationToken))
|
||||
.Unwrap();
|
||||
var desc = default(D3D11_TEXTURE2D_DESC);
|
||||
tex.Get()->GetDesc(&desc);
|
||||
return new UnknownTextureWrap(
|
||||
(IUnknown*)srv.Get(),
|
||||
(int)desc.Width,
|
||||
(int)desc.Height,
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -125,34 +113,37 @@ internal sealed partial class TextureManager
|
|||
Vector2 uv0,
|
||||
Vector2 uv1,
|
||||
int dxgiFormat,
|
||||
bool leaveWrapOpen,
|
||||
CancellationToken cancellationToken) =>
|
||||
this.GetRawDataFromExistingTextureAsync(wrap, uv0, uv1, (DXGI_FORMAT)dxgiFormat, cancellationToken);
|
||||
this.GetRawDataFromExistingTextureAsync(
|
||||
wrap,
|
||||
uv0,
|
||||
uv1,
|
||||
(DXGI_FORMAT)dxgiFormat,
|
||||
leaveWrapOpen,
|
||||
cancellationToken);
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.GetRawDataFromExistingTextureAsync"/>
|
||||
public async Task<(RawImageSpecification Specification, byte[] RawData)> GetRawDataFromExistingTextureAsync(
|
||||
IDalamudTextureWrap wrap,
|
||||
Vector2 uv0,
|
||||
Vector2 uv1,
|
||||
DXGI_FORMAT dxgiFormat,
|
||||
CancellationToken cancellationToken)
|
||||
DXGI_FORMAT dxgiFormat = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN,
|
||||
bool leaveWrapOpen = false,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var resUnk = default(ComPtr<IUnknown>);
|
||||
using var wrapDispose = leaveWrapOpen ? null : wrap;
|
||||
using var texSrv = default(ComPtr<ID3D11ShaderResourceView>);
|
||||
using var device = default(ComPtr<ID3D11Device>);
|
||||
using var context = default(ComPtr<ID3D11DeviceContext>);
|
||||
using var tex2D = default(ComPtr<ID3D11Texture2D>);
|
||||
var texDesc = default(D3D11_TEXTURE2D_DESC);
|
||||
|
||||
unsafe
|
||||
{
|
||||
resUnk.Attach((IUnknown*)wrap.ImGuiHandle);
|
||||
resUnk.Get()->AddRef();
|
||||
fixed (Guid* piid = &IID.IID_ID3D11ShaderResourceView)
|
||||
((IUnknown*)wrap.ImGuiHandle)->QueryInterface(piid, (void**)texSrv.GetAddressOf()).ThrowOnError();
|
||||
|
||||
resUnk.As(&texSrv).ThrowOnError();
|
||||
|
||||
texSrv.Get()->GetDevice(device.GetAddressOf());
|
||||
|
||||
device.Get()->GetImmediateContext(context.GetAddressOf());
|
||||
this.Device.Get()->GetImmediateContext(context.GetAddressOf());
|
||||
|
||||
using (var texRes = default(ComPtr<ID3D11Resource>))
|
||||
{
|
||||
|
|
@ -177,7 +168,7 @@ internal sealed partial class TextureManager
|
|||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await this.interfaceManager.RunBeforePresent(
|
||||
() => ExtractMappedResource(device, context, tex2D, cancellationToken));
|
||||
() => ExtractMappedResource(this.Device, context, tex2D, cancellationToken));
|
||||
|
||||
static unsafe (RawImageSpecification Specification, byte[] RawData) ExtractMappedResource(
|
||||
ComPtr<ID3D11Device> device,
|
||||
|
|
@ -242,28 +233,17 @@ internal sealed partial class TextureManager
|
|||
Vector2 uv1,
|
||||
DXGI_FORMAT format)
|
||||
{
|
||||
using var resUnk = default(ComPtr<IUnknown>);
|
||||
using var texSrv = default(ComPtr<ID3D11ShaderResourceView>);
|
||||
using var device = default(ComPtr<ID3D11Device>);
|
||||
using var context = default(ComPtr<ID3D11DeviceContext>);
|
||||
using var tex2D = default(ComPtr<ID3D11Texture2D>);
|
||||
var texDesc = default(D3D11_TEXTURE2D_DESC);
|
||||
|
||||
unsafe
|
||||
{
|
||||
resUnk.Attach((IUnknown*)wrap.ImGuiHandle);
|
||||
resUnk.Get()->AddRef();
|
||||
fixed (Guid* piid = &IID.IID_ID3D11ShaderResourceView)
|
||||
((IUnknown*)wrap.ImGuiHandle)->QueryInterface(piid, (void**)texSrv.GetAddressOf()).ThrowOnError();
|
||||
|
||||
using (var texSrv2 = default(ComPtr<ID3D11ShaderResourceView>))
|
||||
{
|
||||
resUnk.As(&texSrv2).ThrowOnError();
|
||||
texSrv.Attach(texSrv2);
|
||||
texSrv2.Detach();
|
||||
}
|
||||
|
||||
texSrv.Get()->GetDevice(device.GetAddressOf());
|
||||
|
||||
device.Get()->GetImmediateContext(context.GetAddressOf());
|
||||
this.Device.Get()->GetImmediateContext(context.GetAddressOf());
|
||||
|
||||
using (var texRes = default(ComPtr<ID3D11Resource>))
|
||||
{
|
||||
|
|
@ -274,6 +254,9 @@ internal sealed partial class TextureManager
|
|||
tex2D.Get()->GetDesc(&texDesc);
|
||||
}
|
||||
|
||||
if (format == DXGI_FORMAT.DXGI_FORMAT_UNKNOWN)
|
||||
format = texDesc.Format;
|
||||
|
||||
var newWidth = checked((uint)MathF.Round((uv1.X - uv0.X) * texDesc.Width));
|
||||
var newHeight = checked((uint)MathF.Round((uv1.Y - uv0.Y) * texDesc.Height));
|
||||
|
||||
|
|
@ -289,11 +272,12 @@ internal sealed partial class TextureManager
|
|||
Format = format,
|
||||
SampleDesc = new(1, 0),
|
||||
Usage = D3D11_USAGE.D3D11_USAGE_DEFAULT,
|
||||
BindFlags = (uint)(D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_FLAG.D3D11_BIND_RENDER_TARGET),
|
||||
BindFlags =
|
||||
(uint)(D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_FLAG.D3D11_BIND_RENDER_TARGET),
|
||||
CPUAccessFlags = 0u,
|
||||
MiscFlags = 0u,
|
||||
};
|
||||
device.Get()->CreateTexture2D(&tex2DCopyTempDesc, null, tex2DCopyTemp.GetAddressOf()).ThrowOnError();
|
||||
this.Device.Get()->CreateTexture2D(&tex2DCopyTempDesc, null, tex2DCopyTemp.GetAddressOf()).ThrowOnError();
|
||||
}
|
||||
|
||||
await this.interfaceManager.RunBeforePresent(
|
||||
|
|
@ -305,13 +289,13 @@ internal sealed partial class TextureManager
|
|||
var rtvCopyTempDesc = new D3D11_RENDER_TARGET_VIEW_DESC(
|
||||
tex2DCopyTemp,
|
||||
D3D11_RTV_DIMENSION.D3D11_RTV_DIMENSION_TEXTURE2D);
|
||||
device.Get()->CreateRenderTargetView(
|
||||
this.Device.Get()->CreateRenderTargetView(
|
||||
(ID3D11Resource*)tex2DCopyTemp.Get(),
|
||||
&rtvCopyTempDesc,
|
||||
rtvCopyTemp.GetAddressOf()).ThrowOnError();
|
||||
|
||||
this.drawsOneSquare ??= new();
|
||||
this.drawsOneSquare.Setup(device.Get());
|
||||
this.drawsOneSquare.Setup(this.Device.Get());
|
||||
|
||||
context.Get()->OMSetRenderTargets(1u, rtvCopyTemp.GetAddressOf(), null);
|
||||
this.drawsOneSquare.Draw(
|
||||
|
|
@ -593,6 +577,9 @@ internal sealed partial class TextureManager
|
|||
ctx->DSSetShader(null, null, 0);
|
||||
ctx->CSSetShader(null, null, 0);
|
||||
ctx->DrawIndexed(6, 0, 0);
|
||||
|
||||
var ppn = default(ID3D11ShaderResourceView*);
|
||||
ctx->PSSetShaderResources(0, 1, &ppn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,23 +37,21 @@ internal sealed partial class TextureManager
|
|||
IDalamudTextureWrap wrap,
|
||||
Guid containerGuid,
|
||||
Stream stream,
|
||||
bool leaveOpen = false,
|
||||
IReadOnlyDictionary<string, object>? props = null,
|
||||
bool leaveWrapOpen = false,
|
||||
bool leaveStreamOpen = false,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var istream = ManagedIStream.Create(stream, leaveOpen);
|
||||
using var wrapDispose = leaveWrapOpen ? null : wrap;
|
||||
using var istream = ManagedIStream.Create(stream, leaveStreamOpen);
|
||||
|
||||
RawImageSpecification specs;
|
||||
byte[] bytes;
|
||||
using (var wrapCopy = wrap.CreateWrapSharingLowLevelResource())
|
||||
{
|
||||
(specs, bytes) = await this.GetRawDataFromExistingTextureAsync(
|
||||
wrapCopy,
|
||||
var (specs, bytes) = await this.GetRawDataFromExistingTextureAsync(
|
||||
wrap,
|
||||
Vector2.Zero,
|
||||
Vector2.One,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
true,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
this.Wic.SaveToStreamUsingWic(
|
||||
specs,
|
||||
|
|
@ -70,12 +68,21 @@ internal sealed partial class TextureManager
|
|||
Guid containerGuid,
|
||||
string path,
|
||||
IReadOnlyDictionary<string, object>? props = null,
|
||||
bool leaveWrapOpen = false,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var wrapDispose = leaveWrapOpen ? null : wrap;
|
||||
var pathTemp = $"{path}.{GetCurrentThreadId():X08}{Environment.TickCount64:X16}.tmp";
|
||||
try
|
||||
{
|
||||
await this.SaveToStreamAsync(wrap, containerGuid, File.Create(pathTemp), false, props, cancellationToken);
|
||||
await this.SaveToStreamAsync(
|
||||
wrap,
|
||||
containerGuid,
|
||||
File.Create(pathTemp),
|
||||
props,
|
||||
true,
|
||||
false,
|
||||
cancellationToken);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,12 +16,8 @@ using Dalamud.Utility;
|
|||
using Lumina.Data;
|
||||
using Lumina.Data.Files;
|
||||
|
||||
using SharpDX;
|
||||
using SharpDX.Direct3D;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.DXGI;
|
||||
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Dalamud.Interface.Textures.Internal;
|
||||
|
||||
|
|
@ -67,6 +63,23 @@ internal sealed partial class TextureManager : IServiceType, IDisposable, ITextu
|
|||
this.wicManager = new(this);
|
||||
}
|
||||
|
||||
/// <summary>Gets the D3D11 Device used to create textures.</summary>
|
||||
public unsafe ComPtr<ID3D11Device> Device
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.interfaceManager.Scene is not { } scene)
|
||||
{
|
||||
_ = Service<InterfaceManager.InterfaceManagerWithScene>.Get();
|
||||
scene = this.interfaceManager.Scene ?? throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var device = default(ComPtr<ID3D11Device>);
|
||||
device.Attach((ID3D11Device*)scene.Device.NativePointer);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets the shared texture manager.</summary>
|
||||
public SharedTextureManager Shared =>
|
||||
this.sharedTextureManager ??
|
||||
|
|
@ -183,65 +196,54 @@ internal sealed partial class TextureManager : IServiceType, IDisposable, ITextu
|
|||
this.IsDxgiFormatSupported((DXGI_FORMAT)dxgiFormat);
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.IsDxgiFormatSupported"/>
|
||||
public bool IsDxgiFormatSupported(DXGI_FORMAT dxgiFormat)
|
||||
public unsafe bool IsDxgiFormatSupported(DXGI_FORMAT dxgiFormat)
|
||||
{
|
||||
if (this.interfaceManager.Scene is not { } scene)
|
||||
{
|
||||
_ = Service<InterfaceManager.InterfaceManagerWithScene>.Get();
|
||||
scene = this.interfaceManager.Scene ?? throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var format = (Format)dxgiFormat;
|
||||
var support = scene.Device.CheckFormatSupport(format);
|
||||
const FormatSupport required = FormatSupport.Texture2D;
|
||||
return (support & required) == required;
|
||||
D3D11_FORMAT_SUPPORT supported;
|
||||
if (this.Device.Get()->CheckFormatSupport(dxgiFormat, (uint*)&supported).FAILED)
|
||||
return false;
|
||||
|
||||
const D3D11_FORMAT_SUPPORT required = D3D11_FORMAT_SUPPORT.D3D11_FORMAT_SUPPORT_TEXTURE2D;
|
||||
return (supported & required) == required;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.CreateFromRaw"/>
|
||||
internal IDalamudTextureWrap NoThrottleCreateFromRaw(
|
||||
internal unsafe IDalamudTextureWrap NoThrottleCreateFromRaw(
|
||||
RawImageSpecification specs,
|
||||
ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (this.interfaceManager.Scene is not { } scene)
|
||||
var device = this.Device;
|
||||
|
||||
var texd = new D3D11_TEXTURE2D_DESC
|
||||
{
|
||||
_ = Service<InterfaceManager.InterfaceManagerWithScene>.Get();
|
||||
scene = this.interfaceManager.Scene ?? throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
ShaderResourceView resView;
|
||||
unsafe
|
||||
Width = (uint)specs.Width,
|
||||
Height = (uint)specs.Height,
|
||||
MipLevels = 1,
|
||||
ArraySize = 1,
|
||||
Format = (DXGI_FORMAT)specs.DxgiFormat,
|
||||
SampleDesc = new(1, 0),
|
||||
Usage = D3D11_USAGE.D3D11_USAGE_IMMUTABLE,
|
||||
BindFlags = (uint)D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE,
|
||||
CPUAccessFlags = 0,
|
||||
MiscFlags = 0,
|
||||
};
|
||||
using var texture = default(ComPtr<ID3D11Texture2D>);
|
||||
fixed (void* dataPtr = bytes)
|
||||
{
|
||||
fixed (void* pData = bytes)
|
||||
{
|
||||
var texDesc = new Texture2DDescription
|
||||
{
|
||||
Width = specs.Width,
|
||||
Height = specs.Height,
|
||||
MipLevels = 1,
|
||||
ArraySize = 1,
|
||||
Format = (Format)specs.DxgiFormat,
|
||||
SampleDescription = new(1, 0),
|
||||
Usage = ResourceUsage.Immutable,
|
||||
BindFlags = BindFlags.ShaderResource,
|
||||
CpuAccessFlags = CpuAccessFlags.None,
|
||||
OptionFlags = ResourceOptionFlags.None,
|
||||
};
|
||||
|
||||
using var texture = new Texture2D(scene.Device, texDesc, new DataRectangle(new(pData), specs.Pitch));
|
||||
resView = new(
|
||||
scene.Device,
|
||||
texture,
|
||||
new()
|
||||
{
|
||||
Format = texDesc.Format,
|
||||
Dimension = ShaderResourceViewDimension.Texture2D,
|
||||
Texture2D = { MipLevels = texDesc.MipLevels },
|
||||
});
|
||||
}
|
||||
var subrdata = new D3D11_SUBRESOURCE_DATA { pSysMem = dataPtr, SysMemPitch = (uint)specs.Pitch };
|
||||
device.Get()->CreateTexture2D(&texd, &subrdata, texture.GetAddressOf()).ThrowOnError();
|
||||
}
|
||||
|
||||
var viewDesc = new D3D11_SHADER_RESOURCE_VIEW_DESC
|
||||
{
|
||||
Format = texd.Format,
|
||||
ViewDimension = D3D_SRV_DIMENSION.D3D11_SRV_DIMENSION_TEXTURE2D,
|
||||
Texture2D = new() { MipLevels = texd.MipLevels },
|
||||
};
|
||||
using var view = default(ComPtr<ID3D11ShaderResourceView>);
|
||||
device.Get()->CreateShaderResourceView((ID3D11Resource*)texture.Get(), &viewDesc, view.GetAddressOf())
|
||||
.ThrowOnError();
|
||||
|
||||
// no sampler for now because the ImGui implementation we copied doesn't allow for changing it
|
||||
return new DalamudTextureWrap(new D3DTextureWrap(resView, specs.Width, specs.Height));
|
||||
return new UnknownTextureWrap((IUnknown*)view.Get(), specs.Width, specs.Height, true);
|
||||
}
|
||||
|
||||
/// <summary>Creates a texture from the given <see cref="TexFile"/>. Skips the load throttler; intended to be used
|
||||
|
|
@ -257,7 +259,7 @@ internal sealed partial class TextureManager : IServiceType, IDisposable, ITextu
|
|||
if (conversion != TexFile.DxgiFormatConversion.NoConversion ||
|
||||
!this.IsDxgiFormatSupported((DXGI_FORMAT)dxgiFormat))
|
||||
{
|
||||
dxgiFormat = (int)Format.B8G8R8A8_UNorm;
|
||||
dxgiFormat = (int)DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
buffer = buffer.Filter(0, 0, TexFile.TextureFormat.B8G8R8A8);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ public partial interface ITextureProvider
|
|||
/// without having to wait for the completion of the returned <see cref="Task{TResult}"/>.</param>
|
||||
/// <param name="uv0">The left top coordinates relative to the size of the source texture.</param>
|
||||
/// <param name="uv1">The right bottom coordinates relative to the size of the source texture.</param>
|
||||
/// <param name="dxgiFormat">The desired target format.</param>
|
||||
/// <param name="dxgiFormat">The desired target format. Use 0 to use the source format.</param>
|
||||
/// <param name="leaveWrapOpen">Whether to leave <paramref name="wrap"/> non-disposed when the returned
|
||||
/// <see cref="Task{TResult}"/> completes.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> containing the copied texture on success. Dispose after use.</returns>
|
||||
/// <remarks>
|
||||
|
|
@ -49,7 +51,8 @@ public partial interface ITextureProvider
|
|||
IDalamudTextureWrap wrap,
|
||||
Vector2 uv0,
|
||||
Vector2 uv1,
|
||||
int dxgiFormat,
|
||||
int dxgiFormat = 0,
|
||||
bool leaveWrapOpen = false,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Gets a texture from the given bytes, trying to interpret it as a .tex file or other well-known image
|
||||
|
|
@ -185,12 +188,13 @@ public partial interface ITextureProvider
|
|||
bool TryGetIconPath(in GameIconLookup lookup, [NotNullWhen(true)] out string? path);
|
||||
|
||||
/// <summary>Gets the raw data of a texture wrap.</summary>
|
||||
/// <param name="wrap">The source texture wrap. The passed value may be disposed once this function returns,
|
||||
/// without having to wait for the completion of the returned <see cref="Task{TResult}"/>.</param>
|
||||
/// <param name="wrap">The source texture wrap.</param>
|
||||
/// <param name="uv0">The left top coordinates relative to the size of the source texture.</param>
|
||||
/// <param name="uv1">The right bottom coordinates relative to the size of the source texture.</param>
|
||||
/// <param name="dxgiFormat">The desired target format.
|
||||
/// If 0 (unknown) is passed, then the format will not be converted.</param>
|
||||
/// <param name="leaveWrapOpen">Whether to leave <paramref name="wrap"/> non-disposed when the returned
|
||||
/// <see cref="Task{TResult}"/> completes.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The raw data and its specifications.</returns>
|
||||
/// <remarks>
|
||||
|
|
@ -206,27 +210,32 @@ public partial interface ITextureProvider
|
|||
Vector2 uv0,
|
||||
Vector2 uv1,
|
||||
int dxgiFormat = 0,
|
||||
bool leaveWrapOpen = false,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Saves a texture wrap to a stream in an image file format.</summary>
|
||||
/// <param name="wrap">The texture wrap to save.</param>
|
||||
/// <param name="containerGuid">The container GUID, obtained from <see cref="GetSupportedImageEncoderInfos"/>.</param>
|
||||
/// <param name="stream">The stream to save to.</param>
|
||||
/// <param name="leaveOpen">Whether to leave <paramref name="stream"/> open.</param>
|
||||
/// <param name="props">Properties to pass to the encoder. See
|
||||
/// <a href="https://learn.microsoft.com/en-us/windows/win32/wic/-wic-creating-encoder#encoder-options">Microsoft
|
||||
/// Learn</a> for available parameters.</param>
|
||||
/// <param name="leaveWrapOpen">Whether to leave <paramref name="wrap"/> non-disposed when the returned
|
||||
/// <see cref="Task{TResult}"/> completes.</param>
|
||||
/// <param name="leaveStreamOpen">Whether to leave <paramref name="stream"/> open when the returned
|
||||
/// <see cref="Task{TResult}"/> completes.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the save process.</returns>
|
||||
/// <remarks>
|
||||
/// <para><paramref name="wrap"/> may be disposed as soon as this function returns.</para>
|
||||
/// <para><paramref name="wrap"/> must not be disposed until the task finishes.</para>
|
||||
/// </remarks>
|
||||
Task SaveToStreamAsync(
|
||||
IDalamudTextureWrap wrap,
|
||||
Guid containerGuid,
|
||||
Stream stream,
|
||||
bool leaveOpen = false,
|
||||
IReadOnlyDictionary<string, object>? props = null,
|
||||
bool leaveWrapOpen = false,
|
||||
bool leaveStreamOpen = false,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Saves a texture wrap to a file as an image file.</summary>
|
||||
|
|
@ -236,16 +245,19 @@ public partial interface ITextureProvider
|
|||
/// <param name="props">Properties to pass to the encoder. See
|
||||
/// <a href="https://learn.microsoft.com/en-us/windows/win32/wic/-wic-creating-encoder#encoder-options">Microsoft
|
||||
/// Learn</a> for available parameters.</param>
|
||||
/// <param name="leaveWrapOpen">Whether to leave <paramref name="wrap"/> non-disposed when the returned
|
||||
/// <see cref="Task{TResult}"/> completes.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A task representing the save process.</returns>
|
||||
/// <remarks>
|
||||
/// <para><paramref name="wrap"/> may be disposed as soon as this function returns.</para>
|
||||
/// <para><paramref name="wrap"/> must not be disposed until the task finishes.</para>
|
||||
/// </remarks>
|
||||
Task SaveToFileAsync(
|
||||
IDalamudTextureWrap wrap,
|
||||
Guid containerGuid,
|
||||
string path,
|
||||
IReadOnlyDictionary<string, object>? props = null,
|
||||
bool leaveWrapOpen = false,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue