Sfoglia il codice sorgente

Add a GetSpan method to the memory manager and use it on GPU (#877)

gdkchan 6 anni fa
parent
commit
b8e3909d80

+ 45 - 0
ARMeilleure/Memory/MemoryManager.cs

@@ -1,6 +1,7 @@
 using ARMeilleure.State;
 using System;
 using System.Collections.Generic;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Threading;
 
@@ -552,6 +553,50 @@ namespace ARMeilleure.Memory
             return data;
         }
 
+        public ReadOnlySpan<byte> GetSpan(ulong address, ulong size)
+        {
+            if (IsContiguous(address, size))
+            {
+                return new ReadOnlySpan<byte>((void*)Translate((long)address), (int)size);
+            }
+            else
+            {
+                return ReadBytes((long)address, (long)size);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private bool IsContiguous(ulong address, ulong size)
+        {
+            if (!IsValidPosition((long)address))
+            {
+                return false;
+            }
+
+            ulong endVa = (address + size + PageMask) & ~(ulong)PageMask;
+
+            address &= ~(ulong)PageMask;
+
+            int pages = (int)((endVa - address) / PageSize);
+
+            for (int page = 0; page < pages - 1; page++)
+            {
+                if (!IsValidPosition((long)address + PageSize))
+                {
+                    return false;
+                }
+
+                if (GetPtEntry((long)address) + PageSize != GetPtEntry((long)address + PageSize))
+                {
+                    return false;
+                }
+
+                address += PageSize;
+            }
+
+            return true;
+        }
+
         public void WriteSByte(long position, sbyte value)
         {
             WriteByte(position, (byte)value);

+ 2 - 2
Ryujinx.Graphics.GAL/IBuffer.cs

@@ -8,8 +8,8 @@ namespace Ryujinx.Graphics.GAL
 
         byte[] GetData(int offset, int size);
 
-        void SetData(Span<byte> data);
+        void SetData(ReadOnlySpan<byte> data);
 
-        void SetData(int offset, Span<byte> data);
+        void SetData(int offset, ReadOnlySpan<byte> data);
     }
 }

+ 1 - 1
Ryujinx.Graphics.GAL/ITexture.cs

@@ -11,6 +11,6 @@ namespace Ryujinx.Graphics.GAL
 
         byte[] GetData();
 
-        void SetData(Span<byte> data);
+        void SetData(ReadOnlySpan<byte> data);
     }
 }

+ 1 - 1
Ryujinx.Graphics.Gpu/Engine/Compute.cs

@@ -77,7 +77,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
                 sbDescAddress += (ulong)sbDescOffset;
 
-                Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
+                ReadOnlySpan<byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);
 
                 SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
 

+ 1 - 1
Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs

@@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
                     ulong srcAddress = srcBaseAddress + (ulong)srcOffset;
                     ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
 
-                    Span<byte> pixel = _context.PhysicalMemory.Read(srcAddress, (ulong)srcBpp);
+                    ReadOnlySpan<byte> pixel = _context.PhysicalMemory.GetSpan(srcAddress, (ulong)srcBpp);
 
                     _context.PhysicalMemory.Write(dstAddress, pixel);
                 }

+ 1 - 1
Ryujinx.Graphics.Gpu/Engine/Methods.cs

@@ -235,7 +235,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
                     sbDescAddress += (ulong)sbDescOffset;
 
-                    Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
+                    ReadOnlySpan<byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);
 
                     SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
 

+ 1 - 1
Ryujinx.Graphics.Gpu/Image/SamplerPool.cs

@@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             {
                 ulong address = Address + (ulong)(uint)id * DescriptorSize;
 
-                Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize);
+                ReadOnlySpan<byte> data = Context.PhysicalMemory.GetSpan(address, DescriptorSize);
 
                 SamplerDescriptor descriptor = MemoryMarshal.Cast<byte, SamplerDescriptor>(data)[0];
 

+ 1 - 1
Ryujinx.Graphics.Gpu/Image/Texture.cs

@@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 return;
             }
 
-            Span<byte> data = _context.PhysicalMemory.Read(Address, Size);
+            ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Address, Size);
 
             if (Info.IsLinear)
             {

+ 2 - 2
Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs

@@ -197,7 +197,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                         address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, binding.CbufSlot);
                     }
 
-                    packedId = MemoryMarshal.Cast<byte, int>(_context.PhysicalMemory.Read(address + (ulong)binding.CbufOffset * 4, 4))[0];
+                    packedId = MemoryMarshal.Cast<byte, int>(_context.PhysicalMemory.GetSpan(address + (ulong)binding.CbufOffset * 4, 4))[0];
                 }
                 else
                 {
@@ -321,7 +321,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             address += (uint)wordOffset * 4;
 
-            return BitConverter.ToInt32(_context.PhysicalMemory.Read(address, 4));
+            return BitConverter.ToInt32(_context.PhysicalMemory.GetSpan(address, 4));
         }
 
         /// <summary>

+ 2 - 2
Ryujinx.Graphics.Gpu/Image/TexturePool.cs

@@ -85,7 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Image
         {
             ulong address = Address + (ulong)(uint)id * DescriptorSize;
 
-            Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize);
+            ReadOnlySpan<byte> data = Context.PhysicalMemory.GetSpan(address, DescriptorSize);
 
             return MemoryMarshal.Cast<byte, TextureDescriptor>(data)[0];
         }
@@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
                 if (texture != null)
                 {
-                    Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize);
+                    ReadOnlySpan<byte> data = Context.PhysicalMemory.GetSpan(address, DescriptorSize);
 
                     TextureDescriptor descriptor = MemoryMarshal.Cast<byte, TextureDescriptor>(data)[0];
 

+ 2 - 2
Ryujinx.Graphics.Gpu/Memory/Buffer.cs

@@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
                 int offset = (int)(mAddress - Address);
 
-                HostBuffer.SetData(offset, _context.PhysicalMemory.Read(mAddress, mSize));
+                HostBuffer.SetData(offset, _context.PhysicalMemory.GetSpan(mAddress, mSize));
             }
         }
 
@@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
         /// </summary>
         public void Invalidate()
         {
-            HostBuffer.SetData(0, _context.PhysicalMemory.Read(Address, Size));
+            HostBuffer.SetData(0, _context.PhysicalMemory.GetSpan(Address, Size));
         }
 
         /// <summary>

+ 8 - 8
Ryujinx.Graphics.Gpu/Memory/MemoryAccessor.cs

@@ -27,23 +27,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
         /// <returns>Byte array with the data</returns>
         public byte[] ReadBytes(ulong gpuVa, ulong size)
         {
-            return Read(gpuVa, size).ToArray();
+            return GetSpan(gpuVa, size).ToArray();
         }
 
         /// <summary>
-        /// Reads data from GPU mapped memory.
+        /// Gets a read-only span of data from GPU mapped memory.
         /// This reads as much data as possible, up to the specified maximum size.
         /// </summary>
         /// <param name="gpuVa">GPU virtual address where the data is located</param>
         /// <param name="maxSize">Maximum size of the data</param>
-        /// <returns>The data at the specified memory location</returns>
-        public Span<byte> Read(ulong gpuVa, ulong maxSize)
+        /// <returns>The span of the data at the specified memory location</returns>
+        public ReadOnlySpan<byte> GetSpan(ulong gpuVa, ulong maxSize)
         {
             ulong processVa = _context.MemoryManager.Translate(gpuVa);
 
             ulong size = Math.Min(_context.MemoryManager.GetSubSize(gpuVa), maxSize);
 
-            return _context.PhysicalMemory.Read(processVa, size);
+            return _context.PhysicalMemory.GetSpan(processVa, size);
         }
 
         /// <summary>
@@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
             ulong size = (uint)Marshal.SizeOf<T>();
 
-            return MemoryMarshal.Cast<byte, T>(_context.PhysicalMemory.Read(processVa, size))[0];
+            return MemoryMarshal.Cast<byte, T>(_context.PhysicalMemory.GetSpan(processVa, size))[0];
         }
 
         /// <summary>
@@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
         {
             ulong processVa = _context.MemoryManager.Translate(gpuVa);
 
-            return BitConverter.ToInt32(_context.PhysicalMemory.Read(processVa, 4));
+            return BitConverter.ToInt32(_context.PhysicalMemory.GetSpan(processVa, 4));
         }
 
         /// <summary>
@@ -82,7 +82,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
         {
             ulong processVa = _context.MemoryManager.Translate(gpuVa);
 
-            return BitConverter.ToUInt64(_context.PhysicalMemory.Read(processVa, 8));
+            return BitConverter.ToUInt64(_context.PhysicalMemory.GetSpan(processVa, 8));
         }
 
         /// <summary>

+ 7 - 7
Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs

@@ -22,14 +22,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
         }
 
         /// <summary>
-        /// Reads data from the application process.
+        /// Gets a span of data from the application process.
         /// </summary>
-        /// <param name="address">Address to be read</param>
-        /// <param name="size">Size in bytes to be read</param>
-        /// <returns>The data at the specified memory location</returns>
-        public Span<byte> Read(ulong address, ulong size)
+        /// <param name="address">Start address of the range</param>
+        /// <param name="size">Size in bytes to be range</param>
+        /// <returns>A read only span of the data at the specified memory location</returns>
+        public ReadOnlySpan<byte> GetSpan(ulong address, ulong size)
         {
-            return _cpuMemory.ReadBytes((long)address, (long)size);
+            return _cpuMemory.GetSpan(address, size);
         }
 
         /// <summary>
@@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
         /// </summary>
         /// <param name="address">Address to write into</param>
         /// <param name="data">Data to be written</param>
-        public void Write(ulong address, Span<byte> data)
+        public void Write(ulong address, ReadOnlySpan<byte> data)
         {
             _cpuMemory.WriteBytes((long)address, data.ToArray());
         }

+ 4 - 4
Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs

@@ -265,7 +265,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
             ShaderProgram program;
 
-            Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
+            ReadOnlySpan<byte> code = _context.MemoryAccessor.GetSpan(gpuVa, MaxProgramSize);
 
             program = Translator.Translate(code, callbacks, DefaultFlags | TranslationFlags.Compute);
 
@@ -319,8 +319,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
             if (gpuVaA != 0)
             {
-                Span<byte> codeA = _context.MemoryAccessor.Read(gpuVaA, MaxProgramSize);
-                Span<byte> codeB = _context.MemoryAccessor.Read(gpuVa,  MaxProgramSize);
+                ReadOnlySpan<byte> codeA = _context.MemoryAccessor.GetSpan(gpuVaA, MaxProgramSize);
+                ReadOnlySpan<byte> codeB = _context.MemoryAccessor.GetSpan(gpuVa,  MaxProgramSize);
 
                 program = Translator.Translate(codeA, codeB, callbacks, DefaultFlags);
 
@@ -340,7 +340,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
             }
             else
             {
-                Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
+                ReadOnlySpan<byte> code = _context.MemoryAccessor.GetSpan(gpuVa, MaxProgramSize);
 
                 program = Translator.Translate(code, callbacks, DefaultFlags);
 

+ 1 - 1
Ryujinx.Graphics.Gpu/Shader/ShaderDumper.cs

@@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <param name="compute">True for compute shader code, false for graphics shader code</param>
         /// <param name="fullPath">Output path for the shader code with header included</param>
         /// <param name="codePath">Output path for the shader code without header</param>
-        public void Dump(Span<byte> code, bool compute, out string fullPath, out string codePath)
+        public void Dump(ReadOnlySpan<byte> code, bool compute, out string fullPath, out string codePath)
         {
             _dumpPath = GraphicsConfig.ShadersDumpPath;
 

+ 2 - 2
Ryujinx.Graphics.OpenGL/Buffer.cs

@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.OpenGL
             return data;
         }
 
-        public void SetData(Span<byte> data)
+        public void SetData(ReadOnlySpan<byte> data)
         {
             unsafe
             {
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
-        public void SetData(int offset, Span<byte> data)
+        public void SetData(int offset, ReadOnlySpan<byte> data)
         {
             GL.BindBuffer(BufferTarget.CopyWriteBuffer, Handle);
 

+ 1 - 1
Ryujinx.Graphics.OpenGL/TextureView.cs

@@ -217,7 +217,7 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
-        public void SetData(Span<byte> data)
+        public void SetData(ReadOnlySpan<byte> data)
         {
             unsafe
             {

+ 5 - 5
Ryujinx.Graphics.Shader/Decoders/Decoder.cs

@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
             _opActivators = new ConcurrentDictionary<Type, OpActivator>();
         }
 
-        public static Block[] Decode(Span<byte> code, ulong headerSize)
+        public static Block[] Decode(ReadOnlySpan<byte> code, ulong headerSize)
         {
             List<Block> blocks = new List<Block>();
 
@@ -214,10 +214,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
         }
 
         private static void FillBlock(
-            Span<byte> code,
-            Block      block,
-            ulong      limitAddress,
-            ulong      startAddress)
+            ReadOnlySpan<byte> code,
+            Block              block,
+            ulong              limitAddress,
+            ulong              startAddress)
         {
             ulong address = block.Address;
 

+ 2 - 2
Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs

@@ -76,9 +76,9 @@ namespace Ryujinx.Graphics.Shader.Translation
         public bool              OmapSampleMask { get; }
         public bool              OmapDepth      { get; }
 
-        public ShaderHeader(Span<byte> code)
+        public ShaderHeader(ReadOnlySpan<byte> code)
         {
-            Span<int> header = MemoryMarshal.Cast<byte, int>(code);
+            ReadOnlySpan<int> header = MemoryMarshal.Cast<byte, int>(code);
 
             int commonWord0 = header[0];
             int commonWord1 = header[1];

+ 4 - 4
Ryujinx.Graphics.Shader/Translation/Translator.cs

@@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
     {
         private const int HeaderSize = 0x50;
 
-        public static Span<byte> ExtractCode(Span<byte> code, bool compute, out int headerSize)
+        public static ReadOnlySpan<byte> ExtractCode(ReadOnlySpan<byte> code, bool compute, out int headerSize)
         {
             headerSize = compute ? 0 : HeaderSize;
 
@@ -38,14 +38,14 @@ namespace Ryujinx.Graphics.Shader.Translation
             return code.Slice(0, headerSize + (int)endAddress);
         }
 
-        public static ShaderProgram Translate(Span<byte> code, TranslatorCallbacks callbacks, TranslationFlags flags)
+        public static ShaderProgram Translate(ReadOnlySpan<byte> code, TranslatorCallbacks callbacks, TranslationFlags flags)
         {
             Operation[] ops = DecodeShader(code, callbacks, flags, out ShaderConfig config, out int size);
 
             return Translate(ops, config, size);
         }
 
-        public static ShaderProgram Translate(Span<byte> vpACode, Span<byte> vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags)
+        public static ShaderProgram Translate(ReadOnlySpan<byte> vpACode, ReadOnlySpan<byte> vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags)
         {
             Operation[] vpAOps = DecodeShader(vpACode, callbacks, flags, out _, out _);
             Operation[] vpBOps = DecodeShader(vpBCode, callbacks, flags, out ShaderConfig config, out int sizeB);
@@ -88,7 +88,7 @@ namespace Ryujinx.Graphics.Shader.Translation
         }
 
         private static Operation[] DecodeShader(
-            Span<byte>          code,
+            ReadOnlySpan<byte>  code,
             TranslatorCallbacks callbacks,
             TranslationFlags    flags,
             out ShaderConfig    config,