ASTC optimizations (#845)

* ASTC optimizations

* Move code to Ryujinx.Common

* Support 3D textures

* Address feedback

* Remove ASTC logging

* Use stackalloc instead of a Buffer20 struct

* Code style and cleanup

* Respond to feedback

* Rearrange public/private property ordering
This commit is contained in:
Alex Barney 2019-12-26 23:09:49 -07:00 committed by Thog
parent 947e14d3be
commit d1ab9fb42c
12 changed files with 1009 additions and 599 deletions

View file

@ -1,16 +1,23 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Texture.Astc
{
class AstcPixel
[StructLayout(LayoutKind.Sequential)]
struct AstcPixel
{
public short R { get; set; }
public short G { get; set; }
public short B { get; set; }
public short A { get; set; }
internal const int StructSize = 12;
byte[] _bitDepth = new byte[4];
public short A;
public short R;
public short G;
public short B;
private uint _bitDepthInt;
private Span<byte> BitDepth => MemoryMarshal.CreateSpan(ref Unsafe.As<uint, byte>(ref _bitDepthInt), 4);
private Span<short> Components => MemoryMarshal.CreateSpan(ref A, 4);
public AstcPixel(short a, short r, short g, short b)
{
@ -19,8 +26,7 @@ namespace Ryujinx.Graphics.Texture.Astc
G = g;
B = b;
for (int i = 0; i < 4; i++)
_bitDepth[i] = 8;
_bitDepthInt = 0x08080808;
}
public void ClampByte()
@ -33,96 +39,20 @@ namespace Ryujinx.Graphics.Texture.Astc
public short GetComponent(int index)
{
switch(index)
{
case 0: return A;
case 1: return R;
case 2: return G;
case 3: return B;
}
return 0;
return Components[index];
}
public void SetComponent(int index, int value)
{
switch (index)
{
case 0:
A = (short)value;
break;
case 1:
R = (short)value;
break;
case 2:
G = (short)value;
break;
case 3:
B = (short)value;
break;
}
}
public void ChangeBitDepth(byte[] depth)
{
for (int i = 0; i< 4; i++)
{
int value = ChangeBitDepth(GetComponent(i), _bitDepth[i], depth[i]);
SetComponent(i, value);
_bitDepth[i] = depth[i];
}
}
short ChangeBitDepth(short value, byte oldDepth, byte newDepth)
{
Debug.Assert(newDepth <= 8);
Debug.Assert(oldDepth <= 8);
if (oldDepth == newDepth)
{
// Do nothing
return value;
}
else if (oldDepth == 0 && newDepth != 0)
{
return (short)((1 << newDepth) - 1);
}
else if (newDepth > oldDepth)
{
return (short)BitArrayStream.Replicate(value, oldDepth, newDepth);
}
else
{
// oldDepth > newDepth
if (newDepth == 0)
{
return 0xFF;
}
else
{
byte bitsWasted = (byte)(oldDepth - newDepth);
short tempValue = value;
tempValue = (short)((tempValue + (1 << (bitsWasted - 1))) >> bitsWasted);
tempValue = Math.Min(Math.Max((short)0, tempValue), (short)((1 << newDepth) - 1));
return (byte)(tempValue);
}
}
Components[index] = (short)value;
}
public int Pack()
{
AstcPixel newPixel = new AstcPixel(A, R, G, B);
byte[] eightBitDepth = { 8, 8, 8, 8 };
newPixel.ChangeBitDepth(eightBitDepth);
return (byte)newPixel.A << 24 |
(byte)newPixel.B << 16 |
(byte)newPixel.G << 8 |
(byte)newPixel.R << 0;
return A << 24 |
B << 16 |
G << 8 |
R << 0;
}
// Adds more precision to the blue channel as described