Merge branch 'master' into luna

# Conflicts:
#	Penumbra/Api/Api/RedrawApi.cs
#	Penumbra/Api/Api/ResolveApi.cs
#	Penumbra/Api/Api/UiApi.cs
#	Penumbra/Interop/Services/TextureArraySlicer.cs
#	Penumbra/UI/CollectionTab/CollectionPanel.cs
#	Penumbra/UI/Tabs/CollectionsTab.cs
#	Penumbra/UI/Tabs/Debug/DebugTab.cs
#	Penumbra/UI/Tabs/Debug/GlobalVariablesDrawer.cs
#	Penumbra/UI/Tabs/ModsTab.cs
#	Penumbra/UI/Tabs/ResourceTab.cs
#	Penumbra/packages.lock.json
This commit is contained in:
Ottermandias 2025-12-19 14:52:06 +01:00
commit f035073966
26 changed files with 378 additions and 140 deletions

View file

@ -5,12 +5,12 @@ using Dalamud.Plugin.Services;
using Lumina.Data.Files;
using Luna;
using OtterTex;
using SharpDX.Direct3D11;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.PixelFormats;
using DxgiDevice = SharpDX.DXGI.Device;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using Image = SixLabors.ImageSharp.Image;
namespace Penumbra.Import.Textures;
@ -123,11 +123,11 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
switch (_type)
{
case TextureType.Png:
data?.SaveAsync(_outputPath, new PngEncoder() { CompressionLevel = PngCompressionLevel.NoCompression }, cancel)
data?.SaveAsync(_outputPath, new PngEncoder { CompressionLevel = PngCompressionLevel.NoCompression }, cancel)
.Wait(cancel);
return;
case TextureType.Targa:
data?.SaveAsync(_outputPath, new TgaEncoder()
data?.SaveAsync(_outputPath, new TgaEncoder
{
Compression = TgaCompression.None,
BitsPerPixel = TgaBitsPerPixel.Pixel32,
@ -202,11 +202,16 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
rgba, width, height),
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Dds => AddMipMaps(image.AsDds!, _mipMaps),
CombinedTexture.TextureSaveType.Bitmap => ConvertToRgbaDds(image, _mipMaps, cancel, rgba, width, height),
CombinedTexture.TextureSaveType.BC1 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC1UNorm, cancel, rgba, width, height),
CombinedTexture.TextureSaveType.BC3 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC3UNorm, cancel, rgba, width, height),
CombinedTexture.TextureSaveType.BC4 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC4UNorm, cancel, rgba, width, height),
CombinedTexture.TextureSaveType.BC5 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC5UNorm, cancel, rgba, width, height),
CombinedTexture.TextureSaveType.BC7 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC7UNorm, cancel, rgba, width, height),
CombinedTexture.TextureSaveType.BC1 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC1UNorm, cancel, rgba,
width, height),
CombinedTexture.TextureSaveType.BC3 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC3UNorm, cancel, rgba,
width, height),
CombinedTexture.TextureSaveType.BC4 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC4UNorm, cancel, rgba,
width, height),
CombinedTexture.TextureSaveType.BC5 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC5UNorm, cancel, rgba,
width, height),
CombinedTexture.TextureSaveType.BC7 => _textures.ConvertToCompressedDds(image, _mipMaps, DXGIFormat.BC7UNorm, cancel, rgba,
width, height),
_ => throw new Exception("Wrong save type."),
};
@ -388,7 +393,7 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
}
/// <summary> Create a BC3 or BC7 block-compressed .dds from the input (optionally with mipmaps). Returns input (+ mipmaps) if it is already the correct format. </summary>
public ScratchImage CreateCompressed(ScratchImage input, bool mipMaps, DXGIFormat format, CancellationToken cancel)
public unsafe ScratchImage CreateCompressed(ScratchImage input, bool mipMaps, DXGIFormat format, CancellationToken cancel)
{
if (input.Meta.Format == format)
return input;
@ -404,11 +409,58 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
// See https://github.com/microsoft/DirectXTex/wiki/Compress#parameters for the format condition.
if (format is DXGIFormat.BC6HUF16 or DXGIFormat.BC6HSF16 or DXGIFormat.BC7UNorm or DXGIFormat.BC7UNormSRGB)
{
var device = new Device(uiBuilder.DeviceHandle);
var dxgiDevice = device.QueryInterface<DxgiDevice>();
ref var device = ref *(ID3D11Device*)uiBuilder.DeviceHandle;
IDXGIDevice* dxgiDevice;
Marshal.ThrowExceptionForHR(device.QueryInterface(TerraFX.Interop.Windows.Windows.__uuidof<IDXGIDevice>(), (void**)&dxgiDevice));
using var deviceClone = new Device(dxgiDevice.Adapter, device.CreationFlags, device.FeatureLevel);
return input.Compress(deviceClone.NativePointer, format, CompressFlags.Parallel);
try
{
IDXGIAdapter* adapter = null;
Marshal.ThrowExceptionForHR(dxgiDevice->GetAdapter(&adapter));
try
{
dxgiDevice->Release();
dxgiDevice = null;
ID3D11Device* deviceClone = null;
ID3D11DeviceContext* contextClone = null;
var featureLevel = device.GetFeatureLevel();
Marshal.ThrowExceptionForHR(DirectX.D3D11CreateDevice(
adapter,
D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_UNKNOWN,
HMODULE.NULL,
device.GetCreationFlags(),
&featureLevel,
1,
D3D11.D3D11_SDK_VERSION,
&deviceClone,
null,
&contextClone));
try
{
adapter->Release();
adapter = null;
return input.Compress((nint)deviceClone, format, CompressFlags.Parallel);
}
finally
{
if (contextClone is not null)
contextClone->Release();
if (deviceClone is not null)
deviceClone->Release();
}
}
finally
{
if (adapter is not null)
adapter->Release();
}
}
finally
{
if (dxgiDevice is not null)
dxgiDevice->Release();
}
}
return input.Compress(format, CompressFlags.BC7Quick | CompressFlags.Parallel);
@ -454,7 +506,7 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
GC.KeepAlive(input);
}
private readonly struct ImageInputData
private readonly struct ImageInputData : IEquatable<ImageInputData>
{
private readonly string? _inputPath;
@ -522,5 +574,8 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
public override int GetHashCode()
=> _inputPath != null ? _inputPath.ToLowerInvariant().GetHashCode() : HashCode.Combine(_width, _height);
public override bool Equals(object? obj)
=> obj is ImageInputData o && Equals(o);
}
}