mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-02 05:43:40 +01:00
Add ITextureProvider.CreateFromExistingTextureAsync
This commit is contained in:
parent
c86be31255
commit
1ae11440aa
8 changed files with 612 additions and 22 deletions
|
|
@ -70,6 +70,8 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
[ServiceManager.ServiceDependency]
|
[ServiceManager.ServiceDependency]
|
||||||
private readonly DalamudIme dalamudIme = Service<DalamudIme>.Get();
|
private readonly DalamudIme dalamudIme = Service<DalamudIme>.Get();
|
||||||
|
|
||||||
|
private readonly ConcurrentQueue<Action> runBeforePresent = new();
|
||||||
|
|
||||||
private readonly SwapChainVtableResolver address = new();
|
private readonly SwapChainVtableResolver address = new();
|
||||||
private readonly Hook<SetCursorDelegate> setCursorHook;
|
private readonly Hook<SetCursorDelegate> setCursorHook;
|
||||||
private RawDX11Scene? scene;
|
private RawDX11Scene? scene;
|
||||||
|
|
@ -283,6 +285,10 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
this.deferredDisposeDisposables.Add(locked);
|
this.deferredDisposeDisposables.Add(locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Queues an action to be run before Present call.</summary>
|
||||||
|
/// <param name="action">The action.</param>
|
||||||
|
public void RunBeforePresent(Action action) => this.runBeforePresent.Enqueue(action);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get video memory information.
|
/// Get video memory information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -520,6 +526,9 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
if (!this.dalamudAtlas!.HasBuiltAtlas)
|
if (!this.dalamudAtlas!.HasBuiltAtlas)
|
||||||
return this.presentHook!.Original(swapChain, syncInterval, presentFlags);
|
return this.presentHook!.Original(swapChain, syncInterval, presentFlags);
|
||||||
|
|
||||||
|
while (this.runBeforePresent.TryDequeue(out var action))
|
||||||
|
action.InvokeSafely();
|
||||||
|
|
||||||
if (this.address.IsReshade)
|
if (this.address.IsReshade)
|
||||||
{
|
{
|
||||||
var pRes = this.presentHook!.Original(swapChain, syncInterval, presentFlags);
|
var pRes = this.presentHook!.Original(swapChain, syncInterval, presentFlags);
|
||||||
|
|
|
||||||
484
Dalamud/Interface/Internal/TextureManager.FormatConvert.cs
Normal file
484
Dalamud/Interface/Internal/TextureManager.FormatConvert.cs
Normal file
|
|
@ -0,0 +1,484 @@
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using SharpDX.Direct3D11;
|
||||||
|
using SharpDX.DXGI;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.Internal;
|
||||||
|
|
||||||
|
/// <summary>Service responsible for loading and disposing ImGui texture wraps.</summary>
|
||||||
|
internal sealed partial class TextureManager
|
||||||
|
{
|
||||||
|
private DrawsOneSquare? drawsOneSquare;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
bool ITextureProvider.IsDxgiFormatSupportedForCreateFromExistingTextureAsync(int dxgiFormat) =>
|
||||||
|
this.IsDxgiFormatSupportedForCreateFromExistingTextureAsync((DXGI_FORMAT)dxgiFormat);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ITextureProvider.IsDxgiFormatSupportedForCreateFromExistingTextureAsync"/>
|
||||||
|
public bool IsDxgiFormatSupportedForCreateFromExistingTextureAsync(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);
|
||||||
|
return (support & FormatSupport.RenderTarget) != 0
|
||||||
|
&& (support & FormatSupport.Texture2D) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
Task<IDalamudTextureWrap> ITextureProvider.CreateFromExistingTextureAsync(
|
||||||
|
IDalamudTextureWrap wrap,
|
||||||
|
Vector2 uv0,
|
||||||
|
Vector2 uv1,
|
||||||
|
int dxgiFormat,
|
||||||
|
CancellationToken cancellationToken) =>
|
||||||
|
this.CreateFromExistingTextureAsync(wrap, uv0, uv1, (DXGI_FORMAT)dxgiFormat, cancellationToken);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ITextureProvider.CreateFromExistingTextureAsync"/>
|
||||||
|
public Task<IDalamudTextureWrap> CreateFromExistingTextureAsync(
|
||||||
|
IDalamudTextureWrap wrap,
|
||||||
|
Vector2 uv0,
|
||||||
|
Vector2 uv1,
|
||||||
|
DXGI_FORMAT format,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var wrapCopy = wrap.CreateWrapSharingLowLevelResource();
|
||||||
|
return this.textureLoadThrottler.LoadTextureAsync(
|
||||||
|
new TextureLoadThrottler.ReadOnlyThrottleBasisProvider(),
|
||||||
|
ct =>
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<IDalamudTextureWrap>();
|
||||||
|
this.interfaceManager.RunBeforePresent(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
using var tex = new ComPtr<ID3D11Texture2D>(
|
||||||
|
this.NoThrottleCreateFromExistingTextureCore(
|
||||||
|
wrapCopy,
|
||||||
|
uv0,
|
||||||
|
uv1,
|
||||||
|
format,
|
||||||
|
false));
|
||||||
|
|
||||||
|
using var device = default(ComPtr<ID3D11Device>);
|
||||||
|
tex.Get()->GetDevice(device.GetAddressOf());
|
||||||
|
|
||||||
|
using var srv = default(ComPtr<ID3D11ShaderResourceView>);
|
||||||
|
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();
|
||||||
|
|
||||||
|
var desc = default(D3D11_TEXTURE2D_DESC);
|
||||||
|
tex.Get()->GetDesc(&desc);
|
||||||
|
|
||||||
|
tcs.SetResult(
|
||||||
|
new UnknownTextureWrap(
|
||||||
|
(IUnknown*)srv.Get(),
|
||||||
|
(int)desc.Width,
|
||||||
|
(int)desc.Height,
|
||||||
|
true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
tcs.SetException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return tcs.Task;
|
||||||
|
},
|
||||||
|
cancellationToken)
|
||||||
|
.ContinueWith(
|
||||||
|
r =>
|
||||||
|
{
|
||||||
|
wrapCopy.Dispose();
|
||||||
|
return r;
|
||||||
|
},
|
||||||
|
default(CancellationToken))
|
||||||
|
.Unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe ID3D11Texture2D* NoThrottleCreateFromExistingTextureCore(
|
||||||
|
IDalamudTextureWrap wrap,
|
||||||
|
Vector2 uv0,
|
||||||
|
Vector2 uv1,
|
||||||
|
DXGI_FORMAT format,
|
||||||
|
bool enableCpuRead)
|
||||||
|
{
|
||||||
|
ThreadSafety.AssertMainThread();
|
||||||
|
|
||||||
|
using var resUnk = new ComPtr<IUnknown>((IUnknown*)wrap.ImGuiHandle);
|
||||||
|
|
||||||
|
using var texSrv = default(ComPtr<ID3D11ShaderResourceView>);
|
||||||
|
resUnk.As(&texSrv).ThrowOnError();
|
||||||
|
|
||||||
|
using var device = default(ComPtr<ID3D11Device>);
|
||||||
|
texSrv.Get()->GetDevice(device.GetAddressOf());
|
||||||
|
|
||||||
|
using var deviceContext = default(ComPtr<ID3D11DeviceContext>);
|
||||||
|
device.Get()->GetImmediateContext(deviceContext.GetAddressOf());
|
||||||
|
|
||||||
|
using var tex2D = default(ComPtr<ID3D11Texture2D>);
|
||||||
|
using (var texRes = default(ComPtr<ID3D11Resource>))
|
||||||
|
{
|
||||||
|
texSrv.Get()->GetResource(texRes.GetAddressOf());
|
||||||
|
texRes.As(&tex2D).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
var texDesc = default(D3D11_TEXTURE2D_DESC);
|
||||||
|
tex2D.Get()->GetDesc(&texDesc);
|
||||||
|
|
||||||
|
using var tex2DCopyTemp = default(ComPtr<ID3D11Texture2D>);
|
||||||
|
var tex2DCopyTempDesc = new D3D11_TEXTURE2D_DESC
|
||||||
|
{
|
||||||
|
Width = checked((uint)MathF.Round((uv1.X - uv0.X) * wrap.Width)),
|
||||||
|
Height = checked((uint)MathF.Round((uv1.Y - uv0.Y) * wrap.Height)),
|
||||||
|
MipLevels = 1,
|
||||||
|
ArraySize = 1,
|
||||||
|
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),
|
||||||
|
CPUAccessFlags = 0u,
|
||||||
|
MiscFlags = 0u,
|
||||||
|
};
|
||||||
|
device.Get()->CreateTexture2D(&tex2DCopyTempDesc, null, tex2DCopyTemp.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
|
using (var rtvCopyTemp = default(ComPtr<ID3D11RenderTargetView>))
|
||||||
|
{
|
||||||
|
var rtvCopyTempDesc = new D3D11_RENDER_TARGET_VIEW_DESC(
|
||||||
|
tex2DCopyTemp,
|
||||||
|
D3D11_RTV_DIMENSION.D3D11_RTV_DIMENSION_TEXTURE2D);
|
||||||
|
device.Get()->CreateRenderTargetView(
|
||||||
|
(ID3D11Resource*)tex2DCopyTemp.Get(),
|
||||||
|
&rtvCopyTempDesc,
|
||||||
|
rtvCopyTemp.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
|
this.drawsOneSquare ??= new();
|
||||||
|
this.drawsOneSquare.Setup(device.Get());
|
||||||
|
|
||||||
|
deviceContext.Get()->OMSetRenderTargets(1u, rtvCopyTemp.GetAddressOf(), null);
|
||||||
|
this.drawsOneSquare.Draw(
|
||||||
|
deviceContext.Get(),
|
||||||
|
texSrv.Get(),
|
||||||
|
(int)tex2DCopyTempDesc.Width,
|
||||||
|
(int)tex2DCopyTempDesc.Height,
|
||||||
|
uv0,
|
||||||
|
uv1);
|
||||||
|
deviceContext.Get()->OMSetRenderTargets(0, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enableCpuRead)
|
||||||
|
{
|
||||||
|
tex2DCopyTemp.Get()->AddRef();
|
||||||
|
return tex2DCopyTemp.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var tex2DTarget = default(ComPtr<ID3D11Texture2D>);
|
||||||
|
var tex2DTargetDesc = tex2DCopyTempDesc with
|
||||||
|
{
|
||||||
|
Usage = D3D11_USAGE.D3D11_USAGE_DYNAMIC,
|
||||||
|
BindFlags = 0u,
|
||||||
|
CPUAccessFlags = (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ,
|
||||||
|
};
|
||||||
|
device.Get()->CreateTexture2D(&tex2DTargetDesc, null, tex2DTarget.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
|
deviceContext.Get()->CopyResource((ID3D11Resource*)tex2DTarget.Get(), (ID3D11Resource*)tex2DCopyTemp.Get());
|
||||||
|
|
||||||
|
tex2DTarget.Get()->AddRef();
|
||||||
|
return tex2DTarget.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage(
|
||||||
|
"StyleCop.CSharp.LayoutRules",
|
||||||
|
"SA1519:Braces should not be omitted from multi-line child statement",
|
||||||
|
Justification = "Multiple fixed blocks")]
|
||||||
|
private sealed unsafe class DrawsOneSquare : IDisposable
|
||||||
|
{
|
||||||
|
private ComPtr<ID3D11SamplerState> sampler;
|
||||||
|
private ComPtr<ID3D11VertexShader> vertexShader;
|
||||||
|
private ComPtr<ID3D11PixelShader> pixelShader;
|
||||||
|
private ComPtr<ID3D11InputLayout> inputLayout;
|
||||||
|
private ComPtr<ID3D11Buffer> vertexConstantBuffer;
|
||||||
|
private ComPtr<ID3D11BlendState> blendState;
|
||||||
|
private ComPtr<ID3D11RasterizerState> rasterizerState;
|
||||||
|
private ComPtr<ID3D11Buffer> vertexBufferFill;
|
||||||
|
private ComPtr<ID3D11Buffer> vertexBufferMutable;
|
||||||
|
private ComPtr<ID3D11Buffer> indexBuffer;
|
||||||
|
|
||||||
|
~DrawsOneSquare() => this.Dispose();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.sampler.Reset();
|
||||||
|
this.vertexShader.Reset();
|
||||||
|
this.pixelShader.Reset();
|
||||||
|
this.inputLayout.Reset();
|
||||||
|
this.vertexConstantBuffer.Reset();
|
||||||
|
this.blendState.Reset();
|
||||||
|
this.rasterizerState.Reset();
|
||||||
|
this.vertexBufferFill.Reset();
|
||||||
|
this.vertexBufferMutable.Reset();
|
||||||
|
this.indexBuffer.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Setup<T>(T* device) where T : unmanaged, ID3D11Device.Interface
|
||||||
|
{
|
||||||
|
var assembly = typeof(ImGuiScene.ImGui_Impl_DX11).Assembly;
|
||||||
|
|
||||||
|
// Create the vertex shader
|
||||||
|
if (this.vertexShader.IsEmpty() || this.inputLayout.IsEmpty())
|
||||||
|
{
|
||||||
|
this.vertexShader.Reset();
|
||||||
|
this.inputLayout.Reset();
|
||||||
|
|
||||||
|
using var stream = assembly.GetManifestResourceStream("imgui-vertex.hlsl.bytes")!;
|
||||||
|
var array = ArrayPool<byte>.Shared.Rent((int)stream.Length);
|
||||||
|
stream.ReadExactly(array, 0, (int)stream.Length);
|
||||||
|
fixed (byte* pArray = array)
|
||||||
|
fixed (ID3D11VertexShader** ppShader = &this.vertexShader.GetPinnableReference())
|
||||||
|
fixed (ID3D11InputLayout** ppInputLayout = &this.inputLayout.GetPinnableReference())
|
||||||
|
fixed (void* pszPosition = "POSITION"u8)
|
||||||
|
fixed (void* pszTexCoord = "TEXCOORD"u8)
|
||||||
|
fixed (void* pszColor = "COLOR"u8)
|
||||||
|
{
|
||||||
|
device->CreateVertexShader(pArray, (nuint)stream.Length, null, ppShader).ThrowOnError();
|
||||||
|
|
||||||
|
var ied = stackalloc D3D11_INPUT_ELEMENT_DESC[]
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SemanticName = (sbyte*)pszPosition,
|
||||||
|
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT,
|
||||||
|
AlignedByteOffset = uint.MaxValue,
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SemanticName = (sbyte*)pszTexCoord,
|
||||||
|
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT,
|
||||||
|
AlignedByteOffset = uint.MaxValue,
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SemanticName = (sbyte*)pszColor,
|
||||||
|
Format = DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||||
|
AlignedByteOffset = uint.MaxValue,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
device->CreateInputLayout(ied, 3, pArray, (nuint)stream.Length, ppInputLayout).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayPool<byte>.Shared.Return(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the constant buffer
|
||||||
|
if (this.vertexConstantBuffer.IsEmpty())
|
||||||
|
{
|
||||||
|
var bufferDesc = new D3D11_BUFFER_DESC(
|
||||||
|
(uint)sizeof(Matrix4x4),
|
||||||
|
(uint)D3D11_BIND_FLAG.D3D11_BIND_CONSTANT_BUFFER,
|
||||||
|
D3D11_USAGE.D3D11_USAGE_IMMUTABLE);
|
||||||
|
var data = Matrix4x4.Identity;
|
||||||
|
var subr = new D3D11_SUBRESOURCE_DATA { pSysMem = &data };
|
||||||
|
fixed (ID3D11Buffer** ppBuffer = &this.vertexConstantBuffer.GetPinnableReference())
|
||||||
|
device->CreateBuffer(&bufferDesc, &subr, ppBuffer).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
if (this.pixelShader.IsEmpty())
|
||||||
|
{
|
||||||
|
using var stream = assembly.GetManifestResourceStream("imgui-frag.hlsl.bytes")!;
|
||||||
|
var array = ArrayPool<byte>.Shared.Rent((int)stream.Length);
|
||||||
|
stream.ReadExactly(array, 0, (int)stream.Length);
|
||||||
|
fixed (byte* pArray = array)
|
||||||
|
fixed (ID3D11PixelShader** ppShader = &this.pixelShader.GetPinnableReference())
|
||||||
|
device->CreatePixelShader(pArray, (nuint)stream.Length, null, ppShader).ThrowOnError();
|
||||||
|
|
||||||
|
ArrayPool<byte>.Shared.Return(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
if (this.blendState.IsEmpty())
|
||||||
|
{
|
||||||
|
var blendStateDesc = new D3D11_BLEND_DESC
|
||||||
|
{
|
||||||
|
RenderTarget =
|
||||||
|
{
|
||||||
|
e0 =
|
||||||
|
{
|
||||||
|
BlendEnable = true,
|
||||||
|
SrcBlend = D3D11_BLEND.D3D11_BLEND_SRC_ALPHA,
|
||||||
|
DestBlend = D3D11_BLEND.D3D11_BLEND_INV_SRC_ALPHA,
|
||||||
|
BlendOp = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD,
|
||||||
|
SrcBlendAlpha = D3D11_BLEND.D3D11_BLEND_INV_DEST_ALPHA,
|
||||||
|
DestBlendAlpha = D3D11_BLEND.D3D11_BLEND_ONE,
|
||||||
|
BlendOpAlpha = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD,
|
||||||
|
RenderTargetWriteMask = (byte)D3D11_COLOR_WRITE_ENABLE.D3D11_COLOR_WRITE_ENABLE_ALL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
fixed (ID3D11BlendState** ppBlendState = &this.blendState.GetPinnableReference())
|
||||||
|
device->CreateBlendState(&blendStateDesc, ppBlendState).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the rasterizer state
|
||||||
|
if (this.rasterizerState.IsEmpty())
|
||||||
|
{
|
||||||
|
var rasterizerDesc = new D3D11_RASTERIZER_DESC
|
||||||
|
{
|
||||||
|
FillMode = D3D11_FILL_MODE.D3D11_FILL_SOLID,
|
||||||
|
CullMode = D3D11_CULL_MODE.D3D11_CULL_NONE,
|
||||||
|
};
|
||||||
|
fixed (ID3D11RasterizerState** ppRasterizerState = &this.rasterizerState.GetPinnableReference())
|
||||||
|
device->CreateRasterizerState(&rasterizerDesc, ppRasterizerState).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the font sampler
|
||||||
|
if (this.sampler.IsEmpty())
|
||||||
|
{
|
||||||
|
var samplerDesc = new D3D11_SAMPLER_DESC(
|
||||||
|
D3D11_FILTER.D3D11_FILTER_MIN_MAG_MIP_LINEAR,
|
||||||
|
D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_WRAP,
|
||||||
|
D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_WRAP,
|
||||||
|
D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_WRAP,
|
||||||
|
0f,
|
||||||
|
0,
|
||||||
|
D3D11_COMPARISON_FUNC.D3D11_COMPARISON_ALWAYS,
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
fixed (ID3D11SamplerState** ppSampler = &this.sampler.GetPinnableReference())
|
||||||
|
device->CreateSamplerState(&samplerDesc, ppSampler).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.vertexBufferFill.IsEmpty())
|
||||||
|
{
|
||||||
|
var data = stackalloc ImDrawVert[]
|
||||||
|
{
|
||||||
|
new() { col = uint.MaxValue, pos = new(-1, 1), uv = new(0, 0) },
|
||||||
|
new() { col = uint.MaxValue, pos = new(-1, -1), uv = new(0, 1) },
|
||||||
|
new() { col = uint.MaxValue, pos = new(1, 1), uv = new(1, 0) },
|
||||||
|
new() { col = uint.MaxValue, pos = new(1, -1), uv = new(1, 1) },
|
||||||
|
};
|
||||||
|
var desc = new D3D11_BUFFER_DESC(
|
||||||
|
(uint)(sizeof(ImDrawVert) * 4),
|
||||||
|
(uint)D3D11_BIND_FLAG.D3D11_BIND_VERTEX_BUFFER,
|
||||||
|
D3D11_USAGE.D3D11_USAGE_IMMUTABLE);
|
||||||
|
var subr = new D3D11_SUBRESOURCE_DATA { pSysMem = data };
|
||||||
|
var buffer = default(ID3D11Buffer*);
|
||||||
|
device->CreateBuffer(&desc, &subr, &buffer).ThrowOnError();
|
||||||
|
this.vertexBufferFill.Attach(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.vertexBufferMutable.IsEmpty())
|
||||||
|
{
|
||||||
|
var desc = new D3D11_BUFFER_DESC(
|
||||||
|
(uint)(sizeof(ImDrawVert) * 4),
|
||||||
|
(uint)D3D11_BIND_FLAG.D3D11_BIND_VERTEX_BUFFER,
|
||||||
|
D3D11_USAGE.D3D11_USAGE_DYNAMIC,
|
||||||
|
(uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_WRITE);
|
||||||
|
var buffer = default(ID3D11Buffer*);
|
||||||
|
device->CreateBuffer(&desc, null, &buffer).ThrowOnError();
|
||||||
|
this.vertexBufferMutable.Attach(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.indexBuffer.IsEmpty())
|
||||||
|
{
|
||||||
|
var data = stackalloc ushort[] { 0, 1, 2, 1, 2, 3 };
|
||||||
|
var desc = new D3D11_BUFFER_DESC(
|
||||||
|
sizeof(ushort) * 6,
|
||||||
|
(uint)D3D11_BIND_FLAG.D3D11_BIND_INDEX_BUFFER,
|
||||||
|
D3D11_USAGE.D3D11_USAGE_IMMUTABLE);
|
||||||
|
var subr = new D3D11_SUBRESOURCE_DATA { pSysMem = data };
|
||||||
|
var buffer = default(ID3D11Buffer*);
|
||||||
|
device->CreateBuffer(&desc, &subr, &buffer).ThrowOnError();
|
||||||
|
this.indexBuffer.Attach(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(
|
||||||
|
ID3D11DeviceContext* ctx,
|
||||||
|
ID3D11ShaderResourceView* srv,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
Vector2 uv0,
|
||||||
|
Vector2 uv1)
|
||||||
|
{
|
||||||
|
ID3D11Buffer* buffer;
|
||||||
|
if (uv0 == Vector2.Zero && uv1 == Vector2.One)
|
||||||
|
{
|
||||||
|
buffer = this.vertexBufferFill.Get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer = this.vertexBufferMutable.Get();
|
||||||
|
var mapped = default(D3D11_MAPPED_SUBRESOURCE);
|
||||||
|
ctx->Map((ID3D11Resource*)buffer, 0, D3D11_MAP.D3D11_MAP_WRITE_DISCARD, 0u, &mapped).ThrowOnError();
|
||||||
|
_ = new Span<ImDrawVert>(mapped.pData, 4)
|
||||||
|
{
|
||||||
|
[0] = new() { col = uint.MaxValue, pos = new(-1, 1), uv = uv0 },
|
||||||
|
[1] = new() { col = uint.MaxValue, pos = new(-1, -1), uv = new(uv0.X, uv1.Y) },
|
||||||
|
[2] = new() { col = uint.MaxValue, pos = new(1, 1), uv = new(uv1.X, uv0.Y) },
|
||||||
|
[3] = new() { col = uint.MaxValue, pos = new(1, -1), uv = uv1 },
|
||||||
|
};
|
||||||
|
ctx->Unmap((ID3D11Resource*)buffer, 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
var stride = (uint)sizeof(ImDrawVert);
|
||||||
|
var offset = 0u;
|
||||||
|
|
||||||
|
ctx->IASetInputLayout(this.inputLayout);
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &buffer, &stride, &offset);
|
||||||
|
ctx->IASetIndexBuffer(this.indexBuffer, DXGI_FORMAT.DXGI_FORMAT_R16_UINT, 0);
|
||||||
|
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY.D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
|
||||||
|
var viewport = new D3D11_VIEWPORT(0, 0, width, height);
|
||||||
|
ctx->RSSetState(this.rasterizerState);
|
||||||
|
ctx->RSSetViewports(1, &viewport);
|
||||||
|
|
||||||
|
var blendColor = default(Vector4);
|
||||||
|
ctx->OMSetBlendState(this.blendState, (float*)&blendColor, 0xffffffff);
|
||||||
|
ctx->OMSetDepthStencilState(null, 0);
|
||||||
|
|
||||||
|
ctx->VSSetShader(this.vertexShader.Get(), null, 0);
|
||||||
|
buffer = this.vertexConstantBuffer.Get();
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &buffer);
|
||||||
|
|
||||||
|
ctx->PSSetShader(this.pixelShader, null, 0);
|
||||||
|
var simp = this.sampler.Get();
|
||||||
|
ctx->PSSetSamplers(0, 1, &simp);
|
||||||
|
ctx->PSSetShaderResources(0, 1, &srv);
|
||||||
|
|
||||||
|
ctx->GSSetShader(null, null, 0);
|
||||||
|
ctx->HSSetShader(null, null, 0);
|
||||||
|
ctx->DSSetShader(null, null, 0);
|
||||||
|
ctx->CSSetShader(null, null, 0);
|
||||||
|
ctx->DrawIndexed(6, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,8 @@ using SharpDX.Direct3D;
|
||||||
using SharpDX.Direct3D11;
|
using SharpDX.Direct3D11;
|
||||||
using SharpDX.DXGI;
|
using SharpDX.DXGI;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal;
|
namespace Dalamud.Interface.Internal;
|
||||||
|
|
||||||
/// <summary>Service responsible for loading and disposing ImGui texture wraps.</summary>
|
/// <summary>Service responsible for loading and disposing ImGui texture wraps.</summary>
|
||||||
|
|
@ -36,7 +38,7 @@ namespace Dalamud.Interface.Internal;
|
||||||
[ResolveVia<ITextureProvider>]
|
[ResolveVia<ITextureProvider>]
|
||||||
[ResolveVia<ITextureSubstitutionProvider>]
|
[ResolveVia<ITextureSubstitutionProvider>]
|
||||||
#pragma warning restore SA1015
|
#pragma warning restore SA1015
|
||||||
internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvider, ITextureSubstitutionProvider
|
internal sealed partial class TextureManager : IServiceType, IDisposable, ITextureProvider, ITextureSubstitutionProvider
|
||||||
{
|
{
|
||||||
private const int PathLookupLruCount = 8192;
|
private const int PathLookupLruCount = 8192;
|
||||||
|
|
||||||
|
|
@ -109,6 +111,9 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
||||||
ReleaseSelfReferences(this.manifestResourceTextures);
|
ReleaseSelfReferences(this.manifestResourceTextures);
|
||||||
this.lookupToPath.Clear();
|
this.lookupToPath.Clear();
|
||||||
|
|
||||||
|
this.drawsOneSquare?.Dispose();
|
||||||
|
this.drawsOneSquare = null;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static void ReleaseSelfReferences<T>(ConcurrentDictionary<T, SharedImmediateTexture> dict)
|
static void ReleaseSelfReferences<T>(ConcurrentDictionary<T, SharedImmediateTexture> dict)
|
||||||
|
|
@ -302,7 +307,11 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsDxgiFormatSupported(int dxgiFormat)
|
bool ITextureProvider.IsDxgiFormatSupported(int dxgiFormat) =>
|
||||||
|
this.IsDxgiFormatSupported((DXGI_FORMAT)dxgiFormat);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ITextureProvider.IsDxgiFormatSupported"/>
|
||||||
|
public bool IsDxgiFormatSupported(DXGI_FORMAT dxgiFormat)
|
||||||
{
|
{
|
||||||
if (this.interfaceManager.Scene is not { } scene)
|
if (this.interfaceManager.Scene is not { } scene)
|
||||||
{
|
{
|
||||||
|
|
@ -310,7 +319,9 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
||||||
scene = this.interfaceManager.Scene ?? throw new InvalidOperationException();
|
scene = this.interfaceManager.Scene ?? throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return scene.Device.CheckFormatSupport((Format)dxgiFormat).HasFlag(FormatSupport.Texture2D);
|
var format = (Format)dxgiFormat;
|
||||||
|
var support = scene.Device.CheckFormatSupport(format);
|
||||||
|
return (support & FormatSupport.Texture2D) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|
@ -522,7 +533,8 @@ internal sealed class TextureManager : IServiceType, IDisposable, ITextureProvid
|
||||||
|
|
||||||
var buffer = file.TextureBuffer;
|
var buffer = file.TextureBuffer;
|
||||||
var (dxgiFormat, conversion) = TexFile.GetDxgiFormatFromTextureFormat(file.Header.Format, false);
|
var (dxgiFormat, conversion) = TexFile.GetDxgiFormatFromTextureFormat(file.Header.Format, false);
|
||||||
if (conversion != TexFile.DxgiFormatConversion.NoConversion || !this.IsDxgiFormatSupported(dxgiFormat))
|
if (conversion != TexFile.DxgiFormatConversion.NoConversion ||
|
||||||
|
!this.IsDxgiFormatSupported((DXGI_FORMAT)dxgiFormat))
|
||||||
{
|
{
|
||||||
dxgiFormat = (int)Format.B8G8R8A8_UNorm;
|
dxgiFormat = (int)Format.B8G8R8A8_UNorm;
|
||||||
buffer = buffer.Filter(0, 0, TexFile.TextureFormat.B8G8R8A8);
|
buffer = buffer.Filter(0, 0, TexFile.TextureFormat.B8G8R8A8);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ using Dalamud.Utility;
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -41,6 +43,10 @@ internal class TexWidget : IDataWindowWidget
|
||||||
private Vector2 inputTexScale = Vector2.Zero;
|
private Vector2 inputTexScale = Vector2.Zero;
|
||||||
private TextureManager textureManager = null!;
|
private TextureManager textureManager = null!;
|
||||||
|
|
||||||
|
private string[]? supportedRenderTargetFormatNames;
|
||||||
|
private DXGI_FORMAT[]? supportedRenderTargetFormats;
|
||||||
|
private int renderTargetChoiceInt;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string[]? CommandShortcuts { get; init; } = { "tex", "texture" };
|
public string[]? CommandShortcuts { get; init; } = { "tex", "texture" };
|
||||||
|
|
||||||
|
|
@ -66,6 +72,8 @@ internal class TexWidget : IDataWindowWidget
|
||||||
this.inputManifestResourceAssemblyIndex = 0;
|
this.inputManifestResourceAssemblyIndex = 0;
|
||||||
this.inputManifestResourceNameCandidates = null;
|
this.inputManifestResourceNameCandidates = null;
|
||||||
this.inputManifestResourceNameIndex = 0;
|
this.inputManifestResourceNameIndex = 0;
|
||||||
|
this.supportedRenderTargetFormats = null;
|
||||||
|
this.supportedRenderTargetFormatNames = null;
|
||||||
this.Ready = true;
|
this.Ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,19 +150,63 @@ internal class TexWidget : IDataWindowWidget
|
||||||
ImGui.PopID();
|
ImGui.PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureEntry? toRemove = null;
|
ImGui.Dummy(new(ImGui.GetTextLineHeightWithSpacing()));
|
||||||
TextureEntry? toCopy = null;
|
|
||||||
|
if (this.supportedRenderTargetFormats is null)
|
||||||
|
{
|
||||||
|
this.supportedRenderTargetFormatNames = null;
|
||||||
|
this.supportedRenderTargetFormats =
|
||||||
|
Enum.GetValues<DXGI_FORMAT>()
|
||||||
|
.Where(this.textureManager.IsDxgiFormatSupportedForCreateFromExistingTextureAsync)
|
||||||
|
.ToArray();
|
||||||
|
this.renderTargetChoiceInt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.supportedRenderTargetFormatNames ??= this.supportedRenderTargetFormats.Select(Enum.GetName).ToArray();
|
||||||
|
ImGui.Combo(
|
||||||
|
"CropCopy Format",
|
||||||
|
ref this.renderTargetChoiceInt,
|
||||||
|
this.supportedRenderTargetFormatNames,
|
||||||
|
this.supportedRenderTargetFormatNames.Length);
|
||||||
|
|
||||||
|
Action? runLater = null;
|
||||||
foreach (var t in this.addedTextures)
|
foreach (var t in this.addedTextures)
|
||||||
{
|
{
|
||||||
ImGui.PushID(t.Id);
|
ImGui.PushID(t.Id);
|
||||||
if (ImGui.CollapsingHeader($"Tex #{t.Id} {t}###header", ImGuiTreeNodeFlags.DefaultOpen))
|
if (ImGui.CollapsingHeader($"Tex #{t.Id} {t}###header", ImGuiTreeNodeFlags.DefaultOpen))
|
||||||
{
|
{
|
||||||
if (ImGui.Button("X"))
|
if (ImGui.Button("X"))
|
||||||
toRemove = t;
|
{
|
||||||
|
runLater = () =>
|
||||||
|
{
|
||||||
|
t.Dispose();
|
||||||
|
this.addedTextures.Remove(t);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGui.Button("Copy"))
|
if (ImGui.Button("Copy Reference"))
|
||||||
toCopy = t;
|
runLater = () => this.addedTextures.Add(t.CreateFromSharedLowLevelResource(this.textureManager));
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("CropCopy"))
|
||||||
|
{
|
||||||
|
runLater = () =>
|
||||||
|
{
|
||||||
|
if (t.GetTexture(this.textureManager) is not { } source)
|
||||||
|
return;
|
||||||
|
if (this.supportedRenderTargetFormats is not { } supportedFormats)
|
||||||
|
return;
|
||||||
|
if (this.renderTargetChoiceInt < 0 || this.renderTargetChoiceInt >= supportedFormats.Length)
|
||||||
|
return;
|
||||||
|
var texTask = this.textureManager.CreateFromExistingTextureAsync(
|
||||||
|
source,
|
||||||
|
new(0.25f),
|
||||||
|
new(0.75f),
|
||||||
|
supportedFormats[this.renderTargetChoiceInt]);
|
||||||
|
this.addedTextures.Add(new() { Api10 = texTask });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -162,7 +214,7 @@ internal class TexWidget : IDataWindowWidget
|
||||||
{
|
{
|
||||||
var scale = new Vector2(tex.Width, tex.Height);
|
var scale = new Vector2(tex.Width, tex.Height);
|
||||||
if (this.inputTexScale != Vector2.Zero)
|
if (this.inputTexScale != Vector2.Zero)
|
||||||
scale = this.inputTexScale;
|
scale *= this.inputTexScale;
|
||||||
|
|
||||||
ImGui.Image(tex.ImGuiHandle, scale, this.inputTexUv0, this.inputTexUv1, this.inputTintCol);
|
ImGui.Image(tex.ImGuiHandle, scale, this.inputTexUv0, this.inputTexUv1, this.inputTintCol);
|
||||||
}
|
}
|
||||||
|
|
@ -180,16 +232,7 @@ internal class TexWidget : IDataWindowWidget
|
||||||
ImGui.PopID();
|
ImGui.PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toRemove != null)
|
runLater?.Invoke();
|
||||||
{
|
|
||||||
toRemove.Dispose();
|
|
||||||
this.addedTextures.Remove(toRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toCopy != null)
|
|
||||||
{
|
|
||||||
this.addedTextures.Add(toCopy.CreateFromSharedLowLevelResource(this.textureManager));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void DrawLoadedTextures(ICollection<SharedImmediateTexture> textures)
|
private unsafe void DrawLoadedTextures(ICollection<SharedImmediateTexture> textures)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ using ImGuiNET;
|
||||||
|
|
||||||
using SharpDX.DXGI;
|
using SharpDX.DXGI;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -580,7 +582,7 @@ internal sealed partial class FontAtlasFactory
|
||||||
var buf = Array.Empty<byte>();
|
var buf = Array.Empty<byte>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var use4 = this.factory.TextureManager.IsDxgiFormatSupported((int)Format.B4G4R4A4_UNorm);
|
var use4 = this.factory.TextureManager.IsDxgiFormatSupported(DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM);
|
||||||
var bpp = use4 ? 2 : 4;
|
var bpp = use4 ? 2 : 4;
|
||||||
var width = this.NewImAtlas.TexWidth;
|
var width = this.NewImAtlas.TexWidth;
|
||||||
var height = this.NewImAtlas.TexHeight;
|
var height = this.NewImAtlas.TexHeight;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ using SharpDX;
|
||||||
using SharpDX.Direct3D11;
|
using SharpDX.Direct3D11;
|
||||||
using SharpDX.DXGI;
|
using SharpDX.DXGI;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -353,7 +355,7 @@ internal sealed partial class FontAtlasFactory
|
||||||
var numPixels = texFile.Header.Width * texFile.Header.Height;
|
var numPixels = texFile.Header.Width * texFile.Header.Height;
|
||||||
|
|
||||||
_ = Service<InterfaceManager.InterfaceManagerWithScene>.Get();
|
_ = Service<InterfaceManager.InterfaceManagerWithScene>.Get();
|
||||||
var targetIsB4G4R4A4 = this.TextureManager.IsDxgiFormatSupported((int)Format.B4G4R4A4_UNorm);
|
var targetIsB4G4R4A4 = this.TextureManager.IsDxgiFormatSupported(DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM);
|
||||||
var bpp = targetIsB4G4R4A4 ? 2 : 4;
|
var bpp = targetIsB4G4R4A4 ? 2 : 4;
|
||||||
var buffer = ArrayPool<byte>.Shared.Rent(numPixels * bpp);
|
var buffer = ArrayPool<byte>.Shared.Rent(numPixels * bpp);
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -27,6 +28,28 @@ namespace Dalamud.Plugin.Services;
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public partial interface ITextureProvider
|
public partial interface ITextureProvider
|
||||||
{
|
{
|
||||||
|
/// <summary>Creates a texture from the given existing texture, cropping and converting pixel format as needed.
|
||||||
|
/// </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="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="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> containing the copied texture on success. Dispose after use.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>Coordinates in <paramref name="uv0"/> and <paramref name="uv1"/> should be in range between 0 and 1.
|
||||||
|
/// </para>
|
||||||
|
/// <para>Supported values for <paramref name="dxgiFormat"/> may not necessarily match
|
||||||
|
/// <see cref="IsDxgiFormatSupported"/>.</para>
|
||||||
|
/// </remarks>
|
||||||
|
Task<IDalamudTextureWrap> CreateFromExistingTextureAsync(
|
||||||
|
IDalamudTextureWrap wrap,
|
||||||
|
Vector2 uv0,
|
||||||
|
Vector2 uv1,
|
||||||
|
int dxgiFormat,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>Gets a texture from the given bytes, trying to interpret it as a .tex file or other well-known image
|
/// <summary>Gets a texture from the given bytes, trying to interpret it as a .tex file or other well-known image
|
||||||
/// files, such as .png.</summary>
|
/// files, such as .png.</summary>
|
||||||
/// <param name="bytes">The bytes to load.</param>
|
/// <param name="bytes">The bytes to load.</param>
|
||||||
|
|
@ -143,4 +166,10 @@ public partial interface ITextureProvider
|
||||||
/// <param name="dxgiFormat">The DXGI format.</param>
|
/// <param name="dxgiFormat">The DXGI format.</param>
|
||||||
/// <returns><c>true</c> if supported.</returns>
|
/// <returns><c>true</c> if supported.</returns>
|
||||||
bool IsDxgiFormatSupported(int dxgiFormat);
|
bool IsDxgiFormatSupported(int dxgiFormat);
|
||||||
|
|
||||||
|
/// <summary>Determines whether the system supports the given DXGI format for use with
|
||||||
|
/// <see cref="CreateFromExistingTextureAsync"/>.</summary>
|
||||||
|
/// <param name="dxgiFormat">The DXGI format.</param>
|
||||||
|
/// <returns><c>true</c> if supported.</returns>
|
||||||
|
bool IsDxgiFormatSupportedForCreateFromExistingTextureAsync(int dxgiFormat);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -692,12 +692,21 @@ public static class Util
|
||||||
/// Throws a corresponding exception if <see cref="HRESULT.FAILED"/> is true.
|
/// Throws a corresponding exception if <see cref="HRESULT.FAILED"/> is true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hr">The result value.</param>
|
/// <param name="hr">The result value.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static void ThrowOnError(this HRESULT hr)
|
internal static void ThrowOnError(this HRESULT hr)
|
||||||
{
|
{
|
||||||
if (hr.FAILED)
|
if (hr.FAILED)
|
||||||
Marshal.ThrowExceptionForHR(hr.Value);
|
Marshal.ThrowExceptionForHR(hr.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines if the specified instance of <see cref="ComPtr{T}"/> points to null.</summary>
|
||||||
|
/// <param name="f">The pointer.</param>
|
||||||
|
/// <typeparam name="T">The COM interface type from TerraFX.</typeparam>
|
||||||
|
/// <returns><c>true</c> if not empty.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static unsafe bool IsEmpty<T>(in this ComPtr<T> f) where T : unmanaged, IUnknown.Interface =>
|
||||||
|
f.Get() is null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calls <see cref="TaskCompletionSource.SetException(System.Exception)"/> if the task is incomplete.
|
/// Calls <see cref="TaskCompletionSource.SetException(System.Exception)"/> if the task is incomplete.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue