From 3853191c48bc75b1090a229b493cf3ba7c15f2b5 Mon Sep 17 00:00:00 2001 From: Soreepeong Date: Sun, 3 Mar 2024 00:51:28 +0900 Subject: [PATCH] More cleanup --- .../Windows/Data/Widgets/TexWidget.cs | 26 ++- .../Internals/FontAtlasFactory.cs | 29 +-- .../Textures/Internal/TextureLoadThrottler.cs | 37 +++- .../TextureManager.FromExistingTexture.cs | 165 ++++++++---------- .../Textures/Internal/TextureManager.Wic.cs | 27 +-- .../Textures/Internal/TextureManager.cs | 110 ++++++------ Dalamud/Plugin/Services/ITextureProvider.cs | 28 ++- 7 files changed, 226 insertions(+), 196 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs index 6779d0d60..fb4330bea 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs @@ -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 { diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs index 87776f53a..27888bb0b 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs @@ -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(Task t) => t.IsCompleted ? t.Result : t.GetAwaiter().GetResult(); - /// - /// Clones a texture wrap, by getting a new reference to the underlying and the - /// texture behind. - /// - /// The to clone from. - /// The cloned . - private static IDalamudTextureWrap CloneTextureWrap(IDalamudTextureWrap wrap) - { - var srv = CppObject.FromPointer(wrap.ImGuiHandle); - using var res = srv.Resource; - using var tex2D = res.QueryInterface(); - var description = tex2D.Description; - return new DalamudTextureWrap( - new D3DTextureWrap( - srv.QueryInterface(), - description.Width, - description.Height)); - } - private static unsafe void ExtractChannelFromB8G8R8A8( Span target, ReadOnlySpan 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 diff --git a/Dalamud/Interface/Textures/Internal/TextureLoadThrottler.cs b/Dalamud/Interface/Textures/Internal/TextureLoadThrottler.cs index a996a2890..1e7db4659 100644 --- a/Dalamud/Interface/Textures/Internal/TextureLoadThrottler.cs +++ b/Dalamud/Interface/Textures/Internal/TextureLoadThrottler.cs @@ -72,18 +72,21 @@ internal class TextureLoadThrottler : IServiceType, IDisposable /// The throttle basis. /// The immediate load function. /// The cancellation token. + /// Disposables to dispose when the task completes. /// The task. public Task LoadTextureAsync( IThrottleBasisProvider basis, Func> 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(new ObjectDisposedException(nameof(TextureLoadThrottler))); + if (this.newItemChannel.Writer.TryWrite(work)) + return work.Task; + + work.Dispose(); + return Task.FromException(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 + private sealed class WorkItem : IComparable, IDisposable { private readonly TaskCompletionSource taskCompletionSource; private readonly IThrottleBasisProvider basis; private readonly CancellationToken cancellationToken; private readonly Func> immediateLoadFunction; + private readonly IDisposable?[] disposables; public WorkItem( IThrottleBasisProvider basis, Func> immediateLoadFunction, - CancellationToken cancellationToken) + CancellationToken cancellationToken, IDisposable?[] disposables) { this.taskCompletionSource = new(); this.basis = basis; this.cancellationToken = cancellationToken; + this.disposables = disposables; this.immediateLoadFunction = immediateLoadFunction; } public Task 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) diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.FromExistingTexture.cs b/Dalamud/Interface/Textures/Internal/TextureManager.FromExistingTexture.cs index e3a130a14..fc2a9e70f 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.FromExistingTexture.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.FromExistingTexture.cs @@ -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); /// - public bool IsDxgiFormatSupportedForCreateFromExistingTextureAsync(DXGI_FORMAT dxgiFormat) + public unsafe bool IsDxgiFormatSupportedForCreateFromExistingTextureAsync(DXGI_FORMAT dxgiFormat) { - if (this.interfaceManager.Scene is not { } scene) - { - _ = Service.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; } /// @@ -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); /// public Task 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); - using var srv = default(ComPtr); - 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 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); + 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); + } + } } /// @@ -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); /// 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); + using var wrapDispose = leaveWrapOpen ? null : wrap; using var texSrv = default(ComPtr); - using var device = default(ComPtr); using var context = default(ComPtr); using var tex2D = default(ComPtr); 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)) { @@ -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 device, @@ -242,28 +233,17 @@ internal sealed partial class TextureManager Vector2 uv1, DXGI_FORMAT format) { - using var resUnk = default(ComPtr); using var texSrv = default(ComPtr); - using var device = default(ComPtr); using var context = default(ComPtr); using var tex2D = default(ComPtr); 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)) - { - 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)) { @@ -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); } } } diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs b/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs index 6da68b7e0..ba70a95bf 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs @@ -37,23 +37,21 @@ internal sealed partial class TextureManager IDalamudTextureWrap wrap, Guid containerGuid, Stream stream, - bool leaveOpen = false, IReadOnlyDictionary? 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? 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) { diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.cs b/Dalamud/Interface/Textures/Internal/TextureManager.cs index 2a17f4d73..522167c55 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.cs @@ -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); } + /// Gets the D3D11 Device used to create textures. + public unsafe ComPtr Device + { + get + { + if (this.interfaceManager.Scene is not { } scene) + { + _ = Service.Get(); + scene = this.interfaceManager.Scene ?? throw new InvalidOperationException(); + } + + var device = default(ComPtr); + device.Attach((ID3D11Device*)scene.Device.NativePointer); + return device; + } + } + /// Gets the shared texture manager. public SharedTextureManager Shared => this.sharedTextureManager ?? @@ -183,65 +196,54 @@ internal sealed partial class TextureManager : IServiceType, IDisposable, ITextu this.IsDxgiFormatSupported((DXGI_FORMAT)dxgiFormat); /// - public bool IsDxgiFormatSupported(DXGI_FORMAT dxgiFormat) + public unsafe bool IsDxgiFormatSupported(DXGI_FORMAT dxgiFormat) { - if (this.interfaceManager.Scene is not { } scene) - { - _ = Service.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; } /// - internal IDalamudTextureWrap NoThrottleCreateFromRaw( + internal unsafe IDalamudTextureWrap NoThrottleCreateFromRaw( RawImageSpecification specs, ReadOnlySpan bytes) { - if (this.interfaceManager.Scene is not { } scene) + var device = this.Device; + + var texd = new D3D11_TEXTURE2D_DESC { - _ = Service.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); + 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); + 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); } /// Creates a texture from the given . 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); } diff --git a/Dalamud/Plugin/Services/ITextureProvider.cs b/Dalamud/Plugin/Services/ITextureProvider.cs index 7715bd5d0..854579bcd 100644 --- a/Dalamud/Plugin/Services/ITextureProvider.cs +++ b/Dalamud/Plugin/Services/ITextureProvider.cs @@ -36,7 +36,9 @@ public partial interface ITextureProvider /// without having to wait for the completion of the returned . /// The left top coordinates relative to the size of the source texture. /// The right bottom coordinates relative to the size of the source texture. - /// The desired target format. + /// The desired target format. Use 0 to use the source format. + /// Whether to leave non-disposed when the returned + /// completes. /// The cancellation token. /// A containing the copied texture on success. Dispose after use. /// @@ -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); /// 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); /// Gets the raw data of a texture 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 . + /// The source texture wrap. /// The left top coordinates relative to the size of the source texture. /// The right bottom coordinates relative to the size of the source texture. /// The desired target format. /// If 0 (unknown) is passed, then the format will not be converted. + /// Whether to leave non-disposed when the returned + /// completes. /// The cancellation token. /// The raw data and its specifications. /// @@ -206,27 +210,32 @@ public partial interface ITextureProvider Vector2 uv0, Vector2 uv1, int dxgiFormat = 0, + bool leaveWrapOpen = false, CancellationToken cancellationToken = default); /// Saves a texture wrap to a stream in an image file format. /// The texture wrap to save. /// The container GUID, obtained from . /// The stream to save to. - /// Whether to leave open. /// Properties to pass to the encoder. See /// Microsoft /// Learn for available parameters. + /// Whether to leave non-disposed when the returned + /// completes. + /// Whether to leave open when the returned + /// completes. /// The cancellation token. /// A task representing the save process. /// - /// may be disposed as soon as this function returns. + /// must not be disposed until the task finishes. /// Task SaveToStreamAsync( IDalamudTextureWrap wrap, Guid containerGuid, Stream stream, - bool leaveOpen = false, IReadOnlyDictionary? props = null, + bool leaveWrapOpen = false, + bool leaveStreamOpen = false, CancellationToken cancellationToken = default); /// Saves a texture wrap to a file as an image file. @@ -236,16 +245,19 @@ public partial interface ITextureProvider /// Properties to pass to the encoder. See /// Microsoft /// Learn for available parameters. + /// Whether to leave non-disposed when the returned + /// completes. /// The cancellation token. /// A task representing the save process. /// - /// may be disposed as soon as this function returns. + /// must not be disposed until the task finishes. /// Task SaveToFileAsync( IDalamudTextureWrap wrap, Guid containerGuid, string path, IReadOnlyDictionary? props = null, + bool leaveWrapOpen = false, CancellationToken cancellationToken = default); ///