| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- using Ryujinx.Common;
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- namespace Ryujinx.Graphics.Texture
- {
- public static class BCnDecoder
- {
- private const int BlockWidth = 4;
- private const int BlockHeight = 4;
- public static byte[] DecodeBC4(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;
- }
- byte[] output = new byte[size];
- ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
- Span<byte> rPal = stackalloc byte[8];
- int baseOOffs = 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++)
- {
- for (int y = 0; y < h; y++)
- {
- int baseY = y * BlockHeight;
- for (int x = 0; x < w; x++)
- {
- int baseX = x * BlockWidth;
- int lineBaseOOffs = baseOOffs + baseX;
- ulong block = data64[0];
- rPal[0] = (byte)block;
- rPal[1] = (byte)(block >> 8);
- if (signed)
- {
- CalculateBC3AlphaS(rPal);
- }
- else
- {
- CalculateBC3Alpha(rPal);
- }
- ulong rI = block >> 16;
- for (int texel = 0; texel < BlockWidth * BlockHeight; texel++)
- {
- int tX = texel & 3;
- int tY = texel >> 2;
- if (baseX + tX >= width || baseY + tY >= height)
- {
- continue;
- }
- int shift = texel * 3;
- byte r = rPal[(int)((rI >> shift) & 7)];
- int oOffs = lineBaseOOffs + tY * width + tX;
- output[oOffs] = r;
- }
- data64 = data64.Slice(1);
- }
- baseOOffs += width * (baseY + BlockHeight > height ? (height & (BlockHeight - 1)) : BlockHeight);
- }
- }
- }
- width = Math.Max(1, width >> 1);
- height = Math.Max(1, height >> 1);
- depth = Math.Max(1, depth >> 1);
- }
- return output;
- }
- public static byte[] DecodeBC5(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 * 2;
- }
- byte[] output = new byte[size];
- ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
- Span<byte> rPal = stackalloc byte[8];
- Span<byte> gPal = stackalloc byte[8];
- int baseOOffs = 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++)
- {
- for (int y = 0; y < h; y++)
- {
- int baseY = y * BlockHeight;
- for (int x = 0; x < w; x++)
- {
- int baseX = x * BlockWidth;
- int lineBaseOOffs = baseOOffs + baseX;
- ulong blockL = data64[0];
- ulong blockH = data64[1];
- rPal[0] = (byte)blockL;
- rPal[1] = (byte)(blockL >> 8);
- gPal[0] = (byte)blockH;
- gPal[1] = (byte)(blockH >> 8);
- if (signed)
- {
- CalculateBC3AlphaS(rPal);
- CalculateBC3AlphaS(gPal);
- }
- else
- {
- CalculateBC3Alpha(rPal);
- CalculateBC3Alpha(gPal);
- }
- ulong rI = blockL >> 16;
- ulong gI = blockH >> 16;
- for (int texel = 0; texel < BlockWidth * BlockHeight; texel++)
- {
- int tX = texel & 3;
- int tY = texel >> 2;
- if (baseX + tX >= width || baseY + tY >= height)
- {
- continue;
- }
- int shift = texel * 3;
- byte r = rPal[(int)((rI >> shift) & 7)];
- byte g = gPal[(int)((gI >> shift) & 7)];
- int oOffs = (lineBaseOOffs + tY * width + tX) * 2;
- output[oOffs + 0] = r;
- output[oOffs + 1] = g;
- }
- data64 = data64.Slice(2);
- }
- baseOOffs += width * (baseY + BlockHeight > height ? (height & (BlockHeight - 1)) : BlockHeight);
- }
- }
- }
- width = Math.Max(1, width >> 1);
- height = Math.Max(1, height >> 1);
- depth = Math.Max(1, depth >> 1);
- }
- return output;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void CalculateBC3Alpha(Span<byte> alpha)
- {
- for (int i = 2; i < 8; i++)
- {
- if (alpha[0] > alpha[1])
- {
- alpha[i] = (byte)(((8 - i) * alpha[0] + (i - 1) * alpha[1]) / 7);
- }
- else if (i < 6)
- {
- alpha[i] = (byte)(((6 - i) * alpha[0] + (i - 1) * alpha[1]) / 7);
- }
- else if (i == 6)
- {
- alpha[i] = 0;
- }
- else /* i == 7 */
- {
- alpha[i] = 0xff;
- }
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void CalculateBC3AlphaS(Span<byte> alpha)
- {
- for (int i = 2; i < 8; i++)
- {
- if ((sbyte)alpha[0] > (sbyte)alpha[1])
- {
- alpha[i] = (byte)(((8 - i) * (sbyte)alpha[0] + (i - 1) * (sbyte)alpha[1]) / 7);
- }
- else if (i < 6)
- {
- alpha[i] = (byte)(((6 - i) * (sbyte)alpha[0] + (i - 1) * (sbyte)alpha[1]) / 7);
- }
- else if (i == 6)
- {
- alpha[i] = 0x80;
- }
- else /* i == 7 */
- {
- alpha[i] = 0x7f;
- }
- }
- }
- }
- }
|