Move GPU emulation from Ryujinx.HLE to Ryujinx.Graphics and misc changes (#402)
* Move GPU LLE emulation from HLE to Graphics * Graphics: Move Gal/Texture to Texture * Remove Engines/ directory and namespace * Use tables for image formats * Abstract OpCode decoding * Simplify image table * Do not leak Read* symbols in TextureReader * Fixups * Rename IGalFrameBuffer -> IGalRenderTarget * Remove MaxBpp hardcoded value * Change yet again texture data and add G8R8 flipping * Rename GalFrameBufferFormat to GalSurfaceFormat * Unident EnsureSetup in ImageHandler * Add IsCompressed * Address some feedback
This commit is contained in:
parent
a0c78f7920
commit
ce1d5be212
58 changed files with 3378 additions and 3448 deletions
1384
Ryujinx.Graphics/Texture/ASTCDecoder.cs
Normal file
1384
Ryujinx.Graphics/Texture/ASTCDecoder.cs
Normal file
File diff suppressed because it is too large
Load diff
138
Ryujinx.Graphics/Texture/ASTCPixel.cs
Normal file
138
Ryujinx.Graphics/Texture/ASTCPixel.cs
Normal file
|
@ -0,0 +1,138 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
class ASTCPixel
|
||||
{
|
||||
public short R { get; set; }
|
||||
public short G { get; set; }
|
||||
public short B { get; set; }
|
||||
public short A { get; set; }
|
||||
|
||||
byte[] BitDepth = new byte[4];
|
||||
|
||||
public ASTCPixel(short _A, short _R, short _G, short _B)
|
||||
{
|
||||
A = _A;
|
||||
R = _R;
|
||||
G = _G;
|
||||
B = _B;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
BitDepth[i] = 8;
|
||||
}
|
||||
|
||||
public void ClampByte()
|
||||
{
|
||||
R = Math.Min(Math.Max(R, (short)0), (short)255);
|
||||
G = Math.Min(Math.Max(G, (short)0), (short)255);
|
||||
B = Math.Min(Math.Max(B, (short)0), (short)255);
|
||||
A = Math.Min(Math.Max(A, (short)0), (short)255);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Adds more precision to the blue channel as described
|
||||
// in C.2.14
|
||||
public static ASTCPixel BlueContract(int a, int r, int g, int b)
|
||||
{
|
||||
return new ASTCPixel((short)(a),
|
||||
(short)((r + b) >> 1),
|
||||
(short)((g + b) >> 1),
|
||||
(short)(b));
|
||||
}
|
||||
}
|
||||
}
|
121
Ryujinx.Graphics/Texture/BitArrayStream.cs
Normal file
121
Ryujinx.Graphics/Texture/BitArrayStream.cs
Normal file
|
@ -0,0 +1,121 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public class BitArrayStream
|
||||
{
|
||||
public BitArray BitsArray;
|
||||
|
||||
public int Position { get; private set; }
|
||||
|
||||
public BitArrayStream(BitArray BitArray)
|
||||
{
|
||||
BitsArray = BitArray;
|
||||
Position = 0;
|
||||
}
|
||||
|
||||
public short ReadBits(int Length)
|
||||
{
|
||||
int RetValue = 0;
|
||||
for (int i = Position; i < Position + Length; i++)
|
||||
{
|
||||
if (BitsArray[i])
|
||||
{
|
||||
RetValue |= 1 << (i - Position);
|
||||
}
|
||||
}
|
||||
|
||||
Position += Length;
|
||||
return (short)RetValue;
|
||||
}
|
||||
|
||||
public int ReadBits(int Start, int End)
|
||||
{
|
||||
int RetValue = 0;
|
||||
for (int i = Start; i <= End; i++)
|
||||
{
|
||||
if (BitsArray[i])
|
||||
{
|
||||
RetValue |= 1 << (i - Start);
|
||||
}
|
||||
}
|
||||
|
||||
return RetValue;
|
||||
}
|
||||
|
||||
public int ReadBit(int Index)
|
||||
{
|
||||
return Convert.ToInt32(BitsArray[Index]);
|
||||
}
|
||||
|
||||
public void WriteBits(int Value, int Length)
|
||||
{
|
||||
for (int i = Position; i < Position + Length; i++)
|
||||
{
|
||||
BitsArray[i] = ((Value >> (i - Position)) & 1) != 0;
|
||||
}
|
||||
|
||||
Position += Length;
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] RetArray = new byte[(BitsArray.Length + 7) / 8];
|
||||
BitsArray.CopyTo(RetArray, 0);
|
||||
return RetArray;
|
||||
}
|
||||
|
||||
public static int Replicate(int Value, int NumberBits, int ToBit)
|
||||
{
|
||||
if (NumberBits == 0) return 0;
|
||||
if (ToBit == 0) return 0;
|
||||
|
||||
int TempValue = Value & ((1 << NumberBits) - 1);
|
||||
int RetValue = TempValue;
|
||||
int ResLength = NumberBits;
|
||||
|
||||
while (ResLength < ToBit)
|
||||
{
|
||||
int Comp = 0;
|
||||
if (NumberBits > ToBit - ResLength)
|
||||
{
|
||||
int NewShift = ToBit - ResLength;
|
||||
Comp = NumberBits - NewShift;
|
||||
NumberBits = NewShift;
|
||||
}
|
||||
RetValue <<= NumberBits;
|
||||
RetValue |= TempValue >> Comp;
|
||||
ResLength += NumberBits;
|
||||
}
|
||||
return RetValue;
|
||||
}
|
||||
|
||||
public static int PopCnt(int Number)
|
||||
{
|
||||
int Counter;
|
||||
for (Counter = 0; Number != 0; Counter++)
|
||||
{
|
||||
Number &= Number - 1;
|
||||
}
|
||||
return Counter;
|
||||
}
|
||||
|
||||
public static void Swap<T>(ref T lhs, ref T rhs)
|
||||
{
|
||||
T Temp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = Temp;
|
||||
}
|
||||
|
||||
// Transfers a bit as described in C.2.14
|
||||
public static void BitTransferSigned(ref int a, ref int b)
|
||||
{
|
||||
b >>= 1;
|
||||
b |= a & 0x80;
|
||||
a >>= 1;
|
||||
a &= 0x3F;
|
||||
if ((a & 0x20) != 0) a -= 0x40;
|
||||
}
|
||||
}
|
||||
}
|
59
Ryujinx.Graphics/Texture/BlockLinearSwizzle.cs
Normal file
59
Ryujinx.Graphics/Texture/BlockLinearSwizzle.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
class BlockLinearSwizzle : ISwizzle
|
||||
{
|
||||
private int BhShift;
|
||||
private int BppShift;
|
||||
private int BhMask;
|
||||
|
||||
private int XShift;
|
||||
private int GobStride;
|
||||
|
||||
public BlockLinearSwizzle(int Width, int Bpp, int BlockHeight = 16)
|
||||
{
|
||||
BhMask = (BlockHeight * 8) - 1;
|
||||
|
||||
BhShift = CountLsbZeros(BlockHeight * 8);
|
||||
BppShift = CountLsbZeros(Bpp);
|
||||
|
||||
int WidthInGobs = (int)MathF.Ceiling(Width * Bpp / 64f);
|
||||
|
||||
GobStride = 512 * BlockHeight * WidthInGobs;
|
||||
|
||||
XShift = CountLsbZeros(512 * BlockHeight);
|
||||
}
|
||||
|
||||
private int CountLsbZeros(int Value)
|
||||
{
|
||||
int Count = 0;
|
||||
|
||||
while (((Value >> Count) & 1) == 0)
|
||||
{
|
||||
Count++;
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
public int GetSwizzleOffset(int X, int Y)
|
||||
{
|
||||
X <<= BppShift;
|
||||
|
||||
int Position = (Y >> BhShift) * GobStride;
|
||||
|
||||
Position += (X >> 6) << XShift;
|
||||
|
||||
Position += ((Y & BhMask) >> 3) << 9;
|
||||
|
||||
Position += ((X & 0x3f) >> 5) << 8;
|
||||
Position += ((Y & 0x07) >> 1) << 6;
|
||||
Position += ((X & 0x1f) >> 4) << 5;
|
||||
Position += ((Y & 0x01) >> 0) << 4;
|
||||
Position += ((X & 0x0f) >> 0) << 0;
|
||||
|
||||
return Position;
|
||||
}
|
||||
}
|
||||
}
|
7
Ryujinx.Graphics/Texture/ISwizzle.cs
Normal file
7
Ryujinx.Graphics/Texture/ISwizzle.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
interface ISwizzle
|
||||
{
|
||||
int GetSwizzleOffset(int X, int Y);
|
||||
}
|
||||
}
|
24
Ryujinx.Graphics/Texture/ImageConverter.cs
Normal file
24
Ryujinx.Graphics/Texture/ImageConverter.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class ImageConverter
|
||||
{
|
||||
public static byte[] G8R8ToR8G8(
|
||||
byte[] Data,
|
||||
int Width,
|
||||
int Height,
|
||||
int Depth)
|
||||
{
|
||||
int Texels = Width * Height * Depth;
|
||||
|
||||
byte[] Output = new byte[Texels * 2];
|
||||
|
||||
for (int Texel = 0; Texel < Texels; Texel++)
|
||||
{
|
||||
Output[Texel * 2 + 0] = Data[Texel * 2 + 1];
|
||||
Output[Texel * 2 + 1] = Data[Texel * 2 + 0];
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
}
|
||||
}
|
357
Ryujinx.Graphics/Texture/ImageUtils.cs
Normal file
357
Ryujinx.Graphics/Texture/ImageUtils.cs
Normal file
|
@ -0,0 +1,357 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class ImageUtils
|
||||
{
|
||||
struct ImageDescriptor
|
||||
{
|
||||
public TextureReaderDelegate Reader;
|
||||
|
||||
public bool HasColor;
|
||||
public bool HasDepth;
|
||||
public bool HasStencil;
|
||||
|
||||
public bool Compressed;
|
||||
|
||||
public ImageDescriptor(
|
||||
TextureReaderDelegate Reader,
|
||||
bool HasColor,
|
||||
bool HasDepth,
|
||||
bool HasStencil,
|
||||
bool Compressed)
|
||||
{
|
||||
this.Reader = Reader;
|
||||
this.HasColor = HasColor;
|
||||
this.HasDepth = HasDepth;
|
||||
this.HasStencil = HasStencil;
|
||||
this.Compressed = Compressed;
|
||||
}
|
||||
}
|
||||
|
||||
private const GalImageFormat Snorm = GalImageFormat.Snorm;
|
||||
private const GalImageFormat Unorm = GalImageFormat.Unorm;
|
||||
private const GalImageFormat Sint = GalImageFormat.Sint;
|
||||
private const GalImageFormat Uint = GalImageFormat.Uint;
|
||||
private const GalImageFormat Sfloat = GalImageFormat.Sfloat;
|
||||
|
||||
private static readonly Dictionary<GalTextureFormat, GalImageFormat> s_TextureTable =
|
||||
new Dictionary<GalTextureFormat, GalImageFormat>()
|
||||
{
|
||||
{ GalTextureFormat.R32G32B32A32, GalImageFormat.R32G32B32A32 | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.R16G16B16A16, GalImageFormat.R16G16B16A16 | Snorm | Unorm | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.R32G32, GalImageFormat.R32G32 | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.A8B8G8R8, GalImageFormat.A8B8G8R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.A2B10G10R10, GalImageFormat.A2B10G10R10 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.G8R8, GalImageFormat.G8R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.A4B4G4R4, GalImageFormat.A4B4G4R4 | Unorm },
|
||||
{ GalTextureFormat.A1B5G5R5, GalImageFormat.A1R5G5B5 | Unorm },
|
||||
{ GalTextureFormat.B5G6R5, GalImageFormat.B5G6R5 | Unorm },
|
||||
{ GalTextureFormat.BF10GF11RF11, GalImageFormat.B10G11R11 | Sfloat },
|
||||
{ GalTextureFormat.Z24S8, GalImageFormat.D24_S8 | Unorm },
|
||||
{ GalTextureFormat.ZF32, GalImageFormat.D32 | Sfloat },
|
||||
{ GalTextureFormat.ZF32_X24S8, GalImageFormat.D32_S8 | Unorm },
|
||||
|
||||
//Compressed formats
|
||||
{ GalTextureFormat.BC6H_SF16, GalImageFormat.BC6H_SF16 | Unorm },
|
||||
{ GalTextureFormat.BC6H_UF16, GalImageFormat.BC6H_UF16 | Unorm },
|
||||
{ GalTextureFormat.BC7U, GalImageFormat.BC7 | Unorm },
|
||||
{ GalTextureFormat.BC1, GalImageFormat.BC1_RGBA | Unorm },
|
||||
{ GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm },
|
||||
{ GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm },
|
||||
{ GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
|
||||
{ GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
|
||||
{ GalTextureFormat.Astc2D4x4, GalImageFormat.ASTC_4x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x5, GalImageFormat.ASTC_5x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x6, GalImageFormat.ASTC_6x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x8, GalImageFormat.ASTC_8x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x10, GalImageFormat.ASTC_10x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x12, GalImageFormat.ASTC_12x12 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x4, GalImageFormat.ASTC_5x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x5, GalImageFormat.ASTC_6x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x6, GalImageFormat.ASTC_8x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x8, GalImageFormat.ASTC_10x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x10, GalImageFormat.ASTC_12x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x5, GalImageFormat.ASTC_8x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x5, GalImageFormat.ASTC_10x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x6, GalImageFormat.ASTC_10x6 | Unorm }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
|
||||
new Dictionary<GalImageFormat, ImageDescriptor>()
|
||||
{
|
||||
{ GalImageFormat.R32G32B32A32, new ImageDescriptor(TextureReader.Read16Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R16G16B16A16, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R32G32, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A8B8G8R8, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A2B10G10R10, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R32, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A4B4G4R4, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.BC6H_SF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC6H_UF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.A1R5G5B5, new ImageDescriptor(TextureReader.Read5551, true, false, false, false) },
|
||||
{ GalImageFormat.B5G6R5, new ImageDescriptor(TextureReader.Read565, true, false, false, false) },
|
||||
{ GalImageFormat.BC7, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.R16G16, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R8G8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.G8R8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R16, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R8, new ImageDescriptor(TextureReader.Read1Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.B10G11R11, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.BC1_RGBA, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC2, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC3, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC4, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_4x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_5x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_6x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x6, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_8x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x8, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x10, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_12x12, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x12, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_5x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x4, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_6x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_8x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x6, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x8, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_12x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x10, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_8x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x6, true, false, false, true) },
|
||||
|
||||
{ GalImageFormat.D24_S8, new ImageDescriptor(TextureReader.Read4Bpp, false, true, true, false) },
|
||||
{ GalImageFormat.D32, new ImageDescriptor(TextureReader.Read4Bpp, false, true, false, false) },
|
||||
{ GalImageFormat.D16, new ImageDescriptor(TextureReader.Read2Bpp, false, true, false, false) },
|
||||
{ GalImageFormat.D32_S8, new ImageDescriptor(TextureReader.Read8Bpp, false, true, true, false) },
|
||||
};
|
||||
|
||||
public static GalImageFormat ConvertTexture(
|
||||
GalTextureFormat Format,
|
||||
GalTextureType RType,
|
||||
GalTextureType GType,
|
||||
GalTextureType BType,
|
||||
GalTextureType AType)
|
||||
{
|
||||
if (RType != GType || RType != BType || RType != AType)
|
||||
{
|
||||
throw new NotImplementedException("Per component types are not implemented");
|
||||
}
|
||||
|
||||
if (!s_TextureTable.TryGetValue(Format, out GalImageFormat ImageFormat))
|
||||
{
|
||||
throw new NotImplementedException("Texture with format " + ((int)Format).ToString("x2") + " not implemented");
|
||||
}
|
||||
|
||||
GalTextureType Type = RType;
|
||||
|
||||
GalImageFormat FormatType = GetFormatType(RType);
|
||||
|
||||
if (ImageFormat.HasFlag(FormatType))
|
||||
{
|
||||
return (ImageFormat & GalImageFormat.FormatMask) | FormatType;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Texture with format " + Format +
|
||||
" and component type " + Type + " is not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
public static GalImageFormat ConvertSurface(GalSurfaceFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalSurfaceFormat.RGBA32Float: return GalImageFormat.R32G32B32A32 | Sfloat;
|
||||
case GalSurfaceFormat.RGBA16Float: return GalImageFormat.R16G16B16A16 | Sfloat;
|
||||
case GalSurfaceFormat.RG32Float: return GalImageFormat.R32G32 | Sfloat;
|
||||
case GalSurfaceFormat.RG32Sint: return GalImageFormat.R32G32 | Sint;
|
||||
case GalSurfaceFormat.RG32Uint: return GalImageFormat.R32G32 | Uint;
|
||||
case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.R8G8B8A8 | Unorm; //Is this right?
|
||||
case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.A8B8G8R8_SRGB; //This one might be wrong
|
||||
case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.A2B10G10R10 | Unorm;
|
||||
case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.A8B8G8R8 | Unorm;
|
||||
case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.A8B8G8R8_SRGB;
|
||||
case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.A8B8G8R8 | Snorm;
|
||||
case GalSurfaceFormat.RG16Snorm: return GalImageFormat.R16G16 | Snorm;
|
||||
case GalSurfaceFormat.RG16Float: return GalImageFormat.R16G16 | Sfloat;
|
||||
case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.B10G11R11 | Sfloat;
|
||||
case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Sfloat;
|
||||
case GalSurfaceFormat.RG8Unorm: return GalImageFormat.R8G8 | Unorm;
|
||||
case GalSurfaceFormat.RG8Snorm: return GalImageFormat.R8 | Snorm;
|
||||
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Sfloat;
|
||||
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static GalImageFormat ConvertZeta(GalZetaFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalZetaFormat.Z32Float: return GalImageFormat.D32 | Sfloat;
|
||||
case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_S8 | Unorm;
|
||||
case GalZetaFormat.Z16Unorm: return GalImageFormat.D16 | Unorm;
|
||||
//This one might not be Uint, change when a texture uses this format
|
||||
case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Uint;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static TextureReaderDelegate GetReader(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).Reader;
|
||||
}
|
||||
|
||||
public static int GetSize(GalImage Image)
|
||||
{
|
||||
switch (Image.Format & GalImageFormat.FormatMask)
|
||||
{
|
||||
case GalImageFormat.R32G32B32A32:
|
||||
return Image.Width * Image.Height * 16;
|
||||
|
||||
case GalImageFormat.R16G16B16A16:
|
||||
case GalImageFormat.D32_S8:
|
||||
case GalImageFormat.R32G32:
|
||||
return Image.Width * Image.Height * 8;
|
||||
|
||||
case GalImageFormat.A8B8G8R8:
|
||||
case GalImageFormat.A8B8G8R8_SRGB:
|
||||
case GalImageFormat.A2B10G10R10:
|
||||
case GalImageFormat.R16G16:
|
||||
case GalImageFormat.R32:
|
||||
case GalImageFormat.D32:
|
||||
case GalImageFormat.B10G11R11:
|
||||
case GalImageFormat.D24_S8:
|
||||
return Image.Width * Image.Height * 4;
|
||||
|
||||
case GalImageFormat.B4G4R4A4:
|
||||
case GalImageFormat.A1R5G5B5:
|
||||
case GalImageFormat.B5G6R5:
|
||||
case GalImageFormat.R8G8:
|
||||
case GalImageFormat.R16:
|
||||
case GalImageFormat.D16:
|
||||
return Image.Width * Image.Height * 2;
|
||||
|
||||
case GalImageFormat.R8:
|
||||
return Image.Width * Image.Height;
|
||||
|
||||
case GalImageFormat.BC1_RGBA:
|
||||
case GalImageFormat.BC4:
|
||||
{
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 8);
|
||||
}
|
||||
|
||||
case GalImageFormat.BC6H_SF16:
|
||||
case GalImageFormat.BC6H_UF16:
|
||||
case GalImageFormat.BC7:
|
||||
case GalImageFormat.BC2:
|
||||
case GalImageFormat.BC3:
|
||||
case GalImageFormat.BC5:
|
||||
case GalImageFormat.ASTC_4x4:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 16);
|
||||
|
||||
case GalImageFormat.ASTC_5x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 5, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_6x6:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 6, 6, 16);
|
||||
|
||||
case GalImageFormat.ASTC_8x8:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 8, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x10:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 10, 16);
|
||||
|
||||
case GalImageFormat.ASTC_12x12:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 12, 12, 16);
|
||||
|
||||
case GalImageFormat.ASTC_5x4:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 5, 4, 16);
|
||||
|
||||
case GalImageFormat.ASTC_6x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 6, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_8x6:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 6, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x8:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 8, 16);
|
||||
|
||||
case GalImageFormat.ASTC_12x10:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 12, 10, 16);
|
||||
|
||||
case GalImageFormat.ASTC_8x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x6:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 6, 16);
|
||||
}
|
||||
|
||||
throw new NotImplementedException((Image.Format & GalImageFormat.FormatMask).ToString());
|
||||
}
|
||||
|
||||
public static bool HasColor(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).HasColor;
|
||||
}
|
||||
|
||||
public static bool HasDepth(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).HasDepth;
|
||||
}
|
||||
|
||||
public static bool HasStencil(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).HasStencil;
|
||||
}
|
||||
|
||||
public static bool IsCompressed(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).Compressed;
|
||||
}
|
||||
|
||||
private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
|
||||
{
|
||||
GalImageFormat TypeLess = (Format & GalImageFormat.FormatMask);
|
||||
|
||||
if (s_ImageTable.TryGetValue(TypeLess, out ImageDescriptor Descriptor))
|
||||
{
|
||||
return Descriptor;
|
||||
}
|
||||
|
||||
throw new NotImplementedException("Image with format " + TypeLess.ToString() + " not implemented");
|
||||
}
|
||||
|
||||
private static GalImageFormat GetFormatType(GalTextureType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case GalTextureType.Snorm: return Snorm;
|
||||
case GalTextureType.Unorm: return Unorm;
|
||||
case GalTextureType.Sint: return Sint;
|
||||
case GalTextureType.Uint: return Uint;
|
||||
case GalTextureType.Float: return Sfloat;
|
||||
|
||||
default: throw new NotImplementedException(((int)Type).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb)
|
||||
{
|
||||
int W = (TextureWidth + (BlockWidth - 1)) / BlockWidth;
|
||||
int H = (TextureHeight + (BlockHeight - 1)) / BlockHeight;
|
||||
|
||||
return W * H * Bpb;
|
||||
}
|
||||
}
|
||||
}
|
269
Ryujinx.Graphics/Texture/IntegerEncoded.cs
Normal file
269
Ryujinx.Graphics/Texture/IntegerEncoded.cs
Normal file
|
@ -0,0 +1,269 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public struct IntegerEncoded
|
||||
{
|
||||
public enum EIntegerEncoding
|
||||
{
|
||||
JustBits,
|
||||
Quint,
|
||||
Trit
|
||||
}
|
||||
|
||||
EIntegerEncoding Encoding;
|
||||
public int NumberBits { get; private set; }
|
||||
public int BitValue { get; private set; }
|
||||
public int TritValue { get; private set; }
|
||||
public int QuintValue { get; private set; }
|
||||
|
||||
public IntegerEncoded(EIntegerEncoding _Encoding, int NumBits)
|
||||
{
|
||||
Encoding = _Encoding;
|
||||
NumberBits = NumBits;
|
||||
BitValue = 0;
|
||||
TritValue = 0;
|
||||
QuintValue = 0;
|
||||
}
|
||||
|
||||
public bool MatchesEncoding(IntegerEncoded Other)
|
||||
{
|
||||
return Encoding == Other.Encoding && NumberBits == Other.NumberBits;
|
||||
}
|
||||
|
||||
public EIntegerEncoding GetEncoding()
|
||||
{
|
||||
return Encoding;
|
||||
}
|
||||
|
||||
public int GetBitLength(int NumberVals)
|
||||
{
|
||||
int TotalBits = NumberBits * NumberVals;
|
||||
if (Encoding == EIntegerEncoding.Trit)
|
||||
{
|
||||
TotalBits += (NumberVals * 8 + 4) / 5;
|
||||
}
|
||||
else if (Encoding == EIntegerEncoding.Quint)
|
||||
{
|
||||
TotalBits += (NumberVals * 7 + 2) / 3;
|
||||
}
|
||||
return TotalBits;
|
||||
}
|
||||
|
||||
public static IntegerEncoded CreateEncoding(int MaxVal)
|
||||
{
|
||||
while (MaxVal > 0)
|
||||
{
|
||||
int Check = MaxVal + 1;
|
||||
|
||||
// Is maxVal a power of two?
|
||||
if ((Check & (Check - 1)) == 0)
|
||||
{
|
||||
return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(MaxVal));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 3*2^n - 1?
|
||||
if ((Check % 3 == 0) && ((Check / 3) & ((Check / 3) - 1)) == 0)
|
||||
{
|
||||
return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(Check / 3 - 1));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 5*2^n - 1?
|
||||
if ((Check % 5 == 0) && ((Check / 5) & ((Check / 5) - 1)) == 0)
|
||||
{
|
||||
return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(Check / 5 - 1));
|
||||
}
|
||||
|
||||
// Apparently it can't be represented with a bounded integer sequence...
|
||||
// just iterate.
|
||||
MaxVal--;
|
||||
}
|
||||
|
||||
return new IntegerEncoded(EIntegerEncoding.JustBits, 0);
|
||||
}
|
||||
|
||||
public static void DecodeTritBlock(
|
||||
BitArrayStream BitStream,
|
||||
List<IntegerEncoded> ListIntegerEncoded,
|
||||
int NumberBitsPerValue)
|
||||
{
|
||||
// Implement the algorithm in section C.2.12
|
||||
int[] m = new int[5];
|
||||
int[] t = new int[5];
|
||||
int T;
|
||||
|
||||
// Read the trit encoded block according to
|
||||
// table C.2.14
|
||||
m[0] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
T = BitStream.ReadBits(2);
|
||||
m[1] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
T |= BitStream.ReadBits(2) << 2;
|
||||
m[2] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
T |= BitStream.ReadBits(1) << 4;
|
||||
m[3] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
T |= BitStream.ReadBits(2) << 5;
|
||||
m[4] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
T |= BitStream.ReadBits(1) << 7;
|
||||
|
||||
int C = 0;
|
||||
|
||||
BitArrayStream Tb = new BitArrayStream(new BitArray(new int[] { T }));
|
||||
if (Tb.ReadBits(2, 4) == 7)
|
||||
{
|
||||
C = (Tb.ReadBits(5, 7) << 2) | Tb.ReadBits(0, 1);
|
||||
t[4] = t[3] = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
C = Tb.ReadBits(0, 4);
|
||||
if (Tb.ReadBits(5, 6) == 3)
|
||||
{
|
||||
t[4] = 2;
|
||||
t[3] = Tb.ReadBit(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
t[4] = Tb.ReadBit(7);
|
||||
t[3] = Tb.ReadBits(5, 6);
|
||||
}
|
||||
}
|
||||
|
||||
BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C }));
|
||||
if (Cb.ReadBits(0, 1) == 3)
|
||||
{
|
||||
t[2] = 2;
|
||||
t[1] = Cb.ReadBit(4);
|
||||
t[0] = (Cb.ReadBit(3) << 1) | (Cb.ReadBit(2) & ~Cb.ReadBit(3));
|
||||
}
|
||||
else if (Cb.ReadBits(2, 3) == 3)
|
||||
{
|
||||
t[2] = 2;
|
||||
t[1] = 2;
|
||||
t[0] = Cb.ReadBits(0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
t[2] = Cb.ReadBit(4);
|
||||
t[1] = Cb.ReadBits(2, 3);
|
||||
t[0] = (Cb.ReadBit(1) << 1) | (Cb.ReadBit(0) & ~Cb.ReadBit(1));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Trit, NumberBitsPerValue)
|
||||
{
|
||||
BitValue = m[i],
|
||||
TritValue = t[i]
|
||||
};
|
||||
ListIntegerEncoded.Add(IntEncoded);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DecodeQuintBlock(
|
||||
BitArrayStream BitStream,
|
||||
List<IntegerEncoded> ListIntegerEncoded,
|
||||
int NumberBitsPerValue)
|
||||
{
|
||||
// Implement the algorithm in section C.2.12
|
||||
int[] m = new int[3];
|
||||
int[] q = new int[3];
|
||||
int Q;
|
||||
|
||||
// Read the trit encoded block according to
|
||||
// table C.2.15
|
||||
m[0] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
Q = BitStream.ReadBits(3);
|
||||
m[1] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
Q |= BitStream.ReadBits(2) << 3;
|
||||
m[2] = BitStream.ReadBits(NumberBitsPerValue);
|
||||
Q |= BitStream.ReadBits(2) << 5;
|
||||
|
||||
BitArrayStream Qb = new BitArrayStream(new BitArray(new int[] { Q }));
|
||||
if (Qb.ReadBits(1, 2) == 3 && Qb.ReadBits(5, 6) == 0)
|
||||
{
|
||||
q[0] = q[1] = 4;
|
||||
q[2] = (Qb.ReadBit(0) << 2) | ((Qb.ReadBit(4) & ~Qb.ReadBit(0)) << 1) | (Qb.ReadBit(3) & ~Qb.ReadBit(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
int C = 0;
|
||||
if (Qb.ReadBits(1, 2) == 3)
|
||||
{
|
||||
q[2] = 4;
|
||||
C = (Qb.ReadBits(3, 4) << 3) | ((~Qb.ReadBits(5, 6) & 3) << 1) | Qb.ReadBit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
q[2] = Qb.ReadBits(5, 6);
|
||||
C = Qb.ReadBits(0, 4);
|
||||
}
|
||||
|
||||
BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C }));
|
||||
if (Cb.ReadBits(0, 2) == 5)
|
||||
{
|
||||
q[1] = 4;
|
||||
q[0] = Cb.ReadBits(3, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
q[1] = Cb.ReadBits(3, 4);
|
||||
q[0] = Cb.ReadBits(0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Quint, NumberBitsPerValue)
|
||||
{
|
||||
BitValue = m[i],
|
||||
QuintValue = q[i]
|
||||
};
|
||||
ListIntegerEncoded.Add(IntEncoded);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DecodeIntegerSequence(
|
||||
List<IntegerEncoded> DecodeIntegerSequence,
|
||||
BitArrayStream BitStream,
|
||||
int MaxRange,
|
||||
int NumberValues)
|
||||
{
|
||||
// Determine encoding parameters
|
||||
IntegerEncoded IntEncoded = CreateEncoding(MaxRange);
|
||||
|
||||
// Start decoding
|
||||
int NumberValuesDecoded = 0;
|
||||
while (NumberValuesDecoded < NumberValues)
|
||||
{
|
||||
switch (IntEncoded.GetEncoding())
|
||||
{
|
||||
case EIntegerEncoding.Quint:
|
||||
{
|
||||
DecodeQuintBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits);
|
||||
NumberValuesDecoded += 3;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EIntegerEncoding.Trit:
|
||||
{
|
||||
DecodeTritBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits);
|
||||
NumberValuesDecoded += 5;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EIntegerEncoding.JustBits:
|
||||
{
|
||||
IntEncoded.BitValue = BitStream.ReadBits(IntEncoded.NumberBits);
|
||||
DecodeIntegerSequence.Add(IntEncoded);
|
||||
NumberValuesDecoded++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
Ryujinx.Graphics/Texture/LinearSwizzle.cs
Normal file
19
Ryujinx.Graphics/Texture/LinearSwizzle.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
class LinearSwizzle : ISwizzle
|
||||
{
|
||||
private int Pitch;
|
||||
private int Bpp;
|
||||
|
||||
public LinearSwizzle(int Pitch, int Bpp)
|
||||
{
|
||||
this.Pitch = Pitch;
|
||||
this.Bpp = Bpp;
|
||||
}
|
||||
|
||||
public int GetSwizzleOffset(int X, int Y)
|
||||
{
|
||||
return X * Bpp + Y * Pitch;
|
||||
}
|
||||
}
|
||||
}
|
132
Ryujinx.Graphics/Texture/TextureFactory.cs
Normal file
132
Ryujinx.Graphics/Texture/TextureFactory.cs
Normal file
|
@ -0,0 +1,132 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class TextureFactory
|
||||
{
|
||||
public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition)
|
||||
{
|
||||
int[] Tic = ReadWords(Vmm, TicPosition, 8);
|
||||
|
||||
GalImageFormat Format = GetImageFormat(Tic);
|
||||
|
||||
GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7);
|
||||
GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7);
|
||||
GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7);
|
||||
GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7);
|
||||
|
||||
int Width = (Tic[4] & 0xffff) + 1;
|
||||
int Height = (Tic[5] & 0xffff) + 1;
|
||||
|
||||
return new GalImage(
|
||||
Width,
|
||||
Height,
|
||||
Format,
|
||||
XSource,
|
||||
YSource,
|
||||
ZSource,
|
||||
WSource);
|
||||
}
|
||||
|
||||
public static byte[] GetTextureData(NvGpuVmm Vmm, long TicPosition)
|
||||
{
|
||||
int[] Tic = ReadWords(Vmm, TicPosition, 8);
|
||||
|
||||
GalImageFormat Format = GetImageFormat(Tic);
|
||||
|
||||
long TextureAddress = (uint)Tic[1];
|
||||
|
||||
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
||||
|
||||
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
|
||||
|
||||
if (Swizzle == TextureSwizzle.BlockLinear ||
|
||||
Swizzle == TextureSwizzle.BlockLinearColorKey)
|
||||
{
|
||||
TextureAddress &= ~0x1ffL;
|
||||
}
|
||||
else if (Swizzle == TextureSwizzle.Pitch ||
|
||||
Swizzle == TextureSwizzle.PitchColorKey)
|
||||
{
|
||||
TextureAddress &= ~0x1fL;
|
||||
}
|
||||
|
||||
int Pitch = (Tic[3] & 0xffff) << 5;
|
||||
|
||||
int BlockHeightLog2 = (Tic[3] >> 3) & 7;
|
||||
int TileWidthLog2 = (Tic[3] >> 10) & 7;
|
||||
|
||||
int BlockHeight = 1 << BlockHeightLog2;
|
||||
int TileWidth = 1 << TileWidthLog2;
|
||||
|
||||
int Width = (Tic[4] & 0xffff) + 1;
|
||||
int Height = (Tic[5] & 0xffff) + 1;
|
||||
|
||||
TextureInfo Texture = new TextureInfo(
|
||||
TextureAddress,
|
||||
Width,
|
||||
Height,
|
||||
Pitch,
|
||||
BlockHeight,
|
||||
TileWidth,
|
||||
Swizzle,
|
||||
Format);
|
||||
|
||||
return TextureReader.Read(Vmm, Texture);
|
||||
}
|
||||
|
||||
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
||||
{
|
||||
int[] Tsc = ReadWords(Vmm, TscPosition, 8);
|
||||
|
||||
GalTextureWrap AddressU = (GalTextureWrap)((Tsc[0] >> 0) & 7);
|
||||
GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7);
|
||||
GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7);
|
||||
|
||||
GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3);
|
||||
GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3);
|
||||
GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3);
|
||||
|
||||
GalColorF BorderColor = new GalColorF(
|
||||
BitConverter.Int32BitsToSingle(Tsc[4]),
|
||||
BitConverter.Int32BitsToSingle(Tsc[5]),
|
||||
BitConverter.Int32BitsToSingle(Tsc[6]),
|
||||
BitConverter.Int32BitsToSingle(Tsc[7]));
|
||||
|
||||
return new GalTextureSampler(
|
||||
AddressU,
|
||||
AddressV,
|
||||
AddressP,
|
||||
MinFilter,
|
||||
MagFilter,
|
||||
MipFilter,
|
||||
BorderColor);
|
||||
}
|
||||
|
||||
private static GalImageFormat GetImageFormat(int[] Tic)
|
||||
{
|
||||
GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7);
|
||||
GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7);
|
||||
GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7);
|
||||
GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7);
|
||||
|
||||
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
||||
|
||||
return ImageUtils.ConvertTexture(Format, RType, GType, BType, AType);
|
||||
}
|
||||
|
||||
private static int[] ReadWords(NvGpuVmm Vmm, long Position, int Count)
|
||||
{
|
||||
int[] Words = new int[Count];
|
||||
|
||||
for (int Index = 0; Index < Count; Index++, Position += 4)
|
||||
{
|
||||
Words[Index] = Vmm.ReadInt32(Position);
|
||||
}
|
||||
|
||||
return Words;
|
||||
}
|
||||
}
|
||||
}
|
45
Ryujinx.Graphics/Texture/TextureHelper.cs
Normal file
45
Ryujinx.Graphics/Texture/TextureHelper.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class TextureHelper
|
||||
{
|
||||
public static ISwizzle GetSwizzle(TextureInfo Texture, int BlockWidth, int Bpp)
|
||||
{
|
||||
int Width = (Texture.Width + (BlockWidth - 1)) / BlockWidth;
|
||||
|
||||
int AlignMask = Texture.TileWidth * (64 / Bpp) - 1;
|
||||
|
||||
Width = (Width + AlignMask) & ~AlignMask;
|
||||
|
||||
switch (Texture.Swizzle)
|
||||
{
|
||||
case TextureSwizzle._1dBuffer:
|
||||
case TextureSwizzle.Pitch:
|
||||
case TextureSwizzle.PitchColorKey:
|
||||
return new LinearSwizzle(Texture.Pitch, Bpp);
|
||||
|
||||
case TextureSwizzle.BlockLinear:
|
||||
case TextureSwizzle.BlockLinearColorKey:
|
||||
return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Texture.Swizzle.ToString());
|
||||
}
|
||||
|
||||
public static (AMemory Memory, long Position) GetMemoryAndPosition(
|
||||
IAMemory Memory,
|
||||
long Position)
|
||||
{
|
||||
if (Memory is NvGpuVmm Vmm)
|
||||
{
|
||||
return (Vmm.Memory, Vmm.GetPhysicalAddress(Position));
|
||||
}
|
||||
|
||||
return ((AMemory)Memory, Position);
|
||||
}
|
||||
}
|
||||
}
|
60
Ryujinx.Graphics/Texture/TextureInfo.cs
Normal file
60
Ryujinx.Graphics/Texture/TextureInfo.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public struct TextureInfo
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public int Pitch { get; private set; }
|
||||
|
||||
public int BlockHeight { get; private set; }
|
||||
public int TileWidth { get; private set; }
|
||||
|
||||
public TextureSwizzle Swizzle { get; private set; }
|
||||
|
||||
public GalImageFormat Format { get; private set; }
|
||||
|
||||
public TextureInfo(
|
||||
long Position,
|
||||
int Width,
|
||||
int Height)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
|
||||
Pitch = 0;
|
||||
|
||||
BlockHeight = 16;
|
||||
|
||||
TileWidth = 1;
|
||||
|
||||
Swizzle = TextureSwizzle.BlockLinear;
|
||||
|
||||
Format = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
|
||||
}
|
||||
|
||||
public TextureInfo(
|
||||
long Position,
|
||||
int Width,
|
||||
int Height,
|
||||
int Pitch,
|
||||
int BlockHeight,
|
||||
int TileWidth,
|
||||
TextureSwizzle Swizzle,
|
||||
GalImageFormat Format)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.Pitch = Pitch;
|
||||
this.BlockHeight = BlockHeight;
|
||||
this.TileWidth = TileWidth;
|
||||
this.Swizzle = Swizzle;
|
||||
this.Format = Format;
|
||||
}
|
||||
}
|
||||
}
|
398
Ryujinx.Graphics/Texture/TextureReader.cs
Normal file
398
Ryujinx.Graphics/Texture/TextureReader.cs
Normal file
|
@ -0,0 +1,398 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
delegate byte[] TextureReaderDelegate(IAMemory Memory, TextureInfo Texture);
|
||||
|
||||
public static class TextureReader
|
||||
{
|
||||
public static byte[] Read(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
TextureReaderDelegate Reader = ImageUtils.GetReader(Texture.Format);
|
||||
|
||||
return Reader(Memory, Texture);
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read1Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 1);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
byte Pixel = CpuMem.ReadByte(Position + Offset);
|
||||
|
||||
*(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs++;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read5551(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 2];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset);
|
||||
|
||||
Pixel = (Pixel & 0x001f) << 11 |
|
||||
(Pixel & 0x03e0) << 1 |
|
||||
(Pixel & 0x7c00) >> 9 |
|
||||
(Pixel & 0x8000) >> 15;
|
||||
|
||||
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
|
||||
|
||||
OutOffs += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read565(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 2];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset);
|
||||
|
||||
Pixel = (Pixel & 0x001f) << 11 |
|
||||
(Pixel & 0x07e0) |
|
||||
(Pixel & 0xf800) >> 11;
|
||||
|
||||
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
|
||||
|
||||
OutOffs += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read2Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 2];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
short Pixel = CpuMem.ReadInt16(Position + Offset);
|
||||
|
||||
*(short*)(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read4Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 4];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
int Pixel = CpuMem.ReadInt32(Position + Offset);
|
||||
|
||||
*(int*)(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read8Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 8];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 8);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long Pixel = CpuMem.ReadInt64(Position + Offset);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read16Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 16];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 16);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long PxLow = CpuMem.ReadInt64(Position + Offset + 0);
|
||||
long PxHigh = CpuMem.ReadInt64(Position + Offset + 8);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs + 0) = PxLow;
|
||||
*(long*)(BuffPtr + OutOffs + 8) = PxHigh;
|
||||
|
||||
OutOffs += 16;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read8Bpt4x4(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = (Texture.Width + 3) / 4;
|
||||
int Height = (Texture.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 8];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 4, 8);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long Tile = CpuMem.ReadInt64(Position + Offset);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs) = Tile;
|
||||
|
||||
OutOffs += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read16BptCompressedTexture(IAMemory Memory, TextureInfo Texture, int BlockWidth, int BlockHeight)
|
||||
{
|
||||
int Width = (Texture.Width + (BlockWidth - 1)) / BlockWidth;
|
||||
int Height = (Texture.Height + (BlockHeight - 1)) / BlockHeight;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 16];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, BlockWidth, 16);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long Tile0 = CpuMem.ReadInt64(Position + Offset + 0);
|
||||
long Tile1 = CpuMem.ReadInt64(Position + Offset + 8);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs + 0) = Tile0;
|
||||
*(long*)(BuffPtr + OutOffs + 8) = Tile1;
|
||||
|
||||
OutOffs += 16;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture4x4(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 4, 4);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture5x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture6x6(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 6, 6);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture8x8(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 8, 8);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x10(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 10);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture12x12(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 12, 12);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture5x4(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 5, 4);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture6x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 6, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture8x6(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 8, 6);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x8(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 8);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture12x10(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 12, 10);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture8x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x6(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 6);
|
||||
}
|
||||
}
|
||||
}
|
11
Ryujinx.Graphics/Texture/TextureSwizzle.cs
Normal file
11
Ryujinx.Graphics/Texture/TextureSwizzle.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public enum TextureSwizzle
|
||||
{
|
||||
_1dBuffer = 0,
|
||||
PitchColorKey = 1,
|
||||
Pitch = 2,
|
||||
BlockLinear = 3,
|
||||
BlockLinearColorKey = 4
|
||||
}
|
||||
}
|
35
Ryujinx.Graphics/Texture/TextureWriter.cs
Normal file
35
Ryujinx.Graphics/Texture/TextureWriter.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class TextureWriter
|
||||
{
|
||||
public unsafe static void Write(IAMemory Memory, TextureInfo Texture, byte[] Data)
|
||||
{
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Data)
|
||||
{
|
||||
long InOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Texture.Height; Y++)
|
||||
for (int X = 0; X < Texture.Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
int Pixel = *(int*)(BuffPtr + InOffs);
|
||||
|
||||
CpuMem.WriteInt32(Position + Offset, Pixel);
|
||||
|
||||
InOffs += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue