mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-19 07:43:35 +00:00
Add support for BC6 and BC7 decompression, decompress all BC formats if they are not supported by the host
This commit is contained in:
parent
65cecb0c2f
commit
782a0c4e93
18 changed files with 1435 additions and 138 deletions
|
@ -11,6 +11,9 @@ namespace Ryujinx.Graphics.GAL
|
|||
public readonly bool HasVectorIndexingBug;
|
||||
|
||||
public readonly bool SupportsAstcCompression;
|
||||
public readonly bool SupportsBc123Compression;
|
||||
public readonly bool SupportsBc45Compression;
|
||||
public readonly bool SupportsBc67Compression;
|
||||
public readonly bool Supports3DTextureCompression;
|
||||
public readonly bool SupportsBgraFormat;
|
||||
public readonly bool SupportsR4G4Format;
|
||||
|
@ -40,6 +43,9 @@ namespace Ryujinx.Graphics.GAL
|
|||
bool hasFrontFacingBug,
|
||||
bool hasVectorIndexingBug,
|
||||
bool supportsAstcCompression,
|
||||
bool supportsBc123Compression,
|
||||
bool supportsBc45Compression,
|
||||
bool supportsBc67Compression,
|
||||
bool supports3DTextureCompression,
|
||||
bool supportsBgraFormat,
|
||||
bool supportsR4G4Format,
|
||||
|
@ -66,6 +72,9 @@ namespace Ryujinx.Graphics.GAL
|
|||
HasFrontFacingBug = hasFrontFacingBug;
|
||||
HasVectorIndexingBug = hasVectorIndexingBug;
|
||||
SupportsAstcCompression = supportsAstcCompression;
|
||||
SupportsBc123Compression = supportsBc123Compression;
|
||||
SupportsBc45Compression = supportsBc45Compression;
|
||||
SupportsBc67Compression = supportsBc67Compression;
|
||||
Supports3DTextureCompression = supports3DTextureCompression;
|
||||
SupportsBgraFormat = supportsBgraFormat;
|
||||
SupportsR4G4Format = supportsR4G4Format;
|
||||
|
|
|
@ -844,7 +844,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
data = PixelConverter.ConvertR4G4ToR4G4B4A4(data);
|
||||
}
|
||||
else if (!_context.Capabilities.Supports3DTextureCompression && Target == Target.Texture3D)
|
||||
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
|
@ -868,6 +868,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
case Format.Bc5Unorm:
|
||||
data = BCnDecoder.DecodeBC5(data, width, height, depth, levels, layers, Format == Format.Bc5Snorm);
|
||||
break;
|
||||
case Format.Bc6HSfloat:
|
||||
case Format.Bc6HUfloat:
|
||||
data = BCnDecoder.DecodeBC6(data, width, height, depth, levels, layers, Format == Format.Bc6HSfloat);
|
||||
break;
|
||||
case Format.Bc7Srgb:
|
||||
case Format.Bc7Unorm:
|
||||
data = BCnDecoder.DecodeBC7(data, width, height, depth, levels, layers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,9 +88,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
|
||||
}
|
||||
|
||||
if (!caps.Supports3DTextureCompression && info.Target == Target.Texture3D)
|
||||
if (!HostSupportsBcFormat(info.FormatInfo.Format, info.Target, caps))
|
||||
{
|
||||
// The host API does not support 3D compressed formats.
|
||||
// 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)
|
||||
|
@ -98,10 +98,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
case Format.Bc1RgbaSrgb:
|
||||
case Format.Bc2Srgb:
|
||||
case Format.Bc3Srgb:
|
||||
case Format.Bc7Srgb:
|
||||
return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4);
|
||||
case Format.Bc1RgbaUnorm:
|
||||
case Format.Bc2Unorm:
|
||||
case Format.Bc3Unorm:
|
||||
case Format.Bc7Unorm:
|
||||
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
|
||||
case Format.Bc4Unorm:
|
||||
return new FormatInfo(Format.R8Unorm, 1, 1, 1, 1);
|
||||
|
@ -111,12 +113,50 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return new FormatInfo(Format.R8G8Unorm, 1, 1, 2, 2);
|
||||
case Format.Bc5Snorm:
|
||||
return new FormatInfo(Format.R8G8Snorm, 1, 1, 2, 2);
|
||||
case Format.Bc6HSfloat:
|
||||
case Format.Bc6HUfloat:
|
||||
return new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8, 4);
|
||||
}
|
||||
}
|
||||
|
||||
return info.FormatInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the host API supports a given texture compression format of the BC family.
|
||||
/// </summary>
|
||||
/// <param name="format">BC format to be checked</param>
|
||||
/// <param name="target">Target usage of the texture</param>
|
||||
/// <param name="caps">Host GPU Capabilities</param>
|
||||
/// <returns>True if the texture host supports the format with the given target usage, false otherwise</returns>
|
||||
public static bool HostSupportsBcFormat(Format format, Target target, Capabilities caps)
|
||||
{
|
||||
bool not3DOr3DCompressionSupported = target != Target.Texture3D || caps.Supports3DTextureCompression;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case Format.Bc1RgbaSrgb:
|
||||
case Format.Bc1RgbaUnorm:
|
||||
case Format.Bc2Srgb:
|
||||
case Format.Bc2Unorm:
|
||||
case Format.Bc3Srgb:
|
||||
case Format.Bc3Unorm:
|
||||
return caps.SupportsBc123Compression && not3DOr3DCompressionSupported;
|
||||
case Format.Bc4Unorm:
|
||||
case Format.Bc4Snorm:
|
||||
case Format.Bc5Unorm:
|
||||
case Format.Bc5Snorm:
|
||||
return caps.SupportsBc45Compression && not3DOr3DCompressionSupported;
|
||||
case Format.Bc6HSfloat:
|
||||
case Format.Bc6HUfloat:
|
||||
case Format.Bc7Srgb:
|
||||
case Format.Bc7Unorm:
|
||||
return caps.SupportsBc67Compression && not3DOr3DCompressionSupported;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a texture can flush its data back to guest memory.
|
||||
/// </summary>
|
||||
|
@ -748,7 +788,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// <returns>True if the texture target and samples count matches, false otherwise</returns>
|
||||
public static bool TargetAndSamplesCompatible(TextureInfo lhs, TextureInfo rhs)
|
||||
{
|
||||
return lhs.Target == rhs.Target &&
|
||||
return lhs.Target == rhs.Target &&
|
||||
lhs.SamplesInX == rhs.SamplesInX &&
|
||||
lhs.SamplesInY == rhs.SamplesInY;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
private static readonly Lazy<bool> _supportsQuads = new Lazy<bool>(SupportsQuadsCheck);
|
||||
private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture = new Lazy<bool>(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
|
||||
private static readonly Lazy<bool> _supportsShaderBallot = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionBptc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_bptc"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionRgtc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_rgtc"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionS3tc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_s3tc"));
|
||||
private static readonly Lazy<bool> _supportsTextureShadowLod = new Lazy<bool>(() => HasExtension("GL_EXT_texture_shadow_lod"));
|
||||
private static readonly Lazy<bool> _supportsViewportSwizzle = new Lazy<bool>(() => HasExtension("GL_NV_viewport_swizzle"));
|
||||
|
||||
|
@ -56,6 +59,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
public static bool SupportsQuads => _supportsQuads.Value;
|
||||
public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
|
||||
public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
|
||||
public static bool SupportsTextureCompressionBptc => _supportsTextureCompressionBptc.Value;
|
||||
public static bool SupportsTextureCompressionRgtc => _supportsTextureCompressionRgtc.Value;
|
||||
public static bool SupportsTextureCompressionS3tc => _supportsTextureCompressionS3tc.Value;
|
||||
public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
|
||||
public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
|
||||
|
||||
|
|
|
@ -105,6 +105,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
hasFrontFacingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
|
||||
hasVectorIndexingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
|
||||
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
|
||||
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
|
||||
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
|
||||
supportsBc67Compression: true, // Should check BPTC extension, but for some reason NVIDIA is not exposing the extension.
|
||||
supports3DTextureCompression: false,
|
||||
supportsBgraFormat: false,
|
||||
supportsR4G4Format: false,
|
||||
|
|
819
Ryujinx.Graphics.Texture/BC6Decoder.cs
Normal file
819
Ryujinx.Graphics.Texture/BC6Decoder.cs
Normal file
|
@ -0,0 +1,819 @@
|
|||
using Ryujinx.Graphics.Texture.Utils;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class BC6Decoder
|
||||
{
|
||||
private const int HalfOne = 0x3C00;
|
||||
|
||||
public static void Decode(Span<byte> output, ReadOnlySpan<byte> data, int width, int height, bool signed)
|
||||
{
|
||||
ReadOnlySpan<Block> blocks = MemoryMarshal.Cast<byte, Block>(data);
|
||||
|
||||
Span<ulong> output64 = MemoryMarshal.Cast<byte, ulong>(output);
|
||||
|
||||
int wInBlocks = (width + 3) / 4;
|
||||
int hInBlocks = (height + 3) / 4;
|
||||
|
||||
for (int y = 0; y < hInBlocks; y++)
|
||||
{
|
||||
int y2 = y * 4;
|
||||
int bh = Math.Min(4, height - y2);
|
||||
|
||||
for (int x = 0; x < wInBlocks; x++)
|
||||
{
|
||||
int x2 = x * 4;
|
||||
int bw = Math.Min(4, width - x2);
|
||||
|
||||
DecodeBlock(blocks[y * wInBlocks + x], output64.Slice(y2 * width + x2), bw, bh, width, signed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeBlock(Block block, Span<ulong> output, int w, int h, int width, bool signed)
|
||||
{
|
||||
int mode = (int)(block.Low & 3);
|
||||
if ((mode & 2) != 0)
|
||||
{
|
||||
mode = (int)(block.Low & 0x1f);
|
||||
}
|
||||
|
||||
Span<RgbaColor32> endPoints = stackalloc RgbaColor32[4];
|
||||
int subsetCount = DecodeEndPoints(ref block, endPoints, mode, signed);
|
||||
if (subsetCount == 0)
|
||||
{
|
||||
// Mode is invalid, the spec mandates that hardware fills the block with
|
||||
// a opaque black color.
|
||||
for (int ty = 0; ty < h; ty++)
|
||||
{
|
||||
int baseOffs = ty * width;
|
||||
|
||||
for (int tx = 0; tx < w; tx++)
|
||||
{
|
||||
output[baseOffs + tx] = (ulong)HalfOne << 48;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int partition;
|
||||
int indexBitCount;
|
||||
ulong indices;
|
||||
|
||||
if (subsetCount > 1)
|
||||
{
|
||||
partition = (int)((block.High >> 13) & 0x1F);
|
||||
indexBitCount = 3;
|
||||
|
||||
int fixUpIndex = BC67Tables.FixUpIndices[subsetCount - 1][partition][1] * 3;
|
||||
ulong lowMask = (ulong.MaxValue >> (65 - fixUpIndex)) << 3;
|
||||
ulong highMask = ulong.MaxValue << (fixUpIndex + 3);
|
||||
|
||||
indices = ((block.High >> 16) & highMask) | ((block.High >> 17) & lowMask) | ((block.High >> 18) & 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
partition = 0;
|
||||
indexBitCount = 4;
|
||||
indices = (block.High & ~0xFUL) | ((block.High >> 1) & 7);
|
||||
}
|
||||
|
||||
ulong indexMask = (1UL << indexBitCount) - 1;
|
||||
|
||||
for (int ty = 0; ty < h; ty++)
|
||||
{
|
||||
int baseOffs = ty * width;
|
||||
|
||||
for (int tx = 0; tx < w; tx++)
|
||||
{
|
||||
int offs = baseOffs + tx;
|
||||
int index = (int)(indices & indexMask);
|
||||
int endPointBase = BC67Tables.PartitionTable[subsetCount - 1][partition][ty * 4 + tx] << 1;
|
||||
|
||||
RgbaColor32 color1 = endPoints[endPointBase];
|
||||
RgbaColor32 color2 = endPoints[endPointBase + 1];
|
||||
|
||||
RgbaColor32 color = BC67Utils.Interpolate(color1, color2, index, indexBitCount);
|
||||
|
||||
output[offs] =
|
||||
(ulong)FinishUnquantize(color.R, signed) |
|
||||
((ulong)FinishUnquantize(color.G, signed) << 16) |
|
||||
((ulong)FinishUnquantize(color.B, signed) << 32) |
|
||||
((ulong)HalfOne << 48);
|
||||
|
||||
indices >>= indexBitCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int DecodeEndPoints(ref Block block, Span<RgbaColor32> endPoints, int mode, bool signed)
|
||||
{
|
||||
ulong low = block.Low;
|
||||
ulong high = block.High;
|
||||
|
||||
int r0 = 0, g0 = 0, b0 = 0, r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0, r3 = 0, g3 = 0, b3 = 0;
|
||||
int subsetCount;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case 0:
|
||||
r0 = (int)(low >> 5) & 0x3FF;
|
||||
g0 = (int)(low >> 15) & 0x3FF;
|
||||
b0 = (int)(low >> 25) & 0x3FF;
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 10);
|
||||
g0 = SignExtend(g0, 10);
|
||||
b0 = SignExtend(b0, 10);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 5);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 5);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 5);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 5);
|
||||
g2 = g0 + SignExtend((int)(((low << 2) & 0x10) | ((low >> 41) & 0xF)), 5);
|
||||
b2 = b0 + SignExtend((int)(((low << 1) & 0x10) | ((high << 3) & 0x08) | (low >> 61)), 5);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 5);
|
||||
g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((low) & 0x10) |
|
||||
((high >> 9) & 0x08) |
|
||||
((high >> 4) & 0x04) |
|
||||
((low >> 59) & 0x02) |
|
||||
((low >> 50) & 0x01)), 5);
|
||||
|
||||
r0 = Unquantize(r0, 10, signed);
|
||||
g0 = Unquantize(g0, 10, signed);
|
||||
b0 = Unquantize(b0, 10, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0x3FF, 10, signed);
|
||||
g1 = Unquantize(g1 & 0x3FF, 10, signed);
|
||||
b1 = Unquantize(b1 & 0x3FF, 10, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0x3FF, 10, signed);
|
||||
g2 = Unquantize(g2 & 0x3FF, 10, signed);
|
||||
b2 = Unquantize(b2 & 0x3FF, 10, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0x3FF, 10, signed);
|
||||
g3 = Unquantize(g3 & 0x3FF, 10, signed);
|
||||
b3 = Unquantize(b3 & 0x3FF, 10, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 1:
|
||||
r0 = (int)(low >> 5) & 0x7F;
|
||||
g0 = (int)(low >> 15) & 0x7F;
|
||||
b0 = (int)(low >> 25) & 0x7F;
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 7);
|
||||
g0 = SignExtend(g0, 7);
|
||||
b0 = SignExtend(b0, 7);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 6);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 6);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 6);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 6);
|
||||
g2 = g0 + SignExtend((int)(((low << 3) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0x0F)), 6);
|
||||
b2 = b0 + SignExtend((int)(
|
||||
((low >> 17) & 0x20) |
|
||||
((low >> 10) & 0x10) |
|
||||
((high << 3) & 0x08) |
|
||||
(low >> 61)), 6);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 6);
|
||||
g3 = g0 + SignExtend((int)(((low << 1) & 0x30) | ((low >> 51) & 0xF)), 6);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((low >> 28) & 0x20) |
|
||||
((low >> 30) & 0x10) |
|
||||
((low >> 29) & 0x08) |
|
||||
((low >> 21) & 0x04) |
|
||||
((low >> 12) & 0x03)), 6);
|
||||
|
||||
r0 = Unquantize(r0, 7, signed);
|
||||
g0 = Unquantize(g0, 7, signed);
|
||||
b0 = Unquantize(b0, 7, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0x7F, 7, signed);
|
||||
g1 = Unquantize(g1 & 0x7F, 7, signed);
|
||||
b1 = Unquantize(b1 & 0x7F, 7, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0x7F, 7, signed);
|
||||
g2 = Unquantize(g2 & 0x7F, 7, signed);
|
||||
b2 = Unquantize(b2 & 0x7F, 7, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0x7F, 7, signed);
|
||||
g3 = Unquantize(g3 & 0x7F, 7, signed);
|
||||
b3 = Unquantize(b3 & 0x7F, 7, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 2:
|
||||
r0 = (int)(((low >> 30) & 0x400) | ((low >> 5) & 0x3FF));
|
||||
g0 = (int)(((low >> 39) & 0x400) | ((low >> 15) & 0x3FF));
|
||||
b0 = (int)(((low >> 49) & 0x400) | ((low >> 25) & 0x3FF));
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 11);
|
||||
g0 = SignExtend(g0, 11);
|
||||
b0 = SignExtend(b0, 11);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 5);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 4);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 4);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 5);
|
||||
g2 = g0 + SignExtend((int)(low >> 41), 4);
|
||||
b2 = b0 + SignExtend((int)(((high << 3) & 8) | (low >> 61)), 4);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 5);
|
||||
g3 = g0 + SignExtend((int)(low >> 51), 4);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((high >> 9) & 8) |
|
||||
((high >> 4) & 4) |
|
||||
((low >> 59) & 2) |
|
||||
((low >> 50) & 1)), 4);
|
||||
|
||||
r0 = Unquantize(r0, 11, signed);
|
||||
g0 = Unquantize(g0, 11, signed);
|
||||
b0 = Unquantize(b0, 11, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0x7FF, 11, signed);
|
||||
g1 = Unquantize(g1 & 0x7FF, 11, signed);
|
||||
b1 = Unquantize(b1 & 0x7FF, 11, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0x7FF, 11, signed);
|
||||
g2 = Unquantize(g2 & 0x7FF, 11, signed);
|
||||
b2 = Unquantize(b2 & 0x7FF, 11, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0x7FF, 11, signed);
|
||||
g3 = Unquantize(g3 & 0x7FF, 11, signed);
|
||||
b3 = Unquantize(b3 & 0x7FF, 11, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 3:
|
||||
r0 = (int)(low >> 5) & 0x3FF;
|
||||
g0 = (int)(low >> 15) & 0x3FF;
|
||||
b0 = (int)(low >> 25) & 0x3FF;
|
||||
|
||||
r1 = (int)(low >> 35) & 0x3FF;
|
||||
g1 = (int)(low >> 45) & 0x3FF;
|
||||
b1 = (int)(((high << 9) & 0x200) | (low >> 55));
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 10);
|
||||
g0 = SignExtend(g0, 10);
|
||||
b0 = SignExtend(b0, 10);
|
||||
|
||||
r1 = SignExtend(r1, 10);
|
||||
g1 = SignExtend(g1, 10);
|
||||
b1 = SignExtend(b1, 10);
|
||||
}
|
||||
|
||||
r0 = Unquantize(r0, 10, signed);
|
||||
g0 = Unquantize(g0, 10, signed);
|
||||
b0 = Unquantize(b0, 10, signed);
|
||||
|
||||
r1 = Unquantize(r1, 10, signed);
|
||||
g1 = Unquantize(g1, 10, signed);
|
||||
b1 = Unquantize(b1, 10, signed);
|
||||
|
||||
subsetCount = 1;
|
||||
break;
|
||||
case 6:
|
||||
r0 = (int)(((low >> 29) & 0x400) | ((low >> 5) & 0x3FF));
|
||||
g0 = (int)(((low >> 40) & 0x400) | ((low >> 15) & 0x3FF));
|
||||
b0 = (int)(((low >> 49) & 0x400) | ((low >> 25) & 0x3FF));
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 11);
|
||||
g0 = SignExtend(g0, 11);
|
||||
b0 = SignExtend(b0, 11);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 4);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 5);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 4);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 4);
|
||||
g2 = g0 + SignExtend((int)(((high >> 7) & 0x10) | ((low >> 41) & 0x0F)), 5);
|
||||
b2 = b0 + SignExtend((int)(((high << 3) & 0x08) | ((low >> 61))), 4);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 4);
|
||||
g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0x0F)), 5);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((high >> 9) & 8) |
|
||||
((high >> 4) & 4) |
|
||||
((low >> 59) & 2) |
|
||||
((high >> 5) & 1)), 4);
|
||||
|
||||
r0 = Unquantize(r0, 11, signed);
|
||||
g0 = Unquantize(g0, 11, signed);
|
||||
b0 = Unquantize(b0, 11, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0x7FF, 11, signed);
|
||||
g1 = Unquantize(g1 & 0x7FF, 11, signed);
|
||||
b1 = Unquantize(b1 & 0x7FF, 11, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0x7FF, 11, signed);
|
||||
g2 = Unquantize(g2 & 0x7FF, 11, signed);
|
||||
b2 = Unquantize(b2 & 0x7FF, 11, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0x7FF, 11, signed);
|
||||
g3 = Unquantize(g3 & 0x7FF, 11, signed);
|
||||
b3 = Unquantize(b3 & 0x7FF, 11, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 7:
|
||||
r0 = (int)(((low >> 34) & 0x400) | ((low >> 5) & 0x3FF));
|
||||
g0 = (int)(((low >> 44) & 0x400) | ((low >> 15) & 0x3FF));
|
||||
b0 = (int)(((high << 10) & 0x400) | ((low >> 25) & 0x3FF));
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 11);
|
||||
g0 = SignExtend(g0, 11);
|
||||
b0 = SignExtend(b0, 11);
|
||||
}
|
||||
|
||||
r1 = (r0 + SignExtend((int)(low >> 35), 9)) & 0x7FF;
|
||||
g1 = (g0 + SignExtend((int)(low >> 45), 9)) & 0x7FF;
|
||||
b1 = (b0 + SignExtend((int)(low >> 55), 9)) & 0x7FF;
|
||||
|
||||
r0 = Unquantize(r0, 11, signed);
|
||||
g0 = Unquantize(g0, 11, signed);
|
||||
b0 = Unquantize(b0, 11, signed);
|
||||
|
||||
r1 = Unquantize(r1, 11, signed);
|
||||
g1 = Unquantize(g1, 11, signed);
|
||||
b1 = Unquantize(b1, 11, signed);
|
||||
|
||||
subsetCount = 1;
|
||||
break;
|
||||
case 10:
|
||||
r0 = (int)(((low >> 29) & 0x400) | ((low >> 5) & 0x3FF));
|
||||
g0 = (int)(((low >> 39) & 0x400) | ((low >> 15) & 0x3FF));
|
||||
b0 = (int)(((low >> 50) & 0x400) | ((low >> 25) & 0x3FF));
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 11);
|
||||
g0 = SignExtend(g0, 11);
|
||||
b0 = SignExtend(b0, 11);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 4);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 4);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 5);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 4);
|
||||
g2 = g0 + SignExtend((int)(low >> 41), 4);
|
||||
b2 = b0 + SignExtend((int)(((low >> 36) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 4);
|
||||
g3 = g0 + SignExtend((int)(low >> 51), 4);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((high >> 7) & 0x10) |
|
||||
((high >> 9) & 0x08) |
|
||||
((high >> 4) & 0x06) |
|
||||
((low >> 50) & 0x01)), 5);
|
||||
|
||||
r0 = Unquantize(r0, 11, signed);
|
||||
g0 = Unquantize(g0, 11, signed);
|
||||
b0 = Unquantize(b0, 11, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0x7FF, 11, signed);
|
||||
g1 = Unquantize(g1 & 0x7FF, 11, signed);
|
||||
b1 = Unquantize(b1 & 0x7FF, 11, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0x7FF, 11, signed);
|
||||
g2 = Unquantize(g2 & 0x7FF, 11, signed);
|
||||
b2 = Unquantize(b2 & 0x7FF, 11, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0x7FF, 11, signed);
|
||||
g3 = Unquantize(g3 & 0x7FF, 11, signed);
|
||||
b3 = Unquantize(b3 & 0x7FF, 11, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 11:
|
||||
r0 = (int)(((low >> 32) & 0x800) | ((low >> 34) & 0x400) | ((low >> 5) & 0x3FF));
|
||||
g0 = (int)(((low >> 42) & 0x800) | ((low >> 44) & 0x400) | ((low >> 15) & 0x3FF));
|
||||
b0 = (int)(((low >> 52) & 0x800) | ((high << 10) & 0x400) | ((low >> 25) & 0x3FF));
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 12);
|
||||
g0 = SignExtend(g0, 12);
|
||||
b0 = SignExtend(b0, 12);
|
||||
}
|
||||
|
||||
r1 = (r0 + SignExtend((int)(low >> 35), 8)) & 0xFFF;
|
||||
g1 = (g0 + SignExtend((int)(low >> 45), 8)) & 0xFFF;
|
||||
b1 = (b0 + SignExtend((int)(low >> 55), 8)) & 0xFFF;
|
||||
|
||||
r0 = Unquantize(r0, 12, signed);
|
||||
g0 = Unquantize(g0, 12, signed);
|
||||
b0 = Unquantize(b0, 12, signed);
|
||||
|
||||
r1 = Unquantize(r1, 12, signed);
|
||||
g1 = Unquantize(g1, 12, signed);
|
||||
b1 = Unquantize(b1, 12, signed);
|
||||
|
||||
subsetCount = 1;
|
||||
break;
|
||||
case 14:
|
||||
r0 = (int)(low >> 5) & 0x1FF;
|
||||
g0 = (int)(low >> 15) & 0x1FF;
|
||||
b0 = (int)(low >> 25) & 0x1FF;
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 9);
|
||||
g0 = SignExtend(g0, 9);
|
||||
b0 = SignExtend(b0, 9);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 5);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 5);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 5);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 5);
|
||||
g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
|
||||
b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 5);
|
||||
g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((low >> 30) & 0x10) |
|
||||
((high >> 9) & 0x08) |
|
||||
((high >> 4) & 0x04) |
|
||||
((low >> 59) & 0x02) |
|
||||
((low >> 50) & 0x01)), 5);
|
||||
|
||||
r0 = Unquantize(r0, 9, signed);
|
||||
g0 = Unquantize(g0, 9, signed);
|
||||
b0 = Unquantize(b0, 9, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0x1FF, 9, signed);
|
||||
g1 = Unquantize(g1 & 0x1FF, 9, signed);
|
||||
b1 = Unquantize(b1 & 0x1FF, 9, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0x1FF, 9, signed);
|
||||
g2 = Unquantize(g2 & 0x1FF, 9, signed);
|
||||
b2 = Unquantize(b2 & 0x1FF, 9, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0x1FF, 9, signed);
|
||||
g3 = Unquantize(g3 & 0x1FF, 9, signed);
|
||||
b3 = Unquantize(b3 & 0x1FF, 9, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 15:
|
||||
r0 = (BitReverse6((int)(low >> 39) & 0x3F) << 10) | ((int)(low >> 5) & 0x3FF);
|
||||
g0 = (BitReverse6((int)(low >> 49) & 0x3F) << 10) | ((int)(low >> 15) & 0x3FF);
|
||||
b0 = ((BitReverse6((int)(low >> 59)) | (int)(high & 1)) << 10) | ((int)(low >> 25) & 0x3FF);
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 16);
|
||||
g0 = SignExtend(g0, 16);
|
||||
b0 = SignExtend(b0, 16);
|
||||
}
|
||||
|
||||
r1 = (r0 + SignExtend((int)(low >> 35), 4)) & 0xFFFF;
|
||||
g1 = (g0 + SignExtend((int)(low >> 45), 4)) & 0xFFFF;
|
||||
b1 = (b0 + SignExtend((int)(low >> 55), 4)) & 0xFFFF;
|
||||
|
||||
subsetCount = 1;
|
||||
break;
|
||||
case 18:
|
||||
r0 = (int)(low >> 5) & 0xFF;
|
||||
g0 = (int)(low >> 15) & 0xFF;
|
||||
b0 = (int)(low >> 25) & 0xFF;
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 8);
|
||||
g0 = SignExtend(g0, 8);
|
||||
b0 = SignExtend(b0, 8);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 6);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 5);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 5);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 6);
|
||||
g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
|
||||
b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 6);
|
||||
g3 = g0 + SignExtend((int)(((low >> 9) & 0x10) | ((low >> 51) & 0xF)), 5);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((low >> 30) & 0x18) |
|
||||
((low >> 21) & 0x04) |
|
||||
((low >> 59) & 0x02) |
|
||||
((low >> 50) & 0x01)), 5);
|
||||
|
||||
r0 = Unquantize(r0, 8, signed);
|
||||
g0 = Unquantize(g0, 8, signed);
|
||||
b0 = Unquantize(b0, 8, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0xFF, 8, signed);
|
||||
g1 = Unquantize(g1 & 0xFF, 8, signed);
|
||||
b1 = Unquantize(b1 & 0xFF, 8, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0xFF, 8, signed);
|
||||
g2 = Unquantize(g2 & 0xFF, 8, signed);
|
||||
b2 = Unquantize(b2 & 0xFF, 8, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0xFF, 8, signed);
|
||||
g3 = Unquantize(g3 & 0xFF, 8, signed);
|
||||
b3 = Unquantize(b3 & 0xFF, 8, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 22:
|
||||
r0 = (int)(low >> 5) & 0xFF;
|
||||
g0 = (int)(low >> 15) & 0xFF;
|
||||
b0 = (int)(low >> 25) & 0xFF;
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 8);
|
||||
g0 = SignExtend(g0, 8);
|
||||
b0 = SignExtend(b0, 8);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 5);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 6);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 5);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 5);
|
||||
g2 = g0 + SignExtend((int)(((low >> 18) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 6);
|
||||
b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 0x08) | (low >> 61)), 5);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 5);
|
||||
g3 = g0 + SignExtend((int)(((low >> 28) & 0x20) | ((low >> 36) & 0x10) | ((low >> 51) & 0x0F)), 6);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((low >> 30) & 0x10) |
|
||||
((high >> 9) & 0x08) |
|
||||
((high >> 4) & 0x04) |
|
||||
((low >> 59) & 0x02) |
|
||||
((low >> 13) & 0x01)), 5);
|
||||
|
||||
r0 = Unquantize(r0, 8, signed);
|
||||
g0 = Unquantize(g0, 8, signed);
|
||||
b0 = Unquantize(b0, 8, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0xFF, 8, signed);
|
||||
g1 = Unquantize(g1 & 0xFF, 8, signed);
|
||||
b1 = Unquantize(b1 & 0xFF, 8, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0xFF, 8, signed);
|
||||
g2 = Unquantize(g2 & 0xFF, 8, signed);
|
||||
b2 = Unquantize(b2 & 0xFF, 8, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0xFF, 8, signed);
|
||||
g3 = Unquantize(g3 & 0xFF, 8, signed);
|
||||
b3 = Unquantize(b3 & 0xFF, 8, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 26:
|
||||
r0 = (int)(low >> 5) & 0xFF;
|
||||
g0 = (int)(low >> 15) & 0xFF;
|
||||
b0 = (int)(low >> 25) & 0xFF;
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 8);
|
||||
g0 = SignExtend(g0, 8);
|
||||
b0 = SignExtend(b0, 8);
|
||||
}
|
||||
|
||||
r1 = r0 + SignExtend((int)(low >> 35), 5);
|
||||
g1 = g0 + SignExtend((int)(low >> 45), 5);
|
||||
b1 = b0 + SignExtend((int)(low >> 55), 6);
|
||||
|
||||
r2 = r0 + SignExtend((int)(high >> 1), 5);
|
||||
g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
|
||||
b2 = b0 + SignExtend((int)(
|
||||
((low >> 18) & 0x20) |
|
||||
((low >> 10) & 0x10) |
|
||||
((high << 3) & 0x08) |
|
||||
(low >> 61)), 6);
|
||||
|
||||
r3 = r0 + SignExtend((int)(high >> 7), 5);
|
||||
g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
|
||||
b3 = b0 + SignExtend((int)(
|
||||
((low >> 28) & 0x20) |
|
||||
((low >> 30) & 0x10) |
|
||||
((high >> 9) & 0x08) |
|
||||
((high >> 4) & 0x04) |
|
||||
((low >> 12) & 0x02) |
|
||||
((low >> 50) & 0x01)), 6);
|
||||
|
||||
r0 = Unquantize(r0, 8, signed);
|
||||
g0 = Unquantize(g0, 8, signed);
|
||||
b0 = Unquantize(b0, 8, signed);
|
||||
|
||||
r1 = Unquantize(r1 & 0xFF, 8, signed);
|
||||
g1 = Unquantize(g1 & 0xFF, 8, signed);
|
||||
b1 = Unquantize(b1 & 0xFF, 8, signed);
|
||||
|
||||
r2 = Unquantize(r2 & 0xFF, 8, signed);
|
||||
g2 = Unquantize(g2 & 0xFF, 8, signed);
|
||||
b2 = Unquantize(b2 & 0xFF, 8, signed);
|
||||
|
||||
r3 = Unquantize(r3 & 0xFF, 8, signed);
|
||||
g3 = Unquantize(g3 & 0xFF, 8, signed);
|
||||
b3 = Unquantize(b3 & 0xFF, 8, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
case 30:
|
||||
r0 = (int)(low >> 5) & 0x3F;
|
||||
g0 = (int)(low >> 15) & 0x3F;
|
||||
b0 = (int)(low >> 25) & 0x3F;
|
||||
|
||||
r1 = (int)(low >> 35) & 0x3F;
|
||||
g1 = (int)(low >> 45) & 0x3F;
|
||||
b1 = (int)(low >> 55) & 0x3F;
|
||||
|
||||
r2 = (int)(high >> 1) & 0x3F;
|
||||
g2 = (int)(((low >> 16) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0xF));
|
||||
b2 = (int)(((low >> 17) & 0x20) | ((low >> 10) & 0x10) | ((high << 3) & 0x08) | (low >> 61));
|
||||
|
||||
r3 = (int)(high >> 7) & 0x3F;
|
||||
g3 = (int)(((low >> 26) & 0x20) | ((low >> 7) & 0x10) | ((low >> 51) & 0xF));
|
||||
b3 = (int)(
|
||||
((low >> 28) & 0x20) |
|
||||
((low >> 30) & 0x10) |
|
||||
((low >> 29) & 0x08) |
|
||||
((low >> 21) & 0x04) |
|
||||
((low >> 12) & 0x03));
|
||||
|
||||
if (signed)
|
||||
{
|
||||
r0 = SignExtend(r0, 6);
|
||||
g0 = SignExtend(g0, 6);
|
||||
b0 = SignExtend(b0, 6);
|
||||
|
||||
r1 = SignExtend(r1, 6);
|
||||
g1 = SignExtend(g1, 6);
|
||||
b1 = SignExtend(b1, 6);
|
||||
|
||||
r2 = SignExtend(r2, 6);
|
||||
g2 = SignExtend(g2, 6);
|
||||
b2 = SignExtend(b2, 6);
|
||||
|
||||
r3 = SignExtend(r3, 6);
|
||||
g3 = SignExtend(g3, 6);
|
||||
b3 = SignExtend(b3, 6);
|
||||
}
|
||||
|
||||
r0 = Unquantize(r0, 6, signed);
|
||||
g0 = Unquantize(g0, 6, signed);
|
||||
b0 = Unquantize(b0, 6, signed);
|
||||
|
||||
r1 = Unquantize(r1, 6, signed);
|
||||
g1 = Unquantize(g1, 6, signed);
|
||||
b1 = Unquantize(b1, 6, signed);
|
||||
|
||||
r2 = Unquantize(r2, 6, signed);
|
||||
g2 = Unquantize(g2, 6, signed);
|
||||
b2 = Unquantize(b2, 6, signed);
|
||||
|
||||
r3 = Unquantize(r3, 6, signed);
|
||||
g3 = Unquantize(g3, 6, signed);
|
||||
b3 = Unquantize(b3, 6, signed);
|
||||
|
||||
subsetCount = 2;
|
||||
break;
|
||||
default:
|
||||
subsetCount = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (subsetCount > 0)
|
||||
{
|
||||
endPoints[0] = new RgbaColor32(r0, g0, b0, HalfOne);
|
||||
endPoints[1] = new RgbaColor32(r1, g1, b1, HalfOne);
|
||||
|
||||
if (subsetCount > 1)
|
||||
{
|
||||
endPoints[2] = new RgbaColor32(r2, g2, b2, HalfOne);
|
||||
endPoints[3] = new RgbaColor32(r3, g3, b3, HalfOne);
|
||||
}
|
||||
}
|
||||
|
||||
return subsetCount;
|
||||
}
|
||||
|
||||
private static int SignExtend(int value, int bits)
|
||||
{
|
||||
int shift = 32 - bits;
|
||||
return (value << shift) >> shift;
|
||||
}
|
||||
|
||||
private static int Unquantize(int value, int bits, bool signed)
|
||||
{
|
||||
if (signed)
|
||||
{
|
||||
if (bits >= 16)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool sign = value < 0;
|
||||
|
||||
if (sign)
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else if (value >= ((1 << (bits - 1)) - 1))
|
||||
{
|
||||
value = 0x7FFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ((value << 15) + 0x4000) >> (bits - 1);
|
||||
}
|
||||
|
||||
if (sign)
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bits >= 15 || value == 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else if (value == ((1 << bits) - 1))
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((value << 16) + 0x8000) >> bits;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static ushort FinishUnquantize(int value, bool signed)
|
||||
{
|
||||
if (signed)
|
||||
{
|
||||
value = value < 0 ? -((-value * 31) >> 5) : (value * 31) >> 5;
|
||||
|
||||
int sign = 0;
|
||||
if (value < 0)
|
||||
{
|
||||
sign = 0x8000;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return (ushort)(sign | value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (ushort)((value * 31) >> 6);
|
||||
}
|
||||
}
|
||||
|
||||
private static int BitReverse6(int value)
|
||||
{
|
||||
value = ((value >> 1) & 0x55) | ((value << 1) & 0xaa);
|
||||
value = ((value >> 2) & 0x33) | ((value << 2) & 0xcc);
|
||||
value = ((value >> 4) & 0x0f) | ((value << 4) & 0xf0);
|
||||
return value >> 2;
|
||||
}
|
||||
}
|
||||
}
|
220
Ryujinx.Graphics.Texture/BC7Decoder.cs
Normal file
220
Ryujinx.Graphics.Texture/BC7Decoder.cs
Normal file
|
@ -0,0 +1,220 @@
|
|||
using Ryujinx.Graphics.Texture.Utils;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class BC7Decoder
|
||||
{
|
||||
public static void Decode(Span<byte> output, ReadOnlySpan<byte> data, int width, int height)
|
||||
{
|
||||
ReadOnlySpan<Block> blocks = MemoryMarshal.Cast<byte, Block>(data);
|
||||
|
||||
Span<uint> output32 = MemoryMarshal.Cast<byte, uint>(output);
|
||||
|
||||
int wInBlocks = (width + 3) / 4;
|
||||
int hInBlocks = (height + 3) / 4;
|
||||
|
||||
for (int y = 0; y < hInBlocks; y++)
|
||||
{
|
||||
int y2 = y * 4;
|
||||
int bh = Math.Min(4, height - y2);
|
||||
|
||||
for (int x = 0; x < wInBlocks; x++)
|
||||
{
|
||||
int x2 = x * 4;
|
||||
int bw = Math.Min(4, width - x2);
|
||||
|
||||
DecodeBlock(blocks[y * wInBlocks + x], output32.Slice(y2 * width + x2), bw, bh, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeBlock(Block block, Span<uint> output, int w, int h, int width)
|
||||
{
|
||||
int mode = BitOperations.TrailingZeroCount((byte)block.Low | 0x100);
|
||||
if (mode == 8)
|
||||
{
|
||||
// Mode is invalid, the spec mandates that hardware fills the block with
|
||||
// a transparent black color.
|
||||
for (int ty = 0; ty < h; ty++)
|
||||
{
|
||||
int baseOffs = ty * width;
|
||||
|
||||
for (int tx = 0; tx < w; tx++)
|
||||
{
|
||||
int offs = baseOffs + tx;
|
||||
|
||||
output[offs] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BC7ModeInfo modeInfo = BC67Tables.BC7ModeInfos[mode];
|
||||
|
||||
int offset = mode + 1;
|
||||
int partition = (int)block.Decode(ref offset, modeInfo.PartitionBitCount);
|
||||
int rotation = (int)block.Decode(ref offset, modeInfo.RotationBitCount);
|
||||
int indexMode = (int)block.Decode(ref offset, modeInfo.IndexModeBitCount);
|
||||
|
||||
Debug.Assert(partition < 64);
|
||||
Debug.Assert(rotation < 4);
|
||||
Debug.Assert(indexMode < 2);
|
||||
|
||||
int endPointCount = modeInfo.SubsetCount * 2;
|
||||
|
||||
Span<RgbaColor32> endPoints = stackalloc RgbaColor32[endPointCount];
|
||||
Span<byte> pValues = stackalloc byte[modeInfo.PBits];
|
||||
|
||||
endPoints.Fill(new RgbaColor32(0, 0, 0, 255));
|
||||
|
||||
for (int i = 0; i < endPointCount; i++)
|
||||
{
|
||||
endPoints[i].R = (int)block.Decode(ref offset, modeInfo.ColorDepth);
|
||||
}
|
||||
|
||||
for (int i = 0; i < endPointCount; i++)
|
||||
{
|
||||
endPoints[i].G = (int)block.Decode(ref offset, modeInfo.ColorDepth);
|
||||
}
|
||||
|
||||
for (int i = 0; i < endPointCount; i++)
|
||||
{
|
||||
endPoints[i].B = (int)block.Decode(ref offset, modeInfo.ColorDepth);
|
||||
}
|
||||
|
||||
if (modeInfo.AlphaDepth != 0)
|
||||
{
|
||||
for (int i = 0; i < endPointCount; i++)
|
||||
{
|
||||
endPoints[i].A = (int)block.Decode(ref offset, modeInfo.AlphaDepth);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < modeInfo.PBits; i++)
|
||||
{
|
||||
pValues[i] = (byte)block.Decode(ref offset, 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < endPointCount; i++)
|
||||
{
|
||||
int pBit = -1;
|
||||
|
||||
if (modeInfo.PBits != 0)
|
||||
{
|
||||
int pIndex = (i * modeInfo.PBits) / endPointCount;
|
||||
pBit = pValues[pIndex];
|
||||
}
|
||||
|
||||
Unquantize(ref endPoints[i], modeInfo.ColorDepth, modeInfo.AlphaDepth, pBit);
|
||||
}
|
||||
|
||||
byte[] partitionTable = BC67Tables.PartitionTable[modeInfo.SubsetCount - 1][partition];
|
||||
byte[] fixUpTable = BC67Tables.FixUpIndices[modeInfo.SubsetCount - 1][partition];
|
||||
|
||||
Span<byte> colorIndices = stackalloc byte[16];
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
byte subset = partitionTable[i];
|
||||
int bitCount = i == fixUpTable[subset] ? modeInfo.ColorIndexBitCount - 1 : modeInfo.ColorIndexBitCount;
|
||||
|
||||
colorIndices[i] = (byte)block.Decode(ref offset, bitCount);
|
||||
Debug.Assert(colorIndices[i] < 16);
|
||||
}
|
||||
|
||||
Span<byte> alphaIndices = stackalloc byte[16];
|
||||
|
||||
if (modeInfo.AlphaIndexBitCount != 0)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int bitCount = i != 0 ? modeInfo.AlphaIndexBitCount : modeInfo.AlphaIndexBitCount - 1;
|
||||
|
||||
alphaIndices[i] = (byte)block.Decode(ref offset, bitCount);
|
||||
Debug.Assert(alphaIndices[i] < 16);
|
||||
}
|
||||
}
|
||||
|
||||
for (int ty = 0; ty < h; ty++)
|
||||
{
|
||||
int baseOffs = ty * width;
|
||||
|
||||
for (int tx = 0; tx < w; tx++)
|
||||
{
|
||||
int i = ty * 4 + tx;
|
||||
|
||||
RgbaColor32 color;
|
||||
|
||||
byte subset = partitionTable[i];
|
||||
|
||||
RgbaColor32 color1 = endPoints[subset * 2];
|
||||
RgbaColor32 color2 = endPoints[subset * 2 + 1];
|
||||
|
||||
if (modeInfo.AlphaIndexBitCount != 0)
|
||||
{
|
||||
if (indexMode == 0)
|
||||
{
|
||||
color = BC67Utils.Interpolate(color1, color2, colorIndices[i], alphaIndices[i], modeInfo.ColorIndexBitCount, modeInfo.AlphaIndexBitCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = BC67Utils.Interpolate(color1, color2, alphaIndices[i], colorIndices[i], modeInfo.AlphaIndexBitCount, modeInfo.ColorIndexBitCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = BC67Utils.Interpolate(color1, color2, colorIndices[i], colorIndices[i], modeInfo.ColorIndexBitCount, modeInfo.ColorIndexBitCount);
|
||||
}
|
||||
|
||||
if (rotation != 0)
|
||||
{
|
||||
int a = color.A;
|
||||
|
||||
switch (rotation)
|
||||
{
|
||||
case 1: color.A = color.R; color.R = a; break;
|
||||
case 2: color.A = color.G; color.G = a; break;
|
||||
case 3: color.A = color.B; color.B = a; break;
|
||||
}
|
||||
}
|
||||
|
||||
RgbaColor8 color8 = color.GetColor8();
|
||||
|
||||
output[baseOffs + tx] = color8.ToUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Unquantize(ref RgbaColor32 color, int colorDepth, int alphaDepth, int pBit)
|
||||
{
|
||||
color.R = UnquantizeComponent(color.R, colorDepth, pBit);
|
||||
color.G = UnquantizeComponent(color.G, colorDepth, pBit);
|
||||
color.B = UnquantizeComponent(color.B, colorDepth, pBit);
|
||||
color.A = alphaDepth != 0 ? UnquantizeComponent(color.A, alphaDepth, pBit) : 255;
|
||||
}
|
||||
|
||||
private static int UnquantizeComponent(int component, int bits, int pBit)
|
||||
{
|
||||
int shift = 8 - bits;
|
||||
int value = component << shift;
|
||||
|
||||
if (pBit >= 0)
|
||||
{
|
||||
Debug.Assert(pBit <= 1);
|
||||
value |= value >> (bits + 1);
|
||||
value |= pBit << (shift - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
value |= value >> bits;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -515,6 +515,82 @@ namespace Ryujinx.Graphics.Texture
|
|||
return output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC6(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 8;
|
||||
}
|
||||
|
||||
byte[] output = new byte[size];
|
||||
|
||||
int inputOffset = 0;
|
||||
int outputOffset = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
int w = BitUtils.DivRoundUp(width, BlockWidth);
|
||||
int h = BitUtils.DivRoundUp(height, BlockHeight);
|
||||
|
||||
for (int l2 = 0; l2 < layers; l2++)
|
||||
{
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
BC6Decoder.Decode(output.AsSpan().Slice(outputOffset), data.Slice(inputOffset), width, height, signed);
|
||||
|
||||
inputOffset += w * h * 16;
|
||||
outputOffset += width * height * 8;
|
||||
}
|
||||
}
|
||||
|
||||
width = Math.Max(1, width >> 1);
|
||||
height = Math.Max(1, height >> 1);
|
||||
depth = Math.Max(1, depth >> 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeBC7(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
|
||||
}
|
||||
|
||||
byte[] output = new byte[size];
|
||||
|
||||
int inputOffset = 0;
|
||||
int outputOffset = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
int w = BitUtils.DivRoundUp(width, BlockWidth);
|
||||
int h = BitUtils.DivRoundUp(height, BlockHeight);
|
||||
|
||||
for (int l2 = 0; l2 < layers; l2++)
|
||||
{
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
BC7Decoder.Decode(output.AsSpan().Slice(outputOffset), data.Slice(inputOffset), width, height);
|
||||
|
||||
inputOffset += w * h * 16;
|
||||
outputOffset += width * height * 4;
|
||||
}
|
||||
}
|
||||
|
||||
width = Math.Max(1, width >> 1);
|
||||
height = Math.Max(1, height >> 1);
|
||||
depth = Math.Max(1, depth >> 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static ulong InterleaveBytes(uint left, uint right)
|
||||
{
|
||||
return InterleaveBytesWithZeros(left) | (InterleaveBytesWithZeros(right) << 8);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Ryujinx.Graphics.Texture.Utils;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -10,53 +11,6 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
{
|
||||
static class BC7Encoder
|
||||
{
|
||||
private struct ModeInfo
|
||||
{
|
||||
public readonly int SubsetCount;
|
||||
public readonly int PartitionBitCount;
|
||||
public readonly int PBits;
|
||||
public readonly int RotationBitCount;
|
||||
public readonly int IndexModeBitCount;
|
||||
public readonly int ColorIndexBitCount;
|
||||
public readonly int AlphaIndexBitCount;
|
||||
public readonly int ColorDepth;
|
||||
public readonly int AlphaDepth;
|
||||
|
||||
public ModeInfo(
|
||||
int subsetCount,
|
||||
int partitionBitsCount,
|
||||
int pBits,
|
||||
int rotationBitCount,
|
||||
int indexModeBitCount,
|
||||
int colorIndexBitCount,
|
||||
int alphaIndexBitCount,
|
||||
int colorDepth,
|
||||
int alphaDepth)
|
||||
{
|
||||
SubsetCount = subsetCount;
|
||||
PartitionBitCount = partitionBitsCount;
|
||||
PBits = pBits;
|
||||
RotationBitCount = rotationBitCount;
|
||||
IndexModeBitCount = indexModeBitCount;
|
||||
ColorIndexBitCount = colorIndexBitCount;
|
||||
AlphaIndexBitCount = alphaIndexBitCount;
|
||||
ColorDepth = colorDepth;
|
||||
AlphaDepth = alphaDepth;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ModeInfo[] _modeInfos = new ModeInfo[]
|
||||
{
|
||||
new ModeInfo(3, 4, 6, 0, 0, 3, 0, 4, 0),
|
||||
new ModeInfo(2, 6, 2, 0, 0, 3, 0, 6, 0),
|
||||
new ModeInfo(3, 6, 0, 0, 0, 2, 0, 5, 0),
|
||||
new ModeInfo(2, 6, 4, 0, 0, 2, 0, 7, 0),
|
||||
new ModeInfo(1, 0, 0, 2, 1, 2, 3, 5, 6),
|
||||
new ModeInfo(1, 0, 0, 2, 0, 2, 2, 7, 8),
|
||||
new ModeInfo(1, 0, 2, 0, 0, 4, 0, 7, 7),
|
||||
new ModeInfo(2, 6, 4, 0, 0, 2, 0, 5, 5)
|
||||
};
|
||||
|
||||
public static void Encode(Memory<byte> outputStorage, ReadOnlyMemory<byte> data, int width, int height, EncodeMode mode)
|
||||
{
|
||||
int widthInBlocks = (width + 3) / 4;
|
||||
|
@ -105,32 +59,6 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
0, 13, 2, 1, 15, 14, 10, 23
|
||||
};
|
||||
|
||||
private struct Block
|
||||
{
|
||||
public ulong Low;
|
||||
public ulong High;
|
||||
|
||||
public void Encode(ulong value, ref int offset, int bits)
|
||||
{
|
||||
if (offset >= 64)
|
||||
{
|
||||
High |= value << (offset - 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
Low |= value << offset;
|
||||
|
||||
if (offset + bits > 64)
|
||||
{
|
||||
int remainder = 64 - offset;
|
||||
High |= value >> remainder;
|
||||
}
|
||||
}
|
||||
|
||||
offset += bits;
|
||||
}
|
||||
}
|
||||
|
||||
private static Block CompressBlock(ReadOnlySpan<byte> data, int x, int y, int width, int height, bool fastMode)
|
||||
{
|
||||
int w = Math.Min(4, width - x);
|
||||
|
@ -157,10 +85,10 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
private static Block EncodeFast(ReadOnlySpan<uint> tile, int w, int h)
|
||||
{
|
||||
(RgbaColor8 minColor, RgbaColor8 maxColor) = BC7Utils.GetMinMaxColors(tile, w, h);
|
||||
(RgbaColor8 minColor, RgbaColor8 maxColor) = BC67Utils.GetMinMaxColors(tile, w, h);
|
||||
|
||||
bool alphaNotOne = minColor.A != 255 || maxColor.A != 255;
|
||||
int variance = BC7Utils.SquaredDifference(minColor.GetColor32(), maxColor.GetColor32());
|
||||
int variance = BC67Utils.SquaredDifference(minColor.GetColor32(), maxColor.GetColor32());
|
||||
int selectedMode;
|
||||
int indexMode = 0;
|
||||
|
||||
|
@ -253,13 +181,13 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
{
|
||||
for (int im = 0; im < (m == 4 ? 2 : 1); im++)
|
||||
{
|
||||
for (int p = 0; p < 1 << _modeInfos[m].PartitionBitCount; p++)
|
||||
for (int p = 0; p < 1 << BC67Tables.BC7ModeInfos[m].PartitionBitCount; p++)
|
||||
{
|
||||
Block block = Encode(m, p, r, im, fastMode: false, tile, w, h, out int maxError);
|
||||
if (maxError < lowestError || (maxError == lowestError && _modeInfos[m].SubsetCount < lowestErrorSubsets))
|
||||
if (maxError < lowestError || (maxError == lowestError && BC67Tables.BC7ModeInfos[m].SubsetCount < lowestErrorSubsets))
|
||||
{
|
||||
lowestError = maxError;
|
||||
lowestErrorSubsets = _modeInfos[m].SubsetCount;
|
||||
lowestErrorSubsets = BC67Tables.BC7ModeInfos[m].SubsetCount;
|
||||
bestBlock = block;
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +209,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
int h,
|
||||
out int errorSum)
|
||||
{
|
||||
ModeInfo modeInfo = _modeInfos[mode];
|
||||
BC7ModeInfo modeInfo = BC67Tables.BC7ModeInfos[mode];
|
||||
int subsetCount = modeInfo.SubsetCount;
|
||||
int partitionBitCount = modeInfo.PartitionBitCount;
|
||||
int rotationBitCount = modeInfo.RotationBitCount;
|
||||
|
@ -379,7 +307,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Span<byte> colorIndices = stackalloc byte[16];
|
||||
Span<byte> alphaIndices = stackalloc byte[16];
|
||||
|
||||
errorSum = BC7Utils.SelectIndices(
|
||||
errorSum = BC67Utils.SelectIndices(
|
||||
tile,
|
||||
w,
|
||||
h,
|
||||
|
@ -398,7 +326,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
if (separateAlphaIndices)
|
||||
{
|
||||
errorSum += BC7Utils.SelectIndices(
|
||||
errorSum += BC67Utils.SelectIndices(
|
||||
tile,
|
||||
w,
|
||||
h,
|
||||
|
@ -420,7 +348,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
colorSwapSubset[i] = colorIndices[BC7Tables.FixUpIndices[subsetCount - 1][partition][i]] >= (colorIndexCount >> 1);
|
||||
colorSwapSubset[i] = colorIndices[BC67Tables.FixUpIndices[subsetCount - 1][partition][i]] >= (colorIndexCount >> 1);
|
||||
}
|
||||
|
||||
bool alphaSwapSubset = alphaIndices[0] >= (alphaIndexCount >> 1);
|
||||
|
@ -462,13 +390,13 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
if (indexMode == 0 ? colorSwapSubset[subset] : alphaSwapSubset)
|
||||
{
|
||||
block.Encode(BC7Utils.QuantizeComponent(color1.GetComponent(rotatedComp), colorDepth, pBit1), ref offset, colorDepth);
|
||||
block.Encode(BC7Utils.QuantizeComponent(color0.GetComponent(rotatedComp), colorDepth, pBit0), ref offset, colorDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color1.GetComponent(rotatedComp), colorDepth, pBit1), ref offset, colorDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color0.GetComponent(rotatedComp), colorDepth, pBit0), ref offset, colorDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
block.Encode(BC7Utils.QuantizeComponent(color0.GetComponent(rotatedComp), colorDepth, pBit0), ref offset, colorDepth);
|
||||
block.Encode(BC7Utils.QuantizeComponent(color1.GetComponent(rotatedComp), colorDepth, pBit1), ref offset, colorDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color0.GetComponent(rotatedComp), colorDepth, pBit0), ref offset, colorDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color1.GetComponent(rotatedComp), colorDepth, pBit1), ref offset, colorDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -496,13 +424,13 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
if (separateAlphaIndices && indexMode == 0 ? alphaSwapSubset : colorSwapSubset[subset])
|
||||
{
|
||||
block.Encode(BC7Utils.QuantizeComponent(color1.GetComponent(rotatedComp), alphaDepth, pBit1), ref offset, alphaDepth);
|
||||
block.Encode(BC7Utils.QuantizeComponent(color0.GetComponent(rotatedComp), alphaDepth, pBit0), ref offset, alphaDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color1.GetComponent(rotatedComp), alphaDepth, pBit1), ref offset, alphaDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color0.GetComponent(rotatedComp), alphaDepth, pBit0), ref offset, alphaDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
block.Encode(BC7Utils.QuantizeComponent(color0.GetComponent(rotatedComp), alphaDepth, pBit0), ref offset, alphaDepth);
|
||||
block.Encode(BC7Utils.QuantizeComponent(color1.GetComponent(rotatedComp), alphaDepth, pBit1), ref offset, alphaDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color0.GetComponent(rotatedComp), alphaDepth, pBit0), ref offset, alphaDepth);
|
||||
block.Encode(BC67Utils.QuantizeComponent(color1.GetComponent(rotatedComp), alphaDepth, pBit1), ref offset, alphaDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -512,11 +440,11 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
block.Encode((ulong)pBitValues[i], ref offset, 1);
|
||||
}
|
||||
|
||||
byte[] fixUpTable = BC7Tables.FixUpIndices[subsetCount - 1][partition];
|
||||
byte[] fixUpTable = BC67Tables.FixUpIndices[subsetCount - 1][partition];
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int subset = BC7Tables.PartitionTable[subsetCount - 1][partition][i];
|
||||
int subset = BC67Tables.PartitionTable[subsetCount - 1][partition][i];
|
||||
byte index = colorIndices[i];
|
||||
|
||||
if (colorSwapSubset[subset])
|
||||
|
@ -561,12 +489,12 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
private static unsafe int GetEndPointSelectionErrorFast(ReadOnlySpan<uint> tile, int subsetCount, int partition, int w, int h, int maxError)
|
||||
{
|
||||
byte[] partitionTable = BC7Tables.PartitionTable[subsetCount - 1][partition];
|
||||
byte[] partitionTable = BC67Tables.PartitionTable[subsetCount - 1][partition];
|
||||
|
||||
Span<RgbaColor8> minColors = stackalloc RgbaColor8[subsetCount];
|
||||
Span<RgbaColor8> maxColors = stackalloc RgbaColor8[subsetCount];
|
||||
|
||||
BC7Utils.GetMinMaxColors(partitionTable, tile, w, h, minColors, maxColors, subsetCount);
|
||||
BC67Utils.GetMinMaxColors(partitionTable, tile, w, h, minColors, maxColors, subsetCount);
|
||||
|
||||
Span<uint> endPoints0 = stackalloc uint[subsetCount];
|
||||
Span<uint> endPoints1 = stackalloc uint[subsetCount];
|
||||
|
@ -592,8 +520,8 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
int pBit0 = GetPBit(c0, 6, 0);
|
||||
int pBit1 = GetPBit(c1, 6, 0);
|
||||
|
||||
c0 = BC7Utils.Quantize(RgbaColor8.FromUInt32(c0), 6, 0, pBit0).ToUInt32();
|
||||
c1 = BC7Utils.Quantize(RgbaColor8.FromUInt32(c1), 6, 0, pBit1).ToUInt32();
|
||||
c0 = BC67Utils.Quantize(RgbaColor8.FromUInt32(c0), 6, 0, pBit0).ToUInt32();
|
||||
c1 = BC67Utils.Quantize(RgbaColor8.FromUInt32(c1), 6, 0, pBit1).ToUInt32();
|
||||
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
|
@ -605,7 +533,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Vector128<byte> rWeights;
|
||||
Vector128<byte> lWeights;
|
||||
|
||||
fixed (byte* pWeights = BC7Tables.Weights[1], pInvWeights = BC7Tables.InverseWeights[1])
|
||||
fixed (byte* pWeights = BC67Tables.Weights[1], pInvWeights = BC67Tables.InverseWeights[1])
|
||||
{
|
||||
rWeights = Sse2.LoadScalarVector128((ulong*)pWeights).AsByte();
|
||||
lWeights = Sse2.LoadScalarVector128((ulong*)pInvWeights).AsByte();
|
||||
|
@ -670,7 +598,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
for (int i = 1; i < palette.Length - 1; i++)
|
||||
{
|
||||
palette[i] = BC7Utils.Interpolate(e032, e132, i, 3);
|
||||
palette[i] = BC67Utils.Interpolate(e032, e132, i, 3);
|
||||
}
|
||||
|
||||
for (int i = 0; i < tile.Length; i++)
|
||||
|
@ -687,7 +615,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
|
||||
for (int j = 0; j < palette.Length; j++)
|
||||
{
|
||||
int score = BC7Utils.SquaredDifference(color, palette[j]);
|
||||
int score = BC67Utils.SquaredDifference(color, palette[j]);
|
||||
|
||||
if (score < bestMatchScore)
|
||||
{
|
||||
|
@ -723,12 +651,12 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
uint writeMask,
|
||||
bool fastMode)
|
||||
{
|
||||
byte[] partitionTable = BC7Tables.PartitionTable[subsetCount - 1][partition];
|
||||
byte[] partitionTable = BC67Tables.PartitionTable[subsetCount - 1][partition];
|
||||
|
||||
Span<RgbaColor8> minColors = stackalloc RgbaColor8[subsetCount];
|
||||
Span<RgbaColor8> maxColors = stackalloc RgbaColor8[subsetCount];
|
||||
|
||||
BC7Utils.GetMinMaxColors(partitionTable, tile, w, h, minColors, maxColors, subsetCount);
|
||||
BC67Utils.GetMinMaxColors(partitionTable, tile, w, h, minColors, maxColors, subsetCount);
|
||||
|
||||
uint inverseMask = ~writeMask;
|
||||
|
||||
|
@ -934,8 +862,8 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
return (default, default);
|
||||
}
|
||||
|
||||
minValue = BC7Utils.Quantize(minValue, colorDepth, alphaDepth);
|
||||
maxValue = BC7Utils.Quantize(maxValue, colorDepth, alphaDepth);
|
||||
minValue = BC67Utils.Quantize(minValue, colorDepth, alphaDepth);
|
||||
maxValue = BC67Utils.Quantize(maxValue, colorDepth, alphaDepth);
|
||||
|
||||
RgbaColor32 blockDir = maxValue.GetColor32() - minValue.GetColor32();
|
||||
blockDir = RgbaColor32.DivideGuarded(blockDir << 6, new RgbaColor32(blockDir.R + blockDir.G + blockDir.B + blockDir.A), 0);
|
||||
|
@ -946,7 +874,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
RgbaColor8 color = values[i];
|
||||
int dist = RgbaColor32.Dot(BC7Utils.Quantize(color, colorDepth, alphaDepth).GetColor32(), blockDir);
|
||||
int dist = RgbaColor32.Dot(BC67Utils.Quantize(color, colorDepth, alphaDepth).GetColor32(), blockDir);
|
||||
|
||||
if (minDist >= dist)
|
||||
{
|
||||
|
@ -1019,7 +947,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
int pBit0 = GetPBit(candidateE0.ToUInt32(), colorDepth, alphaDepth);
|
||||
int pBit1 = GetPBit(candidateE1.ToUInt32(), colorDepth, alphaDepth);
|
||||
|
||||
int errorSum = BC7Utils.SelectIndices(
|
||||
int errorSum = BC67Utils.SelectIndices(
|
||||
MemoryMarshal.Cast<RgbaColor8, uint>(values),
|
||||
candidateE0.ToUInt32(),
|
||||
candidateE1.ToUInt32(),
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
namespace Ryujinx.Graphics.Texture.Encoders
|
||||
namespace Ryujinx.Graphics.Texture.Utils
|
||||
{
|
||||
static class BC7Tables
|
||||
static class BC67Tables
|
||||
{
|
||||
public static readonly BC7ModeInfo[] BC7ModeInfos = new BC7ModeInfo[]
|
||||
{
|
||||
new BC7ModeInfo(3, 4, 6, 0, 0, 3, 0, 4, 0),
|
||||
new BC7ModeInfo(2, 6, 2, 0, 0, 3, 0, 6, 0),
|
||||
new BC7ModeInfo(3, 6, 0, 0, 0, 2, 0, 5, 0),
|
||||
new BC7ModeInfo(2, 6, 4, 0, 0, 2, 0, 7, 0),
|
||||
new BC7ModeInfo(1, 0, 0, 2, 1, 2, 3, 5, 6),
|
||||
new BC7ModeInfo(1, 0, 0, 2, 0, 2, 2, 7, 8),
|
||||
new BC7ModeInfo(1, 0, 2, 0, 0, 4, 0, 7, 7),
|
||||
new BC7ModeInfo(2, 6, 4, 0, 0, 2, 0, 5, 5)
|
||||
};
|
||||
|
||||
public static readonly byte[][] Weights =
|
||||
{
|
||||
new byte[] { 0, 21, 43, 64 },
|
|
@ -4,14 +4,14 @@ using System.Runtime.CompilerServices;
|
|||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture.Encoders
|
||||
namespace Ryujinx.Graphics.Texture.Utils
|
||||
{
|
||||
static class BC7Utils
|
||||
static class BC67Utils
|
||||
{
|
||||
private static byte[][] _quantizationLut;
|
||||
private static byte[][] _quantizationLutNoPBit;
|
||||
|
||||
static BC7Utils()
|
||||
static BC67Utils()
|
||||
{
|
||||
_quantizationLut = new byte[5][];
|
||||
_quantizationLutNoPBit = new byte[5][];
|
||||
|
@ -322,7 +322,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Vector128<byte> rWeights;
|
||||
Vector128<byte> lWeights;
|
||||
|
||||
fixed (byte* pWeights = BC7Tables.Weights[0], pInvWeights = BC7Tables.InverseWeights[0])
|
||||
fixed (byte* pWeights = BC67Tables.Weights[0], pInvWeights = BC67Tables.InverseWeights[0])
|
||||
{
|
||||
rWeights = Sse2.LoadScalarVector128((uint*)pWeights).AsByte();
|
||||
lWeights = Sse2.LoadScalarVector128((uint*)pInvWeights).AsByte();
|
||||
|
@ -394,7 +394,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Vector128<byte> rWeights;
|
||||
Vector128<byte> lWeights;
|
||||
|
||||
fixed (byte* pWeights = BC7Tables.Weights[1], pInvWeights = BC7Tables.InverseWeights[1])
|
||||
fixed (byte* pWeights = BC67Tables.Weights[1], pInvWeights = BC67Tables.InverseWeights[1])
|
||||
{
|
||||
rWeights = Sse2.LoadScalarVector128((ulong*)pWeights).AsByte();
|
||||
lWeights = Sse2.LoadScalarVector128((ulong*)pInvWeights).AsByte();
|
||||
|
@ -476,7 +476,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Vector128<byte> rWeights;
|
||||
Vector128<byte> lWeights;
|
||||
|
||||
fixed (byte* pWeights = BC7Tables.Weights[2], pInvWeights = BC7Tables.InverseWeights[2])
|
||||
fixed (byte* pWeights = BC67Tables.Weights[2], pInvWeights = BC67Tables.InverseWeights[2])
|
||||
{
|
||||
rWeights = Sse2.LoadVector128(pWeights);
|
||||
lWeights = Sse2.LoadVector128(pInvWeights);
|
||||
|
@ -726,7 +726,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
int pBits,
|
||||
uint alphaMask)
|
||||
{
|
||||
byte[] partitionTable = BC7Tables.PartitionTable[subsetCount - 1][partition];
|
||||
byte[] partitionTable = BC67Tables.PartitionTable[subsetCount - 1][partition];
|
||||
|
||||
uint alphaMaskForPalette = alphaMask;
|
||||
|
||||
|
@ -762,7 +762,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Vector128<byte> rWeights;
|
||||
Vector128<byte> lWeights;
|
||||
|
||||
fixed (byte* pWeights = BC7Tables.Weights[0], pInvWeights = BC7Tables.InverseWeights[0])
|
||||
fixed (byte* pWeights = BC67Tables.Weights[0], pInvWeights = BC67Tables.InverseWeights[0])
|
||||
{
|
||||
rWeights = Sse2.LoadScalarVector128((uint*)pWeights).AsByte();
|
||||
lWeights = Sse2.LoadScalarVector128((uint*)pInvWeights).AsByte();
|
||||
|
@ -831,7 +831,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
int pBits,
|
||||
uint alphaMask)
|
||||
{
|
||||
byte[] partitionTable = BC7Tables.PartitionTable[subsetCount - 1][partition];
|
||||
byte[] partitionTable = BC67Tables.PartitionTable[subsetCount - 1][partition];
|
||||
|
||||
uint alphaMaskForPalette = alphaMask;
|
||||
|
||||
|
@ -867,7 +867,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Vector128<byte> rWeights;
|
||||
Vector128<byte> lWeights;
|
||||
|
||||
fixed (byte* pWeights = BC7Tables.Weights[1], pInvWeights = BC7Tables.InverseWeights[1])
|
||||
fixed (byte* pWeights = BC67Tables.Weights[1], pInvWeights = BC67Tables.InverseWeights[1])
|
||||
{
|
||||
rWeights = Sse2.LoadScalarVector128((ulong*)pWeights).AsByte();
|
||||
lWeights = Sse2.LoadScalarVector128((ulong*)pInvWeights).AsByte();
|
||||
|
@ -973,7 +973,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
Vector128<byte> rWeights;
|
||||
Vector128<byte> lWeights;
|
||||
|
||||
fixed (byte* pWeights = BC7Tables.Weights[2], pInvWeights = BC7Tables.InverseWeights[2])
|
||||
fixed (byte* pWeights = BC67Tables.Weights[2], pInvWeights = BC67Tables.InverseWeights[2])
|
||||
{
|
||||
rWeights = Sse2.LoadVector128(pWeights);
|
||||
lWeights = Sse2.LoadVector128(pInvWeights);
|
||||
|
@ -1129,7 +1129,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
{
|
||||
for (int tx = 0; tx < w; tx++)
|
||||
{
|
||||
int subset = BC7Tables.PartitionTable[subsetCount - 1][partition][ty * 4 + tx];
|
||||
int subset = BC67Tables.PartitionTable[subsetCount - 1][partition][ty * 4 + tx];
|
||||
uint color = tile[i++] | alphaMask;
|
||||
|
||||
int bestMatchScore = int.MaxValue;
|
||||
|
@ -1182,6 +1182,28 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
return (color1 * invWeightV + color2 * weightV + new RgbaColor32(32)) >> 6;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RgbaColor32 Interpolate(
|
||||
RgbaColor32 color1,
|
||||
RgbaColor32 color2,
|
||||
int colorWeightIndex,
|
||||
int alphaWeightIndex,
|
||||
int colorIndexBitCount,
|
||||
int alphaIndexBitCount)
|
||||
{
|
||||
Debug.Assert(colorIndexBitCount >= 2 && colorIndexBitCount <= 4);
|
||||
Debug.Assert(alphaIndexBitCount >= 2 && alphaIndexBitCount <= 4);
|
||||
|
||||
int colorWeight = BC67Tables.Weights[colorIndexBitCount - 2][colorWeightIndex];
|
||||
int alphaWeight = BC67Tables.Weights[alphaIndexBitCount - 2][alphaWeightIndex];
|
||||
|
||||
RgbaColor32 weightV = new RgbaColor32(colorWeight);
|
||||
weightV.A = alphaWeight;
|
||||
RgbaColor32 invWeightV = new RgbaColor32(64) - weightV;
|
||||
|
||||
return (color1 * invWeightV + color2 * weightV + new RgbaColor32(32)) >> 6;
|
||||
}
|
||||
|
||||
public static RgbaColor8 Quantize(RgbaColor8 color, int colorBits, int alphaBits, int pBit = -1)
|
||||
{
|
||||
if (alphaBits == 0)
|
37
Ryujinx.Graphics.Texture/Utils/BC7ModeInfo.cs
Normal file
37
Ryujinx.Graphics.Texture/Utils/BC7ModeInfo.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace Ryujinx.Graphics.Texture.Utils
|
||||
{
|
||||
struct BC7ModeInfo
|
||||
{
|
||||
public readonly int SubsetCount;
|
||||
public readonly int PartitionBitCount;
|
||||
public readonly int PBits;
|
||||
public readonly int RotationBitCount;
|
||||
public readonly int IndexModeBitCount;
|
||||
public readonly int ColorIndexBitCount;
|
||||
public readonly int AlphaIndexBitCount;
|
||||
public readonly int ColorDepth;
|
||||
public readonly int AlphaDepth;
|
||||
|
||||
public BC7ModeInfo(
|
||||
int subsetCount,
|
||||
int partitionBitsCount,
|
||||
int pBits,
|
||||
int rotationBitCount,
|
||||
int indexModeBitCount,
|
||||
int colorIndexBitCount,
|
||||
int alphaIndexBitCount,
|
||||
int colorDepth,
|
||||
int alphaDepth)
|
||||
{
|
||||
SubsetCount = subsetCount;
|
||||
PartitionBitCount = partitionBitsCount;
|
||||
PBits = pBits;
|
||||
RotationBitCount = rotationBitCount;
|
||||
IndexModeBitCount = indexModeBitCount;
|
||||
ColorIndexBitCount = colorIndexBitCount;
|
||||
AlphaIndexBitCount = alphaIndexBitCount;
|
||||
ColorDepth = colorDepth;
|
||||
AlphaDepth = alphaDepth;
|
||||
}
|
||||
}
|
||||
}
|
55
Ryujinx.Graphics.Texture/Utils/Block.cs
Normal file
55
Ryujinx.Graphics.Texture/Utils/Block.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
namespace Ryujinx.Graphics.Texture.Utils
|
||||
{
|
||||
struct Block
|
||||
{
|
||||
public ulong Low;
|
||||
public ulong High;
|
||||
|
||||
public void Encode(ulong value, ref int offset, int bits)
|
||||
{
|
||||
if (offset >= 64)
|
||||
{
|
||||
High |= value << (offset - 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
Low |= value << offset;
|
||||
|
||||
if (offset + bits > 64)
|
||||
{
|
||||
int remainder = 64 - offset;
|
||||
High |= value >> remainder;
|
||||
}
|
||||
}
|
||||
|
||||
offset += bits;
|
||||
}
|
||||
|
||||
public ulong Decode(ref int offset, int bits)
|
||||
{
|
||||
ulong value;
|
||||
ulong mask = bits == 64 ? ulong.MaxValue : (1UL << bits) - 1;
|
||||
|
||||
if (offset >= 64)
|
||||
{
|
||||
value = (High >> (offset - 64)) & mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Low >> offset;
|
||||
|
||||
if (offset + bits > 64)
|
||||
{
|
||||
int remainder = 64 - offset;
|
||||
value |= High << remainder;
|
||||
}
|
||||
|
||||
value &= mask;
|
||||
}
|
||||
|
||||
offset += bits;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,16 +3,35 @@ using System.Runtime.CompilerServices;
|
|||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture.Encoders
|
||||
namespace Ryujinx.Graphics.Texture.Utils
|
||||
{
|
||||
struct RgbaColor32 : IEquatable<RgbaColor32>
|
||||
{
|
||||
private readonly Vector128<int> _color;
|
||||
private Vector128<int> _color;
|
||||
|
||||
public int R => _color.GetElement(0);
|
||||
public int G => _color.GetElement(1);
|
||||
public int B => _color.GetElement(2);
|
||||
public int A => _color.GetElement(3);
|
||||
public int R
|
||||
{
|
||||
get => _color.GetElement(0);
|
||||
set => _color = _color.WithElement(0, value);
|
||||
}
|
||||
|
||||
public int G
|
||||
{
|
||||
get => _color.GetElement(1);
|
||||
set => _color = _color.WithElement(1, value);
|
||||
}
|
||||
|
||||
public int B
|
||||
{
|
||||
get => _color.GetElement(2);
|
||||
set => _color = _color.WithElement(2, value);
|
||||
}
|
||||
|
||||
public int A
|
||||
{
|
||||
get => _color.GetElement(3);
|
||||
set => _color = _color.WithElement(3, value);
|
||||
}
|
||||
|
||||
public RgbaColor32(Vector128<int> color)
|
||||
{
|
||||
|
@ -193,7 +212,7 @@ namespace Ryujinx.Graphics.Texture.Encoders
|
|||
return HashCode.Combine(R, G, B, A);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is RgbaColor32 other && Equals(other);
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
|
|||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture.Encoders
|
||||
namespace Ryujinx.Graphics.Texture.Utils
|
||||
{
|
||||
struct RgbaColor8 : IEquatable<RgbaColor8>
|
||||
{
|
|
@ -20,7 +20,20 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_table = new FormatFeatureFlags[Enum.GetNames(typeof(GAL.Format)).Length];
|
||||
}
|
||||
|
||||
public bool FormatSupports(GAL.Format format, FormatFeatureFlags flags)
|
||||
public bool FormatsSupports(FormatFeatureFlags flags, params GAL.Format[] formats)
|
||||
{
|
||||
foreach (GAL.Format format in formats)
|
||||
{
|
||||
if (!FormatSupports(flags, format))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool FormatSupports(FormatFeatureFlags flags, GAL.Format format)
|
||||
{
|
||||
var formatFeatureFlags = _table[(int)format];
|
||||
|
||||
|
@ -56,7 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit;
|
||||
}
|
||||
|
||||
if (!FormatSupports(srcFormat, requiredFeatures) ||
|
||||
if (!FormatSupports(requiredFeatures, srcFormat) ||
|
||||
(srcFormat == GAL.Format.D24UnormS8Uint && VulkanConfiguration.ForceD24S8Unsupported))
|
||||
{
|
||||
// The format is not supported. Can we convert it to a higher precision format?
|
||||
|
|
|
@ -298,8 +298,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
return;
|
||||
}
|
||||
else if (_gd.FormatCapabilities.FormatSupports(srcFormat, FormatFeatureFlags.FormatFeatureBlitSrcBit) &&
|
||||
_gd.FormatCapabilities.FormatSupports(dstFormat, FormatFeatureFlags.FormatFeatureBlitDstBit))
|
||||
else if (_gd.FormatCapabilities.FormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
|
||||
_gd.FormatCapabilities.FormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
|
||||
{
|
||||
TextureCopy.Blit(
|
||||
_gd.Api,
|
||||
|
@ -604,8 +604,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private bool SupportsBlitFromD32FS8ToD32FAndS8()
|
||||
{
|
||||
var formatFeatureFlags = FormatFeatureFlags.FormatFeatureBlitSrcBit | FormatFeatureFlags.FormatFeatureBlitDstBit;
|
||||
return _gd.FormatCapabilities.FormatSupports(GAL.Format.D32Float, formatFeatureFlags) &&
|
||||
_gd.FormatCapabilities.FormatSupports(GAL.Format.S8Uint, formatFeatureFlags);
|
||||
return _gd.FormatCapabilities.FormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
|
||||
_gd.FormatCapabilities.FormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
|
||||
}
|
||||
|
||||
public TextureView GetView(GAL.Format format)
|
||||
|
|
|
@ -315,6 +315,33 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public Capabilities GetCapabilities()
|
||||
{
|
||||
FormatFeatureFlags compressedFormatFeatureFlags =
|
||||
FormatFeatureFlags.FormatFeatureSampledImageBit |
|
||||
FormatFeatureFlags.FormatFeatureSampledImageFilterLinearBit |
|
||||
FormatFeatureFlags.FormatFeatureBlitSrcBit |
|
||||
FormatFeatureFlags.FormatFeatureTransferSrcBit |
|
||||
FormatFeatureFlags.FormatFeatureTransferDstBit;
|
||||
|
||||
bool supportsBc123CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
|
||||
GAL.Format.Bc1RgbaSrgb,
|
||||
GAL.Format.Bc1RgbaUnorm,
|
||||
GAL.Format.Bc2Srgb,
|
||||
GAL.Format.Bc2Unorm,
|
||||
GAL.Format.Bc3Srgb,
|
||||
GAL.Format.Bc3Unorm);
|
||||
|
||||
bool supportsBc45CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
|
||||
GAL.Format.Bc4Snorm,
|
||||
GAL.Format.Bc4Unorm,
|
||||
GAL.Format.Bc5Snorm,
|
||||
GAL.Format.Bc5Unorm);
|
||||
|
||||
bool supportsBc67CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
|
||||
GAL.Format.Bc6HSfloat,
|
||||
GAL.Format.Bc6HUfloat,
|
||||
GAL.Format.Bc7Srgb,
|
||||
GAL.Format.Bc7Unorm);
|
||||
|
||||
Api.GetPhysicalDeviceFeatures(_physicalDevice, out var features);
|
||||
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
|
||||
|
||||
|
@ -326,6 +353,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
hasFrontFacingBug: IsIntelWindows,
|
||||
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
||||
supportsAstcCompression: features.TextureCompressionAstcLdr,
|
||||
supportsBc123Compression: supportsBc123CompressionFormat,
|
||||
supportsBc45Compression: supportsBc45CompressionFormat,
|
||||
supportsBc67Compression: supportsBc67CompressionFormat,
|
||||
supports3DTextureCompression: true,
|
||||
supportsBgraFormat: true,
|
||||
supportsR4G4Format: false,
|
||||
|
|
Loading…
Reference in a new issue