mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-15 21:24:16 +01:00
Add ITextureProvider.ConvertToKernelTexture (#2003)
* Add ITextureProvider.ConvertToKernelTexture Lets you obtain an instance of Kernel::Texture from IDalamudTextureWrap. * Docs wip
This commit is contained in:
parent
9a0bc50e23
commit
74ab9191d3
6 changed files with 125 additions and 5 deletions
|
|
@ -1,7 +1,9 @@
|
|||
using System.Numerics;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Interface.ImGuiSeStringRenderer.Internal;
|
||||
using Dalamud.Interface.Textures.Internal;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Utility;
|
||||
|
||||
|
|
@ -317,6 +319,32 @@ internal unsafe class UiDebug
|
|||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.Button($"Replace with a random image##{(ulong)textureInfo:X}"))
|
||||
{
|
||||
var texm = Service<TextureManager>.Get();
|
||||
texm.Shared
|
||||
.GetFromGame(
|
||||
Random.Shared.Next(0, 1) == 0
|
||||
? $"ui/loadingimage/-nowloading_base{Random.Shared.Next(1, 33)}.tex"
|
||||
: $"ui/loadingimage/-nowloading_base{Random.Shared.Next(1, 33)}_hr1.tex")
|
||||
.RentAsync()
|
||||
.ContinueWith(
|
||||
r => Service<Framework>.Get().RunOnFrameworkThread(
|
||||
() =>
|
||||
{
|
||||
if (!r.IsCompletedSuccessfully)
|
||||
return;
|
||||
|
||||
using (r.Result)
|
||||
{
|
||||
textureInfo->AtkTexture.ReleaseTexture();
|
||||
textureInfo->AtkTexture.KernelTexture =
|
||||
texm.ConvertToKernelTexture(r.Result);
|
||||
textureInfo->AtkTexture.TextureType = TextureType.KernelTexture;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ public interface ISharedImmediateTexture
|
|||
/// <see cref="ISharedImmediateTexture"/>s may be cached, but the performance benefit will be minimal.</para>
|
||||
/// <para>Calling outside the main thread will fail.</para>
|
||||
/// <para>This function does not throw.</para>
|
||||
/// <para><see cref="IDisposable.Dispose"/> will be ignored.</para>
|
||||
/// <para><see cref="IDisposable.Dispose"/> will be ignored, including the cases when the returned texture wrap
|
||||
/// is passed to a function with <c>leaveWrapOpen</c> parameter.</para>
|
||||
/// <para>If the texture is unavailable for any reason, then the returned instance of
|
||||
/// <see cref="IDalamudTextureWrap"/> will point to an empty texture instead.</para>
|
||||
/// </remarks>
|
||||
|
|
@ -42,7 +43,8 @@ public interface ISharedImmediateTexture
|
|||
/// <see cref="ISharedImmediateTexture"/>s may be cached, but the performance benefit will be minimal.</para>
|
||||
/// <para>Calling outside the main thread will fail.</para>
|
||||
/// <para>This function does not throw.</para>
|
||||
/// <para><see cref="IDisposable.Dispose"/> will be ignored.</para>
|
||||
/// <para><see cref="IDisposable.Dispose"/> will be ignored, including the cases when the returned texture wrap
|
||||
/// is passed to a function with <c>leaveWrapOpen</c> parameter.</para>
|
||||
/// <para>If the texture is unavailable for any reason, then <paramref name="defaultWrap"/> will be returned.</para>
|
||||
/// </remarks>
|
||||
[return: NotNullIfNotNull(nameof(defaultWrap))]
|
||||
|
|
@ -59,7 +61,8 @@ public interface ISharedImmediateTexture
|
|||
/// <see cref="ISharedImmediateTexture"/>s may be cached, but the performance benefit will be minimal.</para>
|
||||
/// <para>Calling outside the main thread will fail.</para>
|
||||
/// <para>This function does not throw.</para>
|
||||
/// <para><see cref="IDisposable.Dispose"/> on the returned <paramref name="texture"/> will be ignored.</para>
|
||||
/// <para><see cref="IDisposable.Dispose"/> on the returned <paramref name="texture"/> will be ignored, including
|
||||
/// the cases when the returned texture wrap is passed to a function with <c>leaveWrapOpen</c> parameter.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">Thrown when called outside the UI thread.</exception>
|
||||
bool TryGetWrap([NotNullWhen(true)] out IDalamudTextureWrap? texture, out Exception? exception);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using System.Runtime.CompilerServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using Dalamud.Interface.Textures.TextureWraps.Internal;
|
||||
using Dalamud.Plugin.Internal.Types;
|
||||
|
|
@ -10,6 +9,8 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility;
|
||||
using Dalamud.Utility.TerraFxCom;
|
||||
|
||||
using Lumina.Data.Files;
|
||||
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
|
|
@ -18,6 +19,72 @@ namespace Dalamud.Interface.Textures.Internal;
|
|||
/// <summary>Service responsible for loading and disposing ImGui texture wraps.</summary>
|
||||
internal sealed partial class TextureManager
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
unsafe nint ITextureProvider.ConvertToKernelTexture(IDalamudTextureWrap wrap, bool leaveWrapOpen) =>
|
||||
(nint)this.ConvertToKernelTexture(wrap, leaveWrapOpen);
|
||||
|
||||
/// <inheritdoc cref="ITextureProvider.ConvertToKernelTexture"/>
|
||||
public unsafe FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture* ConvertToKernelTexture(
|
||||
IDalamudTextureWrap wrap,
|
||||
bool leaveWrapOpen = false)
|
||||
{
|
||||
using var wrapAux = new WrapAux(wrap, leaveWrapOpen);
|
||||
|
||||
var flags = TexFile.Attribute.TextureType2D;
|
||||
if (wrapAux.Desc.Usage == D3D11_USAGE.D3D11_USAGE_IMMUTABLE)
|
||||
flags |= TexFile.Attribute.Immutable;
|
||||
if (wrapAux.Desc.Usage == D3D11_USAGE.D3D11_USAGE_DYNAMIC)
|
||||
flags |= TexFile.Attribute.ReadWrite;
|
||||
if ((wrapAux.Desc.CPUAccessFlags & (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ) != 0)
|
||||
flags |= TexFile.Attribute.CpuRead;
|
||||
if ((wrapAux.Desc.BindFlags & (uint)D3D11_BIND_FLAG.D3D11_BIND_RENDER_TARGET) != 0)
|
||||
flags |= TexFile.Attribute.TextureRenderTarget;
|
||||
if ((wrapAux.Desc.BindFlags & (uint)D3D11_BIND_FLAG.D3D11_BIND_DEPTH_STENCIL) != 0)
|
||||
flags |= TexFile.Attribute.TextureDepthStencil;
|
||||
if (wrapAux.Desc.ArraySize != 1)
|
||||
throw new NotSupportedException("TextureArray2D is currently not supported.");
|
||||
|
||||
var gtex = FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture.CreateTexture2D(
|
||||
(int)wrapAux.Desc.Width,
|
||||
(int)wrapAux.Desc.Height,
|
||||
(byte)wrapAux.Desc.MipLevels,
|
||||
(uint)TexFile.TextureFormat.Null, // instructs the game to skip preprocessing it seems
|
||||
(uint)flags,
|
||||
0);
|
||||
|
||||
// Kernel::Texture owns these resources. We're passing the ownership to them.
|
||||
wrapAux.TexPtr->AddRef();
|
||||
wrapAux.SrvPtr->AddRef();
|
||||
|
||||
// Not sure this is needed
|
||||
var ltf = wrapAux.Desc.Format switch
|
||||
{
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT => TexFile.TextureFormat.R32G32B32A32F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16G16B16A16_FLOAT => TexFile.TextureFormat.R16G16B16A16F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT => TexFile.TextureFormat.R32G32F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16G16_FLOAT => TexFile.TextureFormat.R16G16F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT => TexFile.TextureFormat.R32F,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R24G8_TYPELESS => TexFile.TextureFormat.D24S8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_R16_TYPELESS => TexFile.TextureFormat.D16,
|
||||
DXGI_FORMAT.DXGI_FORMAT_A8_UNORM => TexFile.TextureFormat.A8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM => TexFile.TextureFormat.BC1,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM => TexFile.TextureFormat.BC2,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM => TexFile.TextureFormat.BC3,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM => TexFile.TextureFormat.BC5,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM => TexFile.TextureFormat.B4G4R4A4,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM => TexFile.TextureFormat.B5G5R5A1,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM => TexFile.TextureFormat.B8G8R8A8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_B8G8R8X8_UNORM => TexFile.TextureFormat.B8G8R8X8,
|
||||
DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM => TexFile.TextureFormat.BC7,
|
||||
_ => TexFile.TextureFormat.Null,
|
||||
};
|
||||
gtex->TextureFormat = (FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.TextureFormat)ltf;
|
||||
|
||||
gtex->D3D11Texture2D = wrapAux.TexPtr;
|
||||
gtex->D3D11ShaderResourceView = wrapAux.SrvPtr;
|
||||
return gtex;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ITextureProvider.IsDxgiFormatSupportedForCreateFromExistingTextureAsync(int dxgiFormat) =>
|
||||
this.IsDxgiFormatSupportedForCreateFromExistingTextureAsync((DXGI_FORMAT)dxgiFormat);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,10 @@ internal sealed class TextureManagerPluginScoped
|
|||
: $"{nameof(TextureManagerPluginScoped)}({this.plugin.Name})";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe nint ConvertToKernelTexture(IDalamudTextureWrap wrap, bool leaveWrapOpen = false) =>
|
||||
(nint)this.ManagerOrThrow.ConvertToKernelTexture(wrap, leaveWrapOpen);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDalamudTextureWrap CreateEmpty(
|
||||
RawImageSpecification specs,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System.Reflection;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Interface.Internal.Windows.Data.Widgets;
|
||||
using Dalamud.Interface.Textures;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
|
|
@ -281,4 +280,20 @@ public interface ITextureProvider
|
|||
/// <returns><c>true</c> if supported.</returns>
|
||||
/// <remarks><para>This function does not throw exceptions.</para></remarks>
|
||||
bool IsDxgiFormatSupportedForCreateFromExistingTextureAsync(int dxgiFormat);
|
||||
|
||||
/// <summary>Converts an existing <see cref="IDalamudTextureWrap"/> instance to a new instance of
|
||||
/// <see cref="FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture"/> which can be used to supply a custom
|
||||
/// texture onto an in-game addon (UI element.)</summary>
|
||||
/// <param name="wrap">Instance of <see cref="IDalamudTextureWrap"/> to convert.</param>
|
||||
/// <param name="leaveWrapOpen">Whether to leave <paramref name="wrap"/> non-disposed when the returned
|
||||
/// <see cref="Task{TResult}"/> completes.</param>
|
||||
/// <returns>Address of the new <see cref="FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture"/>.</returns>
|
||||
/// <example>See <c>PrintTextureInfo</c> in <see cref="Interface.Internal.UiDebug.PrintSimpleNode"/> for an example
|
||||
/// of replacing the texture of an image node.</example>
|
||||
/// <remarks>
|
||||
/// <para>If the returned kernel texture is to be destroyed, call the fourth function in its vtable, by calling
|
||||
/// <see cref="FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Texture.DecRef"/> or
|
||||
/// <c>((delegate* unmanaged<nint, void>)(*(nint**)ptr)[3](ptr)</c>.</para>
|
||||
/// </remarks>
|
||||
nint ConvertToKernelTexture(IDalamudTextureWrap wrap, bool leaveWrapOpen = false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ public interface ITextureReadbackProvider
|
|||
/// <remarks>
|
||||
/// <para>The length of the returned <c>RawData</c> may not match
|
||||
/// <see cref="RawImageSpecification.Height"/> * <see cref="RawImageSpecification.Pitch"/>.</para>
|
||||
/// <para><see cref="RawImageSpecification.Pitch"/> may not be the minimal value required to represent the texture
|
||||
/// bitmap data. For example, if a texture is 4x4 B8G8R8A8, the minimal pitch would be 32, but the function may
|
||||
/// return 64 instead.</para>
|
||||
/// <para>This function may throw an exception.</para>
|
||||
/// </remarks>
|
||||
Task<(RawImageSpecification Specification, byte[] RawData)> GetRawImageAsync(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue