Implement a software ETC2 texture decoder (#4121)

* Implement a software ETC2 texture decoder

* Fix output size calculation for non-2D textures

* Address PR feedback
This commit is contained in:
gdkchan 2022-12-21 20:39:58 -03:00 committed by GitHub
parent 219f63ff4e
commit f906eb06c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 763 additions and 10 deletions

View file

@ -208,8 +208,10 @@ namespace Ryujinx.Graphics.Gpu.Image
Bc6HSf16Float = Bc6HSf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff90
Bc6HUf16Float = Bc6HUf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff91
Etc2RgbUnorm = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24906
Etc2RgbPtaUnorm = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490a
Etc2RgbaUnorm = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490b
Etc2RgbUnormSrgb = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa4906
Etc2RgbPtaUnormSrgb = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490a
Etc2RgbaUnormSrgb = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490b
Astc2D4x4Unorm = Astc2D4x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24940
Astc2D5x4Unorm = Astc2D5x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24950
@ -429,8 +431,10 @@ namespace Ryujinx.Graphics.Gpu.Image
{ TextureFormat.Bc6HSf16Float, new FormatInfo(Format.Bc6HSfloat, 4, 4, 16, 4) },
{ TextureFormat.Bc6HUf16Float, new FormatInfo(Format.Bc6HUfloat, 4, 4, 16, 4) },
{ TextureFormat.Etc2RgbUnorm, new FormatInfo(Format.Etc2RgbUnorm, 4, 4, 8, 3) },
{ TextureFormat.Etc2RgbPtaUnorm, new FormatInfo(Format.Etc2RgbPtaUnorm, 4, 4, 8, 4) },
{ TextureFormat.Etc2RgbaUnorm, new FormatInfo(Format.Etc2RgbaUnorm, 4, 4, 16, 4) },
{ TextureFormat.Etc2RgbUnormSrgb, new FormatInfo(Format.Etc2RgbSrgb, 4, 4, 8, 3) },
{ TextureFormat.Etc2RgbPtaUnormSrgb, new FormatInfo(Format.Etc2RgbPtaSrgb, 4, 4, 8, 4) },
{ TextureFormat.Etc2RgbaUnormSrgb, new FormatInfo(Format.Etc2RgbaSrgb, 4, 4, 16, 4) },
{ TextureFormat.Astc2D4x4Unorm, new FormatInfo(Format.Astc4x4Unorm, 4, 4, 16, 4) },
{ TextureFormat.Astc2D5x4Unorm, new FormatInfo(Format.Astc5x4Unorm, 5, 4, 16, 4) },

View file

@ -857,9 +857,23 @@ namespace Ryujinx.Graphics.Gpu.Image
result = decoded;
}
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
{
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
switch (Format)
{
case Format.Etc2RgbaSrgb:
case Format.Etc2RgbaUnorm:
result = ETC2Decoder.DecodeRgba(result, width, height, depth, levels, layers);
break;
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm:
result = ETC2Decoder.DecodePta(result, width, height, depth, levels, layers);
break;
case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm:
result = ETC2Decoder.DecodeRgb(result, width, height, depth, levels, layers);
break;
}
}
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
{
@ -895,6 +909,10 @@ namespace Ryujinx.Graphics.Gpu.Image
break;
}
}
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
{
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
}
return result;
}

View file

@ -67,6 +67,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>A host compatible format</returns>
public static FormatInfo ToHostCompatibleFormat(TextureInfo info, Capabilities caps)
{
// The host API does not support those compressed formats.
// We assume software decompression will be done for those textures,
// and so we adjust the format here to match the decompressor output.
if (!caps.SupportsAstcCompression)
{
if (info.FormatInfo.Format.IsAstcUnorm())
@ -83,16 +87,8 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
{
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
}
if (!HostSupportsBcFormat(info.FormatInfo.Format, info.Target, caps))
{
// The host API does not this compressed format.
// 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:
@ -119,6 +115,26 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
if (!caps.SupportsEtc2Compression)
{
switch (info.FormatInfo.Format)
{
case Format.Etc2RgbaSrgb:
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbSrgb:
return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4);
case Format.Etc2RgbaUnorm:
case Format.Etc2RgbPtaUnorm:
case Format.Etc2RgbUnorm:
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
}
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
{
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
}
return info.FormatInfo;
}