From 88f78ae6c83def8700235e153099190cc4cef890 Mon Sep 17 00:00:00 2001 From: Jonathan Goyvaerts Date: Sun, 12 Jan 2020 18:11:45 +0100 Subject: [PATCH 1/7] Get rid of unused class AboutInfo (#882) --- Ryujinx/Ui/AboutInfo.cs | 9 --------- Ryujinx/Ui/AboutWindow.cs | 2 -- 2 files changed, 11 deletions(-) delete mode 100644 Ryujinx/Ui/AboutInfo.cs diff --git a/Ryujinx/Ui/AboutInfo.cs b/Ryujinx/Ui/AboutInfo.cs deleted file mode 100644 index 01e0d81b57..0000000000 --- a/Ryujinx/Ui/AboutInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Ui -{ - internal struct AboutInfo - { - public string InstallVersion; - public string InstallCommit; - public string InstallBranch; - } -} \ No newline at end of file diff --git a/Ryujinx/Ui/AboutWindow.cs b/Ryujinx/Ui/AboutWindow.cs index 0332d7a48b..122dcaae1f 100644 --- a/Ryujinx/Ui/AboutWindow.cs +++ b/Ryujinx/Ui/AboutWindow.cs @@ -13,8 +13,6 @@ namespace Ryujinx.Ui { public class AboutWindow : Window { - private static AboutInfo AboutInformation { get; set; } - #pragma warning disable CS0649 #pragma warning disable IDE0044 [GUI] Window _aboutWin; From 2bb39ff03e7f8b4f3383d5a5383dc9cbd808f0b6 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 12 Jan 2020 19:12:40 -0300 Subject: [PATCH 2/7] Replace glFinish with barrier for WaitForIdle (#878) --- Ryujinx.Graphics.GAL/IPipeline.cs | 2 ++ Ryujinx.Graphics.GAL/IRenderer.cs | 2 -- Ryujinx.Graphics.Gpu/NvGpuFifo.cs | 2 +- Ryujinx.Graphics.OpenGL/Pipeline.cs | 5 +++++ Ryujinx.Graphics.OpenGL/Renderer.cs | 5 ----- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs index 1a502913b7..41e35dd40a 100644 --- a/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/Ryujinx.Graphics.GAL/IPipeline.cs @@ -4,6 +4,8 @@ namespace Ryujinx.Graphics.GAL { public interface IPipeline { + void Barrier(); + void ClearRenderTargetColor(int index, uint componentMask, ColorF color); void ClearRenderTargetDepthStencil( diff --git a/Ryujinx.Graphics.GAL/IRenderer.cs b/Ryujinx.Graphics.GAL/IRenderer.cs index 1139ba0609..56856b2368 100644 --- a/Ryujinx.Graphics.GAL/IRenderer.cs +++ b/Ryujinx.Graphics.GAL/IRenderer.cs @@ -18,8 +18,6 @@ namespace Ryujinx.Graphics.GAL ISampler CreateSampler(SamplerCreateInfo info); ITexture CreateTexture(TextureCreateInfo info); - void FlushPipelines(); - Capabilities GetCapabilities(); ulong GetCounter(CounterType type); diff --git a/Ryujinx.Graphics.Gpu/NvGpuFifo.cs b/Ryujinx.Graphics.Gpu/NvGpuFifo.cs index 853e5dfdd3..11a9e3fba4 100644 --- a/Ryujinx.Graphics.Gpu/NvGpuFifo.cs +++ b/Ryujinx.Graphics.Gpu/NvGpuFifo.cs @@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Gpu { _context.Methods.PerformDeferredDraws(); - _context.Renderer.FlushPipelines(); + _context.Renderer.Pipeline.Barrier(); break; } diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index 669cfe3e99..c9d8186f26 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -37,6 +37,11 @@ namespace Ryujinx.Graphics.OpenGL _clipDepthMode = ClipDepthMode.NegativeOneToOne; } + public void Barrier() + { + GL.MemoryBarrier(MemoryBarrierFlags.AllBarrierBits); + } + public void ClearRenderTargetColor(int index, uint componentMask, ColorF color) { GL.ColorMask( diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs index 29a0ea2954..ccb53397d1 100644 --- a/Ryujinx.Graphics.OpenGL/Renderer.cs +++ b/Ryujinx.Graphics.OpenGL/Renderer.cs @@ -55,11 +55,6 @@ namespace Ryujinx.Graphics.OpenGL return new TextureStorage(this, info).CreateDefaultView(); } - public void FlushPipelines() - { - GL.Finish(); - } - public Capabilities GetCapabilities() { return new Capabilities( From 8b90924c1ebf7e65d1f170df5dd1ac6c2596926f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 12 Jan 2020 19:14:50 -0300 Subject: [PATCH 3/7] Support instanced draw of quads" (#881) --- Ryujinx.Graphics.OpenGL/Pipeline.cs | 123 ++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 35 deletions(-) diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index c9d8186f26..e308becfe6 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -170,26 +170,35 @@ namespace Ryujinx.Graphics.OpenGL int firstVertex, int firstInstance) { - // TODO: Instanced rendering. int quadsCount = (vertexCount - 2) / 2; - int[] firsts = new int[quadsCount]; - int[] counts = new int[quadsCount]; - - firsts[0] = firstVertex; - counts[0] = 4; - - for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++) + if (firstInstance != 0 || instanceCount != 1) { - firsts[quadIndex] = firstVertex + quadIndex * 2; - counts[quadIndex] = 4; + for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + { + GL.DrawArraysInstancedBaseInstance(PrimitiveType.TriangleFan, firstVertex + quadIndex * 2, 4, instanceCount, firstInstance); + } } + else + { + int[] firsts = new int[quadsCount]; + int[] counts = new int[quadsCount]; - GL.MultiDrawArrays( - PrimitiveType.TriangleFan, - firsts, - counts, - quadsCount); + firsts[0] = firstVertex; + counts[0] = 4; + + for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++) + { + firsts[quadIndex] = firstVertex + quadIndex * 2; + counts[quadIndex] = 4; + } + + GL.MultiDrawArrays( + PrimitiveType.TriangleFan, + firsts, + counts, + quadsCount); + } } private void DrawImpl( @@ -282,31 +291,75 @@ namespace Ryujinx.Graphics.OpenGL int firstVertex, int firstInstance) { - // TODO: Instanced rendering. int quadsCount = indexCount / 4; - IntPtr[] indices = new IntPtr[quadsCount]; - - int[] counts = new int[quadsCount]; - - int[] baseVertices = new int[quadsCount]; - - for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + if (firstInstance != 0 || instanceCount != 1) { - indices[quadIndex] = indexBaseOffset + quadIndex * 4 * indexElemSize; - - counts[quadIndex] = 4; - - baseVertices[quadIndex] = firstVertex; + if (firstVertex != 0 && firstInstance != 0) + { + for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + { + GL.DrawElementsInstancedBaseVertexBaseInstance( + PrimitiveType.TriangleFan, + 4, + _elementsType, + indexBaseOffset + quadIndex * 4 * indexElemSize, + instanceCount, + firstVertex, + firstInstance); + } + } + else if (firstInstance != 0) + { + for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + { + GL.DrawElementsInstancedBaseInstance( + PrimitiveType.TriangleFan, + 4, + _elementsType, + indexBaseOffset + quadIndex * 4 * indexElemSize, + instanceCount, + firstInstance); + } + } + else + { + for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + { + GL.DrawElementsInstanced( + PrimitiveType.TriangleFan, + 4, + _elementsType, + indexBaseOffset + quadIndex * 4 * indexElemSize, + instanceCount); + } + } } + else + { + IntPtr[] indices = new IntPtr[quadsCount]; - GL.MultiDrawElementsBaseVertex( - PrimitiveType.TriangleFan, - counts, - _elementsType, - indices, - quadsCount, - baseVertices); + int[] counts = new int[quadsCount]; + + int[] baseVertices = new int[quadsCount]; + + for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + { + indices[quadIndex] = indexBaseOffset + quadIndex * 4 * indexElemSize; + + counts[quadIndex] = 4; + + baseVertices[quadIndex] = firstVertex; + } + + GL.MultiDrawElementsBaseVertex( + PrimitiveType.TriangleFan, + counts, + _elementsType, + indices, + quadsCount, + baseVertices); + } } private void DrawQuadStripIndexedImpl( From b8e3909d800ff5947683bb169d8efda2ef63d697 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 12 Jan 2020 20:27:50 -0300 Subject: [PATCH 4/7] Add a GetSpan method to the memory manager and use it on GPU (#877) --- ARMeilleure/Memory/MemoryManager.cs | 45 +++++++++++++++++++ Ryujinx.Graphics.GAL/IBuffer.cs | 4 +- Ryujinx.Graphics.GAL/ITexture.cs | 2 +- Ryujinx.Graphics.Gpu/Engine/Compute.cs | 2 +- .../Engine/MethodCopyBuffer.cs | 2 +- Ryujinx.Graphics.Gpu/Engine/Methods.cs | 2 +- Ryujinx.Graphics.Gpu/Image/SamplerPool.cs | 2 +- Ryujinx.Graphics.Gpu/Image/Texture.cs | 2 +- .../Image/TextureBindingsManager.cs | 4 +- Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 4 +- Ryujinx.Graphics.Gpu/Memory/Buffer.cs | 4 +- Ryujinx.Graphics.Gpu/Memory/MemoryAccessor.cs | 16 +++---- Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs | 14 +++--- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 8 ++-- Ryujinx.Graphics.Gpu/Shader/ShaderDumper.cs | 2 +- Ryujinx.Graphics.OpenGL/Buffer.cs | 4 +- Ryujinx.Graphics.OpenGL/TextureView.cs | 2 +- Ryujinx.Graphics.Shader/Decoders/Decoder.cs | 10 ++--- .../Translation/ShaderHeader.cs | 4 +- .../Translation/Translator.cs | 8 ++-- 20 files changed, 93 insertions(+), 48 deletions(-) diff --git a/ARMeilleure/Memory/MemoryManager.cs b/ARMeilleure/Memory/MemoryManager.cs index f813bd7e73..e4e8b2d26d 100644 --- a/ARMeilleure/Memory/MemoryManager.cs +++ b/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 GetSpan(ulong address, ulong size) + { + if (IsContiguous(address, size)) + { + return new ReadOnlySpan((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); diff --git a/Ryujinx.Graphics.GAL/IBuffer.cs b/Ryujinx.Graphics.GAL/IBuffer.cs index 000efd67aa..43e3769186 100644 --- a/Ryujinx.Graphics.GAL/IBuffer.cs +++ b/Ryujinx.Graphics.GAL/IBuffer.cs @@ -8,8 +8,8 @@ namespace Ryujinx.Graphics.GAL byte[] GetData(int offset, int size); - void SetData(Span data); + void SetData(ReadOnlySpan data); - void SetData(int offset, Span data); + void SetData(int offset, ReadOnlySpan data); } } \ No newline at end of file diff --git a/Ryujinx.Graphics.GAL/ITexture.cs b/Ryujinx.Graphics.GAL/ITexture.cs index f5bc1b4705..5278e3b74d 100644 --- a/Ryujinx.Graphics.GAL/ITexture.cs +++ b/Ryujinx.Graphics.GAL/ITexture.cs @@ -11,6 +11,6 @@ namespace Ryujinx.Graphics.GAL byte[] GetData(); - void SetData(Span data); + void SetData(ReadOnlySpan data); } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs index 1f52467126..d24d2d8d72 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs @@ -77,7 +77,7 @@ namespace Ryujinx.Graphics.Gpu.Engine sbDescAddress += (ulong)sbDescOffset; - Span sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10); + ReadOnlySpan sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10); SbDescriptor sbDescriptor = MemoryMarshal.Cast(sbDescriptorData)[0]; diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs index 6b6742ff10..9f638f504c 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs +++ b/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 pixel = _context.PhysicalMemory.Read(srcAddress, (ulong)srcBpp); + ReadOnlySpan pixel = _context.PhysicalMemory.GetSpan(srcAddress, (ulong)srcBpp); _context.PhysicalMemory.Write(dstAddress, pixel); } diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index 90935b34c0..823ac878a6 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -235,7 +235,7 @@ namespace Ryujinx.Graphics.Gpu.Engine sbDescAddress += (ulong)sbDescOffset; - Span sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10); + ReadOnlySpan sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10); SbDescriptor sbDescriptor = MemoryMarshal.Cast(sbDescriptorData)[0]; diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs index f10f800cd7..2abf96de90 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs @@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Gpu.Image { ulong address = Address + (ulong)(uint)id * DescriptorSize; - Span data = Context.PhysicalMemory.Read(address, DescriptorSize); + ReadOnlySpan data = Context.PhysicalMemory.GetSpan(address, DescriptorSize); SamplerDescriptor descriptor = MemoryMarshal.Cast(data)[0]; diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index e33de1fa4e..7d5e9079da 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Gpu.Image return; } - Span data = _context.PhysicalMemory.Read(Address, Size); + ReadOnlySpan data = _context.PhysicalMemory.GetSpan(Address, Size); if (Info.IsLinear) { diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 984d45a952..7cc7f04688 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -197,7 +197,7 @@ namespace Ryujinx.Graphics.Gpu.Image address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, binding.CbufSlot); } - packedId = MemoryMarshal.Cast(_context.PhysicalMemory.Read(address + (ulong)binding.CbufOffset * 4, 4))[0]; + packedId = MemoryMarshal.Cast(_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)); } /// diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index f6aede7979..a4f54c5206 100644 --- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -85,7 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Image { ulong address = Address + (ulong)(uint)id * DescriptorSize; - Span data = Context.PhysicalMemory.Read(address, DescriptorSize); + ReadOnlySpan data = Context.PhysicalMemory.GetSpan(address, DescriptorSize); return MemoryMarshal.Cast(data)[0]; } @@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Gpu.Image if (texture != null) { - Span data = Context.PhysicalMemory.Read(address, DescriptorSize); + ReadOnlySpan data = Context.PhysicalMemory.GetSpan(address, DescriptorSize); TextureDescriptor descriptor = MemoryMarshal.Cast(data)[0]; diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs index 4210ecb982..a0339cce69 100644 --- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs +++ b/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 /// public void Invalidate() { - HostBuffer.SetData(0, _context.PhysicalMemory.Read(Address, Size)); + HostBuffer.SetData(0, _context.PhysicalMemory.GetSpan(Address, Size)); } /// diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryAccessor.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryAccessor.cs index 1877933317..17c0006288 100644 --- a/Ryujinx.Graphics.Gpu/Memory/MemoryAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Memory/MemoryAccessor.cs @@ -27,23 +27,23 @@ namespace Ryujinx.Graphics.Gpu.Memory /// Byte array with the data public byte[] ReadBytes(ulong gpuVa, ulong size) { - return Read(gpuVa, size).ToArray(); + return GetSpan(gpuVa, size).ToArray(); } /// - /// 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. /// /// GPU virtual address where the data is located /// Maximum size of the data - /// The data at the specified memory location - public Span Read(ulong gpuVa, ulong maxSize) + /// The span of the data at the specified memory location + public ReadOnlySpan 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); } /// @@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Gpu.Memory ulong size = (uint)Marshal.SizeOf(); - return MemoryMarshal.Cast(_context.PhysicalMemory.Read(processVa, size))[0]; + return MemoryMarshal.Cast(_context.PhysicalMemory.GetSpan(processVa, size))[0]; } /// @@ -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)); } /// @@ -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)); } /// diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index 71384df237..ca28f31d11 100644 --- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -22,14 +22,14 @@ namespace Ryujinx.Graphics.Gpu.Memory } /// - /// Reads data from the application process. + /// Gets a span of data from the application process. /// - /// Address to be read - /// Size in bytes to be read - /// The data at the specified memory location - public Span Read(ulong address, ulong size) + /// Start address of the range + /// Size in bytes to be range + /// A read only span of the data at the specified memory location + public ReadOnlySpan GetSpan(ulong address, ulong size) { - return _cpuMemory.ReadBytes((long)address, (long)size); + return _cpuMemory.GetSpan(address, size); } /// @@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Address to write into /// Data to be written - public void Write(ulong address, Span data) + public void Write(ulong address, ReadOnlySpan data) { _cpuMemory.WriteBytes((long)address, data.ToArray()); } diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 548a7e07ab..dad1b0ac2e 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -265,7 +265,7 @@ namespace Ryujinx.Graphics.Gpu.Shader ShaderProgram program; - Span code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize); + ReadOnlySpan 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 codeA = _context.MemoryAccessor.Read(gpuVaA, MaxProgramSize); - Span codeB = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize); + ReadOnlySpan codeA = _context.MemoryAccessor.GetSpan(gpuVaA, MaxProgramSize); + ReadOnlySpan codeB = _context.MemoryAccessor.GetSpan(gpuVa, MaxProgramSize); program = Translator.Translate(codeA, codeB, callbacks, DefaultFlags); @@ -340,7 +340,7 @@ namespace Ryujinx.Graphics.Gpu.Shader } else { - Span code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize); + ReadOnlySpan code = _context.MemoryAccessor.GetSpan(gpuVa, MaxProgramSize); program = Translator.Translate(code, callbacks, DefaultFlags); diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderDumper.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderDumper.cs index 3be75564bf..0e22b07e3a 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderDumper.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderDumper.cs @@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// True for compute shader code, false for graphics shader code /// Output path for the shader code with header included /// Output path for the shader code without header - public void Dump(Span code, bool compute, out string fullPath, out string codePath) + public void Dump(ReadOnlySpan code, bool compute, out string fullPath, out string codePath) { _dumpPath = GraphicsConfig.ShadersDumpPath; diff --git a/Ryujinx.Graphics.OpenGL/Buffer.cs b/Ryujinx.Graphics.OpenGL/Buffer.cs index b86719ceb4..db3e94ba59 100644 --- a/Ryujinx.Graphics.OpenGL/Buffer.cs +++ b/Ryujinx.Graphics.OpenGL/Buffer.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.OpenGL return data; } - public void SetData(Span data) + public void SetData(ReadOnlySpan data) { unsafe { @@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.OpenGL } } - public void SetData(int offset, Span data) + public void SetData(int offset, ReadOnlySpan data) { GL.BindBuffer(BufferTarget.CopyWriteBuffer, Handle); diff --git a/Ryujinx.Graphics.OpenGL/TextureView.cs b/Ryujinx.Graphics.OpenGL/TextureView.cs index 91f1865d32..2efaf7c0a1 100644 --- a/Ryujinx.Graphics.OpenGL/TextureView.cs +++ b/Ryujinx.Graphics.OpenGL/TextureView.cs @@ -217,7 +217,7 @@ namespace Ryujinx.Graphics.OpenGL } } - public void SetData(Span data) + public void SetData(ReadOnlySpan data) { unsafe { diff --git a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs index db63712bff..8a502e3c6c 100644 --- a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs +++ b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs @@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Shader.Decoders _opActivators = new ConcurrentDictionary(); } - public static Block[] Decode(Span code, ulong headerSize) + public static Block[] Decode(ReadOnlySpan code, ulong headerSize) { List blocks = new List(); @@ -214,10 +214,10 @@ namespace Ryujinx.Graphics.Shader.Decoders } private static void FillBlock( - Span code, - Block block, - ulong limitAddress, - ulong startAddress) + ReadOnlySpan code, + Block block, + ulong limitAddress, + ulong startAddress) { ulong address = block.Address; diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs index 0c56132d95..42701fbdca 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs +++ b/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 code) + public ShaderHeader(ReadOnlySpan code) { - Span header = MemoryMarshal.Cast(code); + ReadOnlySpan header = MemoryMarshal.Cast(code); int commonWord0 = header[0]; int commonWord1 = header[1]; diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs index 760d616f63..a333db9529 100644 --- a/Ryujinx.Graphics.Shader/Translation/Translator.cs +++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation { private const int HeaderSize = 0x50; - public static Span ExtractCode(Span code, bool compute, out int headerSize) + public static ReadOnlySpan ExtractCode(ReadOnlySpan 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 code, TranslatorCallbacks callbacks, TranslationFlags flags) + public static ShaderProgram Translate(ReadOnlySpan 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 vpACode, Span vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags) + public static ShaderProgram Translate(ReadOnlySpan vpACode, ReadOnlySpan 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 code, + ReadOnlySpan code, TranslatorCallbacks callbacks, TranslationFlags flags, out ShaderConfig config, From f0055482fd1aef9dcae7c6c4c6e01483f11f7839 Mon Sep 17 00:00:00 2001 From: Thog Date: Mon, 13 Jan 2020 01:17:44 +0100 Subject: [PATCH 5/7] Fix race condition in ContentManager (#884) * Fix race condition in ContentManager This fix a race condition happening since #791 when trying to load a game via command line. * Address gdk's comments * Ensure to dispose the FileStream and not the IStorage --- .../FileSystem/Content/ContentManager.cs | 277 ++++++++++-------- 1 file changed, 153 insertions(+), 124 deletions(-) diff --git a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs index b83ae44064..680ebd522e 100644 --- a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs +++ b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs @@ -28,6 +28,8 @@ namespace Ryujinx.HLE.FileSystem.Content private Switch _device; + private readonly object _lock = new object(); + public ContentManager(Switch device) { _contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>(); @@ -58,139 +60,151 @@ namespace Ryujinx.HLE.FileSystem.Content public void LoadEntries(bool ignoreMissingFonts = false) { - _contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>(); - _locationEntries = new Dictionary>(); - - foreach (StorageId storageId in Enum.GetValues(typeof(StorageId))) + lock (_lock) { - string contentDirectory = null; - string contentPathString = null; - string registeredDirectory = null; + _contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>(); + _locationEntries = new Dictionary>(); - try + foreach (StorageId storageId in Enum.GetValues(typeof(StorageId))) { - contentPathString = LocationHelper.GetContentRoot(storageId); - contentDirectory = LocationHelper.GetRealPath(_device.FileSystem, contentPathString); - registeredDirectory = Path.Combine(contentDirectory, "registered"); - } - catch (NotSupportedException) - { - continue; - } + string contentDirectory = null; + string contentPathString = null; + string registeredDirectory = null; - Directory.CreateDirectory(registeredDirectory); - - LinkedList locationList = new LinkedList(); - - void AddEntry(LocationEntry entry) - { - locationList.AddLast(entry); - } - - foreach (string directoryPath in Directory.EnumerateDirectories(registeredDirectory)) - { - if (Directory.GetFiles(directoryPath).Length > 0) + try { - string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty); + contentPathString = LocationHelper.GetContentRoot(storageId); + contentDirectory = LocationHelper.GetRealPath(_device.FileSystem, contentPathString); + registeredDirectory = Path.Combine(contentDirectory, "registered"); + } + catch (NotSupportedException) + { + continue; + } - using (FileStream ncaFile = new FileStream(Directory.GetFiles(directoryPath)[0], FileMode.Open, FileAccess.Read)) + Directory.CreateDirectory(registeredDirectory); + + LinkedList locationList = new LinkedList(); + + void AddEntry(LocationEntry entry) + { + locationList.AddLast(entry); + } + + foreach (string directoryPath in Directory.EnumerateDirectories(registeredDirectory)) + { + if (Directory.GetFiles(directoryPath).Length > 0) { - Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage()); + string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty); - string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar); + using (FileStream ncaFile = File.OpenRead(Directory.GetFiles(directoryPath)[0])) + { + Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage()); - // Change path format to switch's - switchPath = switchPath.Replace('\\', '/'); + string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar); - LocationEntry entry = new LocationEntry(switchPath, - 0, - (long)nca.Header.TitleId, - nca.Header.ContentType); + // Change path format to switch's + switchPath = switchPath.Replace('\\', '/'); - AddEntry(entry); + LocationEntry entry = new LocationEntry(switchPath, + 0, + (long)nca.Header.TitleId, + nca.Header.ContentType); - _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName); + AddEntry(entry); + + _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName); + } } } + + foreach (string filePath in Directory.EnumerateFiles(contentDirectory)) + { + if (Path.GetExtension(filePath) == ".nca") + { + string ncaName = Path.GetFileNameWithoutExtension(filePath); + + using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + { + Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage()); + + string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar); + + // Change path format to switch's + switchPath = switchPath.Replace('\\', '/'); + + LocationEntry entry = new LocationEntry(switchPath, + 0, + (long)nca.Header.TitleId, + nca.Header.ContentType); + + AddEntry(entry); + + _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName); + } + } + } + + if (_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0) + { + _locationEntries.Remove(storageId); + } + + if (!_locationEntries.ContainsKey(storageId)) + { + _locationEntries.Add(storageId, locationList); + } } - foreach (string filePath in Directory.EnumerateFiles(contentDirectory)) - { - if (Path.GetExtension(filePath) == ".nca") - { - string ncaName = Path.GetFileNameWithoutExtension(filePath); + TimeManager.Instance.InitializeTimeZone(_device); - using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read)) - { - Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage()); - - string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar); - - // Change path format to switch's - switchPath = switchPath.Replace('\\', '/'); - - LocationEntry entry = new LocationEntry(switchPath, - 0, - (long)nca.Header.TitleId, - nca.Header.ContentType); - - AddEntry(entry); - - _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName); - } - } - } - - if (_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0) - { - _locationEntries.Remove(storageId); - } - - if (!_locationEntries.ContainsKey(storageId)) - { - _locationEntries.Add(storageId, locationList); - } + _device.System.Font.Initialize(this, ignoreMissingFonts); } - - TimeManager.Instance.InitializeTimeZone(_device); - - _device.System.Font.Initialize(this, ignoreMissingFonts); } public void ClearEntry(long titleId, NcaContentType contentType, StorageId storageId) { - RemoveLocationEntry(titleId, contentType, storageId); + lock (_lock) + { + RemoveLocationEntry(titleId, contentType, storageId); + } } public void RefreshEntries(StorageId storageId, int flag) { - LinkedList locationList = _locationEntries[storageId]; - LinkedListNode locationEntry = locationList.First; - - while (locationEntry != null) + lock (_lock) { - LinkedListNode nextLocationEntry = locationEntry.Next; + LinkedList locationList = _locationEntries[storageId]; + LinkedListNode locationEntry = locationList.First; - if (locationEntry.Value.Flag == flag) + while (locationEntry != null) { - locationList.Remove(locationEntry.Value); - } + LinkedListNode nextLocationEntry = locationEntry.Next; - locationEntry = nextLocationEntry; + if (locationEntry.Value.Flag == flag) + { + locationList.Remove(locationEntry.Value); + } + + locationEntry = nextLocationEntry; + } } } public bool HasNca(string ncaId, StorageId storageId) { - if (_contentDictionary.ContainsValue(ncaId)) + lock (_lock) { - var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId); - long titleId = (long)content.Key.Item1; + if (_contentDictionary.ContainsValue(ncaId)) + { + var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId); + long titleId = (long)content.Key.Item1; - NcaContentType contentType = content.Key.type; - StorageId storage = GetInstalledStorage(titleId, contentType, storageId); + NcaContentType contentType = content.Key.type; + StorageId storage = GetInstalledStorage(titleId, contentType, storageId); - return storage == storageId; + return storage == storageId; + } } return false; @@ -198,9 +212,12 @@ namespace Ryujinx.HLE.FileSystem.Content public UInt128 GetInstalledNcaId(long titleId, NcaContentType contentType) { - if (_contentDictionary.ContainsKey(((ulong)titleId, contentType))) + lock (_lock) { - return new UInt128(_contentDictionary[((ulong)titleId, contentType)]); + if (_contentDictionary.ContainsKey(((ulong)titleId, contentType))) + { + return new UInt128(_contentDictionary[((ulong)titleId, contentType)]); + } } return new UInt128(); @@ -208,19 +225,25 @@ namespace Ryujinx.HLE.FileSystem.Content public StorageId GetInstalledStorage(long titleId, NcaContentType contentType, StorageId storageId) { - LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); + lock (_lock) + { + LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); - return locationEntry.ContentPath != null ? - LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None; + return locationEntry.ContentPath != null ? + LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None; + } } public string GetInstalledContentPath(long titleId, StorageId storageId, NcaContentType contentType) { - LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); - - if (VerifyContentType(locationEntry, contentType)) + lock (_lock) { - return locationEntry.ContentPath; + LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); + + if (VerifyContentType(locationEntry, contentType)) + { + return locationEntry.ContentPath; + } } return string.Empty; @@ -228,14 +251,17 @@ namespace Ryujinx.HLE.FileSystem.Content public void RedirectLocation(LocationEntry newEntry, StorageId storageId) { - LocationEntry locationEntry = GetLocation(newEntry.TitleId, newEntry.ContentType, storageId); - - if (locationEntry.ContentPath != null) + lock (_lock) { - RemoveLocationEntry(newEntry.TitleId, newEntry.ContentType, storageId); - } + LocationEntry locationEntry = GetLocation(newEntry.TitleId, newEntry.ContentType, storageId); - AddLocationEntry(newEntry, storageId); + if (locationEntry.ContentPath != null) + { + RemoveLocationEntry(newEntry.TitleId, newEntry.ContentType, storageId); + } + + AddLocationEntry(newEntry, storageId); + } } private bool VerifyContentType(LocationEntry locationEntry, NcaContentType contentType) @@ -827,28 +853,31 @@ namespace Ryujinx.HLE.FileSystem.Content { LoadEntries(true); - var locationEnties = _locationEntries[StorageId.NandSystem]; - - foreach (var entry in locationEnties) + lock (_lock) { - if (entry.ContentType == NcaContentType.Data) + var locationEnties = _locationEntries[StorageId.NandSystem]; + + foreach (var entry in locationEnties) { - var path = _device.FileSystem.SwitchPathToSystemPath(entry.ContentPath); - - using (IStorage ncaStorage = File.Open(path, FileMode.Open).AsStorage()) + if (entry.ContentType == NcaContentType.Data) { - Nca nca = new Nca(_device.System.KeySet, ncaStorage); + var path = _device.FileSystem.SwitchPathToSystemPath(entry.ContentPath); - if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) + using (FileStream fileStream = File.OpenRead(path)) { - var romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel); + Nca nca = new Nca(_device.System.KeySet, fileStream.AsStorage()); - if (romfs.OpenFile(out IFile systemVersionFile, "/file", OpenMode.Read).IsSuccess()) + if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) { - return new SystemVersion(systemVersionFile.AsStream()); - } - } + var romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel); + if (romfs.OpenFile(out IFile systemVersionFile, "/file", OpenMode.Read).IsSuccess()) + { + return new SystemVersion(systemVersionFile.AsStream()); + } + } + + } } } } From 5facc0c07f8a3f6fd0f39229044fe120501162a7 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Mon, 13 Jan 2020 01:21:54 +0100 Subject: [PATCH 6/7] Name all threads (#886) * Name all threads Close #874 * use ThreadName instead of ThreadId in Logging --- ARMeilleure/Translation/Translator.cs | 7 +++-- .../Renderers/OpenAL/OpenALAudioOut.cs | 5 +++- .../Logging/Formatters/DefaultLogFormatter.cs | 9 ++++-- Ryujinx.Common/Logging/LogEventArgs.cs | 28 +++++++++---------- Ryujinx.Common/Logging/Logger.cs | 4 +-- .../Logging/Targets/AsyncLogTargetWrapper.cs | 1 + Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs | 5 +++- .../HOS/Kernel/Threading/HleScheduler.cs | 5 +++- Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs | 4 +-- Ryujinx.Profiler/InternalProfile.cs | 5 +++- Ryujinx.Profiler/UI/ProfileWindowManager.cs | 10 +++++-- Ryujinx/Ui/GLScreen.cs | 5 +++- Ryujinx/Ui/MainWindow.cs | 1 + 13 files changed, 60 insertions(+), 29 deletions(-) diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs index 6531e9f0f7..4725ca59d8 100644 --- a/ARMeilleure/Translation/Translator.cs +++ b/ARMeilleure/Translation/Translator.cs @@ -58,9 +58,12 @@ namespace ARMeilleure.Translation { if (Interlocked.Increment(ref _threadCount) == 1) { - Thread backgroundTranslatorThread = new Thread(TranslateQueuedSubs); + Thread backgroundTranslatorThread = new Thread(TranslateQueuedSubs) + { + Name = "CPU.BackgroundTranslatorThread", + Priority = ThreadPriority.Lowest + }; - backgroundTranslatorThread.Priority = ThreadPriority.Lowest; backgroundTranslatorThread.Start(); } diff --git a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs index 69f36a4daf..30b325a51a 100644 --- a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs +++ b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs @@ -70,7 +70,10 @@ namespace Ryujinx.Audio _context = new AudioContext(); _tracks = new ConcurrentDictionary(); _keepPolling = true; - _audioPollerThread = new Thread(AudioPollerWork); + _audioPollerThread = new Thread(AudioPollerWork) + { + Name = "Audio.PollerThread" + }; _audioPollerThread.Start(); } diff --git a/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs b/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs index c6605e0e0e..73b0e2b6ac 100644 --- a/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs +++ b/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs @@ -18,8 +18,13 @@ namespace Ryujinx.Common.Logging sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", args.Time); sb.Append(" | "); - sb.AppendFormat("{0:d4}", args.ThreadId); - sb.Append(' '); + + if (args.ThreadName != null) + { + sb.Append(args.ThreadName); + sb.Append(' '); + } + sb.Append(args.Message); if (args.Data != null) diff --git a/Ryujinx.Common/Logging/LogEventArgs.cs b/Ryujinx.Common/Logging/LogEventArgs.cs index 2330dedd36..af33463240 100644 --- a/Ryujinx.Common/Logging/LogEventArgs.cs +++ b/Ryujinx.Common/Logging/LogEventArgs.cs @@ -4,28 +4,28 @@ namespace Ryujinx.Common.Logging { public class LogEventArgs : EventArgs { - public LogLevel Level { get; private set; } - public TimeSpan Time { get; private set; } - public int ThreadId { get; private set; } + public LogLevel Level { get; private set; } + public TimeSpan Time { get; private set; } + public string ThreadName { get; private set; } public string Message { get; private set; } public object Data { get; private set; } - public LogEventArgs(LogLevel level, TimeSpan time, int threadId, string message) + public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message) { - Level = level; - Time = time; - ThreadId = threadId; - Message = message; + Level = level; + Time = time; + ThreadName = threadName; + Message = message; } - public LogEventArgs(LogLevel level, TimeSpan time, int threadId, string message, object data) + public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message, object data) { - Level = level; - Time = time; - ThreadId = threadId; - Message = message; - Data = data; + Level = level; + Time = time; + ThreadName = threadName; + Message = message; + Data = data; } } } \ No newline at end of file diff --git a/Ryujinx.Common/Logging/Logger.cs b/Ryujinx.Common/Logging/Logger.cs index 83af97b122..e3d82201d4 100644 --- a/Ryujinx.Common/Logging/Logger.cs +++ b/Ryujinx.Common/Logging/Logger.cs @@ -155,7 +155,7 @@ namespace Ryujinx.Common.Logging { if (m_EnabledLevels[(int)logLevel] && m_EnabledClasses[(int)logClass]) { - Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.ManagedThreadId, message)); + Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.Name, message)); } } @@ -163,7 +163,7 @@ namespace Ryujinx.Common.Logging { if (m_EnabledLevels[(int)logLevel] && m_EnabledClasses[(int)logClass]) { - Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.ManagedThreadId, message, data)); + Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.Name, message, data)); } } diff --git a/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs b/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs index c946b67880..43c62d319c 100644 --- a/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs +++ b/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs @@ -57,6 +57,7 @@ namespace Ryujinx.Common.Logging } }); + _messageThread.Name = "Logger.MessageThread"; _messageThread.IsBackground = true; _messageThread.Start(); } diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs b/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs index f6a9e6f9d1..8273520fd1 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs @@ -33,7 +33,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Common _keepRunning = true; - Thread work = new Thread(WaitAndCheckScheduledObjects); + Thread work = new Thread(WaitAndCheckScheduledObjects) + { + Name = "HLE.TimeManager" + }; work.Start(); } diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs b/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs index 0b95113481..1a213b924f 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs @@ -17,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public void StartAutoPreemptionThread() { - Thread preemptionThread = new Thread(PreemptCurrentThread); + Thread preemptionThread = new Thread(PreemptCurrentThread) + { + Name = "HLE.PreemptionThread" + }; _keepPreempting = true; diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index e1a49a561a..c4bd781d4e 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -159,7 +159,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading is64Bits = true; } - HostThread = new Thread(customHostThreadStart == null ? () => ThreadStart(entrypoint) : customHostThreadStart); + HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint))); Context = new ARMeilleure.State.ExecutionContext(); @@ -185,7 +185,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading ThreadUid = System.GetThreadUid(); - HostThread.Name = $"Host Thread (thread id {ThreadUid})"; + HostThread.Name = $"HLE.HostThread.{ThreadUid}"; _hasBeenInitialized = true; diff --git a/Ryujinx.Profiler/InternalProfile.cs b/Ryujinx.Profiler/InternalProfile.cs index 46984601b5..0346244423 100644 --- a/Ryujinx.Profiler/InternalProfile.cs +++ b/Ryujinx.Profiler/InternalProfile.cs @@ -55,7 +55,10 @@ namespace Ryujinx.Profiler _cleanupRunning = true; // Create cleanup thread. - _cleanupThread = new Thread(CleanupLoop); + _cleanupThread = new Thread(CleanupLoop) + { + Name = "Profiler.CleanupThread" + }; _cleanupThread.Start(); } diff --git a/Ryujinx.Profiler/UI/ProfileWindowManager.cs b/Ryujinx.Profiler/UI/ProfileWindowManager.cs index c6a65a317c..1360302933 100644 --- a/Ryujinx.Profiler/UI/ProfileWindowManager.cs +++ b/Ryujinx.Profiler/UI/ProfileWindowManager.cs @@ -21,7 +21,10 @@ namespace Ryujinx.Profiler.UI { _profilerRunning = true; _prevTime = 0; - _profileThread = new Thread(ProfileLoop); + _profileThread = new Thread(ProfileLoop) + { + Name = "Profiler.ProfileThread" + }; _profileThread.Start(); } } @@ -60,7 +63,10 @@ namespace Ryujinx.Profiler.UI using (_window = new ProfileWindow()) { // Create thread for render loop - _renderThread = new Thread(RenderLoop); + _renderThread = new Thread(RenderLoop) + { + Name = "Profiler.RenderThread" + }; _renderThread.Start(); while (_profilerRunning) diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index 8e39126224..d32ddb5ca5 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -120,7 +120,10 @@ namespace Ryujinx.Ui Context.MakeCurrent(null); // OpenTK doesn't like sleeps in its thread, to avoid this a renderer thread is created - _renderThread = new Thread(RenderLoop); + _renderThread = new Thread(RenderLoop) + { + Name = "GUI.RenderThread" + }; _renderThread.Start(); diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index af7dd524ab..451df2fd95 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -653,6 +653,7 @@ namespace Ryujinx.Ui } }); + thread.Name = "GUI.FirmwareInstallerThread"; thread.Start(); } else From 892df335e6f633a5bcc2ce265749e15365ea2549 Mon Sep 17 00:00:00 2001 From: Thog Date: Mon, 13 Jan 2020 03:04:28 +0100 Subject: [PATCH 7/7] Rework SVC handling (#883) * Rework SVC handling Prepare for 32 bits support. * QueryMemory64 x1 is an output * Pregenerate all SVC handler Also clean up + 32 bits code path * Address gdk's comments * Simplify local setter loop * Address jd's comments --- .../HOS/Kernel/SupervisorCall/RAttribute.cs | 15 +++ .../HOS/Kernel/SupervisorCall/SvcHandler.cs | 6 +- .../HOS/Kernel/SupervisorCall/SvcIpc.cs | 40 +++---- .../HOS/Kernel/SupervisorCall/SvcMemory.cs | 44 ++++---- .../HOS/Kernel/SupervisorCall/SvcSystem.cs | 24 ++-- .../HOS/Kernel/SupervisorCall/SvcTable.cs | 105 ++++++++++++------ .../HOS/Kernel/SupervisorCall/SvcThread.cs | 30 ++--- .../Kernel/SupervisorCall/SvcThreadSync.cs | 22 ++-- 8 files changed, 167 insertions(+), 119 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Kernel/SupervisorCall/RAttribute.cs diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/RAttribute.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/RAttribute.cs new file mode 100644 index 0000000000..c1d9eeed07 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/RAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall +{ + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] + public class RAttribute : Attribute + { + public readonly int Index; + + public RAttribute(int index) + { + Index = index; + } + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs index 0bf5e5fa3d..d5698e2bc5 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs @@ -20,15 +20,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall public void SvcCall(object sender, InstExceptionEventArgs e) { - Action svcFunc = SvcTable.GetSvcFunc(e.Id); + ExecutionContext context = (ExecutionContext)sender; + + Action svcFunc = context.IsAarch32 ? SvcTable.SvcTable32[e.Id] : SvcTable.SvcTable64[e.Id]; if (svcFunc == null) { throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented."); } - ExecutionContext context = (ExecutionContext)sender; - svcFunc(this, context); PostSvcHandler(); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs index 7c1c981bf0..70767733c1 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs @@ -30,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle) + public KernelResult ConnectToNamedPort64([R(1)] ulong namePtr, [R(1)] out int handle) { return ConnectToNamedPort(namePtr, out handle); } @@ -81,12 +81,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult SendSyncRequest64(int handle) + public KernelResult SendSyncRequest64([R(0)] int handle) { return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle); } - public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle) + public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong size, [R(2)] int handle) { return SendSyncRequest(messagePtr, size, handle); } @@ -168,10 +168,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } public KernelResult CreateSession64( - bool isLight, - ulong namePtr, - out int serverSessionHandle, - out int clientSessionHandle) + [R(2)] bool isLight, + [R(3)] ulong namePtr, + [R(1)] out int serverSessionHandle, + [R(2)] out int clientSessionHandle) { return CreateSession(isLight, namePtr, out serverSessionHandle, out clientSessionHandle); } @@ -242,7 +242,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult AcceptSession64(int portHandle, out int sessionHandle) + public KernelResult AcceptSession64([R(1)] int portHandle, [R(1)] out int sessionHandle) { return AcceptSession(portHandle, out sessionHandle); } @@ -299,11 +299,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } public KernelResult ReplyAndReceive64( - ulong handlesPtr, - int handlesCount, - int replyTargetHandle, - long timeout, - out int handleIndex) + [R(1)] ulong handlesPtr, + [R(2)] int handlesCount, + [R(3)] int replyTargetHandle, + [R(4)] long timeout, + [R(1)] out int handleIndex) { handleIndex = 0; @@ -385,11 +385,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } public KernelResult CreatePort64( - int maxSessions, - bool isLight, - ulong namePtr, - out int serverPortHandle, - out int clientPortHandle) + [R(2)] int maxSessions, + [R(3)] bool isLight, + [R(4)] ulong namePtr, + [R(1)] out int serverPortHandle, + [R(2)] out int clientPortHandle) { return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle); } @@ -429,7 +429,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle) + public KernelResult ManageNamedPort64([R(1)] ulong namePtr, [R(2)] int maxSessions, [R(1)] out int handle) { return ManageNamedPort(namePtr, maxSessions, out handle); } @@ -474,7 +474,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult ConnectToPort64(int clientPortHandle, out int clientSessionHandle) + public KernelResult ConnectToPort64([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle) { return ConnectToPort(clientPortHandle, out clientSessionHandle); } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs index f794d13073..42be266b3a 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs @@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { partial class SvcHandler { - public KernelResult SetHeapSize64(ulong size, out ulong position) + public KernelResult SetHeapSize64([R(1)] ulong size, [R(1)] out ulong position) { return SetHeapSize(size, out position); } @@ -24,10 +24,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } public KernelResult SetMemoryAttribute64( - ulong position, - ulong size, - MemoryAttribute attributeMask, - MemoryAttribute attributeValue) + [R(0)] ulong position, + [R(1)] ulong size, + [R(2)] MemoryAttribute attributeMask, + [R(3)] MemoryAttribute attributeValue) { return SetMemoryAttribute(position, size, attributeMask, attributeValue); } @@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult MapMemory64(ulong dst, ulong src, ulong size) + public KernelResult MapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size) { return MapMemory(dst, src, size); } @@ -104,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _process.MemoryManager.Map(dst, src, size); } - public KernelResult UnmapMemory64(ulong dst, ulong src, ulong size) + public KernelResult UnmapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size) { return UnmapMemory(dst, src, size); } @@ -143,12 +143,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _process.MemoryManager.Unmap(dst, src, size); } - public KernelResult QueryMemory64(ulong infoPtr, ulong x1, ulong position) + public KernelResult QueryMemory64([R(0)] ulong infoPtr, [R(2)] ulong position, [R(1)] out ulong pageInfo) { - return QueryMemory(infoPtr, position); + return QueryMemory(infoPtr, position, out pageInfo); } - private KernelResult QueryMemory(ulong infoPtr, ulong position) + private KernelResult QueryMemory(ulong infoPtr, ulong position, out ulong pageInfo) { KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position); @@ -161,10 +161,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x20, blkInfo.DeviceRefCount); _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x24, 0); + pageInfo = 0; + return KernelResult.Success; } - public KernelResult MapSharedMemory64(int handle, ulong address, ulong size, MemoryPermission permission) + public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission) { return MapSharedMemory(handle, address, size, permission); } @@ -215,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall permission); } - public KernelResult UnmapSharedMemory64(int handle, ulong address, ulong size) + public KernelResult UnmapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size) { return UnmapSharedMemory(handle, address, size); } @@ -261,10 +263,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } public KernelResult CreateTransferMemory64( - ulong address, - ulong size, - MemoryPermission permission, - out int handle) + [R(1)] ulong address, + [R(2)] ulong size, + [R(3)] MemoryPermission permission, + [R(1)] out int handle) { return CreateTransferMemory(address, size, permission, out handle); } @@ -305,7 +307,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _process.HandleTable.GenerateHandle(transferMemory, out handle); } - public KernelResult MapPhysicalMemory64(ulong address, ulong size) + public KernelResult MapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size) { return MapPhysicalMemory(address, size); } @@ -343,7 +345,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _process.MemoryManager.MapPhysicalMemory(address, size); } - public KernelResult UnmapPhysicalMemory64(ulong address, ulong size) + public KernelResult UnmapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size) { return UnmapPhysicalMemory(address, size); } @@ -381,7 +383,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _process.MemoryManager.UnmapPhysicalMemory(address, size); } - public KernelResult MapProcessCodeMemory64(int handle, ulong dst, ulong src, ulong size) + public KernelResult MapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size) { return MapProcessCodeMemory(handle, dst, src, size); } @@ -423,7 +425,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size); } - public KernelResult UnmapProcessCodeMemory64(int handle, ulong dst, ulong src, ulong size) + public KernelResult UnmapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size) { return UnmapProcessCodeMemory(handle, dst, src, size); } @@ -465,7 +467,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size); } - public KernelResult SetProcessMemoryPermission64(int handle, ulong src, ulong size, MemoryPermission permission) + public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission) { return SetProcessMemoryPermission(handle, src, size, permission); } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs index 7961f124d0..dad9612cc6 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall ExitProcess(); } - public KernelResult TerminateProcess64(int handle) + public KernelResult TerminateProcess64([R(0)] int handle) { return TerminateProcess(handle); } @@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall _system.Scheduler.GetCurrentProcess().TerminateCurrentProcess(); } - public KernelResult SignalEvent64(int handle) + public KernelResult SignalEvent64([R(0)] int handle) { return SignalEvent(handle); } @@ -79,7 +79,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult ClearEvent64(int handle) + public KernelResult ClearEvent64([R(0)] int handle) { return ClearEvent(handle); } @@ -104,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult CloseHandle64(int handle) + public KernelResult CloseHandle64([R(0)] int handle) { return CloseHandle(handle); } @@ -134,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult ResetSignal64(int handle) + public KernelResult ResetSignal64([R(0)] int handle) { return ResetSignal(handle); } @@ -173,7 +173,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _system.Scheduler.GetCurrentThread().Context.CntpctEl0; } - public KernelResult GetProcessId64(int handle, out long pid) + public KernelResult GetProcessId64([R(1)] int handle, [R(1)] out long pid) { return GetProcessId(handle, out pid); } @@ -203,7 +203,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall : KernelResult.InvalidHandle; } - public void Break64(ulong reason, ulong x1, ulong info) + public void Break64([R(0)] ulong reason, [R(1)] ulong x1, [R(2)] ulong info) { Break(reason); } @@ -235,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public void OutputDebugString64(ulong strPtr, ulong size) + public void OutputDebugString64([R(0)] ulong strPtr, [R(1)] ulong size) { OutputDebugString(strPtr, size); } @@ -247,7 +247,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall Logger.PrintWarning(LogClass.KernelSvc, str); } - public KernelResult GetInfo64(uint id, int handle, long subId, out long value) + public KernelResult GetInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value) { return GetInfo(id, handle, subId, out value); } @@ -478,7 +478,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult CreateEvent64(out int wEventHandle, out int rEventHandle) + public KernelResult CreateEvent64([R(1)] out int wEventHandle, [R(2)] out int rEventHandle) { return CreateEvent(out wEventHandle, out rEventHandle); } @@ -506,7 +506,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult GetProcessList64(ulong address, int maxCount, out int count) + public KernelResult GetProcessList64([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count) { return GetProcessList(address, maxCount, out count); } @@ -560,7 +560,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult GetSystemInfo64(uint id, int handle, long subId, out long value) + public KernelResult GetSystemInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value) { return GetSystemInfo(id, handle, subId, out value); } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs index 1c2121f0de..27aa70fc71 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Kernel.Common; using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -10,15 +11,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { static class SvcTable { - private const int SvcFuncMaxArguments = 8; + private const int SvcFuncMaxArguments64 = 8; + private const int SvcFuncMaxArguments32 = 4; + private const int SvcMax = 0x80; - private static Dictionary _svcFuncs64; - - private static Action[] _svcTable64; + public static Action[] SvcTable32 { get; } + public static Action[] SvcTable64 { get; } static SvcTable() { - _svcFuncs64 = new Dictionary + SvcTable32 = new Action[SvcMax]; + SvcTable64 = new Action[SvcMax]; + + Dictionary svcFuncs64 = new Dictionary { { 0x01, nameof(SvcHandler.SetHeapSize64) }, { 0x03, nameof(SvcHandler.SetMemoryAttribute64) }, @@ -78,25 +83,23 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { 0x7B, nameof(SvcHandler.TerminateProcess64) } }; - _svcTable64 = new Action[0x80]; - } - - public static Action GetSvcFunc(int svcId) - { - if (_svcTable64[svcId] != null) + foreach (KeyValuePair value in svcFuncs64) { - return _svcTable64[svcId]; + SvcTable64[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments64); } - if (_svcFuncs64.TryGetValue(svcId, out string svcName)) + Dictionary svcFuncs32 = new Dictionary { - return _svcTable64[svcId] = GenerateMethod(svcName); - } + // TODO + }; - return null; + foreach (KeyValuePair value in svcFuncs32) + { + SvcTable32[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments32); + } } - private static Action GenerateMethod(string svcName) + private static Action GenerateMethod(string svcName, int registerCleanCount) { Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) }; @@ -106,11 +109,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall ParameterInfo[] methodArgs = methodInfo.GetParameters(); - if (methodArgs.Length > SvcFuncMaxArguments) - { - throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is 8."); - } - ILGenerator generator = method.GetILGenerator(); void ConvertToArgType(Type sourceType) @@ -152,6 +150,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + RAttribute GetRegisterAttribute(ParameterInfo parameterInfo) + { + RAttribute argumentAttribute = (RAttribute)parameterInfo.GetCustomAttribute(typeof(RAttribute)); + + if (argumentAttribute == null) + { + throw new InvalidOperationException($"Method \"{svcName}\" is missing a {typeof(RAttribute).Name} attribute on parameter \"{parameterInfo.Name}\""); + } + + return argumentAttribute; + } + // For functions returning output values, the first registers // are used to hold pointers where the value will be stored, // so they can't be used to pass argument and we must @@ -179,15 +189,25 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall string argsFormat = svcName; - for (int index = 0; index < inputArgsCount; index++) + for (int index = 0; index < methodArgs.Length; index++) { + Type argType = methodArgs[index].ParameterType; + + // Ignore out argument for printing + if (argType.IsByRef) + { + continue; + } + + RAttribute registerAttribute = GetRegisterAttribute(methodArgs[index]); + argsFormat += $" {methodArgs[index].Name}: 0x{{{index}:X8}},"; generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Ldc_I4, index); generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index); + generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); @@ -200,7 +220,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall argsFormat = argsFormat.Substring(0, argsFormat.Length - 1); - generator.Emit(OpCodes.Ldstr, argsFormat); + generator.Emit(OpCodes.Ldstr, argsFormat); } else { @@ -216,11 +236,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // Call the SVC function handler. generator.Emit(OpCodes.Ldarg_0); - List locals = new List(); + List<(LocalBuilder, RAttribute)> locals = new List<(LocalBuilder, RAttribute)>(); for (int index = 0; index < methodArgs.Length; index++) { Type argType = methodArgs[index].ParameterType; + RAttribute registerAttribute = GetRegisterAttribute(methodArgs[index]); if (argType.IsByRef) { @@ -228,12 +249,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall LocalBuilder local = generator.DeclareLocal(argType); - locals.Add(local); + locals.Add((local, registerAttribute)); if (!methodArgs[index].IsOut) { generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, index); + generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); @@ -249,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall else { generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index); + generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); @@ -261,8 +282,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Call, methodInfo); - int outRegIndex = 0; - Type retType = methodInfo.ReturnType; // Print result code. @@ -275,6 +294,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Call, printResultMethod); } + uint registerInUse = 0; + // Save return value into register X0 (when the method has a return value). if (retType != typeof(void)) { @@ -284,7 +305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Stloc, tempLocal); generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, outRegIndex++); + generator.Emit(OpCodes.Ldc_I4, 0); generator.Emit(OpCodes.Ldloc, tempLocal); ConvertToFieldType(retType); @@ -292,26 +313,36 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX)); generator.Emit(OpCodes.Call, info); + + registerInUse |= 1u << 0; } for (int index = 0; index < locals.Count; index++) { + (LocalBuilder local, RAttribute attribute) = locals[index]; generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, outRegIndex++); - generator.Emit(OpCodes.Ldloc, locals[index]); + generator.Emit(OpCodes.Ldc_I4, attribute.Index); + generator.Emit(OpCodes.Ldloc, local); - ConvertToFieldType(locals[index].LocalType); + ConvertToFieldType(local.LocalType); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX)); generator.Emit(OpCodes.Call, info); + + registerInUse |= 1u << attribute.Index; } // Zero out the remaining unused registers. - while (outRegIndex < SvcFuncMaxArguments) + for (int i = 0; i < registerCleanCount; i++) { + if ((registerInUse & (1u << i)) != 0) + { + continue; + } + generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, outRegIndex++); + generator.Emit(OpCodes.Ldc_I4, i); generator.Emit(OpCodes.Ldc_I8, 0L); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX)); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs index 0908de1083..9e681c80f2 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs @@ -9,12 +9,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall partial class SvcHandler { public KernelResult CreateThread64( - ulong entrypoint, - ulong argsPtr, - ulong stackTop, - int priority, - int cpuCore, - out int handle) + [R(1)] ulong entrypoint, + [R(2)] ulong argsPtr, + [R(3)] ulong stackTop, + [R(4)] int priority, + [R(5)] int cpuCore, + [R(1)] out int handle) { return CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle); } @@ -78,7 +78,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult StartThread64(int handle) + public KernelResult StartThread64([R(0)] int handle) { return StartThread(handle); } @@ -122,7 +122,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall currentThread.Exit(); } - public void SleepThread64(long timeout) + public void SleepThread64([R(0)] long timeout) { SleepThread(timeout); } @@ -146,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public KernelResult GetThreadPriority64(int handle, out int priority) + public KernelResult GetThreadPriority64([R(1)] int handle, [R(1)] out int priority) { return GetThreadPriority(handle, out priority); } @@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public KernelResult SetThreadPriority64(int handle, int priority) + public KernelResult SetThreadPriority64([R(0)] int handle, [R(1)] int priority) { return SetThreadPriority(handle, priority); } @@ -190,7 +190,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult GetThreadCoreMask64(int handle, out int preferredCore, out long affinityMask) + public KernelResult GetThreadCoreMask64([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out long affinityMask) { return GetThreadCoreMask(handle, out preferredCore, out affinityMask); } @@ -215,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public KernelResult SetThreadCoreMask64(int handle, int preferredCore, long affinityMask) + public KernelResult SetThreadCoreMask64([R(0)] int handle, [R(1)] int preferredCore, [R(2)] long affinityMask) { return SetThreadCoreMask(handle, preferredCore, affinityMask); } @@ -271,7 +271,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _system.Scheduler.GetCurrentThread().CurrentCore; } - public KernelResult GetThreadId64(int handle, out long threadUid) + public KernelResult GetThreadId64([R(1)] int handle, [R(1)] out long threadUid) { return GetThreadId(handle, out threadUid); } @@ -294,7 +294,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public KernelResult SetThreadActivity64(int handle, bool pause) + public KernelResult SetThreadActivity64([R(0)] int handle, [R(1)] bool pause) { return SetThreadActivity(handle, pause); } @@ -321,7 +321,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return thread.SetActivity(pause); } - public KernelResult GetThreadContext364(ulong address, int handle) + public KernelResult GetThreadContext364([R(0)] ulong address, [R(1)] int handle) { return GetThreadContext3(address, handle); } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs index 6e5b478251..5eeecd932b 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs @@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { partial class SvcHandler { - public KernelResult WaitSynchronization64(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex) + public KernelResult WaitSynchronization64([R(1)] ulong handlesPtr, [R(2)] int handlesCount, [R(3)] long timeout, [R(1)] out int handleIndex) { return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex); } @@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex); } - public KernelResult CancelSynchronization64(int handle) + public KernelResult CancelSynchronization64([R(0)] int handle) { return CancelSynchronization(handle); } @@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult ArbitrateLock64(int ownerHandle, ulong mutexAddress, int requesterHandle) + public KernelResult ArbitrateLock64([R(0)] int ownerHandle, [R(1)] ulong mutexAddress, [R(2)] int requesterHandle) { return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle); } @@ -81,7 +81,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle); } - public KernelResult ArbitrateUnlock64(ulong mutexAddress) + public KernelResult ArbitrateUnlock64([R(0)] ulong mutexAddress) { return ArbitrateUnlock(mutexAddress); } @@ -104,10 +104,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } public KernelResult WaitProcessWideKeyAtomic64( - ulong mutexAddress, - ulong condVarAddress, - int handle, - long timeout) + [R(0)] ulong mutexAddress, + [R(1)] ulong condVarAddress, + [R(2)] int handle, + [R(3)] long timeout) { return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout); } @@ -137,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall timeout); } - public KernelResult SignalProcessWideKey64(ulong address, int count) + public KernelResult SignalProcessWideKey64([R(0)] ulong address, [R(1)] int count) { return SignalProcessWideKey(address, count); } @@ -151,7 +151,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult WaitForAddress64(ulong address, ArbitrationType type, int value, long timeout) + public KernelResult WaitForAddress64([R(0)] ulong address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] long timeout) { return WaitForAddress(address, type, value, timeout); } @@ -194,7 +194,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult SignalToAddress64(ulong address, SignalType type, int value, int count) + public KernelResult SignalToAddress64([R(0)] ulong address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count) { return SignalToAddress(address, type, value, count); }