Skip to content

Commit

Permalink
Add support for BC1/2/3 decompression (for 3D textures) (#2987)
Browse files Browse the repository at this point in the history
* Add support for BC1/2/3 decompression (for 3D textures)

* Optimize and clean up

* Unsafe not needed here

* Fix alpha value interpolation when a0 <= a1
  • Loading branch information
gdkchan authored Jan 22, 2022
1 parent 8117f6a commit 42c75db
Show file tree
Hide file tree
Showing 8 changed files with 709 additions and 132 deletions.
37 changes: 20 additions & 17 deletions Ryujinx.Graphics.GAL/Capabilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,32 @@ namespace Ryujinx.Graphics.GAL
{
public struct Capabilities
{
public bool HasFrontFacingBug { get; }
public bool HasVectorIndexingBug { get; }
public readonly bool HasFrontFacingBug;
public readonly bool HasVectorIndexingBug;

public bool SupportsAstcCompression { get; }
public bool SupportsBgraFormat { get; }
public bool SupportsR4G4Format { get; }
public bool SupportsFragmentShaderInterlock { get; }
public bool SupportsFragmentShaderOrderingIntel { get; }
public bool SupportsImageLoadFormatted { get; }
public bool SupportsMismatchingViewFormat { get; }
public bool SupportsNonConstantTextureOffset { get; }
public bool SupportsShaderBallot { get; }
public bool SupportsTextureShadowLod { get; }
public bool SupportsViewportSwizzle { get; }
public bool SupportsIndirectParameters { get; }
public readonly bool SupportsAstcCompression;
public readonly bool Supports3DTextureCompression;
public readonly bool SupportsBgraFormat;
public readonly bool SupportsR4G4Format;
public readonly bool SupportsFragmentShaderInterlock;
public readonly bool SupportsFragmentShaderOrderingIntel;
public readonly bool SupportsImageLoadFormatted;
public readonly bool SupportsMismatchingViewFormat;
public readonly bool SupportsNonConstantTextureOffset;
public readonly bool SupportsShaderBallot;
public readonly bool SupportsTextureShadowLod;
public readonly bool SupportsViewportSwizzle;
public readonly bool SupportsIndirectParameters;

public int MaximumComputeSharedMemorySize { get; }
public float MaximumSupportedAnisotropy { get; }
public int StorageBufferOffsetAlignment { get; }
public readonly int MaximumComputeSharedMemorySize;
public readonly float MaximumSupportedAnisotropy;
public readonly int StorageBufferOffsetAlignment;

public Capabilities(
bool hasFrontFacingBug,
bool hasVectorIndexingBug,
bool supportsAstcCompression,
bool supports3DTextureCompression,
bool supportsBgraFormat,
bool supportsR4G4Format,
bool supportsFragmentShaderInterlock,
Expand All @@ -44,6 +46,7 @@ public Capabilities(
HasFrontFacingBug = hasFrontFacingBug;
HasVectorIndexingBug = hasVectorIndexingBug;
SupportsAstcCompression = supportsAstcCompression;
Supports3DTextureCompression = supports3DTextureCompression;
SupportsBgraFormat = supportsBgraFormat;
SupportsR4G4Format = supportsR4G4Format;
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
Expand Down
22 changes: 0 additions & 22 deletions Ryujinx.Graphics.GAL/Format.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,9 @@ public enum Format
R10G10B10A2Uint,
R11G11B10Float,
R9G9B9E5Float,
Bc1RgbUnorm,
Bc1RgbaUnorm,
Bc2Unorm,
Bc3Unorm,
Bc1RgbSrgb,
Bc1RgbaSrgb,
Bc2Srgb,
Bc3Srgb,
Expand Down Expand Up @@ -349,25 +347,5 @@ public static bool IsInteger(this Format format)
{
return format.IsUint() || format.IsSint();
}

/// <summary>
/// Checks if the texture format is a BC4 compressed format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is a BC4 compressed format, false otherwise</returns>
public static bool IsBc4(this Format format)
{
return format == Format.Bc4Unorm || format == Format.Bc4Snorm;
}

/// <summary>
/// Checks if the texture format is a BC5 compressed format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is a BC5 compressed format, false otherwise</returns>
public static bool IsBc5(this Format format)
{
return format == Format.Bc5Unorm || format == Format.Bc5Snorm;
}
}
}
19 changes: 15 additions & 4 deletions Ryujinx.Graphics.Gpu/GpuContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,27 @@ public sealed class GpuContext : IDisposable
/// <summary>
/// Host hardware capabilities.
/// </summary>
internal Capabilities Capabilities => _caps.Value;
internal ref Capabilities Capabilities
{
get
{
if (!_capsLoaded)
{
_caps = Renderer.GetCapabilities();
_capsLoaded = true;
}

return ref _caps;
}
}

/// <summary>
/// Event for signalling shader cache loading progress.
/// </summary>
public event Action<ShaderCacheState, int, int> ShaderCacheStateChanged;

private readonly Lazy<Capabilities> _caps;
private bool _capsLoaded;
private Capabilities _caps;
private Thread _gpuThread;

/// <summary>
Expand All @@ -110,8 +123,6 @@ public GpuContext(IRenderer renderer)
DeferredActions = new Queue<Action>();

PhysicalMemoryRegistry = new ConcurrentDictionary<long, PhysicalMemory>();

_caps = new Lazy<Capabilities>(Renderer.GetCapabilities);
}

/// <summary>
Expand Down
30 changes: 24 additions & 6 deletions Ryujinx.Graphics.Gpu/Image/Texture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -834,13 +834,31 @@ public ReadOnlySpan<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data,
{
data = PixelConverter.ConvertR4G4ToR4G4B4A4(data);
}
else if (Target == Target.Texture3D && Format.IsBc4())
else if (!_context.Capabilities.Supports3DTextureCompression && Target == Target.Texture3D)
{
data = BCnDecoder.DecodeBC4(data, width, height, depth, levels, layers, Info.FormatInfo.Format == Format.Bc4Snorm);
}
else if (Target == Target.Texture3D && Format.IsBc5())
{
data = BCnDecoder.DecodeBC5(data, width, height, depth, levels, layers, Info.FormatInfo.Format == Format.Bc5Snorm);
switch (Format)
{
case Format.Bc1RgbaSrgb:
case Format.Bc1RgbaUnorm:
data = BCnDecoder.DecodeBC1(data, width, height, depth, levels, layers);
break;
case Format.Bc2Srgb:
case Format.Bc2Unorm:
data = BCnDecoder.DecodeBC2(data, width, height, depth, levels, layers);
break;
case Format.Bc3Srgb:
case Format.Bc3Unorm:
data = BCnDecoder.DecodeBC3(data, width, height, depth, levels, layers);
break;
case Format.Bc4Snorm:
case Format.Bc4Unorm:
data = BCnDecoder.DecodeBC4(data, width, height, depth, levels, layers, Format == Format.Bc4Snorm);
break;
case Format.Bc5Snorm:
case Format.Bc5Unorm:
data = BCnDecoder.DecodeBC5(data, width, height, depth, levels, layers, Format == Format.Bc5Snorm);
break;
}
}

return data;
Expand Down
18 changes: 10 additions & 8 deletions Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ static class TextureCompatibility
private enum FormatClass
{
Unclassified,
BCn64,
BCn128,
Bc1Rgb,
Bc1Rgba,
Bc2,
Bc3,
Expand Down Expand Up @@ -88,13 +85,21 @@ public static FormatInfo ToHostCompatibleFormat(TextureInfo info, Capabilities c
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
}

if (info.Target == Target.Texture3D)
if (!caps.Supports3DTextureCompression && info.Target == Target.Texture3D)
{
// The host API does not support 3D BC4/BC5 compressed formats.
// The host API does not support 3D compressed formats.
// We assume software decompression will be done for those textures,
// and so we adjust the format here to match the decompressor output.
switch (info.FormatInfo.Format)
{
case Format.Bc1RgbaSrgb:
case Format.Bc2Srgb:
case Format.Bc3Srgb:
return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4);
case Format.Bc1RgbaUnorm:
case Format.Bc2Unorm:
case Format.Bc3Unorm:
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
case Format.Bc4Unorm:
return new FormatInfo(Format.R8Unorm, 1, 1, 1, 1);
case Format.Bc4Snorm:
Expand Down Expand Up @@ -749,9 +754,6 @@ private static FormatClass GetFormatClass(Format format)
{
switch (format)
{
case Format.Bc1RgbSrgb:
case Format.Bc1RgbUnorm:
return FormatClass.Bc1Rgb;
case Format.Bc1RgbaSrgb:
case Format.Bc1RgbaUnorm:
return FormatClass.Bc1Rgba;
Expand Down
2 changes: 0 additions & 2 deletions Ryujinx.Graphics.OpenGL/FormatTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,9 @@ static FormatTable()
Add(Format.R10G10B10A2Uint, new FormatInfo(4, false, false, All.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed));
Add(Format.R11G11B10Float, new FormatInfo(3, false, false, All.R11fG11fB10f, PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev));
Add(Format.R9G9B9E5Float, new FormatInfo(3, false, false, All.Rgb9E5, PixelFormat.Rgb, PixelType.UnsignedInt5999Rev));
Add(Format.Bc1RgbUnorm, new FormatInfo(3, true, false, All.CompressedRgbS3tcDxt1Ext));
Add(Format.Bc1RgbaUnorm, new FormatInfo(4, true, false, All.CompressedRgbaS3tcDxt1Ext));
Add(Format.Bc2Unorm, new FormatInfo(4, true, false, All.CompressedRgbaS3tcDxt3Ext));
Add(Format.Bc3Unorm, new FormatInfo(4, true, false, All.CompressedRgbaS3tcDxt5Ext));
Add(Format.Bc1RgbSrgb, new FormatInfo(3, false, false, All.CompressedSrgbS3tcDxt1Ext));
Add(Format.Bc1RgbaSrgb, new FormatInfo(4, true, false, All.CompressedSrgbAlphaS3tcDxt1Ext));
Add(Format.Bc2Srgb, new FormatInfo(4, false, false, All.CompressedSrgbAlphaS3tcDxt3Ext));
Add(Format.Bc3Srgb, new FormatInfo(4, false, false, All.CompressedSrgbAlphaS3tcDxt5Ext));
Expand Down
1 change: 1 addition & 0 deletions Ryujinx.Graphics.OpenGL/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public Capabilities GetCapabilities()
hasFrontFacingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
hasVectorIndexingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
supports3DTextureCompression: false,
supportsBgraFormat: false,
supportsR4G4Format: false,
supportsFragmentShaderInterlock: HwCapabilities.SupportsFragmentShaderInterlock,
Expand Down
Loading

0 comments on commit 42c75db

Please sign in to comment.