mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-02 05:43:40 +01:00
cleanup
This commit is contained in:
parent
5fd7457df4
commit
0a658477c6
3 changed files with 230 additions and 178 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
|
@ -57,7 +58,9 @@ internal sealed partial class TextureManager
|
||||||
|
|
||||||
async Task<IDalamudTextureWrap> ImmediateLoadFunction(CancellationToken ct)
|
async Task<IDalamudTextureWrap> ImmediateLoadFunction(CancellationToken ct)
|
||||||
{
|
{
|
||||||
using var tex = await this.NoThrottleCreateFromExistingTextureAsync(wrap, args);
|
// leaveWrapOpen is taken care from calling LoadTextureAsync
|
||||||
|
using var wrapAux = new WrapAux(wrap, true);
|
||||||
|
using var tex = await this.NoThrottleCreateFromExistingTextureAsync(wrapAux, args);
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
|
|
@ -100,34 +103,19 @@ internal sealed partial class TextureManager
|
||||||
bool leaveWrapOpen = false,
|
bool leaveWrapOpen = false,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
using var wrapDispose = leaveWrapOpen ? null : wrap;
|
using var wrapAux = new WrapAux(wrap, leaveWrapOpen);
|
||||||
using var texSrv = default(ComPtr<ID3D11ShaderResourceView>);
|
return await this.GetRawImageAsync(wrapAux, args, cancellationToken);
|
||||||
using var context = default(ComPtr<ID3D11DeviceContext>);
|
}
|
||||||
using var tex2D = default(ComPtr<ID3D11Texture2D>);
|
|
||||||
var texDesc = default(D3D11_TEXTURE2D_DESC);
|
|
||||||
|
|
||||||
unsafe
|
private async Task<(RawImageSpecification Specification, byte[] RawData)> GetRawImageAsync(
|
||||||
|
WrapAux wrapAux,
|
||||||
|
TextureModificationArgs args = default,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
using var tex2D = wrapAux.NewTexRef();
|
||||||
|
if (!args.IsCompleteSourceCopy(wrapAux.Desc))
|
||||||
{
|
{
|
||||||
fixed (Guid* piid = &IID.IID_ID3D11ShaderResourceView)
|
using var tmp = await this.NoThrottleCreateFromExistingTextureAsync(wrapAux, args);
|
||||||
((IUnknown*)wrap.ImGuiHandle)->QueryInterface(piid, (void**)texSrv.GetAddressOf()).ThrowOnError();
|
|
||||||
|
|
||||||
this.Device.Get()->GetImmediateContext(context.GetAddressOf());
|
|
||||||
|
|
||||||
using (var texRes = default(ComPtr<ID3D11Resource>))
|
|
||||||
{
|
|
||||||
texSrv.Get()->GetResource(texRes.GetAddressOf());
|
|
||||||
|
|
||||||
using var tex2DTemp = default(ComPtr<ID3D11Texture2D>);
|
|
||||||
texRes.As(&tex2DTemp).ThrowOnError();
|
|
||||||
tex2D.Swap(&tex2DTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
tex2D.Get()->GetDesc(&texDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!args.IsCompleteSourceCopy(texDesc))
|
|
||||||
{
|
|
||||||
using var tmp = await this.NoThrottleCreateFromExistingTextureAsync(wrap, args);
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
tex2D.Swap(&tmp);
|
tex2D.Swap(&tmp);
|
||||||
|
|
@ -136,11 +124,10 @@ internal sealed partial class TextureManager
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
return await this.interfaceManager.RunBeforeImGuiRender(
|
return await this.interfaceManager.RunBeforeImGuiRender(
|
||||||
() => ExtractMappedResource(this.Device, context, tex2D, cancellationToken));
|
() => ExtractMappedResource(wrapAux, tex2D, cancellationToken));
|
||||||
|
|
||||||
static unsafe (RawImageSpecification Specification, byte[] RawData) ExtractMappedResource(
|
static unsafe (RawImageSpecification Specification, byte[] RawData) ExtractMappedResource(
|
||||||
ComPtr<ID3D11Device> device,
|
in WrapAux wrapAux,
|
||||||
ComPtr<ID3D11DeviceContext> context,
|
|
||||||
ComPtr<ID3D11Texture2D> tex2D,
|
ComPtr<ID3D11Texture2D> tex2D,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
@ -150,11 +137,9 @@ internal sealed partial class TextureManager
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var tmpTex = default(ComPtr<ID3D11Texture2D>);
|
using var tmpTex = default(ComPtr<ID3D11Texture2D>);
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
if ((wrapAux.Desc.CPUAccessFlags & (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ) == 0)
|
||||||
tex2D.Get()->GetDesc(&desc);
|
|
||||||
if ((desc.CPUAccessFlags & (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ) == 0)
|
|
||||||
{
|
{
|
||||||
var tmpTexDesc = desc with
|
var tmpTexDesc = wrapAux.Desc with
|
||||||
{
|
{
|
||||||
MipLevels = 1,
|
MipLevels = 1,
|
||||||
ArraySize = 1,
|
ArraySize = 1,
|
||||||
|
|
@ -164,15 +149,15 @@ internal sealed partial class TextureManager
|
||||||
CPUAccessFlags = (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ,
|
CPUAccessFlags = (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ,
|
||||||
MiscFlags = 0u,
|
MiscFlags = 0u,
|
||||||
};
|
};
|
||||||
device.Get()->CreateTexture2D(&tmpTexDesc, null, tmpTex.GetAddressOf()).ThrowOnError();
|
wrapAux.DevPtr->CreateTexture2D(&tmpTexDesc, null, tmpTex.GetAddressOf()).ThrowOnError();
|
||||||
context.Get()->CopyResource((ID3D11Resource*)tmpTex.Get(), (ID3D11Resource*)tex2D.Get());
|
wrapAux.CtxPtr->CopyResource((ID3D11Resource*)tmpTex.Get(), (ID3D11Resource*)tex2D.Get());
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||||
mapWhat = (ID3D11Resource*)(tmpTex.IsEmpty() ? tex2D.Get() : tmpTex.Get());
|
mapWhat = (ID3D11Resource*)(tmpTex.IsEmpty() ? tex2D.Get() : tmpTex.Get());
|
||||||
context.Get()->Map(
|
wrapAux.CtxPtr->Map(
|
||||||
mapWhat,
|
mapWhat,
|
||||||
0,
|
0,
|
||||||
D3D11_MAP.D3D11_MAP_READ,
|
D3D11_MAP.D3D11_MAP_READ,
|
||||||
|
|
@ -180,9 +165,9 @@ internal sealed partial class TextureManager
|
||||||
&mapped).ThrowOnError();
|
&mapped).ThrowOnError();
|
||||||
|
|
||||||
var specs = new RawImageSpecification(
|
var specs = new RawImageSpecification(
|
||||||
(int)desc.Width,
|
(int)wrapAux.Desc.Width,
|
||||||
(int)desc.Height,
|
(int)wrapAux.Desc.Height,
|
||||||
(int)desc.Format,
|
(int)wrapAux.Desc.Format,
|
||||||
(int)mapped.RowPitch);
|
(int)mapped.RowPitch);
|
||||||
var bytes = new Span<byte>(mapped.pData, checked((int)mapped.DepthPitch)).ToArray();
|
var bytes = new Span<byte>(mapped.pData, checked((int)mapped.DepthPitch)).ToArray();
|
||||||
return (specs, bytes);
|
return (specs, bytes);
|
||||||
|
|
@ -190,44 +175,23 @@ internal sealed partial class TextureManager
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (mapWhat is not null)
|
if (mapWhat is not null)
|
||||||
context.Get()->Unmap(mapWhat, 0);
|
wrapAux.CtxPtr->Unmap(mapWhat, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ComPtr<ID3D11Texture2D>> NoThrottleCreateFromExistingTextureAsync(
|
private async Task<ComPtr<ID3D11Texture2D>> NoThrottleCreateFromExistingTextureAsync(
|
||||||
IDalamudTextureWrap wrap,
|
WrapAux wrapAux,
|
||||||
TextureModificationArgs args)
|
TextureModificationArgs args)
|
||||||
{
|
{
|
||||||
args.ThrowOnInvalidValues();
|
args.ThrowOnInvalidValues();
|
||||||
|
|
||||||
using var texSrv = default(ComPtr<ID3D11ShaderResourceView>);
|
|
||||||
using var context = default(ComPtr<ID3D11DeviceContext>);
|
|
||||||
using var tex2D = default(ComPtr<ID3D11Texture2D>);
|
|
||||||
var texDesc = default(D3D11_TEXTURE2D_DESC);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (Guid* piid = &IID.IID_ID3D11ShaderResourceView)
|
|
||||||
((IUnknown*)wrap.ImGuiHandle)->QueryInterface(piid, (void**)texSrv.GetAddressOf()).ThrowOnError();
|
|
||||||
|
|
||||||
this.Device.Get()->GetImmediateContext(context.GetAddressOf());
|
|
||||||
|
|
||||||
using (var texRes = default(ComPtr<ID3D11Resource>))
|
|
||||||
{
|
|
||||||
texSrv.Get()->GetResource(texRes.GetAddressOf());
|
|
||||||
texRes.As(&tex2D).ThrowOnError();
|
|
||||||
}
|
|
||||||
|
|
||||||
tex2D.Get()->GetDesc(&texDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Format == DXGI_FORMAT.DXGI_FORMAT_UNKNOWN)
|
if (args.Format == DXGI_FORMAT.DXGI_FORMAT_UNKNOWN)
|
||||||
args = args with { Format = texDesc.Format };
|
args = args with { Format = wrapAux.Desc.Format };
|
||||||
if (args.NewWidth == 0)
|
if (args.NewWidth == 0)
|
||||||
args = args with { NewWidth = (int)MathF.Round((args.Uv1Effective.X - args.Uv0.X) * texDesc.Width) };
|
args = args with { NewWidth = (int)MathF.Round((args.Uv1Effective.X - args.Uv0.X) * wrapAux.Desc.Width) };
|
||||||
if (args.NewHeight == 0)
|
if (args.NewHeight == 0)
|
||||||
args = args with { NewHeight = (int)MathF.Round((args.Uv1Effective.Y - args.Uv0.Y) * texDesc.Height) };
|
args = args with { NewHeight = (int)MathF.Round((args.Uv1Effective.Y - args.Uv0.Y) * wrapAux.Desc.Height) };
|
||||||
|
|
||||||
using var tex2DCopyTemp = default(ComPtr<ID3D11Texture2D>);
|
using var tex2DCopyTemp = default(ComPtr<ID3D11Texture2D>);
|
||||||
unsafe
|
unsafe
|
||||||
|
|
@ -263,20 +227,120 @@ internal sealed partial class TextureManager
|
||||||
&rtvCopyTempDesc,
|
&rtvCopyTempDesc,
|
||||||
rtvCopyTemp.GetAddressOf()).ThrowOnError();
|
rtvCopyTemp.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
context.Get()->OMSetRenderTargets(1u, rtvCopyTemp.GetAddressOf(), null);
|
wrapAux.CtxPtr->OMSetRenderTargets(1u, rtvCopyTemp.GetAddressOf(), null);
|
||||||
this.SimpleDrawer.Draw(
|
this.SimpleDrawer.Draw(
|
||||||
context.Get(),
|
wrapAux.CtxPtr,
|
||||||
texSrv.Get(),
|
wrapAux.SrvPtr,
|
||||||
args.Uv0,
|
args.Uv0,
|
||||||
args.Uv1Effective);
|
args.Uv1Effective);
|
||||||
if (args.MakeOpaque)
|
if (args.MakeOpaque)
|
||||||
this.SimpleDrawer.StripAlpha(context.Get());
|
this.SimpleDrawer.StripAlpha(wrapAux.CtxPtr);
|
||||||
|
|
||||||
var dummy = default(ID3D11RenderTargetView*);
|
var dummy = default(ID3D11RenderTargetView*);
|
||||||
context.Get()->OMSetRenderTargets(1u, &dummy, null);
|
wrapAux.CtxPtr->OMSetRenderTargets(1u, &dummy, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return new(tex2DCopyTemp);
|
return new(tex2DCopyTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Auxiliary data from <see cref="IDalamudTextureWrap"/>.</summary>
|
||||||
|
private unsafe struct WrapAux : IDisposable
|
||||||
|
{
|
||||||
|
public readonly D3D11_TEXTURE2D_DESC Desc;
|
||||||
|
|
||||||
|
private IDalamudTextureWrap? wrapToClose;
|
||||||
|
|
||||||
|
private ComPtr<ID3D11ShaderResourceView> srv;
|
||||||
|
private ComPtr<ID3D11Resource> res;
|
||||||
|
private ComPtr<ID3D11Texture2D> tex;
|
||||||
|
private ComPtr<ID3D11Device> device;
|
||||||
|
private ComPtr<ID3D11DeviceContext> context;
|
||||||
|
|
||||||
|
public WrapAux(IDalamudTextureWrap wrap, bool leaveWrapOpen)
|
||||||
|
{
|
||||||
|
this.wrapToClose = leaveWrapOpen ? null : wrap;
|
||||||
|
|
||||||
|
using var unk = new ComPtr<IUnknown>((IUnknown*)wrap.ImGuiHandle);
|
||||||
|
|
||||||
|
using var srvTemp = default(ComPtr<ID3D11ShaderResourceView>);
|
||||||
|
unk.As(&srvTemp).ThrowOnError();
|
||||||
|
|
||||||
|
using var resTemp = default(ComPtr<ID3D11Resource>);
|
||||||
|
srvTemp.Get()->GetResource(resTemp.GetAddressOf());
|
||||||
|
|
||||||
|
using var texTemp = default(ComPtr<ID3D11Texture2D>);
|
||||||
|
resTemp.As(&texTemp).ThrowOnError();
|
||||||
|
|
||||||
|
using var deviceTemp = default(ComPtr<ID3D11Device>);
|
||||||
|
texTemp.Get()->GetDevice(deviceTemp.GetAddressOf());
|
||||||
|
|
||||||
|
using var contextTemp = default(ComPtr<ID3D11DeviceContext>);
|
||||||
|
deviceTemp.Get()->GetImmediateContext(contextTemp.GetAddressOf());
|
||||||
|
|
||||||
|
fixed (D3D11_TEXTURE2D_DESC* pDesc = &this.Desc)
|
||||||
|
texTemp.Get()->GetDesc(pDesc);
|
||||||
|
|
||||||
|
srvTemp.Swap(ref this.srv);
|
||||||
|
resTemp.Swap(ref this.res);
|
||||||
|
texTemp.Swap(ref this.tex);
|
||||||
|
deviceTemp.Swap(ref this.device);
|
||||||
|
contextTemp.Swap(ref this.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ID3D11ShaderResourceView* SrvPtr
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.srv.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ID3D11Resource* ResPtr
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.res.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ID3D11Texture2D* TexPtr
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.tex.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ID3D11Device* DevPtr
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.device.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ID3D11DeviceContext* CtxPtr
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => this.context.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ComPtr<ID3D11ShaderResourceView> NewSrvRef() => new(this.srv);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ComPtr<ID3D11Resource> NewResRef() => new(this.res);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ComPtr<ID3D11Texture2D> NewTexRef() => new(this.tex);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ComPtr<ID3D11Device> NewDevRef() => new(this.device);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ComPtr<ID3D11DeviceContext> NewCtxRef() => new(this.context);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.srv.Reset();
|
||||||
|
this.res.Reset();
|
||||||
|
this.tex.Reset();
|
||||||
|
this.device.Reset();
|
||||||
|
this.context.Reset();
|
||||||
|
Interlocked.Exchange(ref this.wrapToClose, null)?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,124 +27,131 @@ namespace Dalamud.Interface.Textures.Internal;
|
||||||
internal sealed partial class TextureManager
|
internal sealed partial class TextureManager
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[SuppressMessage(
|
|
||||||
"StyleCop.CSharp.LayoutRules",
|
|
||||||
"SA1519:Braces should not be omitted from multi-line child statement",
|
|
||||||
Justification = "Multiple fixed blocks")]
|
|
||||||
public async Task SaveToStreamAsync(
|
public async Task SaveToStreamAsync(
|
||||||
IDalamudTextureWrap wrap,
|
IDalamudTextureWrap? wrap,
|
||||||
Guid containerGuid,
|
Guid containerGuid,
|
||||||
Stream stream,
|
Stream? stream,
|
||||||
IReadOnlyDictionary<string, object>? props = null,
|
IReadOnlyDictionary<string, object>? props = null,
|
||||||
bool leaveWrapOpen = false,
|
bool leaveWrapOpen = false,
|
||||||
bool leaveStreamOpen = false,
|
bool leaveStreamOpen = false,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
using var wrapDispose = leaveWrapOpen ? null : wrap;
|
try
|
||||||
|
{
|
||||||
|
if (wrap is null)
|
||||||
|
throw new NullReferenceException($"{nameof(wrap)} cannot be null.");
|
||||||
|
if (stream is null)
|
||||||
|
throw new NullReferenceException($"{nameof(stream)} cannot be null.");
|
||||||
|
|
||||||
var dxgiFormat = this.GetFormatOf(wrap);
|
using var istream = ManagedIStream.Create(stream, true);
|
||||||
if (!WicManager.GetCorrespondingWicPixelFormat(dxgiFormat, out _, out _))
|
using var wrapAux = new WrapAux(wrap, true);
|
||||||
dxgiFormat = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
||||||
|
|
||||||
using var istream = ManagedIStream.Create(stream, leaveStreamOpen);
|
var dxgiFormat =
|
||||||
|
WicManager.GetCorrespondingWicPixelFormat(wrapAux.Desc.Format, out _, out _)
|
||||||
|
? wrapAux.Desc.Format
|
||||||
|
: DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
|
||||||
var (specs, bytes) = await this.GetRawImageAsync(
|
var (specs, bytes) = await this.GetRawImageAsync(wrapAux, new() { Format = dxgiFormat }, cancellationToken)
|
||||||
wrap,
|
.ConfigureAwait(false);
|
||||||
new() { Format = dxgiFormat },
|
|
||||||
true,
|
|
||||||
cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
this.Wic.SaveToStreamUsingWic(
|
await Task.Run(
|
||||||
specs,
|
() => this.Wic.SaveToStreamUsingWic(
|
||||||
bytes,
|
specs,
|
||||||
containerGuid,
|
bytes,
|
||||||
istream,
|
containerGuid,
|
||||||
props,
|
istream,
|
||||||
cancellationToken);
|
props,
|
||||||
|
cancellationToken),
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!leaveWrapOpen)
|
||||||
|
wrap?.Dispose();
|
||||||
|
if (!leaveStreamOpen)
|
||||||
|
stream?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task SaveToFileAsync(
|
public async Task SaveToFileAsync(
|
||||||
IDalamudTextureWrap wrap,
|
IDalamudTextureWrap? wrap,
|
||||||
Guid containerGuid,
|
Guid containerGuid,
|
||||||
string path,
|
string? path,
|
||||||
IReadOnlyDictionary<string, object>? props = null,
|
IReadOnlyDictionary<string, object>? props = null,
|
||||||
bool leaveWrapOpen = false,
|
bool leaveWrapOpen = false,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
using var wrapDispose = leaveWrapOpen ? null : wrap;
|
|
||||||
var pathTemp = $"{path}.{GetCurrentThreadId():X08}{Environment.TickCount64:X16}.tmp";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dxgiFormat = this.GetFormatOf(wrap);
|
if (wrap is null)
|
||||||
if (!WicManager.GetCorrespondingWicPixelFormat(dxgiFormat, out _, out _))
|
throw new NullReferenceException($"{nameof(wrap)} cannot be null.");
|
||||||
dxgiFormat = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
if (path is null)
|
||||||
|
throw new NullReferenceException($"{nameof(path)} cannot be null.");
|
||||||
|
|
||||||
using var istream = TerraFxComInterfaceExtensions.CreateIStreamFromFile(
|
using var wrapAux = new WrapAux(wrap, true);
|
||||||
pathTemp,
|
var pathTemp = $"{path}.{GetCurrentThreadId():X08}{Environment.TickCount64:X16}.tmp";
|
||||||
FileMode.Create,
|
var trashfire = new List<Exception>();
|
||||||
FileAccess.Write,
|
|
||||||
FileShare.None);
|
|
||||||
|
|
||||||
var (specs, bytes) = await this.GetRawImageAsync(
|
|
||||||
wrap,
|
|
||||||
new() { Format = dxgiFormat },
|
|
||||||
true,
|
|
||||||
cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
this.Wic.SaveToStreamUsingWic(
|
|
||||||
specs,
|
|
||||||
bytes,
|
|
||||||
containerGuid,
|
|
||||||
istream,
|
|
||||||
props,
|
|
||||||
cancellationToken);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (File.Exists(pathTemp))
|
using (var istream = TerraFxComInterfaceExtensions.CreateIStreamFromFile(
|
||||||
File.Delete(pathTemp);
|
pathTemp,
|
||||||
|
FileMode.Create,
|
||||||
|
FileAccess.Write,
|
||||||
|
FileShare.None))
|
||||||
|
{
|
||||||
|
var dxgiFormat =
|
||||||
|
WicManager.GetCorrespondingWicPixelFormat(wrapAux.Desc.Format, out _, out _)
|
||||||
|
? wrapAux.Desc.Format
|
||||||
|
: DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
|
||||||
|
var (specs, bytes) = await this.GetRawImageAsync(
|
||||||
|
wrapAux,
|
||||||
|
new() { Format = dxgiFormat },
|
||||||
|
cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Task.Run(
|
||||||
|
() => this.Wic.SaveToStreamUsingWic(
|
||||||
|
specs,
|
||||||
|
bytes,
|
||||||
|
containerGuid,
|
||||||
|
istream,
|
||||||
|
props,
|
||||||
|
cancellationToken),
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Replace(pathTemp, path, null, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
trashfire.Add(e);
|
||||||
|
File.Move(pathTemp, path, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception e2)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
throw new AggregateException(
|
trashfire.Add(e);
|
||||||
"Failed to save the file, and failed to remove the temporary file.",
|
try
|
||||||
e,
|
{
|
||||||
e2);
|
if (File.Exists(pathTemp))
|
||||||
|
File.Delete(pathTemp);
|
||||||
|
}
|
||||||
|
catch (Exception e2)
|
||||||
|
{
|
||||||
|
trashfire.Add(e2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw;
|
throw new AggregateException($"{nameof(this.SaveToFileAsync)} error.", trashfire);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
try
|
|
||||||
{
|
{
|
||||||
try
|
wrap?.Dispose();
|
||||||
{
|
|
||||||
File.Replace(pathTemp, path, null, true);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
File.Move(pathTemp, path, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(pathTemp))
|
|
||||||
File.Delete(pathTemp);
|
|
||||||
}
|
|
||||||
catch (Exception e2)
|
|
||||||
{
|
|
||||||
throw new AggregateException(
|
|
||||||
"Failed to move the temporary file to the target path, and failed to remove the temporary file.",
|
|
||||||
e,
|
|
||||||
e2);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,26 +228,6 @@ internal sealed partial class TextureManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe DXGI_FORMAT GetFormatOf(IDalamudTextureWrap wrap)
|
|
||||||
{
|
|
||||||
using var texSrv = default(ComPtr<ID3D11ShaderResourceView>);
|
|
||||||
using var context = default(ComPtr<ID3D11DeviceContext>);
|
|
||||||
fixed (Guid* piid = &IID.IID_ID3D11ShaderResourceView)
|
|
||||||
((IUnknown*)wrap.ImGuiHandle)->QueryInterface(piid, (void**)texSrv.GetAddressOf()).ThrowOnError();
|
|
||||||
|
|
||||||
this.Device.Get()->GetImmediateContext(context.GetAddressOf());
|
|
||||||
|
|
||||||
using var texRes = default(ComPtr<ID3D11Resource>);
|
|
||||||
texSrv.Get()->GetResource(texRes.GetAddressOf());
|
|
||||||
|
|
||||||
using var tex2D = default(ComPtr<ID3D11Texture2D>);
|
|
||||||
texRes.As(&tex2D).ThrowOnError();
|
|
||||||
|
|
||||||
var texDesc = default(D3D11_TEXTURE2D_DESC);
|
|
||||||
tex2D.Get()->GetDesc(&texDesc);
|
|
||||||
return texDesc.Format;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>A part of texture manager that uses Windows Imaging Component under the hood.</summary>
|
/// <summary>A part of texture manager that uses Windows Imaging Component under the hood.</summary>
|
||||||
internal sealed class WicManager : IDisposable
|
internal sealed class WicManager : IDisposable
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ public interface ITextureReadbackProvider
|
||||||
/// <returns>A task representing the save process.</returns>
|
/// <returns>A task representing the save process.</returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para><paramref name="wrap"/> must not be disposed until the task finishes.</para>
|
/// <para><paramref name="wrap"/> must not be disposed until the task finishes.</para>
|
||||||
|
/// <para>If the target file exists, it will be overwritten only if the save operation is successful.</para>
|
||||||
/// <para>See the following webpages for the valid values for <paramref name="props"/> per
|
/// <para>See the following webpages for the valid values for <paramref name="props"/> per
|
||||||
/// <paramref name="containerGuid"/>.</para>
|
/// <paramref name="containerGuid"/>.</para>
|
||||||
/// <ul>
|
/// <ul>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue