From 60f2198a1e8e61fe1cfb8da30a6afcd86a672a85 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Thu, 19 Jul 2018 02:30:21 -0300
Subject: [PATCH] Support deswizzle of sparse tiled textures and some frame
 buffer fixes (#275)

* Attempt to support deswizzle of sparse tiled textures

* Use correct frame buffer and viewport sizes, started to clean up the copy engine

* Correct texture width alignment

* Use Scale/Translate registers to calculate viewport rect

* Allow texture copy between frame buffers
---
 Ryujinx.Graphics/Gal/IGalFrameBuffer.cs       |  19 +++
 Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs |  82 +++++++++--
 Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs      | 130 ++++++++++++------
 Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs      |  26 +++-
 Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs   |  14 +-
 Ryujinx.HLE/Gpu/Texture/TextureFactory.cs     |   5 +-
 Ryujinx.HLE/Gpu/Texture/TextureHelper.cs      |   8 +-
 Ryujinx.HLE/Gpu/Texture/TextureInfo.cs        |  19 ++-
 Ryujinx.HLE/Gpu/Texture/TextureReader.cs      |  18 +--
 Ryujinx.HLE/Gpu/Texture/TextureWriter.cs      |  28 +---
 Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs    |   4 +-
 11 files changed, 237 insertions(+), 116 deletions(-)

diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs
index eaae0a492..1f62bdb37 100644
--- a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs
+++ b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs
@@ -22,6 +22,25 @@ namespace Ryujinx.Graphics.Gal
 
         void Render();
 
+        void Copy(
+            long SrcKey,
+            long DstKey,
+            int  SrcX0,
+            int  SrcY0,
+            int  SrcX1,
+            int  SrcY1,
+            int  DstX0,
+            int  DstY0,
+            int  DstX1,
+            int  DstY1);
+
         void GetBufferData(long Key, Action<byte[]> Callback);
+
+        void SetBufferData(
+            long             Key,
+            int              Width,
+            int              Height,
+            GalTextureFormat Format,
+            byte[]           Buffer);
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs
index 305fa37d8..cd52762c7 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs
@@ -78,11 +78,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         public void Create(long Key, int Width, int Height)
         {
-            //TODO: We should either use the original frame buffer size,
-            //or just remove the Width/Height arguments.
-            Width  = Window.Width;
-            Height = Window.Height;
-
             if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
             {
                 if (Fb.Width  != Width ||
@@ -125,8 +120,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
             GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
 
-            GL.Viewport(0, 0, Width, Height);
-
             Fbs.Add(Key, Fb);
         }
 
@@ -230,7 +223,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
         {
             Viewport = new Rect(X, Y, Width, Height);
 
-            //TODO
+            SetViewport(Viewport);
+        }
+
+        private void SetViewport(Rect Viewport)
+        {
+            GL.Viewport(
+                Viewport.X,
+                Viewport.Y,
+                Viewport.Width,
+                Viewport.Height);
         }
 
         public void Render()
@@ -300,10 +302,38 @@ namespace Ryujinx.Graphics.Gal.OpenGL
                     GL.Enable(EnableCap.Blend);
                 }
 
-                //GL.Viewport(0, 0, 1280, 720);
+                SetViewport(Viewport);
             }
         }
 
+        public void Copy(
+            long SrcKey,
+            long DstKey,
+            int  SrcX0,
+            int  SrcY0,
+            int  SrcX1,
+            int  SrcY1,
+            int  DstX0,
+            int  DstY0,
+            int  DstX1,
+            int  DstY1)
+        {
+            if (Fbs.TryGetValue(SrcKey, out FrameBuffer SrcFb) &&
+                Fbs.TryGetValue(DstKey, out FrameBuffer DstFb))
+            {
+                GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb.Handle);
+                GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb.Handle);
+
+                GL.Clear(ClearBufferMask.ColorBufferBit);
+
+                GL.BlitFramebuffer(
+                    SrcX0, SrcY0, SrcX1, SrcY1,
+                    DstX0, DstY0, DstX1, DstY1,
+                    ClearBufferMask.ColorBufferBit,
+                    BlitFramebufferFilter.Linear);
+            }
+}
+
         public void GetBufferData(long Key, Action<byte[]> Callback)
         {
             if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
@@ -329,13 +359,35 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             }
         }
 
-        private void SetViewport(Rect Viewport)
+        public void SetBufferData(
+            long             Key,
+            int              Width,
+            int              Height,
+            GalTextureFormat Format,
+            byte[]           Buffer)
         {
-            GL.Viewport(
-                Viewport.X,
-                Viewport.Y,
-                Viewport.Width,
-                Viewport.Height);
+            if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
+            {
+                GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
+
+                const int Level  = 0;
+                const int Border = 0;
+
+                const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
+
+                (PixelFormat GlFormat, PixelType Type) = OGLEnumConverter.GetTextureFormat(Format);
+
+                GL.TexImage2D(
+                    TextureTarget.Texture2D,
+                    Level,
+                    InternalFmt,
+                    Width,
+                    Height,
+                    Border,
+                    GlFormat,
+                    Type,
+                    Buffer);
+            }
         }
 
         private void EnsureInitialized()
diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs
index f150b3f5e..d2c5f1262 100644
--- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs
+++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Graphics.Gal;
 using Ryujinx.HLE.Gpu.Memory;
 using Ryujinx.HLE.Gpu.Texture;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.Gpu.Engines
@@ -64,6 +65,8 @@ namespace Ryujinx.HLE.Gpu.Engines
             bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
             int  SrcWidth  = ReadRegister(NvGpuEngine2dReg.SrcWidth);
             int  SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
+            int  SrcPitch  = ReadRegister(NvGpuEngine2dReg.SrcPitch);
+            int  SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
 
             bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
             int  DstWidth  = ReadRegister(NvGpuEngine2dReg.DstWidth);
@@ -71,75 +74,114 @@ namespace Ryujinx.HLE.Gpu.Engines
             int  DstPitch  = ReadRegister(NvGpuEngine2dReg.DstPitch);
             int  DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
 
+            TextureSwizzle SrcSwizzle = SrcLinear
+                ? TextureSwizzle.Pitch
+                : TextureSwizzle.BlockLinear;
+
             TextureSwizzle DstSwizzle = DstLinear
                 ? TextureSwizzle.Pitch
                 : TextureSwizzle.BlockLinear;
 
+            int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
             int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
 
-            long Key = Vmm.GetPhysicalAddress(MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress));
-
             long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
             long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
 
-            bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Key);
+            long SrcKey = Vmm.GetPhysicalAddress(SrcAddress);
+            long DstKey = Vmm.GetPhysicalAddress(DstAddress);
 
-            if (IsFbTexture && DstLinear)
+            bool IsSrcFb = Gpu.Engine3d.IsFrameBufferPosition(SrcKey);
+            bool IsDstFb = Gpu.Engine3d.IsFrameBufferPosition(DstKey);
+
+            TextureInfo SrcTexture()
             {
-                DstSwizzle = TextureSwizzle.BlockLinear;
+                return new TextureInfo(
+                    SrcAddress,
+                    SrcWidth,
+                    SrcHeight,
+                    SrcPitch,
+                    SrcBlockHeight, 1,
+                    SrcSwizzle,
+                    GalTextureFormat.A8B8G8R8);
             }
 
-            TextureInfo DstTexture = new TextureInfo(
-                DstAddress,
-                DstWidth,
-                DstHeight,
-                DstBlockHeight,
-                DstBlockHeight,
-                DstSwizzle,
-                GalTextureFormat.A8B8G8R8);
-
-            if (IsFbTexture)
+            TextureInfo DstTexture()
             {
-                //TODO: Change this when the correct frame buffer resolution is used.
-                //Currently, the frame buffer size is hardcoded to 1280x720.
-                SrcWidth  = 1280;
-                SrcHeight = 720;
+                return new TextureInfo(
+                    DstAddress,
+                    DstWidth,
+                    DstHeight,
+                    DstPitch,
+                    DstBlockHeight, 1,
+                    DstSwizzle,
+                    GalTextureFormat.A8B8G8R8);
+            }
 
-                Gpu.Renderer.FrameBuffer.GetBufferData(Key, (byte[] Buffer) =>
+            //TODO: fb -> fb copies, tex -> fb copies, formats other than RGBA8,
+            //make it throw for unimpl stuff (like the copy mode)...
+            if (IsSrcFb && IsDstFb)
+            {
+                //Frame Buffer -> Frame Buffer copy.
+                Gpu.Renderer.FrameBuffer.Copy(
+                    SrcKey,
+                    DstKey,
+                    0,
+                    0,
+                    SrcWidth,
+                    SrcHeight,
+                    0,
+                    0,
+                    DstWidth,
+                    DstHeight);
+            }
+            if (IsSrcFb)
+            {
+                //Frame Buffer -> Texture copy.
+                Gpu.Renderer.FrameBuffer.GetBufferData(SrcKey, (byte[] Buffer) =>
                 {
-                    CopyTexture(
-                        Vmm,
-                        DstTexture,
-                        Buffer,
-                        SrcWidth,
-                        SrcHeight);
+                    TextureInfo Src = SrcTexture();
+                    TextureInfo Dst = DstTexture();
+
+                    if (Src.Width  != Dst.Width ||
+                        Src.Height != Dst.Height)
+                    {
+                        throw new NotImplementedException("Texture resizing is not supported");
+                    }
+
+                    TextureWriter.Write(Vmm, Dst, Buffer);
                 });
             }
+            else if (IsDstFb)
+            {
+                //Texture -> Frame Buffer copy.
+                const GalTextureFormat Format = GalTextureFormat.A8B8G8R8;
+
+                byte[] Buffer = TextureReader.Read(Vmm, SrcTexture());
+
+                Gpu.Renderer.FrameBuffer.SetBufferData(
+                    DstKey,
+                    DstWidth,
+                    DstHeight,
+                    Format,
+                    Buffer);
+            }
             else
             {
-                long Size = SrcWidth * SrcHeight * 4;
+                //Texture -> Texture copy.
+                TextureInfo Src = SrcTexture();
+                TextureInfo Dst = DstTexture();
 
-                byte[] Buffer = Vmm.ReadBytes(SrcAddress, Size);
+                if (Src.Width  != Dst.Width ||
+                    Src.Height != Dst.Height)
+                {
+                    throw new NotImplementedException("Texture resizing is not supported");
+                }
 
-                CopyTexture(
-                    Vmm,
-                    DstTexture,
-                    Buffer,
-                    SrcWidth,
-                    SrcHeight);
+                TextureWriter.Write(Vmm, Dst, TextureReader.Read(Vmm, Src));
             }
         }
 
-        private void CopyTexture(
-            NvGpuVmm    Vmm,
-            TextureInfo Texture,
-            byte[]      Buffer,
-            int         Width,
-            int         Height)
-        {
-            TextureWriter.Write(Vmm, Texture, Buffer, Width, Height);
-        }
-
         private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg)
         {
             return
diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs
index 5c474ab0b..dce25a5e9 100644
--- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs
+++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs
@@ -132,10 +132,22 @@ namespace Ryujinx.HLE.Gpu.Engines
             int Width  = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth  + FbIndex * 0x10);
             int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
 
-            //Note: Using the Width/Height results seems to give incorrect results.
-            //Maybe the size of all frame buffers is hardcoded to screen size? This seems unlikely.
-            Gpu.Renderer.FrameBuffer.Create(Key, 1280, 720);
+            float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 4);
+            float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 4);
+
+            float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 4);
+            float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 4);
+
+            int VpX = (int)MathF.Max(0, TX - MathF.Abs(SX));
+            int VpY = (int)MathF.Max(0, TY - MathF.Abs(SY));
+
+            int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
+            int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
+
+            Gpu.Renderer.FrameBuffer.Create(Key, Width, Height);
             Gpu.Renderer.FrameBuffer.Bind(Key);
+
+            Gpu.Renderer.FrameBuffer.SetViewport(VpX, VpY, VpW, VpH);
         }
 
         private long[] UploadShaders(NvGpuVmm Vmm)
@@ -195,8 +207,8 @@ namespace Ryujinx.HLE.Gpu.Engines
                 Gpu.Renderer.Shader.Bind(Key);
             }
 
-            float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportScaleX);
-            float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportScaleY);
+            float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
+            float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
 
             Gpu.Renderer.Shader.SetFlip(SignX, SignY);
 
@@ -220,8 +232,8 @@ namespace Ryujinx.HLE.Gpu.Engines
 
         private void SetFrontFace()
         {
-            float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportScaleX);
-            float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportScaleY);
+            float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
+            float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
 
             GalFrontFace FrontFace = (GalFrontFace)ReadRegister(NvGpuEngine3dReg.FrontFace);
 
diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs
index 3de2885ef..e7dabe44a 100644
--- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs
+++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs
@@ -6,12 +6,14 @@ namespace Ryujinx.HLE.Gpu.Engines
         FrameBufferNWidth    = 0x202,
         FrameBufferNHeight   = 0x203,
         FrameBufferNFormat   = 0x204,
-        ViewportScaleX       = 0x280,
-        ViewportScaleY       = 0x281,
-        ViewportScaleZ       = 0x282,
-        ViewportTranslateX   = 0x283,
-        ViewportTranslateY   = 0x284,
-        ViewportTranslateZ   = 0x285,
+        ViewportNScaleX      = 0x280,
+        ViewportNScaleY      = 0x281,
+        ViewportNScaleZ      = 0x282,
+        ViewportNTranslateX  = 0x283,
+        ViewportNTranslateY  = 0x284,
+        ViewportNTranslateZ  = 0x285,
+        ViewportNHoriz       = 0x300,
+        ViewportNVert        = 0x301,
         VertexArrayFirst     = 0x35d,
         VertexArrayCount     = 0x35e,
         ClearDepth           = 0x364,
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs
index 9df0b6000..4db0b6f10 100644
--- a/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs
+++ b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs
@@ -55,9 +55,11 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             int Pitch = (Tic[3] & 0xffff) << 5;
 
-            int BlockHeightLog2 = (Tic[3] >> 3) & 7;
+            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;
@@ -68,6 +70,7 @@ namespace Ryujinx.HLE.Gpu.Texture
                 Height,
                 Pitch,
                 BlockHeight,
+                TileWidth,
                 Swizzle,
                 Format);
 
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs
index de26c397d..ecf2b6bf5 100644
--- a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs
+++ b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs
@@ -7,8 +7,14 @@ namespace Ryujinx.HLE.Gpu.Texture
 {
     static class TextureHelper
     {
-        public static ISwizzle GetSwizzle(TextureInfo Texture, int Width, int Bpp)
+        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:
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs b/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs
index 31784bbc5..2a98ce00f 100644
--- a/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs
+++ b/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs
@@ -11,6 +11,7 @@ namespace Ryujinx.HLE.Gpu.Texture
         public int Pitch  { get; private set; }
 
         public int BlockHeight { get; private set; }
+        public int TileWidth   { get; private set; }
 
         public TextureSwizzle Swizzle { get; private set; }
 
@@ -29,6 +30,8 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             BlockHeight = 16;
 
+            TileWidth = 1;
+
             Swizzle = TextureSwizzle.BlockLinear;
 
             Format = GalTextureFormat.A8B8G8R8;
@@ -40,16 +43,18 @@ namespace Ryujinx.HLE.Gpu.Texture
             int              Height,
             int              Pitch,
             int              BlockHeight,
+            int              TileWidth,
             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;
+            this.Position     = Position;
+            this.Width        = Width;
+            this.Height       = Height;
+            this.Pitch        = Pitch;
+            this.BlockHeight  = BlockHeight;
+            this.TileWidth    = TileWidth;
+            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
index 26129877a..350ab825f 100644
--- a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs
+++ b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs
@@ -56,7 +56,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 1);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 1);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -89,7 +89,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 2];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -127,7 +127,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 2];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -164,7 +164,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 2];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -197,7 +197,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 4];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -230,7 +230,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 8];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 8);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 8);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -263,7 +263,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 16];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 16);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 16);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -298,7 +298,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 8];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 8);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 4, 8);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -331,7 +331,7 @@ namespace Ryujinx.HLE.Gpu.Texture
 
             byte[] Output = new byte[Width * Height * 16];
 
-            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 16);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, BlockWidth, 16);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
diff --git a/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs
index b64302a5a..a87d4545b 100644
--- a/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs
+++ b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs
@@ -6,29 +6,9 @@ namespace Ryujinx.HLE.Gpu.Texture
 {
     static class TextureWriter
     {
-        public static void Write(
-            IAMemory    Memory,
-            TextureInfo Texture,
-            byte[]      Data,
-            int         Width,
-            int         Height)
+        public unsafe static void Write(IAMemory Memory, TextureInfo Texture, byte[] Data)
         {
-            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);
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
 
             (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
                 Memory,
@@ -38,8 +18,8 @@ namespace Ryujinx.HLE.Gpu.Texture
             {
                 long InOffs = 0;
 
-                for (int Y = 0; Y < Height; Y++)
-                for (int X = 0; X < Width;  X++)
+                for (int Y = 0; Y < Texture.Height; Y++)
+                for (int X = 0; X < Texture.Width;  X++)
                 {
                     long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
 
diff --git a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs
index a3ed3ab51..5307127be 100644
--- a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs
+++ b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs
@@ -279,8 +279,8 @@ namespace Ryujinx.HLE.OsHle.Services.Android
 
         private void SendFrameBuffer(ServiceCtx Context, int Slot)
         {
-            int FbWidth  = 1280;
-            int FbHeight = 720;
+            int FbWidth  = BufferQueue[Slot].Data.Width;
+            int FbHeight = BufferQueue[Slot].Data.Height;
 
             int NvMapHandle  = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c);
             int BufferOffset = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x50);