Support linear swizzling, upload compressed textures instead of decoding on the CPU (this is a bit faster)
This commit is contained in:
parent
8f0f1c489c
commit
36f85260bb
12 changed files with 411 additions and 74 deletions
|
@ -18,5 +18,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Type));
|
throw new ArgumentException(nameof(Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PixelInternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.BC1: return PixelInternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||||
|
case GalTextureFormat.BC2: return PixelInternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||||
|
case GalTextureFormat.BC3: return PixelInternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException(Format.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Graphics.Gal.Texture;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
@ -58,18 +57,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||||
|
|
||||||
const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
|
|
||||||
|
|
||||||
int W = Texture.Width;
|
int W = Texture.Width;
|
||||||
int H = Texture.Height;
|
int H = Texture.Height;
|
||||||
|
|
||||||
const PixelFormat Pf = PixelFormat.Rgba;
|
byte[] Data = Texture.Data;
|
||||||
|
|
||||||
const PixelType Pt = PixelType.UnsignedByte;
|
int Length = Data.Length;
|
||||||
|
|
||||||
byte[] Buffer = TextureDecoder.Decode(Texture);
|
if (IsCompressedTextureFormat(Texture.Format))
|
||||||
|
{
|
||||||
|
PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format);
|
||||||
|
|
||||||
GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Buffer);
|
GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: Get those from Texture format.
|
||||||
|
const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
|
||||||
|
|
||||||
|
const PixelFormat Pf = PixelFormat.Rgba;
|
||||||
|
|
||||||
|
const PixelType Pt = PixelType.UnsignedByte;
|
||||||
|
|
||||||
|
GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCompressedTextureFormat(GalTextureFormat Format)
|
||||||
|
{
|
||||||
|
return Format == GalTextureFormat.BC1 ||
|
||||||
|
Format == GalTextureFormat.BC2 ||
|
||||||
|
Format == GalTextureFormat.BC3;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int EnsureTextureInitialized(int TextureIndex)
|
private int EnsureTextureInitialized(int TextureIndex)
|
||||||
|
|
|
@ -64,45 +64,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fmul);
|
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Fmul);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Fsetp_R(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitFsetp(Block, OpCode, ShaderOper.RR);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode)
|
public static void Fsetp_C(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
bool Aa = ((OpCode >> 7) & 1) != 0;
|
EmitFsetp(Block, OpCode, ShaderOper.CR);
|
||||||
bool Na = ((OpCode >> 43) & 1) != 0;
|
|
||||||
bool Ab = ((OpCode >> 44) & 1) != 0;
|
|
||||||
|
|
||||||
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
|
||||||
ShaderIrNode OperB = GetOperCbuf34(OpCode);
|
|
||||||
|
|
||||||
ShaderIrInst CmpInst = GetCmp(OpCode);
|
|
||||||
|
|
||||||
ShaderIrOp Op = new ShaderIrOp(CmpInst,
|
|
||||||
GetAluAbsNeg(OperA, Aa, Na),
|
|
||||||
GetAluAbs (OperB, Ab));
|
|
||||||
|
|
||||||
ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
|
|
||||||
ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
|
|
||||||
ShaderIrOperPred P2Node = GetOperPred39(OpCode);
|
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
|
||||||
|
|
||||||
ShaderIrInst LopInst = GetBLop(OpCode);
|
|
||||||
|
|
||||||
if (LopInst == ShaderIrInst.Band &&
|
|
||||||
P1Node.Index == ShaderIrOperPred.UnusedIndex &&
|
|
||||||
P2Node.Index == ShaderIrOperPred.UnusedIndex)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderIrNode P2NNode = GetOperPred39N(OpCode);
|
|
||||||
|
|
||||||
Op = new ShaderIrOp(LopInst, new ShaderIrOp(ShaderIrInst.Bnot, P0Node), P2NNode);
|
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(P1Node, Op), OpCode));
|
|
||||||
|
|
||||||
Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
|
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ipa(ShaderIrBlock Block, long OpCode)
|
public static void Ipa(ShaderIrBlock Block, long OpCode)
|
||||||
|
@ -211,6 +180,61 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
{
|
||||||
|
bool Aa = ((OpCode >> 7) & 1) != 0;
|
||||||
|
bool Np = ((OpCode >> 42) & 1) != 0;
|
||||||
|
bool Na = ((OpCode >> 43) & 1) != 0;
|
||||||
|
bool Ab = ((OpCode >> 44) & 1) != 0;
|
||||||
|
|
||||||
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
||||||
|
|
||||||
|
switch (Oper)
|
||||||
|
{
|
||||||
|
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||||
|
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||||
|
case ShaderOper.Imm: OperB = GetOperImmf19_20(OpCode); break;
|
||||||
|
|
||||||
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrInst CmpInst = GetCmp(OpCode);
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(CmpInst,
|
||||||
|
GetAluAbsNeg(OperA, Aa, Na),
|
||||||
|
GetAluAbs (OperB, Ab));
|
||||||
|
|
||||||
|
ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
|
||||||
|
ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
|
||||||
|
ShaderIrOperPred P2Node = GetOperPred39(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
|
|
||||||
|
ShaderIrInst LopInst = GetBLop(OpCode);
|
||||||
|
|
||||||
|
if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrNode P2NNode = P2Node;
|
||||||
|
|
||||||
|
if (Np)
|
||||||
|
{
|
||||||
|
P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(LopInst, Op, P2NNode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P1Node, Op), OpCode));
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
private static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg)
|
private static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||||
{
|
{
|
||||||
return GetAluNeg(GetAluAbs(Node, Abs), Neg);
|
return GetAluNeg(GetAluAbs(Node, Abs), Neg);
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("0101110001101x", ShaderDecode.Fmul_R);
|
Set("0101110001101x", ShaderDecode.Fmul_R);
|
||||||
Set("0100110001101x", ShaderDecode.Fmul_C);
|
Set("0100110001101x", ShaderDecode.Fmul_C);
|
||||||
Set("0011100x01101x", ShaderDecode.Fmul_Imm);
|
Set("0011100x01101x", ShaderDecode.Fmul_Imm);
|
||||||
|
Set("010110111011xx", ShaderDecode.Fsetp_R);
|
||||||
Set("010010111011xx", ShaderDecode.Fsetp_C);
|
Set("010010111011xx", ShaderDecode.Fsetp_C);
|
||||||
Set("11100000xxxxxx", ShaderDecode.Ipa);
|
Set("11100000xxxxxx", ShaderDecode.Ipa);
|
||||||
Set("111000110011xx", ShaderDecode.Kil);
|
Set("111000110011xx", ShaderDecode.Kil);
|
||||||
|
|
57
Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs
Normal file
57
Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
{
|
||||||
|
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 = Width * Bpp / 64;
|
||||||
|
|
||||||
|
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/Gpu/ISwizzle.cs
Normal file
7
Ryujinx.Graphics/Gpu/ISwizzle.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
{
|
||||||
|
interface ISwizzle
|
||||||
|
{
|
||||||
|
int GetSwizzleOffset(int X, int Y);
|
||||||
|
}
|
||||||
|
}
|
20
Ryujinx.Graphics/Gpu/LinearSwizzle.cs
Normal file
20
Ryujinx.Graphics/Gpu/LinearSwizzle.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
{
|
||||||
|
class LinearSwizzle : ISwizzle
|
||||||
|
{
|
||||||
|
private int Bpp;
|
||||||
|
private int Stride;
|
||||||
|
|
||||||
|
public LinearSwizzle(int Width, int Bpp)
|
||||||
|
{
|
||||||
|
this.Bpp = Bpp;
|
||||||
|
|
||||||
|
Stride = Width * Bpp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetSwizzleOffset(int X, int Y)
|
||||||
|
{
|
||||||
|
return X * Bpp + Y * Stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -232,37 +232,9 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition);
|
TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition);
|
||||||
|
|
||||||
int[] Tic = ReadWords(Memory, TicPosition + TicIndex * 0x20, 8);
|
TicPosition += TicIndex * 0x20;
|
||||||
|
|
||||||
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
return TextureFactory.MakeTexture(Gpu, Memory, TicPosition);
|
||||||
|
|
||||||
long TextureAddress = (uint)Tic[1];
|
|
||||||
|
|
||||||
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
|
||||||
|
|
||||||
TextureAddress = Gpu.GetCpuAddr(TextureAddress);
|
|
||||||
|
|
||||||
int Width = (Tic[4] & 0xffff) + 1;
|
|
||||||
int Height = (Tic[5] & 0xffff) + 1;
|
|
||||||
|
|
||||||
long TextureSize = GetTextureSize(Width, Height, Format);
|
|
||||||
|
|
||||||
byte[] Data = AMemoryHelper.ReadBytes(Memory, TextureAddress, TextureSize);
|
|
||||||
|
|
||||||
return new GalTexture(Data, Width, Height, Format);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long GetTextureSize(int Width, int Height, GalTextureFormat Format)
|
|
||||||
{
|
|
||||||
switch (Format)
|
|
||||||
{
|
|
||||||
case GalTextureFormat.A8B8G8R8: return (Width * Height) << 2;
|
|
||||||
case GalTextureFormat.BC1: return (Width * Height) >> 1;
|
|
||||||
case GalTextureFormat.BC2: return Width * Height;
|
|
||||||
case GalTextureFormat.BC3: return Width * Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] ReadWords(AMemory Memory, long Position, int Count)
|
private int[] ReadWords(AMemory Memory, long Position, int Count)
|
||||||
|
|
34
Ryujinx.Graphics/Gpu/Texture.cs
Normal file
34
Ryujinx.Graphics/Gpu/Texture.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
{
|
||||||
|
struct Texture
|
||||||
|
{
|
||||||
|
public long Position { get; private set; }
|
||||||
|
|
||||||
|
public int Width { get; private set; }
|
||||||
|
public int Height { get; private set; }
|
||||||
|
|
||||||
|
public int BlockHeight { get; private set; }
|
||||||
|
|
||||||
|
public TextureSwizzle Swizzle { get; private set; }
|
||||||
|
|
||||||
|
public GalTextureFormat Format { get; private set; }
|
||||||
|
|
||||||
|
public Texture(
|
||||||
|
long Position,
|
||||||
|
int Width,
|
||||||
|
int Height,
|
||||||
|
int BlockHeight,
|
||||||
|
TextureSwizzle Swizzle,
|
||||||
|
GalTextureFormat Format)
|
||||||
|
{
|
||||||
|
this.Position = Position;
|
||||||
|
this.Width = Width;
|
||||||
|
this.Height = Height;
|
||||||
|
this.BlockHeight = BlockHeight;
|
||||||
|
this.Swizzle = Swizzle;
|
||||||
|
this.Format = Format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
Ryujinx.Graphics/Gpu/TextureFactory.cs
Normal file
54
Ryujinx.Graphics/Gpu/TextureFactory.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using ChocolArm64.Memory;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
{
|
||||||
|
static class TextureFactory
|
||||||
|
{
|
||||||
|
public static GalTexture MakeTexture(NsGpu Gpu, AMemory Memory, long TicPosition)
|
||||||
|
{
|
||||||
|
int[] Tic = ReadWords(Memory, TicPosition, 8);
|
||||||
|
|
||||||
|
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
||||||
|
|
||||||
|
long TextureAddress = (uint)Tic[1];
|
||||||
|
|
||||||
|
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
||||||
|
|
||||||
|
TextureAddress = Gpu.GetCpuAddr(TextureAddress);
|
||||||
|
|
||||||
|
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
|
||||||
|
|
||||||
|
int BlockHeightLog2 = (Tic[3] >> 3) & 7;
|
||||||
|
|
||||||
|
int BlockHeight = 1 << BlockHeightLog2;
|
||||||
|
|
||||||
|
int Width = (Tic[4] & 0xffff) + 1;
|
||||||
|
int Height = (Tic[5] & 0xffff) + 1;
|
||||||
|
|
||||||
|
Texture Texture = new Texture(
|
||||||
|
TextureAddress,
|
||||||
|
Width,
|
||||||
|
Height,
|
||||||
|
BlockHeight,
|
||||||
|
Swizzle,
|
||||||
|
Format);
|
||||||
|
|
||||||
|
byte[] Data = TextureReader.Read(Memory, Texture);
|
||||||
|
|
||||||
|
return new GalTexture(Data, Width, Height, Format);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] ReadWords(AMemory Memory, long Position, int Count)
|
||||||
|
{
|
||||||
|
int[] Words = new int[Count];
|
||||||
|
|
||||||
|
for (int Index = 0; Index < Count; Index++, Position += 4)
|
||||||
|
{
|
||||||
|
Words[Index] = Memory.ReadInt32(Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Words;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
127
Ryujinx.Graphics/Gpu/TextureReader.cs
Normal file
127
Ryujinx.Graphics/Gpu/TextureReader.cs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
using ChocolArm64.Memory;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
{
|
||||||
|
static class TextureReader
|
||||||
|
{
|
||||||
|
public static byte[] Read(AMemory Memory, Texture Texture)
|
||||||
|
{
|
||||||
|
switch (Texture.Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.A8B8G8R8: return Read4Bpp (Memory, Texture);
|
||||||
|
case GalTextureFormat.BC1: return Read8Bpt4x4 (Memory, Texture);
|
||||||
|
case GalTextureFormat.BC2: return Read16Bpt4x4(Memory, Texture);
|
||||||
|
case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException(Texture.Format.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
|
||||||
|
{
|
||||||
|
int Width = Texture.Width;
|
||||||
|
int Height = Texture.Height;
|
||||||
|
|
||||||
|
byte[] Output = new byte[Width * Height * 4];
|
||||||
|
|
||||||
|
ISwizzle Swizzle = GetSwizzle(Texture.Swizzle, Width, 4, Texture.BlockHeight);
|
||||||
|
|
||||||
|
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 = Memory.ReadInt32Unchecked(Texture.Position + Offset);
|
||||||
|
|
||||||
|
*(int*)(BuffPtr + OutOffs) = Pixel;
|
||||||
|
|
||||||
|
OutOffs += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe static byte[] Read8Bpt4x4(AMemory Memory, Texture Texture)
|
||||||
|
{
|
||||||
|
int Width = (Texture.Width + 3) / 4;
|
||||||
|
int Height = (Texture.Height + 3) / 4;
|
||||||
|
|
||||||
|
byte[] Output = new byte[Width * Height * 8];
|
||||||
|
|
||||||
|
ISwizzle Swizzle = GetSwizzle(Texture.Swizzle, Width, 8, Texture.BlockHeight);
|
||||||
|
|
||||||
|
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 = Memory.ReadInt64Unchecked(Texture.Position + Offset);
|
||||||
|
|
||||||
|
*(long*)(BuffPtr + OutOffs) = Tile;
|
||||||
|
|
||||||
|
OutOffs += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe static byte[] Read16Bpt4x4(AMemory Memory, Texture Texture)
|
||||||
|
{
|
||||||
|
int Width = (Texture.Width + 3) / 4;
|
||||||
|
int Height = (Texture.Height + 3) / 4;
|
||||||
|
|
||||||
|
byte[] Output = new byte[Width * Height * 16];
|
||||||
|
|
||||||
|
ISwizzle Swizzle = GetSwizzle(Texture.Swizzle, Width, 16, Texture.BlockHeight);
|
||||||
|
|
||||||
|
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 = Memory.ReadInt64Unchecked(Texture.Position + Offset + 0);
|
||||||
|
long Tile1 = Memory.ReadInt64Unchecked(Texture.Position + Offset + 8);
|
||||||
|
|
||||||
|
*(long*)(BuffPtr + OutOffs + 0) = Tile0;
|
||||||
|
*(long*)(BuffPtr + OutOffs + 8) = Tile1;
|
||||||
|
|
||||||
|
OutOffs += 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ISwizzle GetSwizzle(TextureSwizzle Swizzle, int Width, int Bpp, int BlockHeight)
|
||||||
|
{
|
||||||
|
switch (Swizzle)
|
||||||
|
{
|
||||||
|
case TextureSwizzle.Pitch:
|
||||||
|
case TextureSwizzle.PitchColorKey:
|
||||||
|
return new LinearSwizzle(Width, Bpp);
|
||||||
|
|
||||||
|
case TextureSwizzle.BlockLinear:
|
||||||
|
case TextureSwizzle.BlockLinearColorKey:
|
||||||
|
return new BlockLinearSwizzle(Width, Bpp, BlockHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException(Swizzle.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Ryujinx.Graphics/Gpu/TextureSwizzle.cs
Normal file
11
Ryujinx.Graphics/Gpu/TextureSwizzle.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
{
|
||||||
|
enum TextureSwizzle
|
||||||
|
{
|
||||||
|
_1dBuffer = 0,
|
||||||
|
PitchColorKey = 1,
|
||||||
|
Pitch = 2,
|
||||||
|
BlockLinear = 3,
|
||||||
|
BlockLinearColorKey = 4
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue