aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/Gpu/Texture
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-06-23 21:39:25 -0300
committerGitHub <noreply@github.com>2018-06-23 21:39:25 -0300
commite7559f128f99058774a8d53aa45213b51c085e76 (patch)
tree42d367bfb4248b19cf2ce55439d24437bbbd2ccb /Ryujinx.HLE/Gpu/Texture
parent69697957e6406235d512a89d9144c160fe7efbfd (diff)
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
Diffstat (limited to 'Ryujinx.HLE/Gpu/Texture')
-rw-r--r--Ryujinx.HLE/Gpu/Texture/BlockLinearSwizzle.cs59
-rw-r--r--Ryujinx.HLE/Gpu/Texture/ISwizzle.cs7
-rw-r--r--Ryujinx.HLE/Gpu/Texture/LinearSwizzle.cs19
-rw-r--r--Ryujinx.HLE/Gpu/Texture/TextureFactory.cs117
-rw-r--r--Ryujinx.HLE/Gpu/Texture/TextureHelper.cs78
-rw-r--r--Ryujinx.HLE/Gpu/Texture/TextureInfo.cs55
-rw-r--r--Ryujinx.HLE/Gpu/Texture/TextureReader.cs344
-rw-r--r--Ryujinx.HLE/Gpu/Texture/TextureSwizzle.cs11
-rw-r--r--Ryujinx.HLE/Gpu/Texture/TextureWriter.cs55
9 files changed, 745 insertions, 0 deletions
diff --git a/Ryujinx.HLE/Gpu/Texture/BlockLinearSwizzle.cs b/Ryujinx.HLE/Gpu/Texture/BlockLinearSwizzle.cs
new file mode 100644
index 00000000..e66d7613
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/BlockLinearSwizzle.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/Gpu/Texture/ISwizzle.cs b/Ryujinx.HLE/Gpu/Texture/ISwizzle.cs
new file mode 100644
index 00000000..222aab16
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/ISwizzle.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.HLE.Gpu.Texture
+{
+ interface ISwizzle
+ {
+ int GetSwizzleOffset(int X, int Y);
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/Gpu/Texture/LinearSwizzle.cs b/Ryujinx.HLE/Gpu/Texture/LinearSwizzle.cs
new file mode 100644
index 00000000..720f7832
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/LinearSwizzle.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs
new file mode 100644
index 00000000..9df0b600
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs
new file mode 100644
index 00000000..ac8f75c5
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs
@@ -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);
+ }
+ }
+}
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs b/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs
new file mode 100644
index 00000000..31784bbc
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs
new file mode 100644
index 00000000..48bf1a90
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs
@@ -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;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureSwizzle.cs b/Ryujinx.HLE/Gpu/Texture/TextureSwizzle.cs
new file mode 100644
index 00000000..076df97a
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/TextureSwizzle.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.HLE.Gpu.Texture
+{
+ enum TextureSwizzle
+ {
+ _1dBuffer = 0,
+ PitchColorKey = 1,
+ Pitch = 2,
+ BlockLinear = 3,
+ BlockLinearColorKey = 4
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs
new file mode 100644
index 00000000..b64302a5
--- /dev/null
+++ b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs
@@ -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;
+ }
+ }
+ }
+ }
+}