From 6c8c42ca059a26a2e62afe8299e449789ce39f56 Mon Sep 17 00:00:00 2001 From: Soreepeong Date: Sun, 3 Mar 2024 21:46:49 +0900 Subject: [PATCH] Cleanup --- .../Textures/Internal/TextureManager.Wic.cs | 102 +++++----- .../TerraFxCom/IPropertyBag2Extensions.cs | 83 --------- .../TerraFxComInterfaceExtensions.cs | 175 ++++++++++++++++++ 3 files changed, 225 insertions(+), 135 deletions(-) delete mode 100644 Dalamud/Utility/TerraFxCom/IPropertyBag2Extensions.cs create mode 100644 Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs b/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs index 3f8d9897c..2311923f8 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.Wic.cs @@ -41,31 +41,8 @@ internal sealed partial class TextureManager CancellationToken cancellationToken = default) { using var wrapDispose = leaveWrapOpen ? null : wrap; - var texDesc = default(D3D11_TEXTURE2D_DESC); - unsafe - { - using var texSrv = default(ComPtr); - using var context = default(ComPtr); - using var tex2D = default(ComPtr); - 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)) - { - texSrv.Get()->GetResource(texRes.GetAddressOf()); - - using var tex2DTemp = default(ComPtr); - texRes.As(&tex2DTemp).ThrowOnError(); - tex2D.Swap(&tex2DTemp); - } - - tex2D.Get()->GetDesc(&texDesc); - } - - var dxgiFormat = texDesc.Format; + var dxgiFormat = this.GetFormatOf(wrap); if (!WicManager.GetCorrespondingWicPixelFormat(dxgiFormat, out _, out _)) dxgiFormat = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM; @@ -73,10 +50,7 @@ internal sealed partial class TextureManager var (specs, bytes) = await this.GetRawImageAsync( wrap, - new() - { - Format = dxgiFormat, - }, + new() { Format = dxgiFormat }, true, cancellationToken).ConfigureAwait(false); @@ -102,14 +76,29 @@ internal sealed partial class TextureManager var pathTemp = $"{path}.{GetCurrentThreadId():X08}{Environment.TickCount64:X16}.tmp"; try { - await this.SaveToStreamAsync( - wrap, + var dxgiFormat = this.GetFormatOf(wrap); + if (!WicManager.GetCorrespondingWicPixelFormat(dxgiFormat, out _, out _)) + dxgiFormat = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM; + + using var istream = TerraFxComInterfaceExtensions.CreateIStreamFromFile( + pathTemp, + FileMode.Create, + FileAccess.Write, + FileShare.None); + + var (specs, bytes) = await this.GetRawImageAsync( + wrap, + new() { Format = dxgiFormat }, + true, + cancellationToken).ConfigureAwait(false); + + this.Wic.SaveToStreamUsingWic( + specs, + bytes, containerGuid, - File.Create(pathTemp), + istream, props, - leaveWrapOpen: true, - leaveStreamOpen: false, - cancellationToken: cancellationToken); + cancellationToken); } catch (Exception e) { @@ -182,7 +171,7 @@ internal sealed partial class TextureManager try { using var handle = bytes.Pin(); - using var stream = this.Wic.CreateIStreamFromMemory(handle, bytes.Length); + using var stream = this.Wic.CreateIStreamViewOfMemory(handle, bytes.Length); return this.Wic.NoThrottleCreateFromWicStream(stream, cancellationToken); } catch (Exception e1) @@ -212,7 +201,11 @@ internal sealed partial class TextureManager try { - using var stream = this.Wic.CreateIStreamFromFile(path); + using var stream = TerraFxComInterfaceExtensions.CreateIStreamFromFile( + path, + FileMode.Open, + FileAccess.Read, + FileShare.Read); return this.Wic.NoThrottleCreateFromWicStream(stream, cancellationToken); } catch (Exception e1) @@ -228,6 +221,26 @@ internal sealed partial class TextureManager } } + private unsafe DXGI_FORMAT GetFormatOf(IDalamudTextureWrap wrap) + { + using var texSrv = default(ComPtr); + using var context = default(ComPtr); + 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); + texSrv.Get()->GetResource(texRes.GetAddressOf()); + + using var tex2D = default(ComPtr); + texRes.As(&tex2D).ThrowOnError(); + + var texDesc = default(D3D11_TEXTURE2D_DESC); + tex2D.Get()->GetDesc(&texDesc); + return texDesc.Format; + } + /// A part of texture manager that uses Windows Imaging Component under the hood. internal sealed class WicManager : IDisposable { @@ -355,7 +368,7 @@ internal sealed partial class TextureManager /// An instance of . /// The number of bytes in the memory. /// The new instance of . - public unsafe ComPtr CreateIStreamFromMemory(MemoryHandle handle, int length) + public unsafe ComPtr CreateIStreamViewOfMemory(MemoryHandle handle, int length) { using var wicStream = default(ComPtr); this.wicFactory.Get()->CreateStream(wicStream.GetAddressOf()).ThrowOnError(); @@ -366,21 +379,6 @@ internal sealed partial class TextureManager return res; } - /// Creates a new instance of from a file path. - /// The file path. - /// The new instance of . - public unsafe ComPtr CreateIStreamFromFile(string path) - { - using var wicStream = default(ComPtr); - this.wicFactory.Get()->CreateStream(wicStream.GetAddressOf()).ThrowOnError(); - fixed (char* pPath = path) - wicStream.Get()->InitializeFromFilename((ushort*)pPath, GENERIC_READ).ThrowOnError(); - - var res = default(ComPtr); - wicStream.As(ref res).ThrowOnError(); - return res; - } - /// Creates a new instance of from a . /// The stream that will NOT be closed after. /// The cancellation token. diff --git a/Dalamud/Utility/TerraFxCom/IPropertyBag2Extensions.cs b/Dalamud/Utility/TerraFxCom/IPropertyBag2Extensions.cs deleted file mode 100644 index cfb11ae41..000000000 --- a/Dalamud/Utility/TerraFxCom/IPropertyBag2Extensions.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System.Runtime.InteropServices; - -using TerraFX.Interop.Windows; - -using static TerraFX.Interop.Windows.Windows; - -namespace Dalamud.Utility.TerraFxCom; - -/// Utilities for and its derivatives. -internal static unsafe partial class TerraFxComInterfaceExtensions -{ - /// Calls . - /// The property bag. - /// The name of the item to be interpreted as a VARIANT. - /// The new value, to be interpreted as a . - /// Return value from . - public static HRESULT Write(ref this IPropertyBag2 obj, string name, object? value) - { - VARIANT varValue; - // Marshal calls VariantInit. - Marshal.GetNativeVariantForObject(value, (nint)(&varValue)); - try - { - fixed (char* pName = name) - { - var option = new PROPBAG2 { pstrName = (ushort*)pName }; - return obj.Write(1, &option, &varValue); - } - } - finally - { - VariantClear(&varValue); - } - } - - /// Calls . - /// The object. - /// The name of the metadata. - /// The new value, to be interpreted as a . - /// Return value from . - public static HRESULT SetMetadataByName(ref this IWICMetadataQueryWriter obj, string name, object? value) - { - VARIANT varValue; - // Marshal calls VariantInit. - Marshal.GetNativeVariantForObject(value, (nint)(&varValue)); - try - { - PROPVARIANT propVarValue; - var propVarRes = VariantToPropVariant(&varValue, &propVarValue); - if (propVarRes < 0) - return propVarRes; - - try - { - fixed (char* pName = name) - return obj.SetMetadataByName((ushort*)pName, &propVarValue); - } - finally - { - _ = PropVariantClear(&propVarValue); - } - } - finally - { - _ = VariantClear(&varValue); - } - } - - /// Calls . - /// The object. - /// The name of the metadata. - /// Return value from . - public static HRESULT RemoveMetadataByName(ref this IWICMetadataQueryWriter obj, string name) - { - fixed (char* pName = name) - return obj.RemoveMetadataByName((ushort*)pName); - } - - [LibraryImport("propsys.dll")] - private static partial int VariantToPropVariant( - void* pVarIn, - void* pPropVarOut); -} diff --git a/Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs b/Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs new file mode 100644 index 000000000..f9252839f --- /dev/null +++ b/Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs @@ -0,0 +1,175 @@ +using System.IO; +using System.Runtime.InteropServices; + +using TerraFX.Interop.Windows; + +using static TerraFX.Interop.Windows.Windows; + +namespace Dalamud.Utility.TerraFxCom; + +/// Utilities for and its derivatives. +internal static unsafe partial class TerraFxComInterfaceExtensions +{ + /// Creates a new instance of from a file path. + /// The file path. + /// The file open mode. + /// The file access mode. + /// The file share mode. + /// The file attributes. + /// The new instance of . + public static ComPtr CreateIStreamFromFile( + string path, + FileMode mode, + FileAccess access, + FileShare share, + FileAttributes attributes = FileAttributes.Normal) + { + var grfMode = 0u; + bool fCreate; + switch (mode) + { + case FileMode.CreateNew: + fCreate = true; + grfMode |= STGM.STGM_FAILIFTHERE; + break; + case FileMode.Create: + fCreate = true; + grfMode |= STGM.STGM_CREATE; + break; + case FileMode.Open: + fCreate = false; + grfMode |= STGM.STGM_FAILIFTHERE; // yes + break; + case FileMode.OpenOrCreate: + throw new NotSupportedException( + $"${FileMode.OpenOrCreate} is not supported. It might be, but it needs testing."); + case FileMode.Append: + throw new NotSupportedException($"${FileMode.Append} is not supported."); + case FileMode.Truncate: + throw new NotSupportedException($"${FileMode.Truncate} is not supported."); + default: + throw new ArgumentOutOfRangeException(nameof(mode), mode, null); + } + + switch (access) + { + case FileAccess.Read: + grfMode |= STGM.STGM_READ; + break; + case FileAccess.Write: + grfMode |= STGM.STGM_WRITE; + break; + case FileAccess.ReadWrite: + grfMode |= STGM.STGM_READWRITE; + break; + default: + throw new ArgumentOutOfRangeException(nameof(access), access, null); + } + + switch (share) + { + case FileShare.None: + grfMode |= STGM.STGM_SHARE_EXCLUSIVE; + break; + case FileShare.Read: + grfMode |= STGM.STGM_SHARE_DENY_WRITE; + break; + case FileShare.Write: + grfMode |= STGM.STGM_SHARE_DENY_READ; + break; + case FileShare.ReadWrite: + grfMode |= STGM.STGM_SHARE_DENY_NONE; + break; + default: + throw new NotSupportedException($"Only ${FileShare.Read} and ${FileShare.Write} are supported."); + } + + using var stream = default(ComPtr); + fixed (char* pPath = path) + { + SHCreateStreamOnFileEx( + (ushort*)pPath, + grfMode, + (uint)attributes, + fCreate, + null, + stream.GetAddressOf()).ThrowOnError(); + } + + var res = default(ComPtr); + stream.As(ref res).ThrowOnError(); + return res; + } + + /// Calls . + /// The property bag. + /// The name of the item to be interpreted as a VARIANT. + /// The new value, to be interpreted as a . + /// Return value from . + public static HRESULT Write(ref this IPropertyBag2 obj, string name, object? value) + { + VARIANT varValue; + // Marshal calls VariantInit. + Marshal.GetNativeVariantForObject(value, (nint)(&varValue)); + try + { + fixed (char* pName = name) + { + var option = new PROPBAG2 { pstrName = (ushort*)pName }; + return obj.Write(1, &option, &varValue); + } + } + finally + { + VariantClear(&varValue); + } + } + + /// Calls . + /// The object. + /// The name of the metadata. + /// The new value, to be interpreted as a . + /// Return value from . + public static HRESULT SetMetadataByName(ref this IWICMetadataQueryWriter obj, string name, object? value) + { + VARIANT varValue; + // Marshal calls VariantInit. + Marshal.GetNativeVariantForObject(value, (nint)(&varValue)); + try + { + PROPVARIANT propVarValue; + var propVarRes = VariantToPropVariant(&varValue, &propVarValue); + if (propVarRes < 0) + return propVarRes; + + try + { + fixed (char* pName = name) + return obj.SetMetadataByName((ushort*)pName, &propVarValue); + } + finally + { + _ = PropVariantClear(&propVarValue); + } + } + finally + { + _ = VariantClear(&varValue); + } + } + + /// Calls . + /// The object. + /// The name of the metadata. + /// Return value from . + public static HRESULT RemoveMetadataByName(ref this IWICMetadataQueryWriter obj, string name) + { + fixed (char* pName = name) + return obj.RemoveMetadataByName((ushort*)pName); + } + + [LibraryImport("propsys.dll")] + private static partial int VariantToPropVariant( + void* pVarIn, + void* pPropVarOut); +}