Small OpenGL Renderer refactoring (#177)

* Call OpenGL functions directly, remove the pfifo thread, some refactoring

* Fix PerformanceStatistics calculating the wrong host fps, remove wait event on PFIFO as this wasn't exactly was causing the freezes (may replace with an exception later)

* Organized the Gpu folder a bit more, renamed a few things, address PR feedback

* Make PerformanceStatistics thread safe

* Remove unused constant

* Use unlimited update rate for better pref
This commit is contained in:
gdkchan 2018-06-23 21:39:25 -03:00 committed by GitHub
parent 69697957e6
commit e7559f128f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 518 additions and 633 deletions

View file

@ -0,0 +1,59 @@
using System;
namespace Ryujinx.HLE.Gpu.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;
}
}
}

View file

@ -0,0 +1,7 @@
namespace Ryujinx.HLE.Gpu.Texture
{
interface ISwizzle
{
int GetSwizzleOffset(int X, int Y);
}
}

View file

@ -0,0 +1,19 @@
namespace Ryujinx.HLE.Gpu.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;
}
}
}

View file

@ -0,0 +1,117 @@
using Ryujinx.Graphics.Gal;
using Ryujinx.HLE.Gpu.Memory;
using System;
namespace Ryujinx.HLE.Gpu.Texture
{
static class TextureFactory
{
public static GalTexture MakeTexture(NvGpuVmm Vmm, long TicPosition)
{
int[] Tic = ReadWords(Vmm, TicPosition, 8);
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
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 GalTexture(
Width,
Height,
Format,
XSource,
YSource,
ZSource,
WSource);
}
public static byte[] GetTextureData(NvGpuVmm Vmm, long TicPosition)
{
int[] Tic = ReadWords(Vmm, TicPosition, 8);
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
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 BlockHeight = 1 << BlockHeightLog2;
int Width = (Tic[4] & 0xffff) + 1;
int Height = (Tic[5] & 0xffff) + 1;
TextureInfo Texture = new TextureInfo(
TextureAddress,
Width,
Height,
Pitch,
BlockHeight,
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 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;
}
}
}

View file

@ -0,0 +1,78 @@
using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using Ryujinx.HLE.Gpu.Memory;
using System;
namespace Ryujinx.HLE.Gpu.Texture
{
static class TextureHelper
{
public static ISwizzle GetSwizzle(TextureInfo Texture, int Width, int Bpp)
{
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 int GetTextureSize(GalTexture Texture)
{
switch (Texture.Format)
{
case GalTextureFormat.R32G32B32A32: return Texture.Width * Texture.Height * 16;
case GalTextureFormat.R16G16B16A16: return Texture.Width * Texture.Height * 8;
case GalTextureFormat.A8B8G8R8: return Texture.Width * Texture.Height * 4;
case GalTextureFormat.R32: return Texture.Width * Texture.Height * 4;
case GalTextureFormat.A1B5G5R5: return Texture.Width * Texture.Height * 2;
case GalTextureFormat.B5G6R5: return Texture.Width * Texture.Height * 2;
case GalTextureFormat.G8R8: return Texture.Width * Texture.Height * 2;
case GalTextureFormat.R16: return Texture.Width * Texture.Height * 2;
case GalTextureFormat.R8: return Texture.Width * Texture.Height;
case GalTextureFormat.BC1:
case GalTextureFormat.BC4:
{
int W = (Texture.Width + 3) / 4;
int H = (Texture.Height + 3) / 4;
return W * H * 8;
}
case GalTextureFormat.BC7U:
case GalTextureFormat.BC2:
case GalTextureFormat.BC3:
case GalTextureFormat.BC5:
case GalTextureFormat.Astc2D4x4:
{
int W = (Texture.Width + 3) / 4;
int H = (Texture.Height + 3) / 4;
return W * H * 16;
}
}
throw new NotImplementedException(Texture.Format.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);
}
}
}

View file

@ -0,0 +1,55 @@
using Ryujinx.Graphics.Gal;
namespace Ryujinx.HLE.Gpu.Texture
{
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 TextureSwizzle Swizzle { get; private set; }
public GalTextureFormat 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;
Swizzle = TextureSwizzle.BlockLinear;
Format = GalTextureFormat.A8B8G8R8;
}
public TextureInfo(
long Position,
int Width,
int Height,
int Pitch,
int BlockHeight,
TextureSwizzle Swizzle,
GalTextureFormat Format)
{
this.Position = Position;
this.Width = Width;
this.Height = Height;
this.Pitch = Pitch;
this.BlockHeight = BlockHeight;
this.Swizzle = Swizzle;
this.Format = Format;
}
}
}

View file

@ -0,0 +1,344 @@
using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using System;
namespace Ryujinx.HLE.Gpu.Texture
{
static class TextureReader
{
public static byte[] Read(IAMemory Memory, TextureInfo Texture)
{
switch (Texture.Format)
{
case GalTextureFormat.R32G32B32A32: return Read16Bpp (Memory, Texture);
case GalTextureFormat.R16G16B16A16: return Read8Bpp (Memory, Texture);
case GalTextureFormat.A8B8G8R8: return Read4Bpp (Memory, Texture);
case GalTextureFormat.R32: return Read4Bpp (Memory, Texture);
case GalTextureFormat.A1B5G5R5: return Read5551 (Memory, Texture);
case GalTextureFormat.B5G6R5: return Read565 (Memory, Texture);
case GalTextureFormat.G8R8: return Read2Bpp (Memory, Texture);
case GalTextureFormat.R16: return Read2Bpp (Memory, Texture);
case GalTextureFormat.R8: return Read1Bpp (Memory, Texture);
case GalTextureFormat.BC7U: return Read16Bpt4x4(Memory, Texture);
case GalTextureFormat.BC1: return Read8Bpt4x4 (Memory, Texture);
case GalTextureFormat.BC2: return Read16Bpt4x4(Memory, Texture);
case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture);
case GalTextureFormat.BC4: return Read8Bpt4x4 (Memory, Texture);
case GalTextureFormat.BC5: return Read16Bpt4x4(Memory, Texture);
case GalTextureFormat.Astc2D4x4: return Read16Bpt4x4(Memory, Texture);
}
throw new NotImplementedException(Texture.Format.ToString());
}
private 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, Width, 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.ReadByteUnchecked(Position + Offset);
*(BuffPtr + OutOffs) = Pixel;
OutOffs++;
}
}
return Output;
}
private 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, Width, 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.ReadInt16Unchecked(Position + Offset);
Pixel = (Pixel & 0x001f) << 11 |
(Pixel & 0x03e0) << 1 |
(Pixel & 0x7c00) >> 9 |
(Pixel & 0x8000) >> 15;
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
OutOffs += 2;
}
}
return Output;
}
private 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, Width, 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.ReadInt16Unchecked(Position + Offset);
Pixel = (Pixel & 0x001f) << 11 |
(Pixel & 0x07e0) |
(Pixel & 0xf800) >> 11;
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
OutOffs += 2;
}
}
return Output;
}
private 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, Width, 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.ReadInt16Unchecked(Position + Offset);
*(short*)(BuffPtr + OutOffs) = Pixel;
OutOffs += 2;
}
}
return Output;
}
private 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, Width, 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.ReadInt32Unchecked(Position + Offset);
*(int*)(BuffPtr + OutOffs) = Pixel;
OutOffs += 4;
}
}
return Output;
}
private 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, Width, 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.ReadInt64Unchecked(Position + Offset);
*(long*)(BuffPtr + OutOffs) = Pixel;
OutOffs += 8;
}
}
return Output;
}
private 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, Width, 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.ReadInt64Unchecked(Position + Offset + 0);
long PxHigh = CpuMem.ReadInt64Unchecked(Position + Offset + 8);
*(long*)(BuffPtr + OutOffs + 0) = PxLow;
*(long*)(BuffPtr + OutOffs + 8) = PxHigh;
OutOffs += 16;
}
}
return Output;
}
private 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, Width, 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.ReadInt64Unchecked(Position + Offset);
*(long*)(BuffPtr + OutOffs) = Tile;
OutOffs += 8;
}
}
return Output;
}
private unsafe static byte[] Read16Bpt4x4(IAMemory Memory, TextureInfo Texture)
{
int Width = (Texture.Width + 3) / 4;
int Height = (Texture.Height + 3) / 4;
byte[] Output = new byte[Width * Height * 16];
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 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.ReadInt64Unchecked(Position + Offset + 0);
long Tile1 = CpuMem.ReadInt64Unchecked(Position + Offset + 8);
*(long*)(BuffPtr + OutOffs + 0) = Tile0;
*(long*)(BuffPtr + OutOffs + 8) = Tile1;
OutOffs += 16;
}
}
return Output;
}
}
}

View file

@ -0,0 +1,11 @@
namespace Ryujinx.HLE.Gpu.Texture
{
enum TextureSwizzle
{
_1dBuffer = 0,
PitchColorKey = 1,
Pitch = 2,
BlockLinear = 3,
BlockLinearColorKey = 4
}
}

View file

@ -0,0 +1,55 @@
using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using System;
namespace Ryujinx.HLE.Gpu.Texture
{
static class TextureWriter
{
public static void Write(
IAMemory Memory,
TextureInfo Texture,
byte[] Data,
int Width,
int Height)
{
switch (Texture.Format)
{
case GalTextureFormat.A8B8G8R8: Write4Bpp(Memory, Texture, Data, Width, Height); break;
default: throw new NotImplementedException(Texture.Format.ToString());
}
}
private unsafe static void Write4Bpp(
IAMemory Memory,
TextureInfo Texture,
byte[] Data,
int Width,
int Height)
{
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4);
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
Memory,
Texture.Position);
fixed (byte* BuffPtr = Data)
{
long InOffs = 0;
for (int Y = 0; Y < Height; Y++)
for (int X = 0; X < Width; X++)
{
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
int Pixel = *(int*)(BuffPtr + InOffs);
CpuMem.WriteInt32Unchecked(Position + Offset, Pixel);
InOffs += 4;
}
}
}
}
}