From d4187aaa9d7194aa26d04aee838edbc3a38f1862 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 18 Sep 2018 01:30:35 -0300 Subject: [PATCH] Allow "reinterpretation" of framebuffer/zeta formats (#418) * (Re)Implement format reinterpretation, other changes * Implement writeback to guest memory, some refactoring * More refactoring, implement reinterpretation the old way again * Clean up * Some fixes on M2MF (old Dma engine), added partial support for P2MF, fix conditional ssy, add Z24S8 zeta format, other fixes * nit: Formatting * Address PR feedback --- ChocolArm64/Memory/AMemory.cs | 29 ++ Ryujinx.Graphics/Gal/GalImage.cs | 48 ++- Ryujinx.Graphics/Gal/GalMemoryLayout.cs | 8 + Ryujinx.Graphics/Gal/GalPipelineState.cs | 2 + ...ameBufferFormat.cs => GalSurfaceFormat.cs} | 0 Ryujinx.Graphics/Gal/GalTextureFormat.cs | 1 + Ryujinx.Graphics/Gal/IGalRasterizer.cs | 2 +- Ryujinx.Graphics/Gal/IGalRenderTarget.cs | 18 +- Ryujinx.Graphics/Gal/IGalTexture.cs | 8 +- Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs | 147 +------ .../Gal/OpenGL/OGLCachedResource.cs | 6 +- .../Gal/OpenGL/OGLEnumConverter.cs | 4 +- Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs | 11 + Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs | 6 +- .../Gal/OpenGL/OGLRenderTarget.cs | 358 +++++++--------- Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs | 163 ++++--- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 1 + .../Gal/Shader/ShaderDecodeAlu.cs | 128 +++--- .../Gal/Shader/ShaderDecodeFlow.cs | 24 +- .../{ShaderDecode.cs => ShaderDecodeFunc.cs} | 2 +- .../Gal/Shader/ShaderDecodeHelper.cs | 2 - .../Gal/Shader/ShaderDecodeMem.cs | 16 +- .../Gal/Shader/ShaderDecodeMove.cs | 42 +- .../Gal/Shader/ShaderDecodeSpecial.cs | 6 +- Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs | 44 +- Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs | 6 +- Ryujinx.Graphics/GpuResourceManager.cs | 122 ++++++ Ryujinx.Graphics/Memory/NvGpuVmmCache.cs | 317 ++------------ Ryujinx.Graphics/NvGpu.cs | 19 +- .../{Memory => }/NvGpuBufferType.cs | 2 +- Ryujinx.Graphics/NvGpuEngine.cs | 4 +- Ryujinx.Graphics/NvGpuEngine2d.cs | 125 ++---- Ryujinx.Graphics/NvGpuEngine3d.cs | 125 +++--- Ryujinx.Graphics/NvGpuEngine3dReg.cs | 2 + Ryujinx.Graphics/NvGpuEngineDma.cs | 143 ------- Ryujinx.Graphics/NvGpuEngineM2mf.cs | 192 +++++++++ ...uEngineDmaReg.cs => NvGpuEngineM2mfReg.cs} | 5 +- Ryujinx.Graphics/NvGpuEngineP2mf.cs | 102 +++++ Ryujinx.Graphics/NvGpuEngineP2mfReg.cs | 17 + Ryujinx.Graphics/NvGpuFifo.cs | 65 +-- Ryujinx.Graphics/Texture/ImageUtils.cs | 362 ++++++++-------- Ryujinx.Graphics/Texture/TextureFactory.cs | 52 +-- Ryujinx.Graphics/Texture/TextureHelper.cs | 29 +- Ryujinx.Graphics/Texture/TextureInfo.cs | 60 --- Ryujinx.Graphics/Texture/TextureReader.cs | 398 ------------------ Ryujinx.Graphics/Texture/TextureWriter.cs | 35 -- Ryujinx.Graphics/ValueRange.cs | 17 + Ryujinx.Graphics/ValueRangeSet.cs | 234 ++++++++++ Ryujinx.HLE/HOS/Kernel/SvcSystem.cs | 3 +- Ryujinx.HLE/HOS/Services/Acc/IProfile.cs | 1 - .../HOS/Services/Vi/IHOSBinderDriver.cs | 12 +- Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs | 48 +-- 52 files changed, 1594 insertions(+), 1979 deletions(-) create mode 100644 Ryujinx.Graphics/Gal/GalMemoryLayout.cs rename Ryujinx.Graphics/Gal/{GalFrameBufferFormat.cs => GalSurfaceFormat.cs} (100%) rename Ryujinx.Graphics/Gal/Shader/{ShaderDecode.cs => ShaderDecodeFunc.cs} (83%) create mode 100644 Ryujinx.Graphics/GpuResourceManager.cs rename Ryujinx.Graphics/{Memory => }/NvGpuBufferType.cs (79%) delete mode 100644 Ryujinx.Graphics/NvGpuEngineDma.cs create mode 100644 Ryujinx.Graphics/NvGpuEngineM2mf.cs rename Ryujinx.Graphics/{NvGpuEngineDmaReg.cs => NvGpuEngineM2mfReg.cs} (81%) create mode 100644 Ryujinx.Graphics/NvGpuEngineP2mf.cs create mode 100644 Ryujinx.Graphics/NvGpuEngineP2mfReg.cs delete mode 100644 Ryujinx.Graphics/Texture/TextureInfo.cs delete mode 100644 Ryujinx.Graphics/Texture/TextureReader.cs delete mode 100644 Ryujinx.Graphics/Texture/TextureWriter.cs create mode 100644 Ryujinx.Graphics/ValueRange.cs create mode 100644 Ryujinx.Graphics/ValueRangeSet.cs diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index 566e6b54..806a0b86 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -287,6 +287,14 @@ namespace ChocolArm64.Memory return Data; } + public void ReadBytes(long Position, byte[] Data, int StartIndex, int Size) + { + //Note: This will be moved later. + EnsureRangeIsValid(Position, (uint)Size); + + Marshal.Copy((IntPtr)Translate(Position), Data, StartIndex, Size); + } + public void WriteSByte(long Position, sbyte Value) { WriteByte(Position, (byte)Value); @@ -403,6 +411,27 @@ namespace ChocolArm64.Memory Marshal.Copy(Data, 0, (IntPtr)TranslateWrite(Position), Data.Length); } + public void WriteBytes(long Position, byte[] Data, int StartIndex, int Size) + { + //Note: This will be moved later. + //Using Translate instead of TranslateWrite is on purpose. + EnsureRangeIsValid(Position, (uint)Size); + + Marshal.Copy(Data, StartIndex, (IntPtr)Translate(Position), Size); + } + + public void CopyBytes(long Src, long Dst, long Size) + { + //Note: This will be moved later. + EnsureRangeIsValid(Src, Size); + EnsureRangeIsValid(Dst, Size); + + byte* SrcPtr = Translate(Src); + byte* DstPtr = TranslateWrite(Dst); + + Buffer.MemoryCopy(SrcPtr, DstPtr, Size, Size); + } + public void Map(long VA, long PA, long Size) { SetPTEntries(VA, RamPtr + PA, Size); diff --git a/Ryujinx.Graphics/Gal/GalImage.cs b/Ryujinx.Graphics/Gal/GalImage.cs index dc6f02e0..92f43cc9 100644 --- a/Ryujinx.Graphics/Gal/GalImage.cs +++ b/Ryujinx.Graphics/Gal/GalImage.cs @@ -1,12 +1,17 @@ +using Ryujinx.Graphics.Texture; + namespace Ryujinx.Graphics.Gal { public struct GalImage { public int Width; public int Height; + public int TileWidth; + public int GobBlockHeight; + public int Pitch; - public GalImageFormat Format; - + public GalImageFormat Format; + public GalMemoryLayout Layout; public GalTextureSource XSource; public GalTextureSource YSource; public GalTextureSource ZSource; @@ -15,19 +20,44 @@ namespace Ryujinx.Graphics.Gal public GalImage( int Width, int Height, + int TileWidth, + int GobBlockHeight, + GalMemoryLayout Layout, GalImageFormat Format, GalTextureSource XSource = GalTextureSource.Red, GalTextureSource YSource = GalTextureSource.Green, GalTextureSource ZSource = GalTextureSource.Blue, GalTextureSource WSource = GalTextureSource.Alpha) { - this.Width = Width; - this.Height = Height; - this.Format = Format; - this.XSource = XSource; - this.YSource = YSource; - this.ZSource = ZSource; - this.WSource = WSource; + this.Width = Width; + this.Height = Height; + this.TileWidth = TileWidth; + this.GobBlockHeight = GobBlockHeight; + this.Layout = Layout; + this.Format = Format; + this.XSource = XSource; + this.YSource = YSource; + this.ZSource = ZSource; + this.WSource = WSource; + + Pitch = ImageUtils.GetPitch(Format, Width); + } + + public bool SizeMatches(GalImage Image) + { + if (ImageUtils.GetBytesPerPixel(Format) != + ImageUtils.GetBytesPerPixel(Image.Format)) + { + return false; + } + + if (ImageUtils.GetAlignedWidth(this) != + ImageUtils.GetAlignedWidth(Image)) + { + return false; + } + + return Height == Image.Height; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalMemoryLayout.cs b/Ryujinx.Graphics/Gal/GalMemoryLayout.cs new file mode 100644 index 00000000..73fabf8c --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalMemoryLayout.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalMemoryLayout + { + BlockLinear = 0, + Pitch = 1 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalPipelineState.cs b/Ryujinx.Graphics/Gal/GalPipelineState.cs index 7c669514..6ee6c93e 100644 --- a/Ryujinx.Graphics/Gal/GalPipelineState.cs +++ b/Ryujinx.Graphics/Gal/GalPipelineState.cs @@ -21,6 +21,8 @@ public GalVertexBinding[] VertexBindings; + public bool FramebufferSrgb; + public float FlipX; public float FlipY; diff --git a/Ryujinx.Graphics/Gal/GalFrameBufferFormat.cs b/Ryujinx.Graphics/Gal/GalSurfaceFormat.cs similarity index 100% rename from Ryujinx.Graphics/Gal/GalFrameBufferFormat.cs rename to Ryujinx.Graphics/Gal/GalSurfaceFormat.cs diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs index e8658595..5ad76943 100644 --- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs +++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs @@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.Gal R32G32 = 0x4, A8B8G8R8 = 0x8, A2B10G10R10 = 0x9, + R16G16 = 0xc, R32 = 0xf, BC6H_SF16 = 0x10, BC6H_UF16 = 0x11, diff --git a/Ryujinx.Graphics/Gal/IGalRasterizer.cs b/Ryujinx.Graphics/Gal/IGalRasterizer.cs index a20b6f53..1ee630e2 100644 --- a/Ryujinx.Graphics/Gal/IGalRasterizer.cs +++ b/Ryujinx.Graphics/Gal/IGalRasterizer.cs @@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gal void SetIndexArray(int Size, GalIndexFormat Format); - void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType); + void DrawArrays(int First, int Count, GalPrimitiveType PrimType); void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType); } diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs index c44434ef..6c9166f2 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs @@ -1,23 +1,17 @@ -using System; - namespace Ryujinx.Graphics.Gal { public interface IGalRenderTarget { - void BindColor(long Key, int Attachment); + void BindColor(long Key, int Attachment, GalImage Image); void UnbindColor(int Attachment); - void BindZeta(long Key); + void BindZeta(long Key, GalImage Image); void UnbindZeta(); - void BindTexture(long Key, int Index); - void Set(long Key); - void Set(byte[] Data, int Width, int Height); - void SetMap(int[] Map); void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom); @@ -40,12 +34,8 @@ namespace Ryujinx.Graphics.Gal int DstX1, int DstY1); - void GetBufferData(long Key, Action Callback); + void Reinterpret(long Key, GalImage NewImage); - void SetBufferData( - long Key, - int Width, - int Height, - byte[] Buffer); + byte[] GetData(long Key); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs index 292f59ef..aeecdf1a 100644 --- a/Ryujinx.Graphics/Gal/IGalTexture.cs +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -5,13 +5,13 @@ namespace Ryujinx.Graphics.Gal void LockCache(); void UnlockCache(); + void Create(long Key, int Size, GalImage Image); + void Create(long Key, byte[] Data, GalImage Image); - void CreateFb(long Key, long Size, GalImage Image); + bool TryGetImage(long Key, out GalImage Image); - bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image); - - void Bind(long Key, int Index); + void Bind(long Key, int Index, GalImage Image); void SetSampler(GalTextureSampler Sampler); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs index dda82538..8db0b8a8 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs @@ -1,14 +1,9 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.Texture; -using System; +using Ryujinx.Graphics.Texture; namespace Ryujinx.Graphics.Gal.OpenGL { class ImageHandler { - private static int CopyBuffer = 0; - private static int CopyBufferSize = 0; - public GalImage Image { get; private set; } public int Width => Image.Width; @@ -16,144 +11,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL public GalImageFormat Format => Image.Format; - public PixelInternalFormat InternalFormat { get; private set; } - public PixelFormat PixelFormat { get; private set; } - public PixelType PixelType { get; private set; } - public int Handle { get; private set; } - private bool Initialized; - - public ImageHandler() - { - Handle = GL.GenTexture(); - } - - public ImageHandler(int Handle, GalImage Image) - { - this.Handle = Handle; - - this.Image = Image; - } - - public void EnsureSetup(GalImage NewImage) - { - if (Width == NewImage.Width && - Height == NewImage.Height && - Format == NewImage.Format && - Initialized) - { - return; - } - - PixelInternalFormat InternalFmt; - PixelFormat PixelFormat; - PixelType PixelType; - - if (ImageUtils.IsCompressed(NewImage.Format)) - { - InternalFmt = (PixelInternalFormat)OGLEnumConverter.GetCompressedImageFormat(NewImage.Format); - - PixelFormat = default(PixelFormat); - PixelType = default(PixelType); - } - else - { - (InternalFmt, PixelFormat, PixelType) = OGLEnumConverter.GetImageFormat(NewImage.Format); - } - - GL.BindTexture(TextureTarget.Texture2D, Handle); - - if (Initialized) - { - if (CopyBuffer == 0) - { - CopyBuffer = GL.GenBuffer(); - } - - int CurrentSize = Math.Max(ImageUtils.GetSize(NewImage), - ImageUtils.GetSize(Image)); - - GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer); - GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer); - - if (CopyBufferSize < CurrentSize) - { - CopyBufferSize = CurrentSize; - - GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy); - } - - if (ImageUtils.IsCompressed(Image.Format)) - { - GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, IntPtr.Zero); - } - else - { - GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero); - } - - GL.DeleteTexture(Handle); - - Handle = GL.GenTexture(); - - GL.BindTexture(TextureTarget.Texture2D, Handle); - } - - const int MinFilter = (int)TextureMinFilter.Linear; - const int MagFilter = (int)TextureMagFilter.Linear; - - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter); - - const int Level = 0; - const int Border = 0; - - if (ImageUtils.IsCompressed(NewImage.Format)) - { - Console.WriteLine("Hit"); - - GL.CompressedTexImage2D( - TextureTarget.Texture2D, - Level, - (InternalFormat)InternalFmt, - NewImage.Width, - NewImage.Height, - Border, - ImageUtils.GetSize(NewImage), - IntPtr.Zero); - } - else - { - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - InternalFmt, - NewImage.Width, - NewImage.Height, - Border, - PixelFormat, - PixelType, - IntPtr.Zero); - } - - if (Initialized) - { - GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); - GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); - } - - Image = NewImage; - - this.InternalFormat = InternalFmt; - this.PixelFormat = PixelFormat; - this.PixelType = PixelType; - - Initialized = true; - } - public bool HasColor => ImageUtils.HasColor(Image.Format); public bool HasDepth => ImageUtils.HasDepth(Image.Format); public bool HasStencil => ImageUtils.HasStencil(Image.Format); + + public ImageHandler(int Handle, GalImage Image) + { + this.Handle = Handle; + this.Image = Image; + } } } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs index 01ebf982..839915ea 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs @@ -22,9 +22,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL public CacheBucket(T Value, long DataSize, LinkedListNode Node) { - this.Value = Value; - this.DataSize = DataSize; - this.Node = Node; + this.Value = Value; + this.DataSize = DataSize; + this.Node = Node; Timestamp = Environment.TickCount; } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index 876c7b99..fac3875e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -149,8 +149,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float); case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int); case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt); - case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551); - case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565); + case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed); + case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed); case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat); case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short); case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs index 051b1050..cf856a15 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs @@ -126,6 +126,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL BindVertexLayout(New); + if (New.FramebufferSrgb != Old.FramebufferSrgb) + { + Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb); + } + if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance) { Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance); @@ -337,6 +342,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL foreach (GalVertexAttrib Attrib in Binding.Attribs) { + //Skip uninitialized attributes. + if (Attrib.Size == 0) + { + continue; + } + GL.EnableVertexAttribArray(Attrib.Index); GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index 45106692..ebfba63d 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -113,14 +113,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL IndexBuffer.ElemSizeLog2 = (int)Format; } - public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType) + public void DrawArrays(int First, int Count, GalPrimitiveType PrimType) { - if (PrimCount == 0) + if (Count == 0) { return; } - GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount); + GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count); } public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs index 99bfa350..7dde32d8 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs @@ -15,9 +15,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL public Rect(int X, int Y, int Width, int Height) { - this.X = X; - this.Y = Y; - this.Width = Width; + this.X = X; + this.Y = Y; + this.Width = Width; this.Height = Height; } } @@ -29,7 +29,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL private OGLTexture Texture; - private ImageHandler RawTex; private ImageHandler ReadTex; private Rect Viewport; @@ -64,13 +63,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL this.Texture = Texture; } - public void BindColor(long Key, int Attachment) + public void BindColor(long Key, int Attachment, GalImage Image) { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) + if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage)) { EnsureFrameBuffer(); - Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment); + Attach(ref ColorAttachments[Attachment], CachedImage.Handle, FramebufferAttachment.ColorAttachment0 + Attachment); } else { @@ -84,40 +83,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment); } - - public void BindZeta(long Key) + + public void BindZeta(long Key, GalImage Image) { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) + if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage)) { EnsureFrameBuffer(); - if (Tex.HasDepth && Tex.HasStencil) + if (CachedImage.HasDepth && CachedImage.HasStencil) { - if (DepthAttachment != Tex.Handle || - StencilAttachment != Tex.Handle) + if (DepthAttachment != CachedImage.Handle || + StencilAttachment != CachedImage.Handle) { GL.FramebufferTexture( FramebufferTarget.DrawFramebuffer, FramebufferAttachment.DepthStencilAttachment, - Tex.Handle, + CachedImage.Handle, 0); - DepthAttachment = Tex.Handle; - - StencilAttachment = Tex.Handle; + DepthAttachment = CachedImage.Handle; + StencilAttachment = CachedImage.Handle; } } - else if (Tex.HasDepth) + else if (CachedImage.HasDepth) { - Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment); + Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment); Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment); } - else if (Tex.HasStencil) + else if (CachedImage.HasStencil) { Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment); - Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment); + Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment); } else { @@ -130,12 +128,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } + private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment) + { + if (OldHandle != NewHandle) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FbAttachment, + NewHandle, + 0); + + OldHandle = NewHandle; + } + } + public void UnbindZeta() { EnsureFrameBuffer(); - if (DepthAttachment != 0 || - StencilAttachment != 0) + if (DepthAttachment != 0 || StencilAttachment != 0) { GL.FramebufferTexture( FramebufferTarget.DrawFramebuffer, @@ -143,44 +154,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL 0, 0); - DepthAttachment = 0; - + DepthAttachment = 0; StencilAttachment = 0; } } - public void BindTexture(long Key, int Index) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - GL.ActiveTexture(TextureUnit.Texture0 + Index); - - GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); - } - } - public void Set(long Key) { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - ReadTex = Tex; - } - } - - public void Set(byte[] Data, int Width, int Height) - { - if (RawTex == null) - { - RawTex = new ImageHandler(); - } - - RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat)); - - GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle); - - GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data); - - ReadTex = RawTex; + Texture.TryGetImageHandler(Key, out ReadTex); } public void SetMap(int[] Map) @@ -280,13 +261,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY; int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY; - if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); - - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); - GL.Viewport(0, 0, Window.Width, Window.Height); + if (SrcFb == 0) + { + SrcFb = GL.GenFramebuffer(); + } + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0); @@ -298,7 +281,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.BlitFramebuffer( SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, - ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear); + ClearBufferMask.ColorBufferBit, + BlitFramebufferFilter.Linear); EnsureFrameBuffer(); } @@ -315,110 +299,135 @@ namespace Ryujinx.Graphics.Gal.OpenGL int DstX1, int DstY1) { - if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) && - Texture.TryGetImage(DstKey, out ImageHandler DstTex)) + if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) && + Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex)) { - if (SrcTex.HasColor != DstTex.HasColor || - SrcTex.HasDepth != DstTex.HasDepth || + if (SrcTex.HasColor != DstTex.HasColor || + SrcTex.HasDepth != DstTex.HasDepth || SrcTex.HasStencil != DstTex.HasStencil) { throw new NotImplementedException(); } + if (SrcFb == 0) + { + SrcFb = GL.GenFramebuffer(); + } + + if (DstFb == 0) + { + DstFb = GL.GenFramebuffer(); + } + + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb); + + FramebufferAttachment Attachment = GetAttachment(SrcTex); + + GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0); + GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0); + + BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest; + if (SrcTex.HasColor) { - CopyTextures( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - SrcTex.Handle, - DstTex.Handle, - FramebufferAttachment.ColorAttachment0, - ClearBufferMask.ColorBufferBit, - true); - } - else if (SrcTex.HasDepth && SrcTex.HasStencil) - { - CopyTextures( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - SrcTex.Handle, - DstTex.Handle, - FramebufferAttachment.DepthStencilAttachment, - ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit, - false); - } - else if (SrcTex.HasDepth) - { - CopyTextures( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - SrcTex.Handle, - DstTex.Handle, - FramebufferAttachment.DepthAttachment, - ClearBufferMask.DepthBufferBit, - false); - } - else if (SrcTex.HasStencil) - { - CopyTextures( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - SrcTex.Handle, - DstTex.Handle, - FramebufferAttachment.StencilAttachment, - ClearBufferMask.StencilBufferBit, - false); - } - else - { - throw new InvalidOperationException(); + GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + + Filter = BlitFramebufferFilter.Linear; } + + ClearBufferMask Mask = GetClearMask(SrcTex); + + GL.Clear(Mask); + + GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter); + + EnsureFrameBuffer(); } } - public void GetBufferData(long Key, Action Callback) + public void Reinterpret(long Key, GalImage NewImage) { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) + if (!Texture.TryGetImage(Key, out GalImage OldImage)) { - byte[] Data = new byte[ImageUtils.GetSize(Tex.Image)]; + return; + } - GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); + if (NewImage.Format == OldImage.Format) + { + return; + } - GL.GetTexImage( - TextureTarget.Texture2D, - 0, - Tex.PixelFormat, - Tex.PixelType, - Data); + byte[] Data = GetData(Key); - Callback(Data); + GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width); + + Texture.Create(Key, Data, NewImage); + + GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0); + } + + public byte[] GetData(long Key) + { + if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage)) + { + return null; + } + + if (SrcFb == 0) + { + SrcFb = GL.GenFramebuffer(); + } + + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); + + FramebufferAttachment Attachment = GetAttachment(CachedImage); + + GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, CachedImage.Handle, 0); + + int Size = ImageUtils.GetSize(CachedImage.Image); + + byte[] Data = new byte[Size]; + + int Width = CachedImage.Width; + int Height = CachedImage.Height; + + (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format); + + GL.ReadPixels(0, 0, Width, Height, Format, Type, Data); + + return Data; + } + + private static FramebufferAttachment GetAttachment(ImageHandler CachedImage) + { + if (CachedImage.HasColor) + { + return FramebufferAttachment.ColorAttachment0; + } + else if (CachedImage.HasDepth && CachedImage.HasStencil) + { + return FramebufferAttachment.DepthStencilAttachment; + } + else if (CachedImage.HasDepth) + { + return FramebufferAttachment.DepthAttachment; + } + else if (CachedImage.HasStencil) + { + return FramebufferAttachment.StencilAttachment; + } + else + { + throw new InvalidOperationException(); } } - public void SetBufferData( - long Key, - int Width, - int Height, - byte[] Buffer) + private static ClearBufferMask GetClearMask(ImageHandler CachedImage) { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); - - const int Level = 0; - const int Border = 0; - - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - Tex.InternalFormat, - Width, - Height, - Border, - Tex.PixelFormat, - Tex.PixelType, - Buffer); - } + return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) | + (CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) | + (CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0); } private void EnsureFrameBuffer() @@ -430,68 +439,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); } - - private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment) - { - if (OldHandle != NewHandle) - { - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FbAttachment, - NewHandle, - 0); - - OldHandle = NewHandle; - } - } - - private void CopyTextures( - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1, - int SrcTexture, - int DstTexture, - FramebufferAttachment Attachment, - ClearBufferMask Mask, - bool Color) - { - if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); - if (DstFb == 0) DstFb = GL.GenFramebuffer(); - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb); - - GL.FramebufferTexture( - FramebufferTarget.ReadFramebuffer, - Attachment, - SrcTexture, - 0); - - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - Attachment, - DstTexture, - 0); - - if (Color) - { - GL.DrawBuffer(DrawBufferMode.ColorAttachment0); - } - - GL.Clear(Mask); - - GL.BlitFramebuffer( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - Mask, - Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest); - - EnsureFrameBuffer(); - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index 7e1c0e53..3347afbd 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -28,17 +28,65 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.DeleteTexture(CachedImage.Handle); } - public void Create(long Key, byte[] Data, GalImage Image) + public void Create(long Key, int Size, GalImage Image) { int Handle = GL.GenTexture(); - TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length); - GL.BindTexture(TextureTarget.Texture2D, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; + TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size); + + GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask; + + bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END; + + if (ImageUtils.IsCompressed(Image.Format) && !IsASTC) + { + InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format); + + GL.CompressedTexImage2D( + TextureTarget.Texture2D, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Size, + IntPtr.Zero); + } + else + { + (PixelInternalFormat InternalFmt, + PixelFormat Format, + PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); + + GL.TexImage2D( + TextureTarget.Texture2D, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Format, + Type, + IntPtr.Zero); + } + } + + public void Create(long Key, byte[] Data, GalImage Image) + { + int Handle = GL.GenTexture(); + + GL.BindTexture(TextureTarget.Texture2D, Handle); + + const int Level = 0; //TODO: Support mipmap textures. + const int Border = 0; + + TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length); + GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask; bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END; @@ -62,8 +110,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL //TODO: Use KHR_texture_compression_astc_hdr when available if (IsASTC) { - int TextureBlockWidth = GetAstcBlockWidth(Image.Format); - int TextureBlockHeight = GetAstcBlockHeight(Image.Format); + int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format); + int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format); Data = ASTCDecoder.DecodeToRGBA8888( Data, @@ -85,12 +133,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask); } - (PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); + (PixelInternalFormat InternalFmt, + PixelFormat Format, + PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); GL.TexImage2D( TextureTarget.Texture2D, Level, - InternalFormat, + InternalFmt, Image.Width, Image.Height, Border, @@ -98,31 +148,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL Type, Data); } - - int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource); - int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource); - int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource); - int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource); - - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA); } - public void CreateFb(long Key, long Size, GalImage Image) + public bool TryGetImage(long Key, out GalImage Image) { - if (!TryGetImage(Key, out ImageHandler CachedImage)) + if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) { - CachedImage = new ImageHandler(); + Image = CachedImage.Image; - TextureCache.AddOrUpdate(Key, CachedImage, Size); + return true; } - CachedImage.EnsureSetup(Image); + Image = default(GalImage); + + return false; } - public bool TryGetImage(long Key, out ImageHandler CachedImage) + public bool TryGetImageHandler(long Key, out ImageHandler CachedImage) { if (TextureCache.TryGetValue(Key, out CachedImage)) { @@ -134,76 +176,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL return false; } - private static int GetAstcBlockWidth(GalImageFormat Format) - { - switch (Format) - { - case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4; - case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5; - case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6; - case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8; - case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10; - case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12; - case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 5; - case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 6; - case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 8; - case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 10; - case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 12; - case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 8; - case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 10; - case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 10; - } - - throw new ArgumentException(nameof(Format)); - } - - private static int GetAstcBlockHeight(GalImageFormat Format) - { - switch (Format) - { - case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4; - case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5; - case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6; - case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8; - case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10; - case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12; - case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 4; - case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 5; - case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 6; - case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 8; - case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 10; - case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 5; - case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 5; - case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 6; - } - - throw new ArgumentException(nameof(Format)); - } - - public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image) - { - if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize) - { - if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) - { - Image = CachedImage.Image; - - return true; - } - } - - Image = default(GalImage); - - return false; - } - - public void Bind(long Key, int Index) + public void Bind(long Key, int Index, GalImage Image) { if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) { GL.ActiveTexture(TextureUnit.Texture0 + Index); GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle); + + int[] SwizzleRgba = new int[] + { + (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource), + (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource), + (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource), + (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource) + }; + + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, SwizzleRgba); } } diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index ac34400e..60fe91c2 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -641,6 +641,7 @@ namespace Ryujinx.Graphics.Gal.Shader default: SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";"); + break; } } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index c2ee474b..0a3c0da9 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -6,32 +6,32 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - public static void Bfe_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position) { EmitBfe(Block, OpCode, ShaderOper.CR); } - public static void Bfe_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Bfe_I(ShaderIrBlock Block, long OpCode, int Position) { EmitBfe(Block, OpCode, ShaderOper.Imm); } - public static void Bfe_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Bfe_R(ShaderIrBlock Block, long OpCode, int Position) { EmitBfe(Block, OpCode, ShaderOper.RR); } - public static void Fadd_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Fadd_C(ShaderIrBlock Block, long OpCode, int Position) { EmitFadd(Block, OpCode, ShaderOper.CR); } - public static void Fadd_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Fadd_I(ShaderIrBlock Block, long OpCode, int Position) { EmitFadd(Block, OpCode, ShaderOper.Immf); } - public static void Fadd_I32(ShaderIrBlock Block, long OpCode, long Position) + public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode OperA = OpCode.Gpr8(); ShaderIrNode OperB = OpCode.Immf32_20(); @@ -49,47 +49,47 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); } - public static void Fadd_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Fadd_R(ShaderIrBlock Block, long OpCode, int Position) { EmitFadd(Block, OpCode, ShaderOper.RR); } - public static void Ffma_CR(ShaderIrBlock Block, long OpCode, long Position) + public static void Ffma_CR(ShaderIrBlock Block, long OpCode, int Position) { EmitFfma(Block, OpCode, ShaderOper.CR); } - public static void Ffma_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Ffma_I(ShaderIrBlock Block, long OpCode, int Position) { EmitFfma(Block, OpCode, ShaderOper.Immf); } - public static void Ffma_RC(ShaderIrBlock Block, long OpCode, long Position) + public static void Ffma_RC(ShaderIrBlock Block, long OpCode, int Position) { EmitFfma(Block, OpCode, ShaderOper.RC); } - public static void Ffma_RR(ShaderIrBlock Block, long OpCode, long Position) + public static void Ffma_RR(ShaderIrBlock Block, long OpCode, int Position) { EmitFfma(Block, OpCode, ShaderOper.RR); } - public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, int Position) { EmitFmnmx(Block, OpCode, ShaderOper.CR); } - public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, int Position) { EmitFmnmx(Block, OpCode, ShaderOper.Immf); } - public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, int Position) { EmitFmnmx(Block, OpCode, ShaderOper.RR); } - public static void Fmul_I32(ShaderIrBlock Block, long OpCode, long Position) + public static void Fmul_I32(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode OperA = OpCode.Gpr8(); ShaderIrNode OperB = OpCode.Immf32_20(); @@ -99,62 +99,62 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); } - public static void Fmul_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position) { EmitFmul(Block, OpCode, ShaderOper.CR); } - public static void Fmul_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Fmul_I(ShaderIrBlock Block, long OpCode, int Position) { EmitFmul(Block, OpCode, ShaderOper.Immf); } - public static void Fmul_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Fmul_R(ShaderIrBlock Block, long OpCode, int Position) { EmitFmul(Block, OpCode, ShaderOper.RR); } - public static void Fset_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Fset_C(ShaderIrBlock Block, long OpCode, int Position) { EmitFset(Block, OpCode, ShaderOper.CR); } - public static void Fset_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position) { EmitFset(Block, OpCode, ShaderOper.Immf); } - public static void Fset_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Fset_R(ShaderIrBlock Block, long OpCode, int Position) { EmitFset(Block, OpCode, ShaderOper.RR); } - public static void Fsetp_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Fsetp_C(ShaderIrBlock Block, long OpCode, int Position) { EmitFsetp(Block, OpCode, ShaderOper.CR); } - public static void Fsetp_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Fsetp_I(ShaderIrBlock Block, long OpCode, int Position) { EmitFsetp(Block, OpCode, ShaderOper.Immf); } - public static void Fsetp_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position) { EmitFsetp(Block, OpCode, ShaderOper.RR); } - public static void Iadd_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position) { EmitIadd(Block, OpCode, ShaderOper.CR); } - public static void Iadd_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Iadd_I(ShaderIrBlock Block, long OpCode, int Position) { EmitIadd(Block, OpCode, ShaderOper.Imm); } - public static void Iadd_I32(ShaderIrBlock Block, long OpCode, long Position) + public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode OperA = OpCode.Gpr8(); ShaderIrNode OperB = OpCode.Imm32_20(); @@ -168,42 +168,42 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); } - public static void Iadd_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Iadd_R(ShaderIrBlock Block, long OpCode, int Position) { EmitIadd(Block, OpCode, ShaderOper.RR); } - public static void Iadd3_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Iadd3_C(ShaderIrBlock Block, long OpCode, int Position) { EmitIadd3(Block, OpCode, ShaderOper.CR); } - public static void Iadd3_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Iadd3_I(ShaderIrBlock Block, long OpCode, int Position) { EmitIadd3(Block, OpCode, ShaderOper.Imm); } - public static void Iadd3_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Iadd3_R(ShaderIrBlock Block, long OpCode, int Position) { EmitIadd3(Block, OpCode, ShaderOper.RR); } - public static void Imnmx_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Imnmx_C(ShaderIrBlock Block, long OpCode, int Position) { EmitImnmx(Block, OpCode, ShaderOper.CR); } - public static void Imnmx_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Imnmx_I(ShaderIrBlock Block, long OpCode, int Position) { EmitImnmx(Block, OpCode, ShaderOper.Imm); } - public static void Imnmx_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Imnmx_R(ShaderIrBlock Block, long OpCode, int Position) { EmitImnmx(Block, OpCode, ShaderOper.RR); } - public static void Ipa(ShaderIrBlock Block, long OpCode, long Position) + public static void Ipa(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode OperA = OpCode.Abuf28(); ShaderIrNode OperB = OpCode.Gpr20(); @@ -217,52 +217,52 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); } - public static void Iscadd_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Iscadd_C(ShaderIrBlock Block, long OpCode, int Position) { EmitIscadd(Block, OpCode, ShaderOper.CR); } - public static void Iscadd_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Iscadd_I(ShaderIrBlock Block, long OpCode, int Position) { EmitIscadd(Block, OpCode, ShaderOper.Imm); } - public static void Iscadd_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Iscadd_R(ShaderIrBlock Block, long OpCode, int Position) { EmitIscadd(Block, OpCode, ShaderOper.RR); } - public static void Iset_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Iset_C(ShaderIrBlock Block, long OpCode, int Position) { EmitIset(Block, OpCode, ShaderOper.CR); } - public static void Iset_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Iset_I(ShaderIrBlock Block, long OpCode, int Position) { EmitIset(Block, OpCode, ShaderOper.Imm); } - public static void Iset_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Iset_R(ShaderIrBlock Block, long OpCode, int Position) { EmitIset(Block, OpCode, ShaderOper.RR); } - public static void Isetp_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Isetp_C(ShaderIrBlock Block, long OpCode, int Position) { EmitIsetp(Block, OpCode, ShaderOper.CR); } - public static void Isetp_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Isetp_I(ShaderIrBlock Block, long OpCode, int Position) { EmitIsetp(Block, OpCode, ShaderOper.Imm); } - public static void Isetp_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Isetp_R(ShaderIrBlock Block, long OpCode, int Position) { EmitIsetp(Block, OpCode, ShaderOper.RR); } - public static void Lop_I32(ShaderIrBlock Block, long OpCode, long Position) + public static void Lop_I32(ShaderIrBlock Block, long OpCode, int Position) { int SubOp = OpCode.Read(53, 3); @@ -296,22 +296,22 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Lop_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Lop_C(ShaderIrBlock Block, long OpCode, int Position) { EmitLop(Block, OpCode, ShaderOper.CR); } - public static void Lop_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Lop_I(ShaderIrBlock Block, long OpCode, int Position) { EmitLop(Block, OpCode, ShaderOper.Imm); } - public static void Lop_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Lop_R(ShaderIrBlock Block, long OpCode, int Position) { EmitLop(Block, OpCode, ShaderOper.RR); } - public static void Mufu(ShaderIrBlock Block, long OpCode, long Position) + public static void Mufu(ShaderIrBlock Block, long OpCode, int Position) { int SubOp = OpCode.Read(20, 0xf); @@ -340,7 +340,7 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); } - public static void Psetp(ShaderIrBlock Block, long OpCode, long Position) + public static void Psetp(ShaderIrBlock Block, long OpCode, int Position) { bool NegA = OpCode.Read(15); bool NegB = OpCode.Read(32); @@ -394,47 +394,47 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op))); } - public static void Rro_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Rro_C(ShaderIrBlock Block, long OpCode, int Position) { EmitRro(Block, OpCode, ShaderOper.CR); } - public static void Rro_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Rro_I(ShaderIrBlock Block, long OpCode, int Position) { EmitRro(Block, OpCode, ShaderOper.Immf); } - public static void Rro_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Rro_R(ShaderIrBlock Block, long OpCode, int Position) { EmitRro(Block, OpCode, ShaderOper.RR); } - public static void Shl_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Shl_C(ShaderIrBlock Block, long OpCode, int Position) { EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl); } - public static void Shl_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Shl_I(ShaderIrBlock Block, long OpCode, int Position) { EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl); } - public static void Shl_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Shl_R(ShaderIrBlock Block, long OpCode, int Position) { EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl); } - public static void Shr_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Shr_C(ShaderIrBlock Block, long OpCode, int Position) { EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode)); } - public static void Shr_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Shr_I(ShaderIrBlock Block, long OpCode, int Position) { EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode)); } - public static void Shr_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Shr_R(ShaderIrBlock Block, long OpCode, int Position) { EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode)); } @@ -446,7 +446,7 @@ namespace Ryujinx.Graphics.Gal.Shader return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; } - public static void Vmad(ShaderIrBlock Block, long OpCode, long Position) + public static void Vmad(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode OperA = OpCode.Gpr8(); @@ -481,22 +481,22 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final))); } - public static void Xmad_CR(ShaderIrBlock Block, long OpCode, long Position) + public static void Xmad_CR(ShaderIrBlock Block, long OpCode, int Position) { EmitXmad(Block, OpCode, ShaderOper.CR); } - public static void Xmad_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Xmad_I(ShaderIrBlock Block, long OpCode, int Position) { EmitXmad(Block, OpCode, ShaderOper.Imm); } - public static void Xmad_RC(ShaderIrBlock Block, long OpCode, long Position) + public static void Xmad_RC(ShaderIrBlock Block, long OpCode, int Position) { EmitXmad(Block, OpCode, ShaderOper.RC); } - public static void Xmad_RR(ShaderIrBlock Block, long OpCode, long Position) + public static void Xmad_RR(ShaderIrBlock Block, long OpCode, int Position) { EmitXmad(Block, OpCode, ShaderOper.RR); } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs index dfd10e00..bc2539bd 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs @@ -1,12 +1,10 @@ using System; -using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; - namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - public static void Bra(ShaderIrBlock Block, long OpCode, long Position) + public static void Bra(ShaderIrBlock Block, long OpCode, int Position) { if ((OpCode & 0x20) != 0) { @@ -15,14 +13,12 @@ namespace Ryujinx.Graphics.Gal.Shader throw new NotImplementedException(); } - int Target = OpCode.Branch(); - - ShaderIrOperImm Imm = new ShaderIrOperImm(Target); + ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch()); Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm))); } - public static void Exit(ShaderIrBlock Block, long OpCode, long Position) + public static void Exit(ShaderIrBlock Block, long OpCode, int Position) { int CCode = (int)OpCode & 0x1f; @@ -31,15 +27,14 @@ namespace Ryujinx.Graphics.Gal.Shader { Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit))); } - } - public static void Kil(ShaderIrBlock Block, long OpCode, long Position) + public static void Kil(ShaderIrBlock Block, long OpCode, int Position) { Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil))); } - public static void Ssy(ShaderIrBlock Block, long OpCode, long Position) + public static void Ssy(ShaderIrBlock Block, long OpCode, int Position) { if ((OpCode & 0x20) != 0) { @@ -48,19 +43,14 @@ namespace Ryujinx.Graphics.Gal.Shader throw new NotImplementedException(); } - int Offset = OpCode.Branch(); - - int Target = (int)(Position + Offset); - - ShaderIrOperImm Imm = new ShaderIrOperImm(Target); + ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch()); Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm)); } - public static void Sync(ShaderIrBlock Block, long OpCode, long Position) + public static void Sync(ShaderIrBlock Block, long OpCode, int Position) { //TODO: Implement Sync condition codes - Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync))); } } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs similarity index 83% rename from Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs rename to Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs index 73625f65..73248aa0 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecode.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs @@ -1,4 +1,4 @@ namespace Ryujinx.Graphics.Gal.Shader { - delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, long Position); + delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, int Position); } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs index 010f06aa..ebacd53a 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs @@ -1,5 +1,3 @@ -using System; - namespace Ryujinx.Graphics.Gal.Shader { static class ShaderDecodeHelper diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index 508a0205..cd655995 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Gal.Shader { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } }; - public static void Ld_A(ShaderIrBlock Block, long OpCode, long Position) + public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode[] Opers = OpCode.Abuf20(); @@ -50,7 +50,7 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Ld_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Ld_C(ShaderIrBlock Block, long OpCode, int Position) { int CbufPos = OpCode.Read(22, 0x3fff); int CbufIndex = OpCode.Read(36, 0x1f); @@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void St_A(ShaderIrBlock Block, long OpCode, long Position) + public static void St_A(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode[] Opers = OpCode.Abuf20(); @@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Texq(ShaderIrBlock Block, long OpCode, long Position) + public static void Texq(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode OperD = OpCode.Gpr0(); ShaderIrNode OperA = OpCode.Gpr8(); @@ -132,12 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right? } - public static void Tex(ShaderIrBlock Block, long OpCode, long Position) + public static void Tex(ShaderIrBlock Block, long OpCode, int Position) { EmitTex(Block, OpCode, GprHandle: false); } - public static void Tex_B(ShaderIrBlock Block, long OpCode, long Position) + public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position) { EmitTex(Block, OpCode, GprHandle: true); } @@ -202,12 +202,12 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Texs(ShaderIrBlock Block, long OpCode, long Position) + public static void Texs(ShaderIrBlock Block, long OpCode, int Position) { EmitTexs(Block, OpCode, ShaderIrInst.Texs); } - public static void Tlds(ShaderIrBlock Block, long OpCode, long Position) + public static void Tlds(ShaderIrBlock Block, long OpCode, int Position) { EmitTexs(Block, OpCode, ShaderIrInst.Txlf); } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs index add39402..cd602db7 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs @@ -25,67 +25,67 @@ namespace Ryujinx.Graphics.Gal.Shader F64 = 3 } - public static void F2f_C(ShaderIrBlock Block, long OpCode, long Position) + public static void F2f_C(ShaderIrBlock Block, long OpCode, int Position) { EmitF2f(Block, OpCode, ShaderOper.CR); } - public static void F2f_I(ShaderIrBlock Block, long OpCode, long Position) + public static void F2f_I(ShaderIrBlock Block, long OpCode, int Position) { EmitF2f(Block, OpCode, ShaderOper.Immf); } - public static void F2f_R(ShaderIrBlock Block, long OpCode, long Position) + public static void F2f_R(ShaderIrBlock Block, long OpCode, int Position) { EmitF2f(Block, OpCode, ShaderOper.RR); } - public static void F2i_C(ShaderIrBlock Block, long OpCode, long Position) + public static void F2i_C(ShaderIrBlock Block, long OpCode, int Position) { EmitF2i(Block, OpCode, ShaderOper.CR); } - public static void F2i_I(ShaderIrBlock Block, long OpCode, long Position) + public static void F2i_I(ShaderIrBlock Block, long OpCode, int Position) { EmitF2i(Block, OpCode, ShaderOper.Immf); } - public static void F2i_R(ShaderIrBlock Block, long OpCode, long Position) + public static void F2i_R(ShaderIrBlock Block, long OpCode, int Position) { EmitF2i(Block, OpCode, ShaderOper.RR); } - public static void I2f_C(ShaderIrBlock Block, long OpCode, long Position) + public static void I2f_C(ShaderIrBlock Block, long OpCode, int Position) { EmitI2f(Block, OpCode, ShaderOper.CR); } - public static void I2f_I(ShaderIrBlock Block, long OpCode, long Position) + public static void I2f_I(ShaderIrBlock Block, long OpCode, int Position) { EmitI2f(Block, OpCode, ShaderOper.Imm); } - public static void I2f_R(ShaderIrBlock Block, long OpCode, long Position) + public static void I2f_R(ShaderIrBlock Block, long OpCode, int Position) { EmitI2f(Block, OpCode, ShaderOper.RR); } - public static void I2i_C(ShaderIrBlock Block, long OpCode, long Position) + public static void I2i_C(ShaderIrBlock Block, long OpCode, int Position) { EmitI2i(Block, OpCode, ShaderOper.CR); } - public static void I2i_I(ShaderIrBlock Block, long OpCode, long Position) + public static void I2i_I(ShaderIrBlock Block, long OpCode, int Position) { EmitI2i(Block, OpCode, ShaderOper.Imm); } - public static void I2i_R(ShaderIrBlock Block, long OpCode, long Position) + public static void I2i_R(ShaderIrBlock Block, long OpCode, int Position) { EmitI2i(Block, OpCode, ShaderOper.RR); } - public static void Isberd(ShaderIrBlock Block, long OpCode, long Position) + public static void Isberd(ShaderIrBlock Block, long OpCode, int Position) { //This instruction seems to be used to translate from an address to a vertex index in a GS //Stub it as such @@ -95,50 +95,50 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OpCode.Gpr8()))); } - public static void Mov_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Mov_C(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrOperCbuf Cbuf = OpCode.Cbuf34(); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Cbuf))); } - public static void Mov_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Mov_I(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrOperImm Imm = OpCode.Imm19_20(); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm))); } - public static void Mov_I32(ShaderIrBlock Block, long OpCode, long Position) + public static void Mov_I32(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrOperImm Imm = OpCode.Imm32_20(); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm))); } - public static void Mov_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Mov_R(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrOperGpr Gpr = OpCode.Gpr20(); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Gpr))); } - public static void Sel_C(ShaderIrBlock Block, long OpCode, long Position) + public static void Sel_C(ShaderIrBlock Block, long OpCode, int Position) { EmitSel(Block, OpCode, ShaderOper.CR); } - public static void Sel_I(ShaderIrBlock Block, long OpCode, long Position) + public static void Sel_I(ShaderIrBlock Block, long OpCode, int Position) { EmitSel(Block, OpCode, ShaderOper.Imm); } - public static void Sel_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Sel_R(ShaderIrBlock Block, long OpCode, int Position) { EmitSel(Block, OpCode, ShaderOper.RR); } - public static void Mov_S(ShaderIrBlock Block, long OpCode, long Position) + public static void Mov_S(ShaderIrBlock Block, long OpCode, int Position) { Block.AddNode(new ShaderIrCmnt("Stubbed.")); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs index c3e42654..35abdb76 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs @@ -1,10 +1,8 @@ -using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; - -namespace Ryujinx.Graphics.Gal.Shader +namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - public static void Out_R(ShaderIrBlock Block, long OpCode, long Position) + public static void Out_R(ShaderIrBlock Block, long OpCode, int Position) { //TODO: Those registers have to be used for something ShaderIrOperGpr Gpr0 = OpCode.Gpr0(); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs index 81d8f312..ac6ae8d5 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs @@ -10,12 +10,14 @@ namespace Ryujinx.Graphics.Gal.Shader public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start) { - Dictionary Visited = new Dictionary(); - Dictionary VisitedEnd = new Dictionary(); + Dictionary Visited = new Dictionary(); + Dictionary VisitedEnd = new Dictionary(); Queue Blocks = new Queue(); - ShaderIrBlock Enqueue(long Position, ShaderIrBlock Source = null) + long Beginning = Start + HeaderSize; + + ShaderIrBlock Enqueue(int Position, ShaderIrBlock Source = null) { if (!Visited.TryGetValue(Position, out ShaderIrBlock Output)) { @@ -34,13 +36,13 @@ namespace Ryujinx.Graphics.Gal.Shader return Output; } - ShaderIrBlock Entry = Enqueue(Start + HeaderSize); + ShaderIrBlock Entry = Enqueue(0); while (Blocks.Count > 0) { ShaderIrBlock Current = Blocks.Dequeue(); - FillBlock(Memory, Current, Start + HeaderSize); + FillBlock(Memory, Current, Beginning); //Set child blocks. "Branch" is the block the branch instruction //points to (when taken), "Next" is the block at the next address, @@ -54,20 +56,18 @@ namespace Ryujinx.Graphics.Gal.Shader if (InnerOp?.Inst == ShaderIrInst.Bra) { - int Offset = ((ShaderIrOperImm)InnerOp.OperandA).Value; - - long Target = Current.EndPosition + Offset; + int Target = ((ShaderIrOperImm)InnerOp.OperandA).Value; Current.Branch = Enqueue(Target, Current); } foreach (ShaderIrNode Node in Current.Nodes) { - if (Node is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy) - { - int Offset = ((ShaderIrOperImm)CurrOp.OperandA).Value; + InnerOp = GetInnermostOp(Node); - long Target = Offset; + if (InnerOp is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy) + { + int Target = ((ShaderIrOperImm)CurrOp.OperandA).Value; Current.Branch = Enqueue(Target, Current); } @@ -112,15 +112,15 @@ namespace Ryujinx.Graphics.Gal.Shader while (Visited.Count > 0) { - ulong FirstPos = ulong.MaxValue; + uint FirstPos = uint.MaxValue; foreach (ShaderIrBlock Block in Visited.Values) { - if (FirstPos > (ulong)Block.Position) - FirstPos = (ulong)Block.Position; + if (FirstPos > (uint)Block.Position) + FirstPos = (uint)Block.Position; } - ShaderIrBlock Current = Visited[(long)FirstPos]; + ShaderIrBlock Current = Visited[(int)FirstPos]; do { @@ -138,20 +138,20 @@ namespace Ryujinx.Graphics.Gal.Shader private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning) { - long Position = Block.Position; + int Position = Block.Position; do { //Ignore scheduling instructions, which are written every 32 bytes. - if (((Position - Beginning) & 0x1f) == 0) + if ((Position & 0x1f) == 0) { Position += 8; continue; } - uint Word0 = (uint)Memory.ReadInt32(Position + 0); - uint Word1 = (uint)Memory.ReadInt32(Position + 4); + uint Word0 = (uint)Memory.ReadInt32(Position + Beginning + 0); + uint Word1 = (uint)Memory.ReadInt32(Position + Beginning + 4); Position += 8; @@ -161,7 +161,7 @@ namespace Ryujinx.Graphics.Gal.Shader if (AddDbgComments) { - string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} "; + string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} "; DbgOpCode += (Decode?.Method.Name ?? "???"); @@ -169,7 +169,7 @@ namespace Ryujinx.Graphics.Gal.Shader { int Offset = ((int)(OpCode >> 20) << 8) >> 8; - long Target = Position + Offset - Beginning; + long Target = Position + Offset; DbgOpCode += " (0x" + Target.ToString("x16") + ")"; } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs index 50e563b8..782f9626 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs @@ -4,8 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader { class ShaderIrBlock { - public long Position { get; set; } - public long EndPosition { get; set; } + public int Position { get; set; } + public int EndPosition { get; set; } public ShaderIrBlock Next { get; set; } public ShaderIrBlock Branch { get; set; } @@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gal.Shader public List Nodes { get; private set; } - public ShaderIrBlock(long Position) + public ShaderIrBlock(int Position) { this.Position = Position; diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs new file mode 100644 index 00000000..ba35910d --- /dev/null +++ b/Ryujinx.Graphics/GpuResourceManager.cs @@ -0,0 +1,122 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Memory; +using Ryujinx.Graphics.Texture; +using System.Collections.Generic; + +namespace Ryujinx.Graphics +{ + public class GpuResourceManager + { + private NvGpu Gpu; + + private HashSet[] UploadedKeys; + + public GpuResourceManager(NvGpu Gpu) + { + this.Gpu = Gpu; + + UploadedKeys = new HashSet[(int)NvGpuBufferType.Count]; + + for (int Index = 0; Index < UploadedKeys.Length; Index++) + { + UploadedKeys[Index] = new HashSet(); + } + } + + public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage) + { + long Size = (uint)ImageUtils.GetSize(NewImage); + + MarkAsCached(Vmm, Position, Size, NvGpuBufferType.Texture); + + bool IsCached = Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage); + + if (IsCached && CachedImage.SizeMatches(NewImage)) + { + Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); + Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage); + + return; + } + + Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); + + Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage); + } + + public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage) + { + long Size = (uint)ImageUtils.GetSize(NewImage); + + MarkAsCached(Vmm, Position, Size, NvGpuBufferType.Texture); + + bool IsCached = Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage); + + if (IsCached && CachedImage.SizeMatches(NewImage)) + { + Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); + Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage); + + return; + } + + Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); + + Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage); + } + + public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1) + { + long Size = (uint)ImageUtils.GetSize(NewImage); + + if (!MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture)) + { + if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage)) + { + Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); + + if (TexIndex >= 0) + { + Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage); + } + + return; + } + } + + byte[] Data = ImageUtils.ReadTexture(Vmm, NewImage, Position); + + Gpu.Renderer.Texture.Create(Position, Data, NewImage); + + if (TexIndex >= 0) + { + Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage); + } + } + + private void MarkAsCached(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type) + { + Vmm.IsRegionModified(Position, Size, Type); + } + + private bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type) + { + HashSet Uploaded = UploadedKeys[(int)Type]; + + if (!Uploaded.Add(Position)) + { + return false; + } + + return Vmm.IsRegionModified(Position, Size, Type); + } + + public void ClearPbCache() + { + for (int Index = 0; Index < UploadedKeys.Length; Index++) + { + UploadedKeys[Index].Clear(); + } + } + } +} diff --git a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs index 56979e1f..f1c16a36 100644 --- a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs +++ b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs @@ -1,309 +1,82 @@ using ChocolArm64.Memory; using System; -using System.Collections.Generic; namespace Ryujinx.Graphics.Memory { class NvGpuVmmCache { - private const long RamSize = 4L * 1024 * 1024 * 1024; - - private const int MaxCpCount = 10000; - private const int MaxCpTimeDelta = 60000; - - private class CachedPage - { - private struct Range - { - public long Start; - public long End; - - public Range(long Start, long End) - { - this.Start = Start; - this.End = End; - } - } - - private List[] Regions; - - private HashSet ResidencyKeys; - - public LinkedListNode Node { get; set; } - - public int Timestamp { get; private set; } - - public CachedPage() - { - Regions = new List[(int)NvGpuBufferType.Count]; - - for (int Index = 0; Index < Regions.Length; Index++) - { - Regions[Index] = new List(); - } - - ResidencyKeys = new HashSet(); - } - - public void AddResidency(long Key) - { - ResidencyKeys.Add(Key); - } - - public void RemoveResidency(HashSet[] Residency, long PageSize) - { - for (int i = 0; i < (int)NvGpuBufferType.Count; i++) - { - foreach (Range Region in Regions[i]) - { - foreach (long Key in ResidencyKeys) - { - Residency[Region.Start / PageSize].Remove(Key); - } - } - } - } - - public bool AddRange(long Start, long End, NvGpuBufferType BufferType) - { - List BtRegions = Regions[(int)BufferType]; - - for (int Index = 0; Index < BtRegions.Count; Index++) - { - Range Rg = BtRegions[Index]; - - if (Start >= Rg.Start && End <= Rg.End) - { - return false; - } - - if (Start <= Rg.End && Rg.Start <= End) - { - long MinStart = Math.Min(Rg.Start, Start); - long MaxEnd = Math.Max(Rg.End, End); - - BtRegions[Index] = new Range(MinStart, MaxEnd); - - Timestamp = Environment.TickCount; - - return true; - } - } - - BtRegions.Add(new Range(Start, End)); - - Timestamp = Environment.TickCount; - - return true; - } - - public int GetTotalCount() - { - int Count = 0; - - for (int Index = 0; Index < Regions.Length; Index++) - { - Count += Regions[Index].Count; - } - - return Count; - } - } - - private Dictionary Cache; - - private LinkedList SortedCache; - - private HashSet[] Residency; - - private long ResidencyPageSize; - - private int CpCount; + private ValueRangeSet CachedRanges; public NvGpuVmmCache() { - Cache = new Dictionary(); - - SortedCache = new LinkedList(); + CachedRanges = new ValueRangeSet(); } public bool IsRegionModified(AMemory Memory, NvGpuBufferType BufferType, long PA, long Size) { (bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(PA, Size); - PA = Memory.GetPhysicalAddress(PA); - - ClearCachedPagesIfNeeded(); - - long PageSize = AMemory.PageSize; - - EnsureResidencyInitialized(PageSize); - - bool HasResidents = AddResidency(PA, Size); - - if (!HasResidents && ModifiedCount == 0) - { - return false; - } - - long Mask = PageSize - 1; - - long ResidencyKey = PA; - - long PAEnd = PA + Size; - - bool RegMod = false; - + //Remove all modified ranges. int Index = 0; - while (PA < PAEnd) + long Position = PA & ~NvGpuVmm.PageMask; + + while (ModifiedCount > 0) { - long Key = PA & ~AMemory.PageMask; - - long PAPgEnd = Math.Min((PA + AMemory.PageSize) & ~AMemory.PageMask, PAEnd); - - bool IsCached = Cache.TryGetValue(Key, out CachedPage Cp); - - if (IsCached) + if (Modified[Index++]) { - CpCount -= Cp.GetTotalCount(); + CachedRanges.Remove(new ValueRange(Position, Position + NvGpuVmm.PageSize)); - SortedCache.Remove(Cp.Node); + ModifiedCount--; + } + + Position += NvGpuVmm.PageSize; + } + + //Mask has the bit set for the current resource type. + //If the region is not yet present on the list, then a new ValueRange + //is directly added with the current resource type as the only bit set. + //Otherwise, it just sets the bit for this new resource type on the current mask. + int Mask = 1 << (int)BufferType; + + ValueRange NewCached = new ValueRange(PA, PA + Size); + + ValueRange[] Ranges = CachedRanges.GetAllIntersections(NewCached); + + long LastEnd = NewCached.Start; + + long Coverage = 0; + + for (Index = 0; Index < Ranges.Length; Index++) + { + ValueRange Current = Ranges[Index]; + + long RgStart = Math.Max(Current.Start, NewCached.Start); + long RgEnd = Math.Min(Current.End, NewCached.End); + + if ((Current.Value & Mask) == 0) + { + CachedRanges.Add(new ValueRange(RgStart, RgEnd, Current.Value | Mask)); } else { - Cp = new CachedPage(); - - Cache.Add(Key, Cp); + Coverage += RgEnd - RgStart; } - if (Modified[Index++] && IsCached) + if (RgStart > LastEnd) { - Cp = new CachedPage(); - - Cache[Key] = Cp; + CachedRanges.Add(new ValueRange(LastEnd, RgStart, Mask)); } - Cp.AddResidency(ResidencyKey); - - Cp.Node = SortedCache.AddLast(Key); - - RegMod |= Cp.AddRange(PA, PAPgEnd, BufferType); - - CpCount += Cp.GetTotalCount(); - - PA = PAPgEnd; + LastEnd = RgEnd; } - return RegMod; - } - - private bool AddResidency(long PA, long Size) - { - long PageSize = ResidencyPageSize; - - long Mask = PageSize - 1; - - long Key = PA; - - bool ResidentFound = false; - - for (long Cursor = PA & ~Mask; Cursor < ((PA + Size + PageSize - 1) & ~Mask); Cursor += PageSize) + if (LastEnd < NewCached.End) { - long PageIndex = Cursor / PageSize; - - Residency[PageIndex].Add(Key); - - if (Residency[PageIndex].Count > 1) - { - ResidentFound = true; - } + CachedRanges.Add(new ValueRange(LastEnd, NewCached.End, Mask)); } - return ResidentFound; - } - - private void EnsureResidencyInitialized(long PageSize) - { - if (Residency == null) - { - Residency = new HashSet[RamSize / PageSize]; - - for (int i = 0; i < Residency.Length; i++) - { - Residency[i] = new HashSet(); - } - - ResidencyPageSize = PageSize; - } - else - { - if (ResidencyPageSize != PageSize) - { - throw new InvalidOperationException("Tried to change residency page size"); - } - } - } - - private void ClearCachedPagesIfNeeded() - { - if (CpCount <= MaxCpCount) - { - return; - } - - int Timestamp = Environment.TickCount; - - int TimeDelta; - - do - { - if (!TryPopOldestCachedPageKey(Timestamp, out long Key)) - { - break; - } - - CachedPage Cp = Cache[Key]; - - Cp.RemoveResidency(Residency, ResidencyPageSize); - - Cache.Remove(Key); - - CpCount -= Cp.GetTotalCount(); - - TimeDelta = RingDelta(Cp.Timestamp, Timestamp); - } - while (CpCount > (MaxCpCount >> 1) || (uint)TimeDelta > (uint)MaxCpTimeDelta); - } - - private bool TryPopOldestCachedPageKey(int Timestamp, out long Key) - { - LinkedListNode Node = SortedCache.First; - - if (Node == null) - { - Key = 0; - - return false; - } - - SortedCache.Remove(Node); - - Key = Node.Value; - - return true; - } - - private int RingDelta(int Old, int New) - { - if ((uint)New < (uint)Old) - { - return New + (~Old + 1); - } - else - { - return New - Old; - } + return Coverage != Size; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/NvGpu.cs b/Ryujinx.Graphics/NvGpu.cs index 7ba700b8..4c6abd23 100644 --- a/Ryujinx.Graphics/NvGpu.cs +++ b/Ryujinx.Graphics/NvGpu.cs @@ -1,5 +1,4 @@ using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics; namespace Ryujinx.Graphics { @@ -7,21 +6,27 @@ namespace Ryujinx.Graphics { public IGalRenderer Renderer { get; private set; } + public GpuResourceManager ResourceManager { get; private set; } + public NvGpuFifo Fifo { get; private set; } - public NvGpuEngine2d Engine2d { get; private set; } - public NvGpuEngine3d Engine3d { get; private set; } - public NvGpuEngineDma EngineDma { get; private set; } + internal NvGpuEngine2d Engine2d { get; private set; } + internal NvGpuEngine3d Engine3d { get; private set; } + internal NvGpuEngineM2mf EngineM2mf { get; private set; } + internal NvGpuEngineP2mf EngineP2mf { get; private set; } public NvGpu(IGalRenderer Renderer) { this.Renderer = Renderer; + ResourceManager = new GpuResourceManager(this); + Fifo = new NvGpuFifo(this); - Engine2d = new NvGpuEngine2d(this); - Engine3d = new NvGpuEngine3d(this); - EngineDma = new NvGpuEngineDma(this); + Engine2d = new NvGpuEngine2d(this); + Engine3d = new NvGpuEngine3d(this); + EngineM2mf = new NvGpuEngineM2mf(this); + EngineP2mf = new NvGpuEngineP2mf(this); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Memory/NvGpuBufferType.cs b/Ryujinx.Graphics/NvGpuBufferType.cs similarity index 79% rename from Ryujinx.Graphics/Memory/NvGpuBufferType.cs rename to Ryujinx.Graphics/NvGpuBufferType.cs index 6f0d2571..f6b55597 100644 --- a/Ryujinx.Graphics/Memory/NvGpuBufferType.cs +++ b/Ryujinx.Graphics/NvGpuBufferType.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Graphics.Memory +namespace Ryujinx.Graphics { public enum NvGpuBufferType { diff --git a/Ryujinx.Graphics/NvGpuEngine.cs b/Ryujinx.Graphics/NvGpuEngine.cs index 3d5e118a..d533e478 100644 --- a/Ryujinx.Graphics/NvGpuEngine.cs +++ b/Ryujinx.Graphics/NvGpuEngine.cs @@ -5,7 +5,7 @@ namespace Ryujinx.Graphics _2d = 0x902d, _3d = 0xb197, Compute = 0xb1c0, - Kepler = 0xa140, - Dma = 0xb0b5 + P2mf = 0xa140, + M2mf = 0xb0b5 } } \ No newline at end of file diff --git a/Ryujinx.Graphics/NvGpuEngine2d.cs b/Ryujinx.Graphics/NvGpuEngine2d.cs index f26b0020..4bf7c1e8 100644 --- a/Ryujinx.Graphics/NvGpuEngine2d.cs +++ b/Ryujinx.Graphics/NvGpuEngine2d.cs @@ -1,7 +1,6 @@ using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; -using System; using System.Collections.Generic; namespace Ryujinx.Graphics @@ -62,25 +61,25 @@ namespace Ryujinx.Graphics { CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); + int SrcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat); 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); + int DstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat); bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0; int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth); int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight); int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch); int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions); - TextureSwizzle SrcSwizzle = SrcLinear - ? TextureSwizzle.Pitch - : TextureSwizzle.BlockLinear; + GalImageFormat SrcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)SrcFormat); + GalImageFormat DstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)DstFormat); - TextureSwizzle DstSwizzle = DstLinear - ? TextureSwizzle.Pitch - : TextureSwizzle.BlockLinear; + GalMemoryLayout SrcLayout = GetLayout(SrcLinear); + GalMemoryLayout DstLayout = GetLayout(DstLinear); int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); @@ -91,91 +90,41 @@ namespace Ryujinx.Graphics long SrcKey = Vmm.GetPhysicalAddress(SrcAddress); long DstKey = Vmm.GetPhysicalAddress(DstAddress); - bool IsSrcFb = Gpu.Engine3d.IsFrameBufferPosition(SrcKey); - bool IsDstFb = Gpu.Engine3d.IsFrameBufferPosition(DstKey); + GalImage SrcTexture = new GalImage( + SrcWidth, + SrcHeight, 1, + SrcBlockHeight, + SrcLayout, + SrcImgFormat); - TextureInfo SrcTexture() - { - return new TextureInfo( - SrcAddress, - SrcWidth, - SrcHeight, - SrcPitch, - SrcBlockHeight, 1, - SrcSwizzle, - GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm); - } + GalImage DstTexture = new GalImage( + DstWidth, + DstHeight, 1, + DstBlockHeight, + DstLayout, + DstImgFormat); - TextureInfo DstTexture() - { - return new TextureInfo( - DstAddress, - DstWidth, - DstHeight, - DstPitch, - DstBlockHeight, 1, - DstSwizzle, - GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm); - } + Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture); + Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture); - //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.RenderTarget.Copy( - SrcKey, - DstKey, - 0, - 0, - SrcWidth, - SrcHeight, - 0, - 0, - DstWidth, - DstHeight); - } - if (IsSrcFb) - { - //Frame Buffer -> Texture copy. - Gpu.Renderer.RenderTarget.GetBufferData(SrcKey, (byte[] Buffer) => - { - TextureInfo Src = SrcTexture(); - TextureInfo Dst = DstTexture(); + Gpu.Renderer.RenderTarget.Copy( + SrcKey, + DstKey, + 0, + 0, + SrcWidth, + SrcHeight, + 0, + 0, + DstWidth, + DstHeight); + } - 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) - { - byte[] Buffer = TextureReader.Read(Vmm, SrcTexture()); - - Gpu.Renderer.RenderTarget.SetBufferData( - DstKey, - DstWidth, - DstHeight, - Buffer); - } - else - { - //Texture -> Texture copy. - 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, TextureReader.Read(Vmm, Src)); - } + private static GalMemoryLayout GetLayout(bool Linear) + { + return Linear + ? GalMemoryLayout.Pitch + : GalMemoryLayout.BlockLinear; } private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg) diff --git a/Ryujinx.Graphics/NvGpuEngine3d.cs b/Ryujinx.Graphics/NvGpuEngine3d.cs index 624eddae..a1d0ec80 100644 --- a/Ryujinx.Graphics/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/NvGpuEngine3d.cs @@ -23,8 +23,6 @@ namespace Ryujinx.Graphics private ConstBuffer[][] ConstBuffers; - private HashSet FrameBuffers; - private List[] UploadedKeys; private int CurrentInstance = 0; @@ -60,8 +58,6 @@ namespace Ryujinx.Graphics ConstBuffers[Index] = new ConstBuffer[18]; } - FrameBuffers = new HashSet(); - UploadedKeys = new List[(int)NvGpuBufferType.Count]; for (int i = 0; i < UploadedKeys.Length; i++) @@ -96,7 +92,7 @@ namespace Ryujinx.Graphics GalPipelineState State = new GalPipelineState(); - SetFlip(State); + SetFrameBuffer(State); SetFrontFace(State); SetCullFace(State); SetDepth(State); @@ -104,10 +100,7 @@ namespace Ryujinx.Graphics SetAlphaBlending(State); SetPrimitiveRestart(State); - for (int FbIndex = 0; FbIndex < 8; FbIndex++) - { - SetFrameBuffer(Vmm, 0); - } + SetFrameBuffer(Vmm, 0); SetZeta(Vmm); @@ -173,9 +166,9 @@ namespace Ryujinx.Graphics { long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); - int Format = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10); + int SurfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10); - if (VA == 0 || Format == 0) + if (VA == 0 || SurfFormat == 0) { Gpu.Renderer.RenderTarget.UnbindColor(FbIndex); @@ -184,11 +177,15 @@ namespace Ryujinx.Graphics long Key = Vmm.GetPhysicalAddress(VA); - FrameBuffers.Add(Key); - int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10); int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10); + int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10); + + int GobBlockHeight = 1 << ((BlockDim >> 4) & 7); + + GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1); + float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 8); float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 8); @@ -201,48 +198,54 @@ namespace Ryujinx.Graphics int VpW = (int)(TX + MathF.Abs(SX)) - VpX; int VpH = (int)(TY + MathF.Abs(SY)) - VpY; - GalImageFormat ImageFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)Format); + GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat); - GalImage Image = new GalImage(Width, Height, ImageFormat); + GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format); - long Size = ImageUtils.GetSize(Image); - - Gpu.Renderer.Texture.CreateFb(Key, Size, Image); - - Gpu.Renderer.RenderTarget.BindColor(Key, FbIndex); + Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image); Gpu.Renderer.RenderTarget.SetViewport(VpX, VpY, VpW, VpH); } + private void SetFrameBuffer(GalPipelineState State) + { + State.FramebufferSrgb = (ReadRegister(NvGpuEngine3dReg.FrameBufferSrgb) & 1) != 0; + + State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); + State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); + } + private void SetZeta(NvGpuVmm Vmm) { - long ZA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); + long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); - int Format = ReadRegister(NvGpuEngine3dReg.ZetaFormat); + int ZetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat); + + int BlockDim = ReadRegister(NvGpuEngine3dReg.ZetaBlockDimensions); + + int GobBlockHeight = 1 << ((BlockDim >> 4) & 7); + + GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1); //? bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0; - if (ZA == 0 || Format == 0 || !ZetaEnable) + if (VA == 0 || ZetaFormat == 0 || !ZetaEnable) { Gpu.Renderer.RenderTarget.UnbindZeta(); return; } - long Key = Vmm.GetPhysicalAddress(ZA); + long Key = Vmm.GetPhysicalAddress(VA); int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert); - GalImageFormat ImageFormat = ImageUtils.ConvertZeta((GalZetaFormat)Format); + GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat); - GalImage Image = new GalImage(Width, Height, ImageFormat); + GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format); - long Size = ImageUtils.GetSize(Image); - - Gpu.Renderer.Texture.CreateFb(Key, Size, Image); - - Gpu.Renderer.RenderTarget.BindZeta(Key); + Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image); } private long[] UploadShaders(NvGpuVmm Vmm) @@ -322,12 +325,6 @@ namespace Ryujinx.Graphics throw new ArgumentOutOfRangeException(nameof(Program)); } - private void SetFlip(GalPipelineState State) - { - State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); - State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); - } - private void SetFrontFace(GalPipelineState State) { float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); @@ -504,53 +501,30 @@ namespace Ryujinx.Graphics TicPosition += TicIndex * 0x20; TscPosition += TscIndex * 0x20; + GalImage Image = TextureFactory.MakeTexture(Vmm, TicPosition); + GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition); long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; + if (Image.Layout == GalMemoryLayout.BlockLinear) + { + Key &= ~0x1ffL; + } + else if (Image.Layout == GalMemoryLayout.Pitch) + { + Key &= ~0x1fL; + } + Key = Vmm.GetPhysicalAddress(Key); if (Key == -1) { - //FIXME: Should'nt ignore invalid addresses. + //FIXME: Shouldn't ignore invalid addresses. return; } - if (IsFrameBufferPosition(Key)) - { - //This texture is a frame buffer texture, - //we shouldn't read anything from memory and bind - //the frame buffer texture instead, since we're not - //really writing anything to memory. - Gpu.Renderer.RenderTarget.BindTexture(Key, TexIndex); - } - else - { - GalImage NewImage = TextureFactory.MakeTexture(Vmm, TicPosition); - - long Size = (uint)ImageUtils.GetSize(NewImage); - - bool HasCachedTexture = false; - - if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image)) - { - if (NewImage.Equals(Image) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture)) - { - Gpu.Renderer.Texture.Bind(Key, TexIndex); - - HasCachedTexture = true; - } - } - - if (!HasCachedTexture) - { - byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition); - - Gpu.Renderer.Texture.Create(Key, Data, NewImage); - } - - Gpu.Renderer.Texture.Bind(Key, TexIndex); - } + Gpu.ResourceManager.SendTexture(Vmm, Key, Image, TexIndex); Gpu.Renderer.Texture.SetSampler(Sampler); } @@ -876,11 +850,6 @@ namespace Ryujinx.Graphics Registers[(int)Reg] = Value; } - public bool IsFrameBufferPosition(long Position) - { - return FrameBuffers.Contains(Position); - } - private bool QueryKeyUpload(NvGpuVmm Vmm, long Key, long Size, NvGpuBufferType Type) { List Uploaded = UploadedKeys[(int)Type]; diff --git a/Ryujinx.Graphics/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/NvGpuEngine3dReg.cs index f96e7115..3abcf6f5 100644 --- a/Ryujinx.Graphics/NvGpuEngine3dReg.cs +++ b/Ryujinx.Graphics/NvGpuEngine3dReg.cs @@ -6,6 +6,7 @@ namespace Ryujinx.Graphics FrameBufferNWidth = 0x202, FrameBufferNHeight = 0x203, FrameBufferNFormat = 0x204, + FrameBufferNBlockDim = 0x205, ViewportNScaleX = 0x280, ViewportNScaleY = 0x281, ViewportNScaleZ = 0x282, @@ -62,6 +63,7 @@ namespace Ryujinx.Graphics StencilBackOpZFail = 0x567, StencilBackOpZPass = 0x568, StencilBackFuncFunc = 0x569, + FrameBufferSrgb = 0x56e, ShaderAddress = 0x582, VertexBeginGl = 0x586, PrimRestartEnable = 0x591, diff --git a/Ryujinx.Graphics/NvGpuEngineDma.cs b/Ryujinx.Graphics/NvGpuEngineDma.cs deleted file mode 100644 index 04be742f..00000000 --- a/Ryujinx.Graphics/NvGpuEngineDma.cs +++ /dev/null @@ -1,143 +0,0 @@ -using Ryujinx.Graphics.Memory; -using Ryujinx.Graphics.Texture; -using System.Collections.Generic; - -namespace Ryujinx.Graphics -{ - public class NvGpuEngineDma : INvGpuEngine - { - public int[] Registers { get; private set; } - - private NvGpu Gpu; - - private Dictionary Methods; - - public NvGpuEngineDma(NvGpu Gpu) - { - this.Gpu = Gpu; - - Registers = new int[0x1d6]; - - Methods = new Dictionary(); - - void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) - { - while (Count-- > 0) - { - Methods.Add(Meth, Method); - - Meth += Stride; - } - } - - AddMethod(0xc0, 1, 1, Execute); - } - - public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) - { - if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) - { - Method(Vmm, PBEntry); - } - else - { - WriteRegister(PBEntry); - } - } - - private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) - { - int Control = PBEntry.Arguments[0]; - - bool SrcLinear = ((Control >> 7) & 1) != 0; - bool DstLinear = ((Control >> 8) & 1) != 0; - - long SrcAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.SrcAddress); - long DstAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.DstAddress); - - int SrcPitch = ReadRegister(NvGpuEngineDmaReg.SrcPitch); - int DstPitch = ReadRegister(NvGpuEngineDmaReg.DstPitch); - - int DstBlkDim = ReadRegister(NvGpuEngineDmaReg.DstBlkDim); - int DstSizeX = ReadRegister(NvGpuEngineDmaReg.DstSizeX); - int DstSizeY = ReadRegister(NvGpuEngineDmaReg.DstSizeY); - int DstSizeZ = ReadRegister(NvGpuEngineDmaReg.DstSizeZ); - int DstPosXY = ReadRegister(NvGpuEngineDmaReg.DstPosXY); - int DstPosZ = ReadRegister(NvGpuEngineDmaReg.DstPosZ); - - int SrcBlkDim = ReadRegister(NvGpuEngineDmaReg.SrcBlkDim); - int SrcSizeX = ReadRegister(NvGpuEngineDmaReg.SrcSizeX); - int SrcSizeY = ReadRegister(NvGpuEngineDmaReg.SrcSizeY); - int SrcSizeZ = ReadRegister(NvGpuEngineDmaReg.SrcSizeZ); - int SrcPosXY = ReadRegister(NvGpuEngineDmaReg.SrcPosXY); - int SrcPosZ = ReadRegister(NvGpuEngineDmaReg.SrcPosZ); - - int DstPosX = (DstPosXY >> 0) & 0xffff; - int DstPosY = (DstPosXY >> 16) & 0xffff; - - int SrcPosX = (SrcPosXY >> 0) & 0xffff; - int SrcPosY = (SrcPosXY >> 16) & 0xffff; - - int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); - int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); - - ISwizzle SrcSwizzle; - - if (SrcLinear) - { - SrcSwizzle = new LinearSwizzle(SrcPitch, 1); - } - else - { - SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, 1, SrcBlockHeight); - } - - ISwizzle DstSwizzle; - - if (DstLinear) - { - DstSwizzle = new LinearSwizzle(DstPitch, 1); - } - else - { - DstSwizzle = new BlockLinearSwizzle(DstSizeX, 1, DstBlockHeight); - } - - for (int Y = 0; Y < DstSizeY; Y++) - for (int X = 0; X < DstSizeX; X++) - { - long SrcOffset = SrcAddress + (uint)SrcSwizzle.GetSwizzleOffset(X, Y); - long DstOffset = DstAddress + (uint)DstSwizzle.GetSwizzleOffset(X, Y); - - Vmm.WriteByte(DstOffset, Vmm.ReadByte(SrcOffset)); - } - } - - private long MakeInt64From2xInt32(NvGpuEngineDmaReg Reg) - { - return - (long)Registers[(int)Reg + 0] << 32 | - (uint)Registers[(int)Reg + 1]; - } - - private void WriteRegister(NvGpuPBEntry PBEntry) - { - int ArgsCount = PBEntry.Arguments.Count; - - if (ArgsCount > 0) - { - Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1]; - } - } - - private int ReadRegister(NvGpuEngineDmaReg Reg) - { - return Registers[(int)Reg]; - } - - private void WriteRegister(NvGpuEngineDmaReg Reg, int Value) - { - Registers[(int)Reg] = Value; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/NvGpuEngineM2mf.cs new file mode 100644 index 00000000..d6121280 --- /dev/null +++ b/Ryujinx.Graphics/NvGpuEngineM2mf.cs @@ -0,0 +1,192 @@ +using Ryujinx.Graphics.Memory; +using Ryujinx.Graphics.Texture; +using System.Collections.Generic; + +namespace Ryujinx.Graphics +{ + public class NvGpuEngineM2mf : INvGpuEngine + { + public int[] Registers { get; private set; } + + private NvGpu Gpu; + + private Dictionary Methods; + + public NvGpuEngineM2mf(NvGpu Gpu) + { + this.Gpu = Gpu; + + Registers = new int[0x1d6]; + + Methods = new Dictionary(); + + void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + { + while (Count-- > 0) + { + Methods.Add(Meth, Method); + + Meth += Stride; + } + } + + AddMethod(0xc0, 1, 1, Execute); + } + + public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) + { + Method(Vmm, PBEntry); + } + else + { + WriteRegister(PBEntry); + } + } + + private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + //TODO: Some registers and copy modes are still not implemented. + int Control = PBEntry.Arguments[0]; + + bool SrcLinear = ((Control >> 7) & 1) != 0; + bool DstLinear = ((Control >> 8) & 1) != 0; + bool Copy2d = ((Control >> 9) & 1) != 0; + + long SrcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress); + long DstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress); + + int SrcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch); + int DstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch); + + int XCount = ReadRegister(NvGpuEngineM2mfReg.XCount); + int YCount = ReadRegister(NvGpuEngineM2mfReg.YCount); + + int Swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle); + + int DstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim); + int DstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX); + int DstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY); + int DstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ); + int DstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY); + int DstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ); + + int SrcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim); + int SrcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX); + int SrcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY); + int SrcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ); + int SrcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY); + int SrcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ); + + int SrcCpp = ((Swizzle >> 20) & 7) + 1; + int DstCpp = ((Swizzle >> 24) & 7) + 1; + + int DstPosX = (DstPosXY >> 0) & 0xffff; + int DstPosY = (DstPosXY >> 16) & 0xffff; + + int SrcPosX = (SrcPosXY >> 0) & 0xffff; + int SrcPosY = (SrcPosXY >> 16) & 0xffff; + + int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); + int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); + + long SrcPA = Vmm.GetPhysicalAddress(SrcAddress); + long DstPA = Vmm.GetPhysicalAddress(DstAddress); + + if (Copy2d) + { + if (SrcLinear) + { + SrcPosX = SrcPosY = SrcPosZ = 0; + } + + if (DstLinear) + { + DstPosX = DstPosY = DstPosZ = 0; + } + + if (SrcLinear && DstLinear) + { + for (int Y = 0; Y < YCount; Y++) + { + int SrcOffset = (SrcPosY + Y) * SrcPitch + SrcPosX * SrcCpp; + int DstOffset = (DstPosY + Y) * DstPitch + DstPosX * DstCpp; + + long Src = SrcPA + (uint)SrcOffset; + long Dst = DstPA + (uint)DstOffset; + + Vmm.Memory.CopyBytes(Src, Dst, XCount * SrcCpp); + } + } + else + { + ISwizzle SrcSwizzle; + + if (SrcLinear) + { + SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp); + } + else + { + SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcCpp, SrcBlockHeight); + } + + ISwizzle DstSwizzle; + + if (DstLinear) + { + DstSwizzle = new LinearSwizzle(DstPitch, DstCpp); + } + else + { + DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstCpp, DstBlockHeight); + } + + for (int Y = 0; Y < YCount; Y++) + for (int X = 0; X < XCount; X++) + { + int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y); + int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y); + + long Src = SrcPA + (uint)SrcOffset; + long Dst = DstPA + (uint)DstOffset; + + Vmm.Memory.CopyBytes(Src, Dst, SrcCpp); + } + } + } + else + { + Vmm.Memory.CopyBytes(SrcPA, DstPA, XCount); + } + } + + private long MakeInt64From2xInt32(NvGpuEngineM2mfReg Reg) + { + return + (long)Registers[(int)Reg + 0] << 32 | + (uint)Registers[(int)Reg + 1]; + } + + private void WriteRegister(NvGpuPBEntry PBEntry) + { + int ArgsCount = PBEntry.Arguments.Count; + + if (ArgsCount > 0) + { + Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1]; + } + } + + private int ReadRegister(NvGpuEngineM2mfReg Reg) + { + return Registers[(int)Reg]; + } + + private void WriteRegister(NvGpuEngineM2mfReg Reg, int Value) + { + Registers[(int)Reg] = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/NvGpuEngineDmaReg.cs b/Ryujinx.Graphics/NvGpuEngineM2mfReg.cs similarity index 81% rename from Ryujinx.Graphics/NvGpuEngineDmaReg.cs rename to Ryujinx.Graphics/NvGpuEngineM2mfReg.cs index b0fa1fbf..170e0b7b 100644 --- a/Ryujinx.Graphics/NvGpuEngineDmaReg.cs +++ b/Ryujinx.Graphics/NvGpuEngineM2mfReg.cs @@ -1,11 +1,14 @@ namespace Ryujinx.Graphics { - enum NvGpuEngineDmaReg + enum NvGpuEngineM2mfReg { SrcAddress = 0x100, DstAddress = 0x102, SrcPitch = 0x104, DstPitch = 0x105, + XCount = 0x106, + YCount = 0x107, + Swizzle = 0x1c2, DstBlkDim = 0x1c3, DstSizeX = 0x1c4, DstSizeY = 0x1c5, diff --git a/Ryujinx.Graphics/NvGpuEngineP2mf.cs b/Ryujinx.Graphics/NvGpuEngineP2mf.cs new file mode 100644 index 00000000..842dfc52 --- /dev/null +++ b/Ryujinx.Graphics/NvGpuEngineP2mf.cs @@ -0,0 +1,102 @@ +using Ryujinx.Graphics.Memory; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Ryujinx.Graphics +{ + public class NvGpuEngineP2mf : INvGpuEngine + { + public int[] Registers { get; private set; } + + private NvGpu Gpu; + + private Dictionary Methods; + + private ReadOnlyCollection DataBuffer; + + public NvGpuEngineP2mf(NvGpu Gpu) + { + this.Gpu = Gpu; + + Registers = new int[0x80]; + + Methods = new Dictionary(); + + void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + { + while (Count-- > 0) + { + Methods.Add(Meth, Method); + + Meth += Stride; + } + } + + AddMethod(0x6c, 1, 1, Execute); + AddMethod(0x6d, 1, 1, PushData); + } + + public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) + { + Method(Vmm, PBEntry); + } + else + { + WriteRegister(PBEntry); + } + } + + private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + //TODO: Some registers and copy modes are still not implemented. + int Control = PBEntry.Arguments[0]; + + long DstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress); + + int LineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn); + + DataBuffer = null; + + Gpu.Fifo.Step(); + + for (int Offset = 0; Offset < LineLengthIn; Offset += 4) + { + Vmm.WriteInt32(DstAddress + Offset, DataBuffer[Offset >> 2]); + } + } + + private void PushData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + DataBuffer = PBEntry.Arguments; + } + + private long MakeInt64From2xInt32(NvGpuEngineP2mfReg Reg) + { + return + (long)Registers[(int)Reg + 0] << 32 | + (uint)Registers[(int)Reg + 1]; + } + + private void WriteRegister(NvGpuPBEntry PBEntry) + { + int ArgsCount = PBEntry.Arguments.Count; + + if (ArgsCount > 0) + { + Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1]; + } + } + + private int ReadRegister(NvGpuEngineP2mfReg Reg) + { + return Registers[(int)Reg]; + } + + private void WriteRegister(NvGpuEngineP2mfReg Reg, int Value) + { + Registers[(int)Reg] = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/NvGpuEngineP2mfReg.cs b/Ryujinx.Graphics/NvGpuEngineP2mfReg.cs new file mode 100644 index 00000000..803ed299 --- /dev/null +++ b/Ryujinx.Graphics/NvGpuEngineP2mfReg.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Graphics +{ + enum NvGpuEngineP2mfReg + { + LineLengthIn = 0x60, + LineCount = 0x61, + DstAddress = 0x62, + DstPitch = 0x64, + DstBlockDim = 0x65, + DstWidth = 0x66, + DstHeight = 0x67, + DstDepth = 0x68, + DstZ = 0x69, + DstX = 0x6a, + DstY = 0x6b + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/NvGpuFifo.cs b/Ryujinx.Graphics/NvGpuFifo.cs index 3b79a055..16d16f5e 100644 --- a/Ryujinx.Graphics/NvGpuFifo.cs +++ b/Ryujinx.Graphics/NvGpuFifo.cs @@ -94,6 +94,8 @@ namespace Ryujinx.Graphics Gpu.Engine3d.ResetCache(); + Gpu.ResourceManager.ClearPbCache(); + CurrPbEntryIndex = 0; } @@ -103,20 +105,36 @@ namespace Ryujinx.Graphics } private void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + if ((NvGpuFifoMeth)PBEntry.Method == NvGpuFifoMeth.BindChannel) + { + NvGpuEngine Engine = (NvGpuEngine)PBEntry.Arguments[0]; + + SubChannels[PBEntry.SubChannel] = Engine; + } + else + { + switch (SubChannels[PBEntry.SubChannel]) + { + case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break; + case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break; + case NvGpuEngine.P2mf: CallP2mfMethod(Vmm, PBEntry); break; + case NvGpuEngine.M2mf: CallM2mfMethod(Vmm, PBEntry); break; + } + } + } + + private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + Gpu.Engine2d.CallMethod(Vmm, PBEntry); + } + + private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { if (PBEntry.Method < 0x80) { switch ((NvGpuFifoMeth)PBEntry.Method) { - case NvGpuFifoMeth.BindChannel: - { - NvGpuEngine Engine = (NvGpuEngine)PBEntry.Arguments[0]; - - SubChannels[PBEntry.SubChannel] = Engine; - - break; - } - case NvGpuFifoMeth.SetMacroUploadAddress: { CurrMacroPosition = PBEntry.Arguments[0]; @@ -150,25 +168,7 @@ namespace Ryujinx.Graphics } } } - else - { - switch (SubChannels[PBEntry.SubChannel]) - { - case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break; - case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break; - case NvGpuEngine.Dma: CallDmaMethod(Vmm, PBEntry); break; - } - } - } - - private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) - { - Gpu.Engine2d.CallMethod(Vmm, PBEntry); - } - - private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) - { - if (PBEntry.Method < 0xe00) + else if (PBEntry.Method < 0xe00) { Gpu.Engine3d.CallMethod(Vmm, PBEntry); } @@ -190,9 +190,14 @@ namespace Ryujinx.Graphics } } - private void CallDmaMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + private void CallP2mfMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { - Gpu.EngineDma.CallMethod(Vmm, PBEntry); + Gpu.EngineP2mf.CallMethod(Vmm, PBEntry); + } + + private void CallM2mfMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + Gpu.EngineM2mf.CallMethod(Vmm, PBEntry); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Texture/ImageUtils.cs b/Ryujinx.Graphics/Texture/ImageUtils.cs index f6db0894..7d3dde49 100644 --- a/Ryujinx.Graphics/Texture/ImageUtils.cs +++ b/Ryujinx.Graphics/Texture/ImageUtils.cs @@ -1,33 +1,37 @@ -using Ryujinx.Graphics.Gal; +using ChocolArm64.Memory; +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Memory; using System; using System.Collections.Generic; namespace Ryujinx.Graphics.Texture { - static class ImageUtils + public static class ImageUtils { - struct ImageDescriptor + [Flags] + private enum TargetBuffer { - public TextureReaderDelegate Reader; + Color = 1 << 0, + Depth = 1 << 1, + Stencil = 1 << 2, - public bool HasColor; - public bool HasDepth; - public bool HasStencil; + DepthStencil = Depth | Stencil + } - public bool Compressed; + private struct ImageDescriptor + { + public int BytesPerPixel { get; private set; } + public int BlockWidth { get; private set; } + public int BlockHeight { get; private set; } - public ImageDescriptor( - TextureReaderDelegate Reader, - bool HasColor, - bool HasDepth, - bool HasStencil, - bool Compressed) + public TargetBuffer Target { get; private set; } + + public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, TargetBuffer Target) { - this.Reader = Reader; - this.HasColor = HasColor; - this.HasDepth = HasDepth; - this.HasStencil = HasStencil; - this.Compressed = Compressed; + this.BytesPerPixel = BytesPerPixel; + this.BlockWidth = BlockWidth; + this.BlockHeight = BlockHeight; + this.Target = Target; } } @@ -48,6 +52,7 @@ namespace Ryujinx.Graphics.Texture { 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.R16G16, GalImageFormat.R16G16 | Snorm }, { GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Sfloat }, { GalTextureFormat.A4B4G4R4, GalImageFormat.A4B4G4R4 | Unorm }, { GalTextureFormat.A1B5G5R5, GalImageFormat.A1R5G5B5 | Unorm }, @@ -85,58 +90,58 @@ namespace Ryujinx.Graphics.Texture private static readonly Dictionary s_ImageTable = new Dictionary() - { - { 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.R32G32B32A32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R16G16B16A16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R32G32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.A8B8G8R8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.A2B10G10R10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.A4B4G4R4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BC6H_SF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC6H_UF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.A1R5G5B5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.B5G6R5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BC7, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.R16G16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R8G8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.G8R8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.B10G11R11, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BC1_RGBA, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.ASTC_4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.ASTC_5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) }, + { GalImageFormat.ASTC_6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) }, + { GalImageFormat.ASTC_8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) }, + { GalImageFormat.ASTC_10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) }, + { GalImageFormat.ASTC_12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) }, + { GalImageFormat.ASTC_5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) }, + { GalImageFormat.ASTC_6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) }, + { GalImageFormat.ASTC_8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) }, + { GalImageFormat.ASTC_10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) }, + { GalImageFormat.ASTC_12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) }, + { GalImageFormat.ASTC_8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) }, + { GalImageFormat.ASTC_10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) }, + { GalImageFormat.ASTC_10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) }, - { 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) }, - }; + { GalImageFormat.D24_S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) }, + { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D32_S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) }, + }; public static GalImageFormat ConvertTexture( GalTextureFormat Format, - GalTextureType RType, - GalTextureType GType, - GalTextureType BType, - GalTextureType AType) + GalTextureType RType, + GalTextureType GType, + GalTextureType BType, + GalTextureType AType) { if (RType != GType || RType != BType || RType != AType) { @@ -202,128 +207,157 @@ namespace Ryujinx.Graphics.Texture 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; + case GalZetaFormat.Z24S8Unorm: return GalImageFormat.D24_S8 | Unorm; + case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Sfloat; } throw new NotImplementedException(Format.ToString()); } - public static TextureReaderDelegate GetReader(GalImageFormat Format) + public static byte[] ReadTexture(IAMemory Memory, GalImage Image, long Position) { - return GetImageDescriptor(Format).Reader; + AMemory CpuMemory; + + if (Memory is NvGpuVmm Vmm) + { + CpuMemory = Vmm.Memory; + } + else + { + CpuMemory = (AMemory)Memory; + } + + ISwizzle Swizzle = TextureHelper.GetSwizzle(Image); + + ImageDescriptor Desc = GetImageDescriptor(Image.Format); + + (int Width, int Height) = GetImageSizeInBlocks(Image); + + int BytesPerPixel = Desc.BytesPerPixel; + + int OutOffs = 0; + + byte[] Data = new byte[Width * Height * BytesPerPixel]; + + for (int Y = 0; Y < Height; Y++) + for (int X = 0; X < Width; X++) + { + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + + CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel); + + OutOffs += BytesPerPixel; + } + + return Data; + } + + public static void WriteTexture(NvGpuVmm Vmm, GalImage Image, long Position, byte[] Data) + { + ISwizzle Swizzle = TextureHelper.GetSwizzle(Image); + + ImageDescriptor Desc = GetImageDescriptor(Image.Format); + + (int Width, int Height) = ImageUtils.GetImageSizeInBlocks(Image); + + int BytesPerPixel = Desc.BytesPerPixel; + + int InOffs = 0; + + for (int Y = 0; Y < Height; Y++) + for (int X = 0; X < Width; X++) + { + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + + Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel); + + InOffs += BytesPerPixel; + } } public static int GetSize(GalImage Image) { - switch (Image.Format & GalImageFormat.FormatMask) + ImageDescriptor Desc = GetImageDescriptor(Image.Format); + + int Width = DivRoundUp(Image.Width, Desc.BlockWidth); + int Height = DivRoundUp(Image.Height, Desc.BlockHeight); + + return Desc.BytesPerPixel * Width * Height; + } + + public static int GetPitch(GalImageFormat Format, int Width) + { + ImageDescriptor Desc = GetImageDescriptor(Format); + + return Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth); + } + + public static int GetBlockWidth(GalImageFormat Format) + { + return GetImageDescriptor(Format).BlockWidth; + } + + public static int GetBlockHeight(GalImageFormat Format) + { + return GetImageDescriptor(Format).BlockHeight; + } + + public static int GetAlignedWidth(GalImage Image) + { + ImageDescriptor Desc = GetImageDescriptor(Image.Format); + + int AlignMask; + + if (Image.Layout == GalMemoryLayout.BlockLinear) { - 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.G8R8: - 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); + AlignMask = Image.TileWidth * (64 / Desc.BytesPerPixel) - 1; + } + else + { + AlignMask = (32 / Desc.BytesPerPixel) - 1; } - throw new NotImplementedException((Image.Format & GalImageFormat.FormatMask).ToString()); + return (Image.Width + AlignMask) & ~AlignMask; + } + + public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image) + { + ImageDescriptor Desc = GetImageDescriptor(Image.Format); + + return (DivRoundUp(Image.Width, Desc.BlockWidth), + DivRoundUp(Image.Height, Desc.BlockHeight)); + } + + public static int GetBytesPerPixel(GalImageFormat Format) + { + return GetImageDescriptor(Format).BytesPerPixel; + } + + private static int DivRoundUp(int LHS, int RHS) + { + return (LHS + (RHS - 1)) / RHS; } public static bool HasColor(GalImageFormat Format) { - return GetImageDescriptor(Format).HasColor; + return (GetImageDescriptor(Format).Target & TargetBuffer.Color) != 0; } public static bool HasDepth(GalImageFormat Format) { - return GetImageDescriptor(Format).HasDepth; + return (GetImageDescriptor(Format).Target & TargetBuffer.Depth) != 0; } public static bool HasStencil(GalImageFormat Format) { - return GetImageDescriptor(Format).HasStencil; + return (GetImageDescriptor(Format).Target & TargetBuffer.Stencil) != 0; } public static bool IsCompressed(GalImageFormat Format) { - return GetImageDescriptor(Format).Compressed; + ImageDescriptor Desc = GetImageDescriptor(Format); + + return (Desc.BlockWidth | Desc.BlockHeight) != 1; } private static ImageDescriptor GetImageDescriptor(GalImageFormat Format) @@ -351,13 +385,5 @@ namespace Ryujinx.Graphics.Texture 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; - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Texture/TextureFactory.cs b/Ryujinx.Graphics/Texture/TextureFactory.cs index fa7a0f80..766c53da 100644 --- a/Ryujinx.Graphics/Texture/TextureFactory.cs +++ b/Ryujinx.Graphics/Texture/TextureFactory.cs @@ -17,44 +17,20 @@ namespace Ryujinx.Graphics.Texture 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); + GalMemoryLayout Layout; + if (Swizzle == TextureSwizzle.BlockLinear || Swizzle == TextureSwizzle.BlockLinearColorKey) { - TextureAddress &= ~0x1ffL; + Layout = GalMemoryLayout.BlockLinear; } - else if (Swizzle == TextureSwizzle.Pitch || - Swizzle == TextureSwizzle.PitchColorKey) + else { - TextureAddress &= ~0x1fL; + Layout = GalMemoryLayout.Pitch; } - int Pitch = (Tic[3] & 0xffff) << 5; - int BlockHeightLog2 = (Tic[3] >> 3) & 7; int TileWidthLog2 = (Tic[3] >> 10) & 7; @@ -64,17 +40,17 @@ namespace Ryujinx.Graphics.Texture int Width = (Tic[4] & 0xffff) + 1; int Height = (Tic[5] & 0xffff) + 1; - TextureInfo Texture = new TextureInfo( - TextureAddress, + return new GalImage( Width, Height, - Pitch, - BlockHeight, TileWidth, - Swizzle, - Format); - - return TextureReader.Read(Vmm, Texture); + BlockHeight, + Layout, + Format, + XSource, + YSource, + ZSource, + WSource); } public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition) @@ -107,7 +83,7 @@ namespace Ryujinx.Graphics.Texture private static GalImageFormat GetImageFormat(int[] Tic) { - GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7); + 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); diff --git a/Ryujinx.Graphics/Texture/TextureHelper.cs b/Ryujinx.Graphics/Texture/TextureHelper.cs index 8130ab41..9e966e6b 100644 --- a/Ryujinx.Graphics/Texture/TextureHelper.cs +++ b/Ryujinx.Graphics/Texture/TextureHelper.cs @@ -1,33 +1,30 @@ 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) + public static ISwizzle GetSwizzle(GalImage Image) { - int Width = (Texture.Width + (BlockWidth - 1)) / BlockWidth; + int BlockWidth = ImageUtils.GetBlockWidth (Image.Format); + int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format); - int AlignMask = Texture.TileWidth * (64 / Bpp) - 1; + int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth; - Width = (Width + AlignMask) & ~AlignMask; - - switch (Texture.Swizzle) + if (Image.Layout == GalMemoryLayout.BlockLinear) { - case TextureSwizzle._1dBuffer: - case TextureSwizzle.Pitch: - case TextureSwizzle.PitchColorKey: - return new LinearSwizzle(Texture.Pitch, Bpp); + int AlignMask = Image.TileWidth * (64 / BytesPerPixel) - 1; - case TextureSwizzle.BlockLinear: - case TextureSwizzle.BlockLinearColorKey: - return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight); + Width = (Width + AlignMask) & ~AlignMask; + + return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight); + } + else + { + return new LinearSwizzle(Image.Pitch, BytesPerPixel); } - - throw new NotImplementedException(Texture.Swizzle.ToString()); } public static (AMemory Memory, long Position) GetMemoryAndPosition( diff --git a/Ryujinx.Graphics/Texture/TextureInfo.cs b/Ryujinx.Graphics/Texture/TextureInfo.cs deleted file mode 100644 index 66445dcc..00000000 --- a/Ryujinx.Graphics/Texture/TextureInfo.cs +++ /dev/null @@ -1,60 +0,0 @@ -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; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Texture/TextureReader.cs b/Ryujinx.Graphics/Texture/TextureReader.cs deleted file mode 100644 index dbaed1a8..00000000 --- a/Ryujinx.Graphics/Texture/TextureReader.cs +++ /dev/null @@ -1,398 +0,0 @@ -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); - } - } -} diff --git a/Ryujinx.Graphics/Texture/TextureWriter.cs b/Ryujinx.Graphics/Texture/TextureWriter.cs deleted file mode 100644 index 16e78c56..00000000 --- a/Ryujinx.Graphics/Texture/TextureWriter.cs +++ /dev/null @@ -1,35 +0,0 @@ -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; - } - } - } - } -} diff --git a/Ryujinx.Graphics/ValueRange.cs b/Ryujinx.Graphics/ValueRange.cs new file mode 100644 index 00000000..6298bd8e --- /dev/null +++ b/Ryujinx.Graphics/ValueRange.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Graphics +{ + struct ValueRange + { + public long Start { get; private set; } + public long End { get; private set; } + + public T Value { get; set; } + + public ValueRange(long Start, long End, T Value = default(T)) + { + this.Start = Start; + this.End = End; + this.Value = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/ValueRangeSet.cs b/Ryujinx.Graphics/ValueRangeSet.cs new file mode 100644 index 00000000..479f41ed --- /dev/null +++ b/Ryujinx.Graphics/ValueRangeSet.cs @@ -0,0 +1,234 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics +{ + class ValueRangeSet + { + private List> Ranges; + + public ValueRangeSet() + { + Ranges = new List>(); + } + + public void Add(ValueRange Range) + { + if (Range.End <= Range.Start) + { + //Empty or invalid range, do nothing. + return; + } + + int First = BinarySearchFirstIntersection(Range); + + if (First == -1) + { + //No intersections case. + //Find first greater than range (after the current one). + //If found, add before, otherwise add to the end of the list. + int GtIndex = BinarySearchGt(Range); + + if (GtIndex != -1) + { + Ranges.Insert(GtIndex, Range); + } + else + { + Ranges.Add(Range); + } + + return; + } + + (int Start, int End) = GetAllIntersectionRanges(Range, First); + + ValueRange Prev = Ranges[Start]; + ValueRange Next = Ranges[End]; + + Ranges.RemoveRange(Start, (End - Start) + 1); + + InsertNextNeighbour(Start, Range, Next); + + int NewIndex = Start; + + Ranges.Insert(Start, Range); + + InsertPrevNeighbour(Start, Range, Prev); + + //Try merging neighbours if the value is equal. + if (NewIndex > 0) + { + Prev = Ranges[NewIndex - 1]; + + if (Prev.End == Range.Start && CompareValues(Prev, Range)) + { + Ranges.RemoveAt(--NewIndex); + + Ranges[NewIndex] = new ValueRange(Prev.Start, Range.End, Range.Value); + } + } + + if (NewIndex < Ranges.Count - 1) + { + Next = Ranges[NewIndex + 1]; + + if (Next.Start == Range.End && CompareValues(Next, Range)) + { + Ranges.RemoveAt(NewIndex + 1); + + Ranges[NewIndex] = new ValueRange(Range.Start, Next.End, Range.Value); + } + } + } + + private bool CompareValues(ValueRange LHS, ValueRange RHS) + { + return LHS.Value?.Equals(RHS.Value) ?? RHS.Value == null; + } + + public void Remove(ValueRange Range) + { + int First = BinarySearchFirstIntersection(Range); + + if (First == -1) + { + //Nothing to remove. + return; + } + + (int Start, int End) = GetAllIntersectionRanges(Range, First); + + ValueRange Prev = Ranges[Start]; + ValueRange Next = Ranges[End]; + + Ranges.RemoveRange(Start, (End - Start) + 1); + + InsertNextNeighbour(Start, Range, Next); + InsertPrevNeighbour(Start, Range, Prev); + } + + private void InsertNextNeighbour(int Index, ValueRange Range, ValueRange Next) + { + //Split last intersection (ordered by Start) if necessary. + if (Range.End < Next.End) + { + InsertNewRange(Index, Range.End, Next.End, Next.Value); + } + } + + private void InsertPrevNeighbour(int Index, ValueRange Range, ValueRange Prev) + { + //Split first intersection (ordered by Start) if necessary. + if (Range.Start > Prev.Start) + { + InsertNewRange(Index, Prev.Start, Range.Start, Prev.Value); + } + } + + private void InsertNewRange(int Index, long Start, long End, T Value) + { + Ranges.Insert(Index, new ValueRange(Start, End, Value)); + } + + public ValueRange[] GetAllIntersections(ValueRange Range) + { + int First = BinarySearchFirstIntersection(Range); + + if (First == -1) + { + return new ValueRange[0]; + } + + (int Start, int End) = GetAllIntersectionRanges(Range, First); + + return Ranges.GetRange(Start, (End - Start) + 1).ToArray(); + } + + private (int Start, int End) GetAllIntersectionRanges(ValueRange Range, int BaseIndex) + { + int Start = BaseIndex; + int End = BaseIndex; + + while (Start > 0 && Intersects(Range, Ranges[Start - 1])) + { + Start--; + } + + while (End < Ranges.Count - 1 && Intersects(Range, Ranges[End + 1])) + { + End++; + } + + return (Start, End); + } + + private int BinarySearchFirstIntersection(ValueRange Range) + { + int Left = 0; + int Right = Ranges.Count - 1; + + while (Left <= Right) + { + int Size = Right - Left; + + int Middle = Left + (Size >> 1); + + ValueRange Current = Ranges[Middle]; + + if (Intersects(Range, Current)) + { + return Middle; + } + + if (Range.Start < Current.Start) + { + Right = Middle - 1; + } + else + { + Left = Middle + 1; + } + } + + return -1; + } + + private int BinarySearchGt(ValueRange Range) + { + int GtIndex = -1; + + int Left = 0; + int Right = Ranges.Count - 1; + + while (Left <= Right) + { + int Size = Right - Left; + + int Middle = Left + (Size >> 1); + + ValueRange Current = Ranges[Middle]; + + if (Range.Start < Current.Start) + { + Right = Middle - 1; + + if (GtIndex == -1 || Current.Start < Ranges[GtIndex].Start) + { + GtIndex = Middle; + } + } + else + { + Left = Middle + 1; + } + } + + return GtIndex; + } + + private bool Intersects(ValueRange LHS, ValueRange RHS) + { + return LHS.Start < RHS.End && RHS.Start < LHS.End; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs index 7cc1c858..d10eb117 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs @@ -288,7 +288,8 @@ namespace Ryujinx.HLE.HOS.Kernel //Fail for info not available on older Kernel versions. if (InfoType == 18 || InfoType == 19 || - InfoType == 20) + InfoType == 20 || + InfoType == 21) { ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); diff --git a/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs b/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs index 316f16d0..f68c8191 100644 --- a/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs +++ b/Ryujinx.HLE/HOS/Services/Acc/IProfile.cs @@ -3,7 +3,6 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Logging; using Ryujinx.HLE.Utilities; -using System; using System.Collections.Generic; using System.IO; using System.Reflection; diff --git a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs index bf5f20a2..19e0d949 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs @@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi public override IReadOnlyDictionary Commands => m_Commands; - private KEvent ReleaseEvent; + private KEvent BinderEvent; private NvFlinger Flinger; @@ -27,9 +27,11 @@ namespace Ryujinx.HLE.HOS.Services.Vi { 3, TransactParcelAuto } }; - ReleaseEvent = new KEvent(); + BinderEvent = new KEvent(); - Flinger = new NvFlinger(Renderer, ReleaseEvent); + BinderEvent.WaitEvent.Set(); + + Flinger = new NvFlinger(Renderer, BinderEvent); } public long TransactParcel(ServiceCtx Context) @@ -75,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi int Id = Context.RequestData.ReadInt32(); uint Unk = Context.RequestData.ReadUInt32(); - int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); + int Handle = Context.Process.HandleTable.OpenHandle(BinderEvent); Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); @@ -91,7 +93,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi { if (Disposing) { - ReleaseEvent.Dispose(); + BinderEvent.Dispose(); Flinger.Dispose(); } diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs index 2a6918c4..a8493758 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs @@ -1,6 +1,7 @@ using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Texture; +using Ryujinx.Graphics.Memory; using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; using Ryujinx.HLE.HOS.Services.Nv.NvMap; using Ryujinx.HLE.Logging; using System; @@ -19,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Android private Dictionary<(string, int), ServiceProcessParcel> Commands; - private KEvent ReleaseEvent; + private KEvent BinderEvent; private IGalRenderer Renderer; @@ -67,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Android private bool Disposed; - public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent) + public NvFlinger(IGalRenderer Renderer, KEvent BinderEvent) { Commands = new Dictionary<(string, int), ServiceProcessParcel>() { @@ -82,8 +83,8 @@ namespace Ryujinx.HLE.HOS.Services.Android { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } }; - this.Renderer = Renderer; - this.ReleaseEvent = ReleaseEvent; + this.Renderer = Renderer; + this.BinderEvent = BinderEvent; BufferQueue = new BufferEntry[0x40]; @@ -301,42 +302,41 @@ namespace Ryujinx.HLE.HOS.Services.Android bool FlipX = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX); bool FlipY = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY); - //Rotation is being ignored + //Note: Rotation is being ignored. int Top = Crop.Top; int Left = Crop.Left; int Right = Crop.Right; int Bottom = Crop.Bottom; - Renderer.QueueAction(() => Renderer.RenderTarget.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom)); + NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm; - //TODO: Support double buffering here aswell, it is broken for GPU - //frame buffers because it seems to be completely out of sync. - if (Context.Device.Gpu.Engine3d.IsFrameBufferPosition(FbAddr)) + Renderer.QueueAction(() => { - //Frame buffer is rendered to by the GPU, we can just - //bind the frame buffer texture, it's not necessary to read anything. - Renderer.QueueAction(() => Renderer.RenderTarget.Set(FbAddr)); - } - else - { - //Frame buffer is not set on the GPU registers, in this case - //assume that the app is manually writing to it. - TextureInfo Texture = new TextureInfo(FbAddr, FbWidth, FbHeight); + if (!Renderer.Texture.TryGetImage(FbAddr, out GalImage Image)) + { + Image = new GalImage( + FbWidth, + FbHeight, 1, 16, + GalMemoryLayout.BlockLinear, + GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm); + } - byte[] Data = TextureReader.Read(Context.Memory, Texture); + Context.Device.Gpu.ResourceManager.ClearPbCache(); + Context.Device.Gpu.ResourceManager.SendTexture(Vmm, FbAddr, Image); - Renderer.QueueAction(() => Renderer.RenderTarget.Set(Data, FbWidth, FbHeight)); - } + Renderer.RenderTarget.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom); + Renderer.RenderTarget.Set(FbAddr); - Context.Device.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot)); + ReleaseBuffer(Slot); + }); } private void ReleaseBuffer(int Slot) { BufferQueue[Slot].State = BufferState.Free; - ReleaseEvent.WaitEvent.Set(); + BinderEvent.WaitEvent.Set(); lock (WaitBufferFree) {