Skip to content

Commit 9ce8311

Browse files
committed
Bc optimizations
1 parent e39b439 commit 9ce8311

File tree

2 files changed

+66
-32
lines changed

2 files changed

+66
-32
lines changed

AssetRipper.TextureDecoder/Bc/BcHelpers.cs

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ public static void DecompressBc5(ReadOnlySpan<byte> compressedBlock, Span<byte>
3434

3535
public static void DecompressBc6h(ReadOnlySpan<byte> compressedBlock, Span<byte> decompressedBlock, int destinationPitch, bool isSigned)
3636
{
37-
BitStream bstream = new(
38-
BinaryPrimitives.ReadUInt64LittleEndian(compressedBlock),
39-
BinaryPrimitives.ReadUInt64LittleEndian(compressedBlock.Slice(sizeof(ulong))));
37+
BitStream bstream = new(compressedBlock);
4038
Span<uint> r = stackalloc uint[4]; // wxyz
4139
Span<uint> g = stackalloc uint[4];
4240
Span<uint> b = stackalloc uint[4];
@@ -475,7 +473,7 @@ public static void DecompressBc6h(ReadOnlySpan<byte> compressedBlock, Span<byte>
475473

476474
// Mode 11 (like Mode 10) does not use delta compression,
477475
// and instead stores both color endpoints explicitly.
478-
if ((mode != 9 && mode != 10) || isSigned)
476+
if ((mode is not 9 and not 10) || isSigned)
479477
{
480478
for (int i = 1; i < (numPartitions + 1) * 2; ++i)
481479
{
@@ -485,7 +483,7 @@ public static void DecompressBc6h(ReadOnlySpan<byte> compressedBlock, Span<byte>
485483
}
486484
}
487485

488-
if (mode != 9 && mode != 10)
486+
if (mode is not 9 and not 10)
489487
{
490488
for (int i = 1; i < (numPartitions + 1) * 2; ++i)
491489
{
@@ -557,9 +555,7 @@ static uint ReadBc6hModeBits(ref BitStream bstream)
557555

558556
public static void DecompressBc7(ReadOnlySpan<byte> compressedBlock, Span<byte> decompressedBlock, int destinationPitch)
559557
{
560-
BitStream bstream = new(
561-
BinaryPrimitives.ReadUInt64LittleEndian(compressedBlock),
562-
BinaryPrimitives.ReadUInt64LittleEndian(compressedBlock.Slice(sizeof(ulong))));
558+
BitStream bstream = new(compressedBlock);
563559
Span2D<uint> endpoints = new(stackalloc uint[6 * 4], 6, 4);
564560
Span2D<int> indices = new(stackalloc int[4 * 4], 4, 4);
565561

@@ -590,24 +586,31 @@ public static void DecompressBc7(ReadOnlySpan<byte> compressedBlock, Span<byte>
590586
uint rotation = 0;
591587
uint indexSelectionBit = 0;
592588

593-
if (mode == 0 || mode == 1 || mode == 2 || mode == 3 || mode == 7)
589+
switch (mode)
594590
{
595-
numPartitions = (mode is 0 or 2) ? 3 : 2;
596-
partition = bstream.ReadBits((mode is 0) ? 4 : 6);
591+
case 0:
592+
numPartitions = 3;
593+
partition = bstream.ReadBits(4);
594+
break;
595+
case 1 or 3 or 7:
596+
numPartitions = 2;
597+
partition = bstream.ReadBits(6);
598+
break;
599+
case 2:
600+
numPartitions = 3;
601+
partition = bstream.ReadBits(6);
602+
break;
603+
case 4:
604+
rotation = bstream.ReadBits(2);
605+
indexSelectionBit = bstream.ReadBit();
606+
break;
607+
case 5:
608+
rotation = bstream.ReadBits(2);
609+
break;
597610
}
598611

599612
int numEndpoints = numPartitions * 2;
600613

601-
if (mode == 4 || mode == 5)
602-
{
603-
rotation = bstream.ReadBits(2);
604-
605-
if (mode == 4)
606-
{
607-
indexSelectionBit = bstream.ReadBit();
608-
}
609-
}
610-
611614
// Extract endpoints
612615
// RGB
613616
for (int i = 0; i < 3; ++i)
@@ -701,9 +704,24 @@ public static void DecompressBc7(ReadOnlySpan<byte> compressedBlock, Span<byte>
701704
}
702705

703706
// Determine weights tables
704-
int indexBits = (mode == 0 || mode == 1) ? 3 : ((mode == 6) ? 4 : 2);
705-
int indexBits2 = (mode == 4) ? 3 : ((mode == 5) ? 2 : 0);
706-
ReadOnlySpan<int> weights = (indexBits == 2) ? Bc7Tables.AWeight2 : ((indexBits == 3) ? Bc7Tables.AWeight3 : Bc7Tables.AWeight4);
707+
int indexBits = mode switch
708+
{
709+
0 or 1 => 3,
710+
6 => 4,
711+
_ => 2
712+
};
713+
int indexBits2 = mode switch
714+
{
715+
4 => 3,
716+
5 => 2,
717+
_ => 0
718+
};
719+
ReadOnlySpan<int> weights = indexBits switch
720+
{
721+
2 => Bc7Tables.AWeight2,
722+
3 => Bc7Tables.AWeight3,
723+
_ => Bc7Tables.AWeight4
724+
};
707725
ReadOnlySpan<int> weights2 = (indexBits2 == 2) ? Bc7Tables.AWeight2 : Bc7Tables.AWeight3;
708726

709727
// Quite inconvenient that indices aren't interleaved so we have to make 2 passes here
@@ -807,12 +825,10 @@ public static void DecompressBc7(ReadOnlySpan<byte> compressedBlock, Span<byte>
807825

808826
static int ReadBc7Mode(ref BitStream bstream)
809827
{
810-
int i = 0;
811-
while (i < 8 && bstream.ReadBit() == 0)
812-
{
813-
i++;
814-
}
815-
return i;
828+
uint eightBits = bstream.PeakBits(8);
829+
int index = BitOperations.TrailingZeroCount(eightBits);
830+
bstream.ReadBits(index + 1);
831+
return index;
816832
}
817833
}
818834

AssetRipper.TextureDecoder/Bc/BitStream.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace AssetRipper.TextureDecoder.Bc;
1+
using System.Buffers.Binary;
2+
3+
namespace AssetRipper.TextureDecoder.Bc;
24

35
internal ref struct BitStream
46
{
@@ -10,16 +12,32 @@ private readonly uint BottomBits
1012
get => unchecked((uint)this.value);
1113
}
1214

15+
public BitStream(UInt128 value)
16+
{
17+
this.value = value;
18+
}
19+
20+
public BitStream(ReadOnlySpan<byte> span) : this(BinaryPrimitives.ReadUInt128LittleEndian(span))
21+
{
22+
}
23+
1324
public BitStream(ulong low, ulong high)
1425
{
1526
value = new UInt128(high, low);
1627
}
1728

1829
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
19-
public uint ReadBits(int numBits)
30+
public readonly uint PeakBits(int numBits)
2031
{
2132
uint mask = (1u << numBits) - 1u;
2233
uint bits = BottomBits & mask;
34+
return bits;
35+
}
36+
37+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
38+
public uint ReadBits(int numBits)
39+
{
40+
uint bits = PeakBits(numBits);
2341
this.value >>= numBits;
2442
return bits;
2543
}

0 commit comments

Comments
 (0)