Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Penumbra/Collections/Cache/CustomResourceCache.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using Luna;
using Penumbra.Api.Enums;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.SafeHandles;
using Penumbra.String.Classes;

namespace Penumbra.Collections.Cache;
Expand Down
4 changes: 4 additions & 0 deletions Penumbra/Config/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Penumbra.Api.Enums;
using Penumbra.Files;
using Penumbra.Import.Structs;
using Penumbra.Import.Textures;
using Penumbra.Interop.Services;
using Penumbra.Services;
using Penumbra.UI.Classes;
Expand Down Expand Up @@ -108,6 +109,9 @@ public bool EnableMods
[ConfigProperty(EventName = "ShowRenameChanged")]
private RenameField _showRename = RenameField.BothDataPrio;

[ConfigProperty(EventName = "AuxiliaryDeviceModeChanged")]
private AuxiliaryDeviceMode _auxiliaryDeviceMode = AuxiliaryDeviceMode.Singleton;

public ChangedItemMode ChangedItemDisplay { get; set; } = ChangedItemMode.GroupedCollapsed;
public int OptionGroupCollapsibleMin { get; set; } = 5;

Expand Down
28 changes: 28 additions & 0 deletions Penumbra/Import/Textures/AuxiliaryDeviceMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Luna.Generators;

namespace Penumbra.Import.Textures;

/// <remarks> Presented to the user as "Hardware Acceleration Mode for Texture Compression". </remarks>
[NamedEnum(Utf16: false)]
[TooltipEnum]
public enum AuxiliaryDeviceMode
{
[Name("Ephemeral")]
[Tooltip("Create an ephemeral Direct3D device object per texture compression operation.")]
Transient,

[Name("Persistent")]
[Tooltip(
"Create a persistent Direct3D device object on the first texture compression operation and keep it until Penumbra is unloaded or when this setting is changed.")]
Singleton,

[Name("Use Main Game Device")]
[Tooltip(
"Do not create an auxiliary Direct3D device object, and use the game's main one instead.\nWill cause freezes while doing texture compression operations.\nPrefer the above options if possible.")]
Borrowed,

[Name("Disable Hardware Acceleration")]
[Tooltip(
"Do not create an auxiliary Direct3D device object, and use a software compression method instead.\nWill significantly slow down texture compression operations, and significantly degrade the output quality.\nONLY USE AS A LAST RESORT.")]
None,
}
70 changes: 70 additions & 0 deletions Penumbra/Import/Textures/SaveToDdsTexFileEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Dalamud.Plugin.Services;
using Luna.DirectX;
using OtterTex;

namespace Penumbra.Import.Textures;

/// <summary> An image processing effect that saves its input to a file. </summary>
/// <param name="readbackProvider"> Dalamud's texture readback provider. </param>
/// <param name="textureManager"> The texture manager service. </param>
/// <param name="asTex"> Whether to save as TEX. </param>
/// <param name="path"> The path to save at. </param>
/// <param name="textureSaveType"> Which texture compression type to use. </param>
/// <param name="mipMaps"> Whether to add mipmaps to the saved texture. </param>
public class SaveToDdsTexFileEffect(
ITextureReadbackProvider readbackProvider,
TextureManager textureManager,
bool asTex,
string path,
CombinedTexture.TextureSaveType textureSaveType = CombinedTexture.TextureSaveType.AsIs,
bool? mipMaps = null) : ScratchImageReadbackEffect(readbackProvider)
{
/// <summary> Constructs a <see cref="SaveToDdsTexFileEffect"/>, inferring the format from the path's extension. </summary>
/// <param name="readbackProvider"> Dalamud's texture readback provider. </param>
/// <param name="textureManager"> The texture manager service. </param>
/// <param name="path"> The path to save at. </param>
/// <param name="textureSaveType"> Which texture compression type to use. </param>
/// <param name="mipMaps"> Whether to add mipmaps to the saved texture. </param>
public SaveToDdsTexFileEffect(ITextureReadbackProvider readbackProvider, TextureManager textureManager, string path,
CombinedTexture.TextureSaveType textureSaveType = CombinedTexture.TextureSaveType.AsIs,
bool? mipMaps = null)
: this(readbackProvider, textureManager, IsTex(path), path, textureSaveType, mipMaps)
{ }

/// <inheritdoc/>
protected override async Task Run(ScratchImage scratch, CancellationToken cancellationToken)
{
var converted = textureSaveType switch
{
CombinedTexture.TextureSaveType.AsIs => mipMaps is { } mips ? TextureManager.AddMipMaps(scratch, mips) : scratch,
CombinedTexture.TextureSaveType.Bitmap => TextureManager.CreateUncompressed(scratch, mipMaps ?? false, cancellationToken),
CombinedTexture.TextureSaveType.BC1 => await textureManager.CreateCompressedAsync(scratch, mipMaps ?? false, DXGIFormat.BC1UNorm,
cancellationToken),
CombinedTexture.TextureSaveType.BC3 => await textureManager.CreateCompressedAsync(scratch, mipMaps ?? false, DXGIFormat.BC3UNorm,
cancellationToken),
CombinedTexture.TextureSaveType.BC4 => await textureManager.CreateCompressedAsync(scratch, mipMaps ?? false, DXGIFormat.BC4UNorm,
cancellationToken),
CombinedTexture.TextureSaveType.BC5 => await textureManager.CreateCompressedAsync(scratch, mipMaps ?? false, DXGIFormat.BC5UNorm,
cancellationToken),
CombinedTexture.TextureSaveType.BC7 => await textureManager.CreateCompressedAsync(scratch, mipMaps ?? false, DXGIFormat.BC7UNorm,
cancellationToken),
_ => throw new Exception("Wrong save type."),
};

try
{
if (asTex)
TextureManager.SaveTex(path, converted);
else
converted.SaveDDS(path);
}
finally
{
if (converted != scratch)
converted.Dispose();
}
}

private static bool IsTex(string? path)
=> Path.GetExtension(path)?.ToLowerInvariant() is ".tex" or ".atex";
}
63 changes: 63 additions & 0 deletions Penumbra/Import/Textures/SaveToScratchImageEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Dalamud.Interface.Textures.TextureWraps;
using Dalamud.Plugin.Services;
using ImSharp;
using Luna.DirectX;
using OtterTex;
using Penumbra.Util;

namespace Penumbra.Import.Textures;

/// <summary> An image processing effect that saves its input to a <see cref="ScratchImage"/>. </summary>
/// <param name="readbackProvider"> Dalamud's texture readback provider. </param>
/// <seealso cref="ITextureReadbackProvider.GetAllRawImagesAsync"/>
public abstract class SaveToScratchImageEffect(ITextureReadbackProvider readbackProvider) : WrapEffectBase, IDisposable
{
private ScratchImage? _scratch;

/// <summary> The last run's image. </summary>
public ScratchImage? ScratchImage
=> _scratch;

/// <inheritdoc/>
public override int Count
=> 0;

/// <inheritdoc/>
public override ImTextureId this[int index]
=> throw new NotSupportedException();

~SaveToScratchImageEffect()
=> Dispose(false);

/// <summary> Gets the last run's image, transferring its ownership to the caller. </summary>
public ScratchImage? DetachScratchImage()
{
var scratch = _scratch;
_scratch = null;
return scratch;
}

/// <inheritdoc/>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

/// <summary> Releases the resources used by this object. </summary>
/// <param name="disposing"> True if called explicitly, false if garbage collected. </param>
protected virtual void Dispose(bool disposing)
{
_scratch?.Dispose();
_scratch = null;
}

/// <inheritdoc/>
protected override async Task Run(IDalamudTextureWrap wrap, CancellationToken cancellationToken)
{
var scratch = await readbackProvider.GetScratchImageAsync(wrap, true, cancellationToken)
.ConfigureAwait(false);
_scratch?.Dispose();
_scratch = scratch;
}
}
37 changes: 37 additions & 0 deletions Penumbra/Import/Textures/ScratchImageReadbackEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Dalamud.Interface.Textures.TextureWraps;
using Dalamud.Plugin.Services;
using ImSharp;
using Luna.DirectX;
using OtterTex;
using Penumbra.Util;

namespace Penumbra.Import.Textures;

/// <summary> Base class for effects that retrieve the pixel data as a <see cref="ScratchImage"/> and process it on the CPU side. </summary>
/// <param name="readbackProvider"> Dalamud's texture readback provider. </param>
/// <seealso cref="ITextureReadbackProvider.GetAllRawImagesAsync"/>
public abstract class ScratchImageReadbackEffect(ITextureReadbackProvider readbackProvider) : WrapEffectBase
{
/// <inheritdoc/>
public override int Count
=> 0;

/// <inheritdoc/>
public override ImTextureId this[int index]
=> throw new NotSupportedException();

/// <inheritdoc/>
protected override async Task Run(IDalamudTextureWrap wrap, CancellationToken cancellationToken)
{
using var scratch = await readbackProvider.GetScratchImageAsync(wrap, true, cancellationToken)
.ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
await Run(scratch, cancellationToken).ConfigureAwait(false);
}

/// <summary> Runs this effect. </summary>
/// <param name="scratch"> The input texture. </param>
/// <param name="cancellationToken"> A cancellation token. </param>
/// <returns> A task that represents this effect running. </returns>
protected abstract Task Run(ScratchImage scratch, CancellationToken cancellationToken);
}
8 changes: 4 additions & 4 deletions Penumbra/Import/Textures/TexFileParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,9 @@ public static TexFile.TextureFormat ToTexFormat(this DXGIFormat format)
DXGIFormat.BC1UNorm => TexFile.TextureFormat.BC1,
DXGIFormat.BC2UNorm => TexFile.TextureFormat.BC2,
DXGIFormat.BC3UNorm => TexFile.TextureFormat.BC3,
DXGIFormat.BC4UNorm => (TexFile.TextureFormat)0x6120, // TODO: upstream to Lumina
DXGIFormat.BC4UNorm => TexFile.TextureFormat.BC4,
DXGIFormat.BC5UNorm => TexFile.TextureFormat.BC5,
DXGIFormat.BC6HSF16 => (TexFile.TextureFormat)0x6330, // TODO: upstream to Lumina
DXGIFormat.BC6HSF16 => TexFile.TextureFormat.BC6H,
DXGIFormat.BC7UNorm => TexFile.TextureFormat.BC7,
DXGIFormat.R16G16B16A16Typeless => TexFile.TextureFormat.D16,
DXGIFormat.R24G8Typeless => TexFile.TextureFormat.D24S8,
Expand All @@ -274,9 +274,9 @@ public static DXGIFormat ToDXGI(this TexFile.TextureFormat format)
TexFile.TextureFormat.BC1 => DXGIFormat.BC1UNorm,
TexFile.TextureFormat.BC2 => DXGIFormat.BC2UNorm,
TexFile.TextureFormat.BC3 => DXGIFormat.BC3UNorm,
(TexFile.TextureFormat)0x6120 => DXGIFormat.BC4UNorm, // TODO: upstream to Lumina
TexFile.TextureFormat.BC4 => DXGIFormat.BC4UNorm,
TexFile.TextureFormat.BC5 => DXGIFormat.BC5UNorm,
(TexFile.TextureFormat)0x6330 => DXGIFormat.BC6HSF16, // TODO: upstream to Lumina
TexFile.TextureFormat.BC6H => DXGIFormat.BC6HSF16,
TexFile.TextureFormat.BC7 => DXGIFormat.BC7UNorm,
TexFile.TextureFormat.D16 => DXGIFormat.R16G16B16A16Typeless,
TexFile.TextureFormat.D24S8 => DXGIFormat.R24G8Typeless,
Expand Down
Loading
Loading