From df70442c46e7ee133b1fb79dc23ddd134e618085 Mon Sep 17 00:00:00 2001 From: merry Date: Sat, 19 Mar 2022 13:32:35 +0000 Subject: [PATCH 1/9] InstEmitMemoryEx: Barrier after write on ordered store (#3193) * InstEmitMemoryEx: Barrier after write on ordered store * increment ptc version * 32 --- ARMeilleure/Instructions/InstEmitMemoryEx.cs | 10 +++++----- ARMeilleure/Instructions/InstEmitMemoryEx32.cs | 15 ++++++++++----- ARMeilleure/Translation/PTC/Ptc.cs | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx.cs b/ARMeilleure/Instructions/InstEmitMemoryEx.cs index 88b9d2f0c..af6adfb93 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryEx.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryEx.cs @@ -130,11 +130,6 @@ namespace ARMeilleure.Instructions bool ordered = (accType & AccessType.Ordered) != 0; bool exclusive = (accType & AccessType.Exclusive) != 0; - if (ordered) - { - EmitBarrier(context); - } - Operand address = context.Copy(GetIntOrSP(context, op.Rn)); Operand t = GetIntOrZR(context, op.Rt); @@ -163,6 +158,11 @@ namespace ARMeilleure.Instructions { EmitStoreExclusive(context, address, t, exclusive, op.Size, op.Rs, a32: false); } + + if (ordered) + { + EmitBarrier(context); + } } private static void EmitBarrier(ArmEmitterContext context) diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs index 9a9787cfb..c2326cde7 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs @@ -146,13 +146,13 @@ namespace ARMeilleure.Instructions var exclusive = (accType & AccessType.Exclusive) != 0; var ordered = (accType & AccessType.Ordered) != 0; - if (ordered) - { - EmitBarrier(context); - } - if ((accType & AccessType.Load) != 0) { + if (ordered) + { + EmitBarrier(context); + } + if (size == DWordSizeLog2) { // Keep loads atomic - make the call to get the whole region and then decompose it into parts @@ -219,6 +219,11 @@ namespace ARMeilleure.Instructions Operand value = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)); EmitStoreExclusive(context, address, value, exclusive, size, op.Rd, a32: true); } + + if (ordered) + { + EmitBarrier(context); + } } } diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 0431bea49..35bbc56e0 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 3179; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 3193; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; From b45d30acf8e4ed1b44543f2287a5e3f57d4621e9 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Sun, 20 Mar 2022 17:25:29 +0100 Subject: [PATCH 2/9] oslc: Fix condition in GetSaveDataBackupSetting (#3208) * oslc: Fix condition in GetSaveDataBackupSetting This PR fixes a condition previously implemented in #3190 where ACNH can't be booted without an existing savedata. Closes #3206 * Addresses gdkchan feedback --- Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForApplication.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForApplication.cs b/Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForApplication.cs index c70134c51..013e90641 100644 --- a/Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForApplication.cs +++ b/Ryujinx.HLE/HOS/Services/Olsc/IOlscServiceForApplication.cs @@ -45,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Olsc return ResultCode.NullArgument; } - if (_saveDataBackupSettingDatabase[userId]) + if (_saveDataBackupSettingDatabase.TryGetValue(userId, out bool enabled) && enabled) { context.ResponseData.Write((byte)1); // TODO: Determine value. } From d461d4f68bf64f008336845ae8a25af4f69ec9ed Mon Sep 17 00:00:00 2001 From: riperiperi Date: Sun, 20 Mar 2022 16:37:45 +0000 Subject: [PATCH 3/9] Fix OpenGL issues with RTSS overlays and OBS Game Capture (#3217) OpenGL game overlays and hooks tend to make a lot of assumptions about how games present frames to the screen, since presentation in OpenGL kind of sucks and they would like to have info such as the size of the screen, or if the contents are SRGB rather than linear. There are two ways of getting this. OBS hooks swap buffers to get a frame for video capture, but it actually checks the bound framebuffer at the time. I made sure that this matches the output framebuffer (the window) so that the output matches the size. RTSS checks the viewport size by default, but this was actually set to the last used viewport by the game, causing the OSD to fly all across the screen depending on how it was used (or res scale). The viewport is now manually set to match the output framebuffer size. In the case of RTSS, it also loads its resources by destructively setting a pixel pack parameter without regard to what it was set to by the guest application. OpenGL state can be set for a long period of time and is not expected to be set before each call to a method, so randomly changing it isn't great practice. To fix this, I've added a line to set the pixel unpack alignment back to 4 after presentation, which should cover RTSS loading its incredibly ugly font. - RTSS and overlays that use it should no longer cause certain textures to load incorrectly. (mario kart 8, pokemon legends arceus) - OBS Game Capture should no longer crop the game output incorrectly, flicker randomly, or capture with incorrect gamma. This doesn't fix issues with how RTSS reports our frame timings. --- Ryujinx.Graphics.OpenGL/Pipeline.cs | 10 ++++++++++ Ryujinx.Graphics.OpenGL/Window.cs | 16 +++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index c20ce8a32..35278629b 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -1478,6 +1478,11 @@ namespace Ryujinx.Graphics.OpenGL _currentComponentMasks |= componentMaskAtIndex; } + public void RestoreClipControl() + { + GL.ClipControl(_clipOrigin, _clipDepthMode); + } + public void RestoreScissor0Enable() { if ((_scissorEnables & 1u) != 0) @@ -1494,6 +1499,11 @@ namespace Ryujinx.Graphics.OpenGL } } + public void RestoreViewport0() + { + GL.ViewportArray(0, 1, _viewportArray); + } + public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) { if (value is CounterQueueEvent) diff --git a/Ryujinx.Graphics.OpenGL/Window.cs b/Ryujinx.Graphics.OpenGL/Window.cs index da214553e..f7f75f4ec 100644 --- a/Ryujinx.Graphics.OpenGL/Window.cs +++ b/Ryujinx.Graphics.OpenGL/Window.cs @@ -27,11 +27,12 @@ namespace Ryujinx.Graphics.OpenGL { GL.Disable(EnableCap.FramebufferSrgb); - CopyTextureToFrameBufferRGB(0, GetCopyFramebufferHandleLazy(), (TextureView)texture, crop); + CopyTextureToFrameBufferRGB(0, GetCopyFramebufferHandleLazy(), (TextureView)texture, crop, swapBuffersCallback); GL.Enable(EnableCap.FramebufferSrgb); - swapBuffersCallback(); + // Restore unpack alignment to 4, as performance overlays such as RTSS may change this to load their resources. + GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4); } public void SetSize(int width, int height) @@ -40,7 +41,7 @@ namespace Ryujinx.Graphics.OpenGL _height = height; } - private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop) + private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop, Action swapBuffersCallback) { (int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers(); @@ -139,11 +140,20 @@ namespace Ryujinx.Graphics.OpenGL ((Pipeline)_renderer.Pipeline).RestoreComponentMask(i); } + // Set clip control, viewport and the framebuffer to the output to placate overlays and OBS capture. + GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.NegativeOneToOne); + GL.Viewport(0, 0, _width, _height); + GL.BindFramebuffer(FramebufferTarget.Framebuffer, drawFramebuffer); + + swapBuffersCallback(); + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle); + ((Pipeline)_renderer.Pipeline).RestoreClipControl(); ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable(); ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard(); + ((Pipeline)_renderer.Pipeline).RestoreViewport0(); if (viewConverted != view) { From 79408b68c3e72c26d42f858089d97d77d58b44d9 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 20 Mar 2022 13:55:07 -0300 Subject: [PATCH 4/9] De-tile GOB when DMA copying from block linear to pitch kind memory regions (#3207) * De-tile GOB when DMA copying from block linear to pitch kind memory regions * XML docs + nits * Remove using * No flush for regular buffer copies * Add back ulong casts, fix regression due to oversight --- Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs | 88 +++++- Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 1 - Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs | 65 ++++- Ryujinx.Graphics.Gpu/Memory/PteKind.cs | 268 ++++++++++++++++++ Ryujinx.Graphics.Gpu/Memory/ResourceName.cs | 13 - Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs | 2 +- .../NvHostAsGpu/NvHostAsGpuDeviceFile.cs | 24 +- .../NvHostChannel/NvHostChannelDeviceFile.cs | 2 +- 8 files changed, 430 insertions(+), 33 deletions(-) create mode 100644 Ryujinx.Graphics.Gpu/Memory/PteKind.cs delete mode 100644 Ryujinx.Graphics.Gpu/Memory/ResourceName.cs diff --git a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs index cbd0902da..df7e55a11 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs @@ -1,7 +1,7 @@ using Ryujinx.Common; -using Ryujinx.Common.Logging; using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Gpu.Engine.Threed; +using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Texture; using System; using System.Collections.Generic; @@ -330,11 +330,95 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma { // TODO: Implement remap functionality. // Buffer to buffer copy. - memoryManager.Physical.BufferCache.CopyBuffer(memoryManager, srcGpuVa, dstGpuVa, size); + + bool srcIsPitchKind = memoryManager.GetKind(srcGpuVa).IsPitch(); + bool dstIsPitchKind = memoryManager.GetKind(dstGpuVa).IsPitch(); + + if (!srcIsPitchKind && dstIsPitchKind) + { + CopyGobBlockLinearToLinear(memoryManager, srcGpuVa, dstGpuVa, size); + } + else if (srcIsPitchKind && !dstIsPitchKind) + { + CopyGobLinearToBlockLinear(memoryManager, srcGpuVa, dstGpuVa, size); + } + else + { + memoryManager.Physical.BufferCache.CopyBuffer(memoryManager, srcGpuVa, dstGpuVa, size); + } } } } + /// + /// Copies block linear data with block linear GOBs to a block linear destination with linear GOBs. + /// + /// GPU memory manager + /// Source GPU virtual address + /// Destination GPU virtual address + /// Size in bytes of the copy + private static void CopyGobBlockLinearToLinear(MemoryManager memoryManager, ulong srcGpuVa, ulong dstGpuVa, ulong size) + { + if (((srcGpuVa | dstGpuVa | size) & 0xf) == 0) + { + for (ulong offset = 0; offset < size; offset += 16) + { + Vector128 data = memoryManager.Read>(ConvertGobLinearToBlockLinearAddress(srcGpuVa + offset), true); + memoryManager.Write(dstGpuVa + offset, data); + } + } + else + { + for (ulong offset = 0; offset < size; offset++) + { + byte data = memoryManager.Read(ConvertGobLinearToBlockLinearAddress(srcGpuVa + offset), true); + memoryManager.Write(dstGpuVa + offset, data); + } + } + } + + /// + /// Copies block linear data with linear GOBs to a block linear destination with block linear GOBs. + /// + /// GPU memory manager + /// Source GPU virtual address + /// Destination GPU virtual address + /// Size in bytes of the copy + private static void CopyGobLinearToBlockLinear(MemoryManager memoryManager, ulong srcGpuVa, ulong dstGpuVa, ulong size) + { + if (((srcGpuVa | dstGpuVa | size) & 0xf) == 0) + { + for (ulong offset = 0; offset < size; offset += 16) + { + Vector128 data = memoryManager.Read>(srcGpuVa + offset, true); + memoryManager.Write(ConvertGobLinearToBlockLinearAddress(dstGpuVa + offset), data); + } + } + else + { + for (ulong offset = 0; offset < size; offset++) + { + byte data = memoryManager.Read(srcGpuVa + offset, true); + memoryManager.Write(ConvertGobLinearToBlockLinearAddress(dstGpuVa + offset), data); + } + } + } + + /// + /// Calculates the GOB block linear address from a linear address. + /// + /// Linear address + /// Block linear address + private static ulong ConvertGobLinearToBlockLinearAddress(ulong address) + { + // y2 y1 y0 x5 x4 x3 x2 x1 x0 -> x5 y2 y1 x4 y0 x3 x2 x1 x0 + return (address & ~0x1f0UL) | + ((address & 0x40) >> 2) | + ((address & 0x10) << 1) | + ((address & 0x180) >> 1) | + ((address & 0x20) << 3); + } + /// /// Performs a buffer to buffer, or buffer to texture copy, then optionally releases a semaphore. /// diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 89ad8aa07..162483081 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -7,7 +7,6 @@ using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Texture; -using Ryujinx.Memory; using Ryujinx.Memory.Range; using System; using System.Collections.Generic; diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 977fbdf98..c57f1a6f1 100644 --- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -264,7 +264,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// CPU virtual address to map into /// GPU virtual address to be mapped /// Size in bytes of the mapping - public void Map(ulong pa, ulong va, ulong size) + /// Kind of the resource located at the mapping + public void Map(ulong pa, ulong va, ulong size, PteKind kind) { lock (_pageTable) { @@ -272,7 +273,7 @@ namespace Ryujinx.Graphics.Gpu.Memory for (ulong offset = 0; offset < size; offset += PageSize) { - SetPte(va + offset, pa + offset); + SetPte(va + offset, PackPte(pa + offset, kind)); } } } @@ -462,14 +463,37 @@ namespace Ryujinx.Graphics.Gpu.Memory return PteUnmapped; } - ulong baseAddress = GetPte(va); + ulong pte = GetPte(va); - if (baseAddress == PteUnmapped) + if (pte == PteUnmapped) { return PteUnmapped; } - return baseAddress + (va & PageMask); + return UnpackPaFromPte(pte) + (va & PageMask); + } + + /// + /// Gets the kind of a given memory page. + /// This might indicate the type of resource that can be allocated on the page, and also texture tiling. + /// + /// GPU virtual address + /// Kind of the memory page + public PteKind GetKind(ulong va) + { + if (!ValidateAddress(va)) + { + return PteKind.Invalid; + } + + ulong pte = GetPte(va); + + if (pte == PteUnmapped) + { + return PteKind.Invalid; + } + + return UnpackKindFromPte(pte); } /// @@ -512,5 +536,36 @@ namespace Ryujinx.Graphics.Gpu.Memory _pageTable[l0][l1] = pte; } + + /// + /// Creates a page table entry from a physical address and kind. + /// + /// Physical address + /// Kind + /// Page table entry + private static ulong PackPte(ulong pa, PteKind kind) + { + return pa | ((ulong)kind << 56); + } + + /// + /// Unpacks kind from a page table entry. + /// + /// Page table entry + /// Kind + private static PteKind UnpackKindFromPte(ulong pte) + { + return (PteKind)(pte >> 56); + } + + /// + /// Unpacks physical address from a page table entry. + /// + /// Page table entry + /// Physical address + private static ulong UnpackPaFromPte(ulong pte) + { + return pte & 0xffffffffffffffUL; + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Memory/PteKind.cs b/Ryujinx.Graphics.Gpu/Memory/PteKind.cs new file mode 100644 index 000000000..4ceb6bcf4 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Memory/PteKind.cs @@ -0,0 +1,268 @@ +namespace Ryujinx.Graphics.Gpu.Memory +{ + /// + /// Kind of the resource at the given memory mapping. + /// + public enum PteKind : byte + { + Invalid = 0xff, + Pitch = 0x00, + Z16 = 0x01, + Z162C = 0x02, + Z16MS22C = 0x03, + Z16MS42C = 0x04, + Z16MS82C = 0x05, + Z16MS162C = 0x06, + Z162Z = 0x07, + Z16MS22Z = 0x08, + Z16MS42Z = 0x09, + Z16MS82Z = 0x0a, + Z16MS162Z = 0x0b, + Z162CZ = 0x36, + Z16MS22CZ = 0x37, + Z16MS42CZ = 0x38, + Z16MS82CZ = 0x39, + Z16MS162CZ = 0x5f, + Z164CZ = 0x0c, + Z16MS24CZ = 0x0d, + Z16MS44CZ = 0x0e, + Z16MS84CZ = 0x0f, + Z16MS164CZ = 0x10, + S8Z24 = 0x11, + S8Z241Z = 0x12, + S8Z24MS21Z = 0x13, + S8Z24MS41Z = 0x14, + S8Z24MS81Z = 0x15, + S8Z24MS161Z = 0x16, + S8Z242CZ = 0x17, + S8Z24MS22CZ = 0x18, + S8Z24MS42CZ = 0x19, + S8Z24MS82CZ = 0x1a, + S8Z24MS162CZ = 0x1b, + S8Z242CS = 0x1c, + S8Z24MS22CS = 0x1d, + S8Z24MS42CS = 0x1e, + S8Z24MS82CS = 0x1f, + S8Z24MS162CS = 0x20, + S8Z244CSZV = 0x21, + S8Z24MS24CSZV = 0x22, + S8Z24MS44CSZV = 0x23, + S8Z24MS84CSZV = 0x24, + S8Z24MS164CSZV = 0x25, + V8Z24MS4VC12 = 0x26, + V8Z24MS4VC4 = 0x27, + V8Z24MS8VC8 = 0x28, + V8Z24MS8VC24 = 0x29, + V8Z24MS4VC121ZV = 0x2e, + V8Z24MS4VC41ZV = 0x2f, + V8Z24MS8VC81ZV = 0x30, + V8Z24MS8VC241ZV = 0x31, + V8Z24MS4VC122CS = 0x32, + V8Z24MS4VC42CS = 0x33, + V8Z24MS8VC82CS = 0x34, + V8Z24MS8VC242CS = 0x35, + V8Z24MS4VC122CZV = 0x3a, + V8Z24MS4VC42CZV = 0x3b, + V8Z24MS8VC82CZV = 0x3c, + V8Z24MS8VC242CZV = 0x3d, + V8Z24MS4VC122ZV = 0x3e, + V8Z24MS4VC42ZV = 0x3f, + V8Z24MS8VC82ZV = 0x40, + V8Z24MS8VC242ZV = 0x41, + V8Z24MS4VC124CSZV = 0x42, + V8Z24MS4VC44CSZV = 0x43, + V8Z24MS8VC84CSZV = 0x44, + V8Z24MS8VC244CSZV = 0x45, + Z24S8 = 0x46, + Z24S81Z = 0x47, + Z24S8MS21Z = 0x48, + Z24S8MS41Z = 0x49, + Z24S8MS81Z = 0x4a, + Z24S8MS161Z = 0x4b, + Z24S82CS = 0x4c, + Z24S8MS22CS = 0x4d, + Z24S8MS42CS = 0x4e, + Z24S8MS82CS = 0x4f, + Z24S8MS162CS = 0x50, + Z24S82CZ = 0x51, + Z24S8MS22CZ = 0x52, + Z24S8MS42CZ = 0x53, + Z24S8MS82CZ = 0x54, + Z24S8MS162CZ = 0x55, + Z24S84CSZV = 0x56, + Z24S8MS24CSZV = 0x57, + Z24S8MS44CSZV = 0x58, + Z24S8MS84CSZV = 0x59, + Z24S8MS164CSZV = 0x5a, + Z24V8MS4VC12 = 0x5b, + Z24V8MS4VC4 = 0x5c, + Z24V8MS8VC8 = 0x5d, + Z24V8MS8VC24 = 0x5e, + YUVB8C12Y = 0x60, + YUVB8C22Y = 0x61, + YUVB10C12Y = 0x62, + YUVB10C22Y = 0x6b, + YUVB12C12Y = 0x6c, + YUVB12C22Y = 0x6d, + Z24V8MS4VC121ZV = 0x63, + Z24V8MS4VC41ZV = 0x64, + Z24V8MS8VC81ZV = 0x65, + Z24V8MS8VC241ZV = 0x66, + Z24V8MS4VC122CS = 0x67, + Z24V8MS4VC42CS = 0x68, + Z24V8MS8VC82CS = 0x69, + Z24V8MS8VC242CS = 0x6a, + Z24V8MS4VC122CZV = 0x6f, + Z24V8MS4VC42CZV = 0x70, + Z24V8MS8VC82CZV = 0x71, + Z24V8MS8VC242CZV = 0x72, + Z24V8MS4VC122ZV = 0x73, + Z24V8MS4VC42ZV = 0x74, + Z24V8MS8VC82ZV = 0x75, + Z24V8MS8VC242ZV = 0x76, + Z24V8MS4VC124CSZV = 0x77, + Z24V8MS4VC44CSZV = 0x78, + Z24V8MS8VC84CSZV = 0x79, + Z24V8MS8VC244CSZV = 0x7a, + ZF32 = 0x7b, + ZF321Z = 0x7c, + ZF32MS21Z = 0x7d, + ZF32MS41Z = 0x7e, + ZF32MS81Z = 0x7f, + ZF32MS161Z = 0x80, + ZF322CS = 0x81, + ZF32MS22CS = 0x82, + ZF32MS42CS = 0x83, + ZF32MS82CS = 0x84, + ZF32MS162CS = 0x85, + ZF322CZ = 0x86, + ZF32MS22CZ = 0x87, + ZF32MS42CZ = 0x88, + ZF32MS82CZ = 0x89, + ZF32MS162CZ = 0x8a, + X8Z24X16V8S8MS4VC12 = 0x8b, + X8Z24X16V8S8MS4VC4 = 0x8c, + X8Z24X16V8S8MS8VC8 = 0x8d, + X8Z24X16V8S8MS8VC24 = 0x8e, + X8Z24X16V8S8MS4VC121CS = 0x8f, + X8Z24X16V8S8MS4VC41CS = 0x90, + X8Z24X16V8S8MS8VC81CS = 0x91, + X8Z24X16V8S8MS8VC241CS = 0x92, + X8Z24X16V8S8MS4VC121ZV = 0x97, + X8Z24X16V8S8MS4VC41ZV = 0x98, + X8Z24X16V8S8MS8VC81ZV = 0x99, + X8Z24X16V8S8MS8VC241ZV = 0x9a, + X8Z24X16V8S8MS4VC121CZV = 0x9b, + X8Z24X16V8S8MS4VC41CZV = 0x9c, + X8Z24X16V8S8MS8VC81CZV = 0x9d, + X8Z24X16V8S8MS8VC241CZV = 0x9e, + X8Z24X16V8S8MS4VC122CS = 0x9f, + X8Z24X16V8S8MS4VC42CS = 0xa0, + X8Z24X16V8S8MS8VC82CS = 0xa1, + X8Z24X16V8S8MS8VC242CS = 0xa2, + X8Z24X16V8S8MS4VC122CSZV = 0xa3, + X8Z24X16V8S8MS4VC42CSZV = 0xa4, + X8Z24X16V8S8MS8VC82CSZV = 0xa5, + X8Z24X16V8S8MS8VC242CSZV = 0xa6, + ZF32X16V8S8MS4VC12 = 0xa7, + ZF32X16V8S8MS4VC4 = 0xa8, + ZF32X16V8S8MS8VC8 = 0xa9, + ZF32X16V8S8MS8VC24 = 0xaa, + ZF32X16V8S8MS4VC121CS = 0xab, + ZF32X16V8S8MS4VC41CS = 0xac, + ZF32X16V8S8MS8VC81CS = 0xad, + ZF32X16V8S8MS8VC241CS = 0xae, + ZF32X16V8S8MS4VC121ZV = 0xb3, + ZF32X16V8S8MS4VC41ZV = 0xb4, + ZF32X16V8S8MS8VC81ZV = 0xb5, + ZF32X16V8S8MS8VC241ZV = 0xb6, + ZF32X16V8S8MS4VC121CZV = 0xb7, + ZF32X16V8S8MS4VC41CZV = 0xb8, + ZF32X16V8S8MS8VC81CZV = 0xb9, + ZF32X16V8S8MS8VC241CZV = 0xba, + ZF32X16V8S8MS4VC122CS = 0xbb, + ZF32X16V8S8MS4VC42CS = 0xbc, + ZF32X16V8S8MS8VC82CS = 0xbd, + ZF32X16V8S8MS8VC242CS = 0xbe, + ZF32X16V8S8MS4VC122CSZV = 0xbf, + ZF32X16V8S8MS4VC42CSZV = 0xc0, + ZF32X16V8S8MS8VC82CSZV = 0xc1, + ZF32X16V8S8MS8VC242CSZV = 0xc2, + ZF32X24S8 = 0xc3, + ZF32X24S81CS = 0xc4, + ZF32X24S8MS21CS = 0xc5, + ZF32X24S8MS41CS = 0xc6, + ZF32X24S8MS81CS = 0xc7, + ZF32X24S8MS161CS = 0xc8, + ZF32X24S82CSZV = 0xce, + ZF32X24S8MS22CSZV = 0xcf, + ZF32X24S8MS42CSZV = 0xd0, + ZF32X24S8MS82CSZV = 0xd1, + ZF32X24S8MS162CSZV = 0xd2, + ZF32X24S82CS = 0xd3, + ZF32X24S8MS22CS = 0xd4, + ZF32X24S8MS42CS = 0xd5, + ZF32X24S8MS82CS = 0xd6, + ZF32X24S8MS162CS = 0xd7, + S8 = 0x2a, + S82S = 0x2b, + Generic16Bx2 = 0xfe, + C322C = 0xd8, + C322CBR = 0xd9, + C322CBA = 0xda, + C322CRA = 0xdb, + C322BRA = 0xdc, + C32MS22C = 0xdd, + C32MS22CBR = 0xde, + C32MS24CBRA = 0xcc, + C32MS42C = 0xdf, + C32MS42CBR = 0xe0, + C32MS42CBA = 0xe1, + C32MS42CRA = 0xe2, + C32MS42BRA = 0xe3, + C32MS44CBRA = 0x2c, + C32MS8MS162C = 0xe4, + C32MS8MS162CRA = 0xe5, + C642C = 0xe6, + C642CBR = 0xe7, + C642CBA = 0xe8, + C642CRA = 0xe9, + C642BRA = 0xea, + C64MS22C = 0xeb, + C64MS22CBR = 0xec, + C64MS24CBRA = 0xcd, + C64MS42C = 0xed, + C64MS42CBR = 0xee, + C64MS42CBA = 0xef, + C64MS42CRA = 0xf0, + C64MS42BRA = 0xf1, + C64MS44CBRA = 0x2d, + C64MS8MS162C = 0xf2, + C64MS8MS162CRA = 0xf3, + C1282C = 0xf4, + C1282CR = 0xf5, + C128MS22C = 0xf6, + C128MS22CR = 0xf7, + C128MS42C = 0xf8, + C128MS42CR = 0xf9, + C128MS8MS162C = 0xfa, + C128MS8MS162CR = 0xfb, + X8C24 = 0xfc, + PitchNoSwizzle = 0xfd, + SmSkedMessage = 0xca, + SmHostMessage = 0xcb + } + + static class PteKindExtensions + { + /// + /// Checks if the kind is pitch. + /// + /// Kind to check + /// True if pitch, false otherwise + public static bool IsPitch(this PteKind kind) + { + return kind == PteKind.Pitch || kind == PteKind.PitchNoSwizzle; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Memory/ResourceName.cs b/Ryujinx.Graphics.Gpu/Memory/ResourceName.cs deleted file mode 100644 index c3d2dc77a..000000000 --- a/Ryujinx.Graphics.Gpu/Memory/ResourceName.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.Graphics.Gpu.Memory -{ - /// - /// Name of a GPU resource. - /// - public enum ResourceName - { - Buffer, - Texture, - TexturePool, - SamplerPool - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs b/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs index a81999321..039a25832 100644 --- a/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs +++ b/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs @@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Nvdec.Image int width = surface.Width; int height = surface.Height; int stride = surface.Stride; - + ReadOnlySpan luma = gmm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1)); ReadLuma(surface.YPlane.AsSpan(), luma, stride, width, height); diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs index ac5761d69..3314002c6 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs @@ -232,7 +232,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu ulong virtualAddress = arguments.Offset + arguments.BufferOffset; physicalAddress += arguments.BufferOffset; - _asContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize); + _asContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize, (PteKind)arguments.Kind); return NvInternalResult.Success; } @@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu { if (_asContext.ValidateFixedBuffer(arguments.Offset, size, pageSize)) { - _asContext.Gmm.Map(physicalAddress, arguments.Offset, size); + _asContext.Gmm.Map(physicalAddress, arguments.Offset, size, (PteKind)arguments.Kind); } else { @@ -301,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu _memoryAllocator.AllocateRange(va, size, freeAddressStartPosition); } - _asContext.Gmm.Map(physicalAddress, va, size); + _asContext.Gmm.Map(physicalAddress, va, size, (PteKind)arguments.Kind); arguments.Offset = va; } @@ -366,26 +366,30 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu for (int index = 0; index < arguments.Length; index++) { - ulong mapOffs = (ulong)arguments[index].MapOffset << 16; - ulong gpuVa = (ulong)arguments[index].GpuOffset << 16; - ulong size = (ulong)arguments[index].Pages << 16; + ref RemapArguments argument = ref arguments[index]; + ulong gpuVa = (ulong)argument.GpuOffset << 16; + ulong size = (ulong)argument.Pages << 16; + int nvmapHandle = argument.NvMapHandle; - if (arguments[index].NvMapHandle == 0) + if (nvmapHandle == 0) { gmm.Unmap(gpuVa, size); } else { - NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments[index].NvMapHandle); + ulong mapOffs = (ulong)argument.MapOffset << 16; + PteKind kind = (PteKind)argument.Kind; + + NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, nvmapHandle); if (map == null) { - Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments[index].NvMapHandle:x8}!"); + Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{nvmapHandle:x8}!"); return NvInternalResult.InvalidInput; } - gmm.Map(mapOffs + map.Address, gpuVa, size); + gmm.Map(mapOffs + map.Address, gpuVa, size, kind); } } diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs index f0c968eb3..f73e38917 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs @@ -251,7 +251,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue) { _host1xContext.MemoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition); - _host1xContext.Smmu.Map(map.Address, va, (uint)map.Size); + _host1xContext.Smmu.Map(map.Address, va, (uint)map.Size, PteKind.Pitch); // FIXME: This should not use the GMMU. map.DmaMapAddress = va; } else From d1146a5af20dcda5bb6bf8cb2f702bca1c789408 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Sun, 20 Mar 2022 17:48:43 +0000 Subject: [PATCH 5/9] Don't restore Viewport 0 if it hasn't been set yet. (#3219) Fixes a driver crash when starting some games caused by #3217 --- Ryujinx.Graphics.OpenGL/Pipeline.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index 35278629b..114fa6855 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -612,7 +612,7 @@ namespace Ryujinx.Graphics.OpenGL _program?.Bind(); _unit0Sampler?.Bind(0); - GL.ViewportArray(0, 1, _viewportArray); + RestoreViewport0(); Enable(EnableCap.CullFace, _cullEnable); Enable(EnableCap.StencilTest, _stencilTestEnable); @@ -1501,7 +1501,10 @@ namespace Ryujinx.Graphics.OpenGL public void RestoreViewport0() { - GL.ViewportArray(0, 1, _viewportArray); + if (_viewportArray.Length > 0) + { + GL.ViewportArray(0, 1, _viewportArray); + } } public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) From ba0171d05464201c1513386b7d0b69b5ea956426 Mon Sep 17 00:00:00 2001 From: merry Date: Mon, 21 Mar 2022 08:21:05 +0000 Subject: [PATCH 6/9] Memory.Tests: Make Multithreading test explicit (#3220) --- Ryujinx.Memory.Tests/TrackingTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ryujinx.Memory.Tests/TrackingTests.cs b/Ryujinx.Memory.Tests/TrackingTests.cs index d273ace32..b0c39ab04 100644 --- a/Ryujinx.Memory.Tests/TrackingTests.cs +++ b/Ryujinx.Memory.Tests/TrackingTests.cs @@ -188,7 +188,7 @@ namespace Ryujinx.Memory.Tests Assert.False(alignedAfterTriggers); } - [Test, Timeout(1000)] + [Test, Explicit, Timeout(1000)] public void Multithreading() { // Multithreading sanity test From e3b36db71c62a34a26b30683dd5ad5410c97cc9c Mon Sep 17 00:00:00 2001 From: Ac_K Date: Tue, 22 Mar 2022 20:46:16 +0100 Subject: [PATCH 7/9] hle: Some cleanup (#3210) * hle: Some cleanup This PR cleaned up a bit the HLE folder and the VirtualFileSystem one, since we use LibHac, we can use some class of it directly instead of duplicate things. The "Content" of VFS folder is removed since it should be handled in the NCM service directly. A larger cleanup should be done later since there is still be duplicated code here and there. * Fix Headless.SDL2 * Addresses gdkchan feedback --- Ryujinx.HLE/FileSystem/Content/ContentPath.cs | 19 ---- .../FileSystem/Content/LocationHelper.cs | 91 ------------------- Ryujinx.HLE/FileSystem/Content/StorageId.cs | 9 -- Ryujinx.HLE/FileSystem/Content/TitleType.cs | 15 --- .../{Content => }/ContentManager.cs | 19 ++-- Ryujinx.HLE/FileSystem/ContentPath.cs | 82 +++++++++++++++++ .../FileSystem/EncryptedFileSystemCreator.cs | 5 +- .../FileSystem/{Content => }/LocationEntry.cs | 2 +- Ryujinx.HLE/FileSystem/SaveDataType.cs | 12 --- Ryujinx.HLE/FileSystem/SaveInfo.cs | 27 ------ Ryujinx.HLE/FileSystem/SaveSpaceId.cs | 10 -- Ryujinx.HLE/FileSystem/StorageId.cs | 12 --- .../FileSystem/{Content => }/SystemVersion.cs | 3 +- Ryujinx.HLE/FileSystem/VirtualFileSystem.cs | 88 +++++++----------- Ryujinx.HLE/HLEConfiguration.cs | 1 - Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs | 4 +- Ryujinx.HLE/HOS/Horizon.cs | 5 +- .../Services/Arp/ApplicationLaunchProperty.cs | 6 +- .../HOS/Services/Fs/IFileSystemProxy.cs | 2 - Ryujinx.HLE/HOS/Services/Hid/Hid.cs | 4 +- .../Ncm/Lr/ILocationResolverManager.cs | 2 +- .../ILocationResolver.cs | 2 +- .../Nim/IShopServiceAccessServerInterface.cs | 4 +- .../HOS/Services/Sdb/Pl/SharedFontManager.cs | 4 +- .../Settings/ISystemSettingsServer.cs | 4 +- .../HOS/Services/Spl/IGeneralInterface.cs | 3 +- .../Services/Ssl/BuiltInCertificateManager.cs | 4 +- .../Time/TimeZone/TimeZoneContentManager.cs | 4 +- Ryujinx.HLE/Switch.cs | 85 ++++++----------- Ryujinx.Headless.SDL2/Program.cs | 2 - Ryujinx/Ui/Helper/SetupValidator.cs | 2 +- Ryujinx/Ui/MainWindow.cs | 22 ++--- Ryujinx/Ui/Windows/AvatarWindow.cs | 4 +- Ryujinx/Ui/Windows/SettingsWindow.cs | 4 +- .../Ui/Windows/UserProfilesManagerWindow.cs | 3 +- 35 files changed, 192 insertions(+), 373 deletions(-) delete mode 100644 Ryujinx.HLE/FileSystem/Content/ContentPath.cs delete mode 100644 Ryujinx.HLE/FileSystem/Content/LocationHelper.cs delete mode 100644 Ryujinx.HLE/FileSystem/Content/StorageId.cs delete mode 100644 Ryujinx.HLE/FileSystem/Content/TitleType.cs rename Ryujinx.HLE/FileSystem/{Content => }/ContentManager.cs (98%) create mode 100644 Ryujinx.HLE/FileSystem/ContentPath.cs rename Ryujinx.HLE/FileSystem/{Content => }/LocationEntry.cs (94%) delete mode 100644 Ryujinx.HLE/FileSystem/SaveDataType.cs delete mode 100644 Ryujinx.HLE/FileSystem/SaveInfo.cs delete mode 100644 Ryujinx.HLE/FileSystem/SaveSpaceId.cs delete mode 100644 Ryujinx.HLE/FileSystem/StorageId.cs rename Ryujinx.HLE/FileSystem/{Content => }/SystemVersion.cs (95%) diff --git a/Ryujinx.HLE/FileSystem/Content/ContentPath.cs b/Ryujinx.HLE/FileSystem/Content/ContentPath.cs deleted file mode 100644 index 1e2c8ab32..000000000 --- a/Ryujinx.HLE/FileSystem/Content/ContentPath.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.HLE.FileSystem.Content -{ - static class ContentPath - { - public const string SystemContent = "@SystemContent"; - public const string UserContent = "@UserContent"; - public const string SdCardContent = "@SdCardContent"; - public const string SdCard = "@SdCard"; - public const string CalibFile = "@CalibFile"; - public const string Safe = "@Safe"; - public const string User = "@User"; - public const string System = "@System"; - public const string Host = "@Host"; - public const string GamecardApp = "@GcApp"; - public const string GamecardContents = "@GcS00000001"; - public const string GamecardUpdate = "@upp"; - public const string RegisteredUpdate = "@RegUpdate"; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/FileSystem/Content/LocationHelper.cs b/Ryujinx.HLE/FileSystem/Content/LocationHelper.cs deleted file mode 100644 index c522b053b..000000000 --- a/Ryujinx.HLE/FileSystem/Content/LocationHelper.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.IO; - -using static Ryujinx.HLE.FileSystem.VirtualFileSystem; - -namespace Ryujinx.HLE.FileSystem.Content -{ - internal static class LocationHelper - { - public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath) - { - string basePath = fileSystem.GetBasePath(); - - switch (switchContentPath) - { - case ContentPath.SystemContent: - return Path.Combine(basePath, SystemNandPath, "Contents"); - case ContentPath.UserContent: - return Path.Combine(basePath, UserNandPath, "Contents"); - case ContentPath.SdCardContent: - return Path.Combine(fileSystem.GetSdCardPath(), "Nintendo", "Contents"); - case ContentPath.System: - return Path.Combine(basePath, SystemNandPath); - case ContentPath.User: - return Path.Combine(basePath, UserNandPath); - default: - throw new NotSupportedException($"Content Path `{switchContentPath}` is not supported."); - } - } - - public static string GetContentPath(ContentStorageId contentStorageId) - { - switch (contentStorageId) - { - case ContentStorageId.NandSystem: - return ContentPath.SystemContent; - case ContentStorageId.NandUser: - return ContentPath.UserContent; - case ContentStorageId.SdCard: - return ContentPath.SdCardContent; - default: - throw new NotSupportedException($"Content Storage `{contentStorageId}` is not supported."); - } - } - - public static string GetContentRoot(StorageId storageId) - { - switch (storageId) - { - case StorageId.NandSystem: - return ContentPath.SystemContent; - case StorageId.NandUser: - return ContentPath.UserContent; - case StorageId.SdCard: - return ContentPath.SdCardContent; - default: - throw new NotSupportedException($"Storage Id `{storageId}` is not supported."); - } - } - - public static StorageId GetStorageId(string contentPathString) - { - string cleanedPath = contentPathString.Split(':')[0]; - - switch (cleanedPath) - { - case ContentPath.SystemContent: - case ContentPath.System: - return StorageId.NandSystem; - - case ContentPath.UserContent: - case ContentPath.User: - return StorageId.NandUser; - - case ContentPath.SdCardContent: - return StorageId.SdCard; - - case ContentPath.Host: - return StorageId.Host; - - case ContentPath.GamecardApp: - case ContentPath.GamecardContents: - case ContentPath.GamecardUpdate: - return StorageId.GameCard; - - default: - return StorageId.None; - } - } - } -} diff --git a/Ryujinx.HLE/FileSystem/Content/StorageId.cs b/Ryujinx.HLE/FileSystem/Content/StorageId.cs deleted file mode 100644 index 4ff3dd657..000000000 --- a/Ryujinx.HLE/FileSystem/Content/StorageId.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.FileSystem.Content -{ - public enum ContentStorageId - { - NandSystem, - NandUser, - SdCard - } -} diff --git a/Ryujinx.HLE/FileSystem/Content/TitleType.cs b/Ryujinx.HLE/FileSystem/Content/TitleType.cs deleted file mode 100644 index 6ad26c9cd..000000000 --- a/Ryujinx.HLE/FileSystem/Content/TitleType.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Ryujinx.HLE.FileSystem.Content -{ - enum TitleType - { - SystemPrograms = 0x01, - SystemDataArchive = 0x02, - SystemUpdate = 0x03, - FirmwarePackageA = 0x04, - FirmwarePackageB = 0x05, - RegularApplication = 0x80, - Update = 0x81, - AddOnContent = 0x82, - DeltaTitle = 0x83 - } -} diff --git a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs b/Ryujinx.HLE/FileSystem/ContentManager.cs similarity index 98% rename from Ryujinx.HLE/FileSystem/Content/ContentManager.cs rename to Ryujinx.HLE/FileSystem/ContentManager.cs index 8ac31a4c5..2544cdda9 100644 --- a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs +++ b/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -20,7 +20,7 @@ using System.IO.Compression; using System.Linq; using Path = System.IO.Path; -namespace Ryujinx.HLE.FileSystem.Content +namespace Ryujinx.HLE.FileSystem { public class ContentManager { @@ -110,8 +110,8 @@ namespace Ryujinx.HLE.FileSystem.Content try { - contentPathString = LocationHelper.GetContentRoot(storageId); - contentDirectory = LocationHelper.GetRealPath(_virtualFileSystem, contentPathString); + contentPathString = ContentPath.GetContentPath(storageId); + contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString); registeredDirectory = Path.Combine(contentDirectory, "registered"); } catch (NotSupportedException) @@ -367,8 +367,7 @@ namespace Ryujinx.HLE.FileSystem.Content { LocationEntry locationEntry = GetLocation(titleId, contentType, storageId); - return locationEntry.ContentPath != null ? - LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None; + return locationEntry.ContentPath != null ? ContentPath.GetStorageId(locationEntry.ContentPath) : StorageId.None; } } @@ -493,8 +492,8 @@ namespace Ryujinx.HLE.FileSystem.Content public void InstallFirmware(string firmwareSource) { - string contentPathString = LocationHelper.GetContentRoot(StorageId.NandSystem); - string contentDirectory = LocationHelper.GetRealPath(_virtualFileSystem, contentPathString); + string contentPathString = ContentPath.GetContentPath(StorageId.BuiltInSystem); + string contentDirectory = ContentPath.GetRealPath(_virtualFileSystem, contentPathString); string registeredDirectory = Path.Combine(contentDirectory, "registered"); string temporaryDirectory = Path.Combine(contentDirectory, "temp"); @@ -998,9 +997,9 @@ namespace Ryujinx.HLE.FileSystem.Content foreach (var entry in updateNcas) { - foreach (var nca in entry.Value) + foreach (var (type, path) in entry.Value) { - extraNcas += nca.path + Environment.NewLine; + extraNcas += path + Environment.NewLine; } } @@ -1019,7 +1018,7 @@ namespace Ryujinx.HLE.FileSystem.Content lock (_lock) { - var locationEnties = _locationEntries[StorageId.NandSystem]; + var locationEnties = _locationEntries[StorageId.BuiltInSystem]; foreach (var entry in locationEnties) { diff --git a/Ryujinx.HLE/FileSystem/ContentPath.cs b/Ryujinx.HLE/FileSystem/ContentPath.cs new file mode 100644 index 000000000..c8663081a --- /dev/null +++ b/Ryujinx.HLE/FileSystem/ContentPath.cs @@ -0,0 +1,82 @@ +using LibHac.Fs; +using LibHac.Ncm; +using Ryujinx.Common.Configuration; +using System; + +using static Ryujinx.HLE.FileSystem.VirtualFileSystem; +using Path = System.IO.Path; + +namespace Ryujinx.HLE.FileSystem +{ + internal static class ContentPath + { + public const string SystemContent = "@SystemContent"; + public const string UserContent = "@UserContent"; + public const string SdCardContent = "@SdCardContent"; + public const string SdCard = "@Sdcard"; + public const string CalibFile = "@CalibFile"; + public const string Safe = "@Safe"; + public const string User = "@User"; + public const string System = "@System"; + public const string Host = "@Host"; + public const string GamecardApp = "@GcApp"; + public const string GamecardContents = "@GcS00000001"; + public const string GamecardUpdate = "@upp"; + public const string RegisteredUpdate = "@RegUpdate"; + + public const string Nintendo = "Nintendo"; + public const string Contents = "Contents"; + + public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath) + { + return switchContentPath switch + { + SystemContent => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath, Contents), + UserContent => Path.Combine(AppDataManager.BaseDirPath, UserNandPath, Contents), + SdCardContent => Path.Combine(fileSystem.GetSdCardPath(), Nintendo, Contents), + System => Path.Combine(AppDataManager.BaseDirPath, SystemNandPath), + User => Path.Combine(AppDataManager.BaseDirPath, UserNandPath), + _ => throw new NotSupportedException($"Content Path \"`{switchContentPath}`\" is not supported.") + }; + } + + public static string GetContentPath(ContentStorageId contentStorageId) + { + return contentStorageId switch + { + ContentStorageId.System => SystemContent, + ContentStorageId.User => UserContent, + ContentStorageId.SdCard => SdCardContent, + _ => throw new NotSupportedException($"Content Storage Id \"`{contentStorageId}`\" is not supported.") + }; + } + + public static string GetContentPath(StorageId storageId) + { + return storageId switch + { + StorageId.BuiltInSystem => SystemContent, + StorageId.BuiltInUser => UserContent, + StorageId.SdCard => SdCardContent, + _ => throw new NotSupportedException($"Storage Id \"`{storageId}`\" is not supported.") + }; + } + + public static StorageId GetStorageId(string contentPathString) + { + return contentPathString.Split(':')[0] switch + { + SystemContent or + System => StorageId.BuiltInSystem, + UserContent or + User => StorageId.BuiltInUser, + SdCardContent => StorageId.SdCard, + Host => StorageId.Host, + GamecardApp or + GamecardContents or + GamecardUpdate => StorageId.GameCard, + _ => StorageId.None + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/FileSystem/EncryptedFileSystemCreator.cs b/Ryujinx.HLE/FileSystem/EncryptedFileSystemCreator.cs index 60c3cfdb4..f32dc2d77 100644 --- a/Ryujinx.HLE/FileSystem/EncryptedFileSystemCreator.cs +++ b/Ryujinx.HLE/FileSystem/EncryptedFileSystemCreator.cs @@ -8,7 +8,6 @@ namespace Ryujinx.HLE.FileSystem { public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator { - public Result Create(ref SharedRef outEncryptedFileSystem, ref SharedRef baseFileSystem, IEncryptedFileSystemCreator.KeyId idIndex, in EncryptionSeed encryptionSeed) @@ -18,10 +17,10 @@ namespace Ryujinx.HLE.FileSystem return ResultFs.InvalidArgument.Log(); } - // Todo: Reenable when AesXtsFileSystem is fixed + // TODO: Reenable when AesXtsFileSystem is fixed. outEncryptedFileSystem = SharedRef.CreateMove(ref baseFileSystem); return Result.Success; } } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/FileSystem/Content/LocationEntry.cs b/Ryujinx.HLE/FileSystem/LocationEntry.cs similarity index 94% rename from Ryujinx.HLE/FileSystem/Content/LocationEntry.cs rename to Ryujinx.HLE/FileSystem/LocationEntry.cs index bf938746d..45cbc8cd5 100644 --- a/Ryujinx.HLE/FileSystem/Content/LocationEntry.cs +++ b/Ryujinx.HLE/FileSystem/LocationEntry.cs @@ -1,6 +1,6 @@ using LibHac.FsSystem; -namespace Ryujinx.HLE.FileSystem.Content +namespace Ryujinx.HLE.FileSystem { public struct LocationEntry { diff --git a/Ryujinx.HLE/FileSystem/SaveDataType.cs b/Ryujinx.HLE/FileSystem/SaveDataType.cs deleted file mode 100644 index 2207fc23b..000000000 --- a/Ryujinx.HLE/FileSystem/SaveDataType.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.FileSystem -{ - enum SaveDataType : byte - { - SystemSaveData, - SaveData, - BcatDeliveryCacheStorage, - DeviceSaveData, - TemporaryStorage, - CacheStorage - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/FileSystem/SaveInfo.cs b/Ryujinx.HLE/FileSystem/SaveInfo.cs deleted file mode 100644 index 96f2f020e..000000000 --- a/Ryujinx.HLE/FileSystem/SaveInfo.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Account.Acc; - -namespace Ryujinx.HLE.FileSystem -{ - struct SaveInfo - { - public ulong TitleId { get; private set; } - public long SaveId { get; private set; } - public SaveDataType SaveDataType { get; private set; } - public SaveSpaceId SaveSpaceId { get; private set; } - public UserId UserId { get; private set; } - - public SaveInfo( - ulong titleId, - long saveId, - SaveDataType saveDataType, - SaveSpaceId saveSpaceId, - UserId userId = new UserId()) - { - TitleId = titleId; - SaveId = saveId; - SaveDataType = saveDataType; - SaveSpaceId = saveSpaceId; - UserId = userId; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/FileSystem/SaveSpaceId.cs b/Ryujinx.HLE/FileSystem/SaveSpaceId.cs deleted file mode 100644 index d51922df1..000000000 --- a/Ryujinx.HLE/FileSystem/SaveSpaceId.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.FileSystem -{ - enum SaveSpaceId - { - NandSystem, - NandUser, - SdCard, - TemporaryStorage - } -} diff --git a/Ryujinx.HLE/FileSystem/StorageId.cs b/Ryujinx.HLE/FileSystem/StorageId.cs deleted file mode 100644 index d4043e2c7..000000000 --- a/Ryujinx.HLE/FileSystem/StorageId.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.FileSystem -{ - public enum StorageId - { - None, - Host, - GameCard, - NandSystem, - NandUser, - SdCard - } -} diff --git a/Ryujinx.HLE/FileSystem/Content/SystemVersion.cs b/Ryujinx.HLE/FileSystem/SystemVersion.cs similarity index 95% rename from Ryujinx.HLE/FileSystem/Content/SystemVersion.cs rename to Ryujinx.HLE/FileSystem/SystemVersion.cs index 3f19e135a..a7926d5d3 100644 --- a/Ryujinx.HLE/FileSystem/Content/SystemVersion.cs +++ b/Ryujinx.HLE/FileSystem/SystemVersion.cs @@ -1,8 +1,7 @@ using Ryujinx.HLE.Utilities; using System.IO; -using System.Text; -namespace Ryujinx.HLE.FileSystem.Content +namespace Ryujinx.HLE.FileSystem { public class SystemVersion { diff --git a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 9359b03c7..001a1f5f5 100644 --- a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -13,7 +13,6 @@ using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS; using System; using System.Buffers.Text; @@ -28,20 +27,29 @@ namespace Ryujinx.HLE.FileSystem { public class VirtualFileSystem : IDisposable { - public const string NandPath = AppDataManager.DefaultNandDir; - public const string SdCardPath = AppDataManager.DefaultSdcardDir; + public static string SafeNandPath = Path.Combine(AppDataManager.DefaultNandDir, "safe"); + public static string SystemNandPath = Path.Combine(AppDataManager.DefaultNandDir, "system"); + public static string UserNandPath = Path.Combine(AppDataManager.DefaultNandDir, "user"); - public static string SafeNandPath = Path.Combine(NandPath, "safe"); - public static string SystemNandPath = Path.Combine(NandPath, "system"); - public static string UserNandPath = Path.Combine(NandPath, "user"); + public KeySet KeySet { get; private set; } + public EmulatedGameCard GameCard { get; private set; } + public EmulatedSdCard SdCard { get; private set; } + public ModLoader ModLoader { get; private set; } + public Stream RomFs { get; private set; } private static bool _isInitialized = false; - public KeySet KeySet { get; private set; } - public EmulatedGameCard GameCard { get; private set; } - public EmulatedSdCard SdCard { get; private set; } + public static VirtualFileSystem CreateInstance() + { + if (_isInitialized) + { + throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!"); + } - public ModLoader ModLoader { get; private set; } + _isInitialized = true; + + return new VirtualFileSystem(); + } private VirtualFileSystem() { @@ -49,8 +57,6 @@ namespace Ryujinx.HLE.FileSystem ModLoader = new ModLoader(); // Should only be created once } - public Stream RomFs { get; private set; } - public void LoadRomFs(string fileName) { RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read); @@ -79,7 +85,7 @@ namespace Ryujinx.HLE.FileSystem string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName)); - if (!fullPath.StartsWith(GetBasePath())) + if (!fullPath.StartsWith(AppDataManager.BaseDirPath)) { return null; } @@ -87,14 +93,8 @@ namespace Ryujinx.HLE.FileSystem return fullPath; } - internal string GetBasePath() => AppDataManager.BaseDirPath; - internal string GetSdCardPath() => MakeFullPath(SdCardPath); - public string GetNandPath() => MakeFullPath(NandPath); - - public string GetFullPartitionPath(string partitionPath) - { - return MakeFullPath(partitionPath); - } + internal string GetSdCardPath() => MakeFullPath(AppDataManager.DefaultSdcardDir); + public string GetNandPath() => MakeFullPath(AppDataManager.DefaultNandDir); public string SwitchPathToSystemPath(string switchPath) { @@ -110,7 +110,7 @@ namespace Ryujinx.HLE.FileSystem public string SystemPathToSwitchPath(string systemPath) { - string baseSystemPath = GetBasePath() + Path.DirectorySeparatorChar; + string baseSystemPath = AppDataManager.BaseDirPath + Path.DirectorySeparatorChar; if (systemPath.StartsWith(baseSystemPath)) { @@ -136,8 +136,7 @@ namespace Ryujinx.HLE.FileSystem switch (path) { case ContentPath.SdCard: - case "@Sdcard": - path = SdCardPath; + path = AppDataManager.DefaultSdcardDir; break; case ContentPath.User: path = UserNandPath; @@ -146,7 +145,7 @@ namespace Ryujinx.HLE.FileSystem path = SystemNandPath; break; case ContentPath.SdCardContent: - path = Path.Combine(SdCardPath, "Nintendo", "Contents"); + path = Path.Combine(AppDataManager.DefaultSdcardDir, "Nintendo", "Contents"); break; case ContentPath.UserContent: path = Path.Combine(UserNandPath, "Contents"); @@ -156,27 +155,19 @@ namespace Ryujinx.HLE.FileSystem break; } - string fullPath = Path.Combine(GetBasePath(), path); + string fullPath = Path.Combine(AppDataManager.BaseDirPath, path); - if (isDirectory) + if (isDirectory && !Directory.Exists(fullPath)) { - if (!Directory.Exists(fullPath)) - { - Directory.CreateDirectory(fullPath); - } + Directory.CreateDirectory(fullPath); } return fullPath; } - public DriveInfo GetDrive() - { - return new DriveInfo(Path.GetPathRoot(GetBasePath())); - } - public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient) { - LocalFileSystem serverBaseFs = new LocalFileSystem(GetBasePath()); + LocalFileSystem serverBaseFs = new LocalFileSystem(AppDataManager.BaseDirPath); fsServerClient = horizon.CreatePrivilegedHorizonClient(); var fsServer = new FileSystemServer(fsServerClient); @@ -505,7 +496,7 @@ namespace Ryujinx.HLE.FileSystem bool canFixBySaveDataId = extraData.Attribute.StaticSaveDataId == 0 && info.StaticSaveDataId != 0; - bool hasEmptyOwnerId = extraData.OwnerId == 0 && info.Type != LibHac.Fs.SaveDataType.System; + bool hasEmptyOwnerId = extraData.OwnerId == 0 && info.Type != SaveDataType.System; if (!canFixByProgramId && !canFixBySaveDataId && !hasEmptyOwnerId) { @@ -523,7 +514,7 @@ namespace Ryujinx.HLE.FileSystem // The rest of the extra data can't be created from the save data info. // On user saves the owner ID will almost certainly be the same as the program ID. - if (info.Type != LibHac.Fs.SaveDataType.System) + if (info.Type != SaveDataType.System) { extraData.OwnerId = info.ProgramId.Value; } @@ -580,11 +571,6 @@ namespace Ryujinx.HLE.FileSystem } }; - public void Unload() - { - RomFs?.Dispose(); - } - public void Dispose() { Dispose(true); @@ -594,20 +580,8 @@ namespace Ryujinx.HLE.FileSystem { if (disposing) { - Unload(); + RomFs?.Dispose(); } } - - public static VirtualFileSystem CreateInstance() - { - if (_isInitialized) - { - throw new InvalidOperationException("VirtualFileSystem can only be instantiated once!"); - } - - _isInitialized = true; - - return new VirtualFileSystem(); - } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HLEConfiguration.cs b/Ryujinx.HLE/HLEConfiguration.cs index 3da02296e..8fd02a962 100644 --- a/Ryujinx.HLE/HLEConfiguration.cs +++ b/Ryujinx.HLE/HLEConfiguration.cs @@ -3,7 +3,6 @@ using Ryujinx.Audio.Integration; using Ryujinx.Common.Configuration; using Ryujinx.Graphics.GAL; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; diff --git a/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs b/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs index c0d99a773..6780f8026 100644 --- a/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs +++ b/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs @@ -2,10 +2,10 @@ using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.SystemState; using System; @@ -106,7 +106,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error private string GetMessageText(uint module, uint description, string key) { - string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.NandSystem, NcaContentType.Data); + string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data); using (LibHac.Fs.IStorage ncaFileStream = new LocalStorage(_horizon.Device.FileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open)) { diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index cadd43fff..24d04c122 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -10,7 +10,7 @@ using Ryujinx.Audio.Integration; using Ryujinx.Audio.Output; using Ryujinx.Audio.Renderer.Device; using Ryujinx.Audio.Renderer.Server; -using Ryujinx.HLE.FileSystem.Content; +using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Process; @@ -238,6 +238,7 @@ namespace Ryujinx.HLE.HOS SurfaceFlinger = new SurfaceFlinger(device); InitializeAudioRenderer(); + InitializeServices(); } private void InitializeAudioRenderer() @@ -288,7 +289,7 @@ namespace Ryujinx.HLE.HOS AudioManager.Start(); } - public void InitializeServices() + private void InitializeServices() { SmServer = new ServerBase(KernelContext, "SmServer", () => new IUserInterface(KernelContext)); diff --git a/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs b/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs index 5e3961101..c985092b8 100644 --- a/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs +++ b/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.FileSystem; +using LibHac.Ncm; namespace Ryujinx.HLE.HOS.Services.Arp { @@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp { TitleId = 0x00, Version = 0x00, - BaseGameStorageId = (byte)StorageId.NandSystem, + BaseGameStorageId = (byte)StorageId.BuiltInSystem, UpdateGameStorageId = (byte)StorageId.None }; } @@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp { TitleId = context.Device.Application.TitleId, Version = 0x00, - BaseGameStorageId = (byte)StorageId.NandSystem, + BaseGameStorageId = (byte)StorageId.BuiltInSystem, UpdateGameStorageId = (byte)StorageId.None }; } diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs index 945783039..01e1aa34d 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -2,7 +2,6 @@ using LibHac; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Shim; -using LibHac.FsSrv; using LibHac.FsSrv.Impl; using LibHac.FsSystem; using LibHac.Ncm; @@ -19,7 +18,6 @@ using static Ryujinx.HLE.Utilities.StringUtils; using IFileSystem = LibHac.FsSrv.Sf.IFileSystem; using IStorage = LibHac.FsSrv.Sf.IStorage; using RightsId = LibHac.Fs.RightsId; -using StorageId = Ryujinx.HLE.FileSystem.StorageId; namespace Ryujinx.HLE.HOS.Services.Fs { diff --git a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs index b8833e9e1..b1466c787 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs @@ -55,9 +55,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid _storage = storage; SharedMemory = SharedMemory.Create(); + + InitDevices(); } - public void InitDevices() + private void InitDevices() { DebugPad = new DebugPadDevice(_device, true); Touchscreen = new TouchDevice(_device, true); diff --git a/Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs b/Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs index 9f0c61ddf..546c05679 100644 --- a/Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs +++ b/Ryujinx.HLE/HOS/Services/Ncm/Lr/ILocationResolverManager.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.FileSystem; +using LibHac.Ncm; using Ryujinx.HLE.HOS.Services.Ncm.Lr.LocationResolverManager; namespace Ryujinx.HLE.HOS.Services.Ncm.Lr diff --git a/Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs b/Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs index 9928285da..0767b148f 100644 --- a/Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs +++ b/Ryujinx.HLE/HOS/Services/Ncm/Lr/LocationResolverManager/ILocationResolver.cs @@ -1,6 +1,6 @@ using LibHac.FsSystem; +using LibHac.Ncm; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using System.Text; using static Ryujinx.HLE.Utilities.StringUtils; diff --git a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs index 14d1990bb..98f5f6a89 100644 --- a/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Nim/IShopServiceAccessServerInterface.cs @@ -1,5 +1,5 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem; +using LibHac.Ncm; +using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Services.Arp; using Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface; diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs index 13ff1adce..f1ef6a2f0 100644 --- a/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs +++ b/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs @@ -2,11 +2,11 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Services.Sdb.Pl.Types; using System; @@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl { if (contentManager.TryGetFontTitle(name, out ulong fontTitle) && contentManager.TryGetFontFilename(name, out string fontFilename)) { - string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, NcaContentType.Data); + string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.BuiltInSystem, NcaContentType.Data); string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath); if (!string.IsNullOrWhiteSpace(fontPath)) diff --git a/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs index ef1a42bac..88888f34f 100644 --- a/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs +++ b/Ryujinx.HLE/HOS/Services/Settings/ISystemSettingsServer.cs @@ -3,9 +3,9 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Utilities; using System; @@ -290,7 +290,7 @@ namespace Ryujinx.HLE.HOS.Services.Settings { const ulong SystemVersionTitleId = 0x0100000000000809; - string contentPath = device.System.ContentManager.GetInstalledContentPath(SystemVersionTitleId, StorageId.NandSystem, NcaContentType.Data); + string contentPath = device.System.ContentManager.GetInstalledContentPath(SystemVersionTitleId, StorageId.BuiltInSystem, NcaContentType.Data); if (string.IsNullOrWhiteSpace(contentPath)) { diff --git a/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs b/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs index 15625fc2e..53c9eb486 100644 --- a/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs @@ -1,5 +1,4 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem.Content; +using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Services.Spl.Types; diff --git a/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs b/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs index b585224d3..70691e1bd 100644 --- a/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs +++ b/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs @@ -3,13 +3,13 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS.Services.Ssl.Types; using System; using System.Collections.Generic; @@ -82,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl public string GetCertStoreTitleContentPath() { - return _contentManager.GetInstalledContentPath(CertStoreTitleId, StorageId.NandSystem, NcaContentType.Data); + return _contentManager.GetInstalledContentPath(CertStoreTitleId, StorageId.BuiltInSystem, NcaContentType.Data); } public bool HasCertStoreTitle() diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs index afcf976a1..8ff090260 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs @@ -3,12 +3,12 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.HLE.Utilities; using System; @@ -241,7 +241,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone public string GetTimeZoneBinaryTitleContentPath() { - return _contentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.NandSystem, NcaContentType.Data); + return _contentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data); } public bool HasTimeZoneBinaryTitle() diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 0dcbc7ec5..366a26f4a 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -13,27 +13,17 @@ namespace Ryujinx.HLE { public class Switch : IDisposable { - public HLEConfiguration Configuration { get; } - + public HLEConfiguration Configuration { get; } public IHardwareDeviceDriver AudioDeviceDriver { get; } - - internal MemoryBlock Memory { get; } - - public GpuContext Gpu { get; } - - public VirtualFileSystem FileSystem => Configuration.VirtualFileSystem; - - public Horizon System { get; } - - public ApplicationLoader Application { get; } - - public PerformanceStatistics Statistics { get; } - - public Hid Hid { get; } - - public TamperMachine TamperMachine { get; } - - public IHostUiHandler UiHandler { get; } + public MemoryBlock Memory { get; } + public GpuContext Gpu { get; } + public VirtualFileSystem FileSystem { get; } + public Horizon System { get; } + public ApplicationLoader Application { get; } + public PerformanceStatistics Statistics { get; } + public Hid Hid { get; } + public TamperMachine TamperMachine { get; } + public IHostUiHandler UiHandler { get; } public bool EnableDeviceVsync { get; set; } = true; @@ -55,47 +45,27 @@ namespace Ryujinx.HLE } Configuration = configuration; + FileSystem = Configuration.VirtualFileSystem; + UiHandler = Configuration.HostUiHandler; - UiHandler = configuration.HostUiHandler; + AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver); + Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), MemoryAllocationFlags.Reserve); + Gpu = new GpuContext(Configuration.GpuRenderer); + System = new Horizon(this); + Statistics = new PerformanceStatistics(); + Hid = new Hid(this, System.HidStorage); + Application = new ApplicationLoader(this); + TamperMachine = new TamperMachine(); - AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(configuration.AudioDeviceDriver); - - Memory = new MemoryBlock(configuration.MemoryConfiguration.ToDramSize(), MemoryAllocationFlags.Reserve); - - Gpu = new GpuContext(configuration.GpuRenderer); - - System = new Horizon(this); - System.InitializeServices(); - - Statistics = new PerformanceStatistics(); - - Hid = new Hid(this, System.HidStorage); - Hid.InitDevices(); - - Application = new ApplicationLoader(this); - - TamperMachine = new TamperMachine(); - - Initialize(); - } - - private void Initialize() - { System.State.SetLanguage(Configuration.SystemLanguage); - System.State.SetRegion(Configuration.Region); - EnableDeviceVsync = Configuration.EnableVsync; - - System.State.DockedMode = Configuration.EnableDockedMode; - + EnableDeviceVsync = Configuration.EnableVsync; + System.State.DockedMode = Configuration.EnableDockedMode; System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; - - System.EnablePtc = Configuration.EnablePtc; - - System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel; - - System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode; + System.EnablePtc = Configuration.EnablePtc; + System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel; + System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode; } public void LoadCart(string exeFsDir, string romFsFile = null) @@ -132,7 +102,6 @@ namespace Ryujinx.HLE { Gpu.ProcessShaderCacheQueue(); Gpu.Renderer.PreFrame(); - Gpu.GPFifo.DispatchCalls(); } @@ -182,9 +151,9 @@ namespace Ryujinx.HLE { System.Dispose(); AudioDeviceDriver.Dispose(); - FileSystem.Unload(); + FileSystem.Dispose(); Memory.Dispose(); } } } -} +} \ No newline at end of file diff --git a/Ryujinx.Headless.SDL2/Program.cs b/Ryujinx.Headless.SDL2/Program.cs index 5915a8817..1d64a8c6c 100644 --- a/Ryujinx.Headless.SDL2/Program.cs +++ b/Ryujinx.Headless.SDL2/Program.cs @@ -20,7 +20,6 @@ using Ryujinx.Graphics.OpenGL; using Ryujinx.Headless.SDL2.OpenGL; using Ryujinx.HLE; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.Input; @@ -29,7 +28,6 @@ using Ryujinx.Input.SDL2; using System; using System.Collections.Generic; using System.IO; -using System.Reflection; using System.Text.Json; using System.Threading; diff --git a/Ryujinx/Ui/Helper/SetupValidator.cs b/Ryujinx/Ui/Helper/SetupValidator.cs index 45315f8fb..8be8497be 100644 --- a/Ryujinx/Ui/Helper/SetupValidator.cs +++ b/Ryujinx/Ui/Helper/SetupValidator.cs @@ -1,5 +1,5 @@ using Ryujinx.Common.Logging; -using Ryujinx.HLE.FileSystem.Content; +using Ryujinx.HLE.FileSystem; using Ryujinx.Ui.Widgets; using System; using System.IO; diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 32e66ee4e..54e28765a 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -1,18 +1,10 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; - -using ARMeilleure.Translation; +using ARMeilleure.Translation; using ARMeilleure.Translation.PTC; - using Gtk; - using LibHac.Common; using LibHac.Common.Keys; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Ns; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.Dummy; @@ -29,7 +21,6 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.OpenGL; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; @@ -42,9 +33,14 @@ using Ryujinx.Ui.Applet; using Ryujinx.Ui.Helper; using Ryujinx.Ui.Widgets; using Ryujinx.Ui.Windows; +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; using GUI = Gtk.Builder.ObjectAttribute; - using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; @@ -1283,7 +1279,7 @@ namespace Ryujinx.Ui private void Load_Mii_Edit_Applet(object sender, EventArgs args) { - string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.NandSystem, NcaContentType.Program); + string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program); LoadApplication(contentPath); } diff --git a/Ryujinx/Ui/Windows/AvatarWindow.cs b/Ryujinx/Ui/Windows/AvatarWindow.cs index 687b3d174..a5c07aed6 100644 --- a/Ryujinx/Ui/Windows/AvatarWindow.cs +++ b/Ryujinx/Ui/Windows/AvatarWindow.cs @@ -3,10 +3,10 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; +using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; @@ -115,7 +115,7 @@ namespace Ryujinx.Ui.Windows return; } - string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.NandSystem, NcaContentType.Data); + string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data); string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath); if (!string.IsNullOrWhiteSpace(avatarPath)) diff --git a/Ryujinx/Ui/Windows/SettingsWindow.cs b/Ryujinx/Ui/Windows/SettingsWindow.cs index 2b423081e..f0e937301 100644 --- a/Ryujinx/Ui/Windows/SettingsWindow.cs +++ b/Ryujinx/Ui/Windows/SettingsWindow.cs @@ -105,9 +105,9 @@ namespace Ryujinx.Ui.Windows #pragma warning restore CS0649, IDE0044 - public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } + public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } - private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle) + private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle) { Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png"); diff --git a/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs index b26e7e201..862d5f15c 100644 --- a/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs +++ b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs @@ -1,6 +1,5 @@ using Gtk; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.Ui.Widgets; using SixLabors.ImageSharp; @@ -12,7 +11,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Image = SixLabors.ImageSharp.Image; +using Image = SixLabors.ImageSharp.Image; using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId; namespace Ryujinx.Ui.Windows From 1402d8391d84f912110104e3e6c1a50a8c000d59 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 23 Mar 2022 17:09:32 -0300 Subject: [PATCH 8/9] Support NVDEC H264 interlaced video decoding and VIC deinterlacing (#3225) * Support NVDEC H264 interlaced video decoding and VIC deinterlacing * Remove unused code --- Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs | 43 ++++ Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs | 10 + Ryujinx.Graphics.Nvdec.FFmpeg/Surface.cs | 6 +- Ryujinx.Graphics.Nvdec.Vp9/Dsp/InvTxfm.cs | 3 +- Ryujinx.Graphics.Nvdec.Vp9/Types/Surface.cs | 2 + Ryujinx.Graphics.Nvdec/H264Decoder.cs | 19 +- Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs | 49 ++++ .../Types/H264/PictureInfo.cs | 6 +- Ryujinx.Graphics.Vic/Blender.cs | 36 +-- Ryujinx.Graphics.Vic/Image/BufferPool.cs | 2 +- Ryujinx.Graphics.Vic/Image/InputSurface.cs | 69 ++++++ Ryujinx.Graphics.Vic/Image/SurfaceReader.cs | 221 +++++++++++++++--- Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs | 6 +- Ryujinx.Graphics.Vic/Scaler.cs | 124 ++++++++++ Ryujinx.Graphics.Vic/Types/DeinterlaceMode.cs | 12 + Ryujinx.Graphics.Vic/Types/FrameFormat.cs | 79 +++++++ Ryujinx.Graphics.Vic/Types/SlotConfig.cs | 4 +- Ryujinx.Graphics.Vic/VicDevice.cs | 4 +- Ryujinx.Graphics.Video/FrameField.cs | 8 + Ryujinx.Graphics.Video/ISurface.cs | 2 + 20 files changed, 623 insertions(+), 82 deletions(-) create mode 100644 Ryujinx.Graphics.Vic/Scaler.cs create mode 100644 Ryujinx.Graphics.Vic/Types/DeinterlaceMode.cs create mode 100644 Ryujinx.Graphics.Vic/Types/FrameFormat.cs create mode 100644 Ryujinx.Graphics.Video/FrameField.cs diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index c57f1a6f1..ae27c7129 100644 --- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -255,6 +255,49 @@ namespace Ryujinx.Graphics.Gpu.Memory } } + /// + /// Writes data to GPU mapped memory, stopping at the first unmapped page at the memory region, if any. + /// + /// GPU virtual address to write the data into + /// The data to be written + public void WriteMapped(ulong va, ReadOnlySpan data) + { + if (IsContiguous(va, data.Length)) + { + Physical.Write(Translate(va), data); + } + else + { + int offset = 0, size; + + if ((va & PageMask) != 0) + { + ulong pa = Translate(va); + + size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask)); + + if (pa != PteUnmapped && Physical.IsMapped(pa)) + { + Physical.Write(pa, data.Slice(0, size)); + } + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + ulong pa = Translate(va + (ulong)offset); + + size = Math.Min(data.Length - offset, (int)PageSize); + + if (pa != PteUnmapped && Physical.IsMapped(pa)) + { + Physical.Write(pa, data.Slice(offset, size)); + } + } + } + } + /// /// Maps a given range of pages to the specified CPU virtual address. /// diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index bfd3c04fa..57590fb38 100644 --- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -340,6 +340,16 @@ namespace Ryujinx.Graphics.Gpu.Memory return _cpuMemory.BeginSmartGranularTracking(address, size, granularity); } + /// + /// Checks if the page at a given address is mapped on CPU memory. + /// + /// CPU virtual address of the page to check + /// True if mapped, false otherwise + public bool IsMapped(ulong address) + { + return _cpuMemory.IsMapped(address); + } + /// /// Release our reference to the CPU memory manager. /// diff --git a/Ryujinx.Graphics.Nvdec.FFmpeg/Surface.cs b/Ryujinx.Graphics.Nvdec.FFmpeg/Surface.cs index 20cee4a18..13d0df498 100644 --- a/Ryujinx.Graphics.Nvdec.FFmpeg/Surface.cs +++ b/Ryujinx.Graphics.Nvdec.FFmpeg/Surface.cs @@ -15,11 +15,13 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg public Plane UPlane => new Plane((IntPtr)Frame->data[1], UvStride * UvHeight); public Plane VPlane => new Plane((IntPtr)Frame->data[2], UvStride * UvHeight); + public FrameField Field => Frame->interlaced_frame != 0 ? FrameField.Interlaced : FrameField.Progressive; + public int Width => Frame->width; public int Height => Frame->height; public int Stride => Frame->linesize[0]; - public int UvWidth => (Frame->width + 1) >> 1; - public int UvHeight => (Frame->height + 1) >> 1; + public int UvWidth => (Width + 1) >> 1; + public int UvHeight => (Height + 1) >> 1; public int UvStride => Frame->linesize[1]; public Surface(int width, int height) diff --git a/Ryujinx.Graphics.Nvdec.Vp9/Dsp/InvTxfm.cs b/Ryujinx.Graphics.Nvdec.Vp9/Dsp/InvTxfm.cs index e41a31cac..873f667ac 100644 --- a/Ryujinx.Graphics.Nvdec.Vp9/Dsp/InvTxfm.cs +++ b/Ryujinx.Graphics.Nvdec.Vp9/Dsp/InvTxfm.cs @@ -486,8 +486,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp Idct8(tempIn, tempOut); for (j = 0; j < 8; ++j) { - dest[j * stride + i] = ClipPixelAdd(dest[j * stride + i], - BitUtils.RoundPowerOfTwo(tempOut[j], 5)); + dest[j * stride + i] = ClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 5)); } } } diff --git a/Ryujinx.Graphics.Nvdec.Vp9/Types/Surface.cs b/Ryujinx.Graphics.Nvdec.Vp9/Types/Surface.cs index 2b2a173eb..d5b51bc2f 100644 --- a/Ryujinx.Graphics.Nvdec.Vp9/Types/Surface.cs +++ b/Ryujinx.Graphics.Nvdec.Vp9/Types/Surface.cs @@ -15,6 +15,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types public unsafe Plane UPlane => new Plane((IntPtr)UBuffer.ToPointer(), UBuffer.Length); public unsafe Plane VPlane => new Plane((IntPtr)VBuffer.ToPointer(), VBuffer.Length); + public FrameField Field => FrameField.Progressive; + public int Width { get; } public int Height { get; } public int AlignedWidth { get; } diff --git a/Ryujinx.Graphics.Nvdec/H264Decoder.cs b/Ryujinx.Graphics.Nvdec/H264Decoder.cs index 69eeb4949..6efeb899e 100644 --- a/Ryujinx.Graphics.Nvdec/H264Decoder.cs +++ b/Ryujinx.Graphics.Nvdec/H264Decoder.cs @@ -31,7 +31,24 @@ namespace Ryujinx.Graphics.Nvdec if (decoder.Decode(ref info, outputSurface, bitstream)) { - SurfaceWriter.Write(rm.Gmm, outputSurface, lumaOffset, chromaOffset); + if (outputSurface.Field == FrameField.Progressive) + { + SurfaceWriter.Write( + rm.Gmm, + outputSurface, + lumaOffset + pictureInfo.LumaFrameOffset, + chromaOffset + pictureInfo.ChromaFrameOffset); + } + else + { + SurfaceWriter.WriteInterlaced( + rm.Gmm, + outputSurface, + lumaOffset + pictureInfo.LumaTopFieldOffset, + chromaOffset + pictureInfo.ChromaTopFieldOffset, + lumaOffset + pictureInfo.LumaBottomFieldOffset, + chromaOffset + pictureInfo.ChromaBottomFieldOffset); + } } rm.Cache.Put(outputSurface); diff --git a/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs b/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs index 5c294621a..cc5c251be 100644 --- a/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs +++ b/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs @@ -38,6 +38,55 @@ namespace Ryujinx.Graphics.Nvdec.Image surface.UvHeight); } + public static void WriteInterlaced( + MemoryManager gmm, + ISurface surface, + uint lumaTopOffset, + uint chromaTopOffset, + uint lumaBottomOffset, + uint chromaBottomOffset) + { + int lumaSize = GetBlockLinearSize(surface.Width, surface.Height / 2, 1); + + using var lumaTop = gmm.GetWritableRegion(ExtendOffset(lumaTopOffset), lumaSize); + using var lumaBottom = gmm.GetWritableRegion(ExtendOffset(lumaBottomOffset), lumaSize); + + WriteLuma( + lumaTop.Memory.Span, + surface.YPlane.AsSpan(), + surface.Stride * 2, + surface.Width, + surface.Height / 2); + + WriteLuma( + lumaBottom.Memory.Span, + surface.YPlane.AsSpan().Slice(surface.Stride), + surface.Stride * 2, + surface.Width, + surface.Height / 2); + + int chromaSize = GetBlockLinearSize(surface.UvWidth, surface.UvHeight / 2, 2); + + using var chromaTop = gmm.GetWritableRegion(ExtendOffset(chromaTopOffset), chromaSize); + using var chromaBottom = gmm.GetWritableRegion(ExtendOffset(chromaBottomOffset), chromaSize); + + WriteChroma( + chromaTop.Memory.Span, + surface.UPlane.AsSpan(), + surface.VPlane.AsSpan(), + surface.UvStride * 2, + surface.UvWidth, + surface.UvHeight / 2); + + WriteChroma( + chromaBottom.Memory.Span, + surface.UPlane.AsSpan().Slice(surface.UvStride), + surface.VPlane.AsSpan().Slice(surface.UvStride), + surface.UvStride * 2, + surface.UvWidth, + surface.UvHeight / 2); + } + private static void WriteLuma(Span dst, ReadOnlySpan src, int srcStride, int width, int height) { LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, srcStride, 1, 2, src); diff --git a/Ryujinx.Graphics.Nvdec/Types/H264/PictureInfo.cs b/Ryujinx.Graphics.Nvdec/Types/H264/PictureInfo.cs index 326c40ae6..7c779dff3 100644 --- a/Ryujinx.Graphics.Nvdec/Types/H264/PictureInfo.cs +++ b/Ryujinx.Graphics.Nvdec/Types/H264/PictureInfo.cs @@ -26,10 +26,10 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264 public uint Transform8x8ModeFlag; public uint LumaPitch; public uint ChromaPitch; - public uint LumaTopOffset; - public uint LumaBottomOffset; + public uint LumaTopFieldOffset; + public uint LumaBottomFieldOffset; public uint LumaFrameOffset; - public uint ChromaTopOffset; + public uint ChromaTopFieldOffset; public uint ChromaBottomFieldOffset; public uint ChromaFrameOffset; public uint HistBufferSize; diff --git a/Ryujinx.Graphics.Vic/Blender.cs b/Ryujinx.Graphics.Vic/Blender.cs index 84171241e..92b641d63 100644 --- a/Ryujinx.Graphics.Vic/Blender.cs +++ b/Ryujinx.Graphics.Vic/Blender.cs @@ -48,38 +48,10 @@ namespace Ryujinx.Graphics.Vic int one = 1 << (mtx.MatrixRShift + 8); - - // NOTE: This is buggy on .NET 5.0.100, we use a workaround for now (see https://github.com/dotnet/runtime/issues/44704) - // TODO: Uncomment this when fixed. - //Vector128 col1 = Vector128.Create(mtx.MatrixCoeff00, mtx.MatrixCoeff10, mtx.MatrixCoeff20, 0); - //Vector128 col2 = Vector128.Create(mtx.MatrixCoeff01, mtx.MatrixCoeff11, mtx.MatrixCoeff21, 0); - //Vector128 col3 = Vector128.Create(mtx.MatrixCoeff02, mtx.MatrixCoeff12, mtx.MatrixCoeff22, one); - //Vector128 col4 = Vector128.Create(mtx.MatrixCoeff03, mtx.MatrixCoeff13, mtx.MatrixCoeff23, 0); - - Vector128 col1 = new Vector128(); - Vector128 col2 = new Vector128(); - Vector128 col3 = new Vector128(); - Vector128 col4 = new Vector128(); - - col1 = Sse41.Insert(col1, mtx.MatrixCoeff00, 0); - col1 = Sse41.Insert(col1, mtx.MatrixCoeff10, 1); - col1 = Sse41.Insert(col1, mtx.MatrixCoeff20, 2); - col1 = Sse41.Insert(col1, 0, 3); - - col2 = Sse41.Insert(col2, mtx.MatrixCoeff01, 0); - col2 = Sse41.Insert(col2, mtx.MatrixCoeff11, 1); - col2 = Sse41.Insert(col2, mtx.MatrixCoeff21, 2); - col2 = Sse41.Insert(col2, 0, 3); - - col3 = Sse41.Insert(col3, mtx.MatrixCoeff02, 0); - col3 = Sse41.Insert(col3, mtx.MatrixCoeff12, 1); - col3 = Sse41.Insert(col3, mtx.MatrixCoeff22, 2); - col3 = Sse41.Insert(col3, one, 3); - - col4 = Sse41.Insert(col4, mtx.MatrixCoeff03, 0); - col4 = Sse41.Insert(col4, mtx.MatrixCoeff13, 1); - col4 = Sse41.Insert(col4, mtx.MatrixCoeff23, 2); - col4 = Sse41.Insert(col4, 0, 3); + Vector128 col1 = Vector128.Create(mtx.MatrixCoeff00, mtx.MatrixCoeff10, mtx.MatrixCoeff20, 0); + Vector128 col2 = Vector128.Create(mtx.MatrixCoeff01, mtx.MatrixCoeff11, mtx.MatrixCoeff21, 0); + Vector128 col3 = Vector128.Create(mtx.MatrixCoeff02, mtx.MatrixCoeff12, mtx.MatrixCoeff22, one); + Vector128 col4 = Vector128.Create(mtx.MatrixCoeff03, mtx.MatrixCoeff13, mtx.MatrixCoeff23, 0); Vector128 rShift = Vector128.CreateScalar(mtx.MatrixRShift); Vector128 clMin = Vector128.Create((ushort)slot.SlotConfig.SoftClampLow); diff --git a/Ryujinx.Graphics.Vic/Image/BufferPool.cs b/Ryujinx.Graphics.Vic/Image/BufferPool.cs index 932d3dc92..cde7e6ebb 100644 --- a/Ryujinx.Graphics.Vic/Image/BufferPool.cs +++ b/Ryujinx.Graphics.Vic/Image/BufferPool.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Vic.Image /// If the required buffer is larger than this, it won't be /// added to the pool to avoid long term high memory usage. /// - private const int MaxBufferSize = 2048 * 1280; + private const int MaxBufferSize = 2048 * 2048; private struct PoolItem { diff --git a/Ryujinx.Graphics.Vic/Image/InputSurface.cs b/Ryujinx.Graphics.Vic/Image/InputSurface.cs index de003194d..15ac04600 100644 --- a/Ryujinx.Graphics.Vic/Image/InputSurface.cs +++ b/Ryujinx.Graphics.Vic/Image/InputSurface.cs @@ -2,16 +2,85 @@ namespace Ryujinx.Graphics.Vic.Image { + ref struct RentedBuffer + { + public static RentedBuffer Empty => new RentedBuffer(Span.Empty, -1); + + public Span Data; + public int Index; + + public RentedBuffer(Span data, int index) + { + Data = data; + Index = index; + } + + public void Return(BufferPool pool) + { + if (Index != -1) + { + pool.Return(Index); + } + } + } + ref struct InputSurface { public ReadOnlySpan Buffer0; public ReadOnlySpan Buffer1; public ReadOnlySpan Buffer2; + public int Buffer0Index; + public int Buffer1Index; + public int Buffer2Index; + public int Width; public int Height; public int UvWidth; public int UvHeight; + + public void Initialize() + { + Buffer0Index = -1; + Buffer1Index = -1; + Buffer2Index = -1; + } + + public void SetBuffer0(RentedBuffer buffer) + { + Buffer0 = buffer.Data; + Buffer0Index = buffer.Index; + } + + public void SetBuffer1(RentedBuffer buffer) + { + Buffer1 = buffer.Data; + Buffer1Index = buffer.Index; + } + + public void SetBuffer2(RentedBuffer buffer) + { + Buffer2 = buffer.Data; + Buffer2Index = buffer.Index; + } + + public void Return(BufferPool pool) + { + if (Buffer0Index != -1) + { + pool.Return(Buffer0Index); + } + + if (Buffer1Index != -1) + { + pool.Return(Buffer1Index); + } + + if (Buffer2Index != -1) + { + pool.Return(Buffer2Index); + } + } } } diff --git a/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs b/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs index aa8809168..dda766a58 100644 --- a/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs +++ b/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs @@ -1,5 +1,5 @@ using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Common.Memory; using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Vic.Types; using System; @@ -12,24 +12,32 @@ namespace Ryujinx.Graphics.Vic.Image { static class SurfaceReader { - public static Surface Read(ResourceManager rm, ref SlotSurfaceConfig config, ref PlaneOffsets offsets) + public static Surface Read( + ResourceManager rm, + ref SlotConfig config, + ref SlotSurfaceConfig surfaceConfig, + ref Array8 offsets) { - switch (config.SlotPixelFormat) + switch (surfaceConfig.SlotPixelFormat) { - case PixelFormat.Y8___V8U8_N420: return ReadNv12(rm, ref config, ref offsets); + case PixelFormat.Y8___V8U8_N420: return ReadNv12(rm, ref config, ref surfaceConfig, ref offsets); } - Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{config.SlotPixelFormat}\"."); + Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{surfaceConfig.SlotPixelFormat}\"."); - int lw = config.SlotLumaWidth + 1; - int lh = config.SlotLumaHeight + 1; + int lw = surfaceConfig.SlotLumaWidth + 1; + int lh = surfaceConfig.SlotLumaHeight + 1; return new Surface(rm.SurfacePool, lw, lh); } - private unsafe static Surface ReadNv12(ResourceManager rm, ref SlotSurfaceConfig config, ref PlaneOffsets offsets) + private unsafe static Surface ReadNv12( + ResourceManager rm, + ref SlotConfig config, + ref SlotSurfaceConfig surfaceConfig, + ref Array8 offsets) { - InputSurface input = ReadSurface(rm.Gmm, ref config, ref offsets, 1, 2); + InputSurface input = ReadSurface(rm, ref config, ref surfaceConfig, ref offsets, 1, 2); int width = input.Width; int height = input.Height; @@ -160,6 +168,8 @@ namespace Ryujinx.Graphics.Vic.Image } } + input.Return(rm.BufferPool); + return output; } @@ -170,84 +180,227 @@ namespace Ryujinx.Graphics.Vic.Image } private static InputSurface ReadSurface( - MemoryManager gmm, - ref SlotSurfaceConfig config, - ref PlaneOffsets offsets, + ResourceManager rm, + ref SlotConfig config, + ref SlotSurfaceConfig surfaceConfig, + ref Array8 offsets, int bytesPerPixel, int planes) { InputSurface surface = new InputSurface(); - int gobBlocksInY = 1 << config.SlotBlkHeight; + surface.Initialize(); - bool linear = config.SlotBlkKind == 0; + int gobBlocksInY = 1 << surfaceConfig.SlotBlkHeight; - int lw = config.SlotLumaWidth + 1; - int lh = config.SlotLumaHeight + 1; + bool linear = surfaceConfig.SlotBlkKind == 0; - int cw = config.SlotChromaWidth + 1; - int ch = config.SlotChromaHeight + 1; + int lw = surfaceConfig.SlotLumaWidth + 1; + int lh = surfaceConfig.SlotLumaHeight + 1; + + int cw = surfaceConfig.SlotChromaWidth + 1; + int ch = surfaceConfig.SlotChromaHeight + 1; + + // Interlaced inputs have double the height when deinterlaced. + int heightShift = config.FrameFormat.IsField() ? 1 : 0; surface.Width = lw; - surface.Height = lh; + surface.Height = lh << heightShift; surface.UvWidth = cw; - surface.UvHeight = ch; + surface.UvHeight = ch << heightShift; if (planes > 0) { - surface.Buffer0 = ReadBuffer(gmm, offsets.LumaOffset, linear, lw, lh, bytesPerPixel, gobBlocksInY); + surface.SetBuffer0(ReadBuffer(rm, ref config, ref offsets, linear, 0, lw, lh, bytesPerPixel, gobBlocksInY)); } if (planes > 1) { - surface.Buffer1 = ReadBuffer(gmm, offsets.ChromaUOffset, linear, cw, ch, planes == 2 ? 2 : 1, gobBlocksInY); + surface.SetBuffer1(ReadBuffer(rm, ref config, ref offsets, linear, 1, cw, ch, planes == 2 ? 2 : 1, gobBlocksInY)); } if (planes > 2) { - surface.Buffer2 = ReadBuffer(gmm, offsets.ChromaVOffset, linear, cw, ch, 1, gobBlocksInY); + surface.SetBuffer2(ReadBuffer(rm, ref config, ref offsets, linear, 2, cw, ch, 1, gobBlocksInY)); } return surface; } - private static ReadOnlySpan ReadBuffer( - MemoryManager gmm, - uint offset, + private static RentedBuffer ReadBuffer( + ResourceManager rm, + ref SlotConfig config, + ref Array8 offsets, bool linear, + int plane, + int width, + int height, + int bytesPerPixel, + int gobBlocksInY) + { + FrameFormat frameFormat = config.FrameFormat; + bool isLuma = plane == 0; + bool isField = frameFormat.IsField(); + bool isTopField = frameFormat.IsTopField(isLuma); + int stride = GetPitch(width, bytesPerPixel); + uint offset = GetOffset(ref offsets[0], plane); + + int dstStart = 0; + int dstStride = stride; + + if (isField) + { + dstStart = isTopField ? 0 : stride; + dstStride = stride * 2; + } + + RentedBuffer buffer; + + if (linear) + { + buffer = ReadBufferLinear(rm, offset, width, height, dstStart, dstStride, bytesPerPixel); + } + else + { + buffer = ReadBufferBlockLinear(rm, offset, width, height, dstStart, dstStride, bytesPerPixel, gobBlocksInY); + } + + if (isField || frameFormat.IsInterlaced()) + { + RentedBuffer prevBuffer = RentedBuffer.Empty; + RentedBuffer nextBuffer = RentedBuffer.Empty; + + if (config.PrevFieldEnable) + { + prevBuffer = ReadBufferNoDeinterlace(rm, ref offsets[1], linear, plane, width, height, bytesPerPixel, gobBlocksInY); + } + + if (config.NextFieldEnable) + { + nextBuffer = ReadBufferNoDeinterlace(rm, ref offsets[2], linear, plane, width, height, bytesPerPixel, gobBlocksInY); + } + + int w = width * bytesPerPixel; + + switch (config.DeinterlaceMode) + { + case DeinterlaceMode.Weave: + Scaler.DeinterlaceWeave(buffer.Data, prevBuffer.Data, w, stride, isTopField); + break; + case DeinterlaceMode.BobField: + Scaler.DeinterlaceBob(buffer.Data, w, stride, isTopField); + break; + case DeinterlaceMode.Bob: + bool isCurrentTop = isLuma ? config.IsEven : config.ChromaEven; + Scaler.DeinterlaceBob(buffer.Data, w, stride, isCurrentTop ^ frameFormat.IsInterlacedBottomFirst()); + break; + case DeinterlaceMode.NewBob: + case DeinterlaceMode.Disi1: + Scaler.DeinterlaceMotionAdaptive(buffer.Data, prevBuffer.Data, nextBuffer.Data, w, stride, isTopField); + break; + case DeinterlaceMode.WeaveLumaBobFieldChroma: + if (isLuma) + { + Scaler.DeinterlaceWeave(buffer.Data, prevBuffer.Data, w, stride, isTopField); + } + else + { + Scaler.DeinterlaceBob(buffer.Data, w, stride, isTopField); + } + break; + default: + Logger.Error?.Print(LogClass.Vic, $"Unsupported deinterlace mode \"{config.DeinterlaceMode}\"."); + break; + } + + prevBuffer.Return(rm.BufferPool); + nextBuffer.Return(rm.BufferPool); + } + + return buffer; + } + + private static uint GetOffset(ref PlaneOffsets offsets, int plane) + { + return plane switch + { + 0 => offsets.LumaOffset, + 1 => offsets.ChromaUOffset, + 2 => offsets.ChromaVOffset, + _ => throw new ArgumentOutOfRangeException(nameof(plane)) + }; + } + + private static RentedBuffer ReadBufferNoDeinterlace( + ResourceManager rm, + ref PlaneOffsets offsets, + bool linear, + int plane, int width, int height, int bytesPerPixel, int gobBlocksInY) { int stride = GetPitch(width, bytesPerPixel); + uint offset = GetOffset(ref offsets, plane); if (linear) { - return gmm.GetSpan(ExtendOffset(offset), stride * height); + return ReadBufferLinear(rm, offset, width, height, 0, stride, bytesPerPixel); } - return ReadBuffer(gmm, offset, width, height, stride, bytesPerPixel, gobBlocksInY); + return ReadBufferBlockLinear(rm, offset, width, height, 0, stride, bytesPerPixel, gobBlocksInY); } - private static ReadOnlySpan ReadBuffer( - MemoryManager gmm, + private static RentedBuffer ReadBufferLinear( + ResourceManager rm, uint offset, int width, int height, + int dstStart, + int dstStride, + int bytesPerPixel) + { + int srcStride = GetPitch(width, bytesPerPixel); + int inSize = srcStride * height; + + ReadOnlySpan src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize); + + int outSize = dstStride * height; + int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); + Span dst = buffer; + dst = dst.Slice(0, outSize); + + for (int y = 0; y < height; y++) + { + src.Slice(y * srcStride, srcStride).CopyTo(dst.Slice(dstStart + y * dstStride, srcStride)); + } + + return new RentedBuffer(dst, bufferIndex); + } + + private static RentedBuffer ReadBufferBlockLinear( + ResourceManager rm, + uint offset, + int width, + int height, + int dstStart, int dstStride, int bytesPerPixel, int gobBlocksInY) { int inSize = GetBlockLinearSize(width, height, bytesPerPixel, gobBlocksInY); - ReadOnlySpan src = gmm.GetSpan(ExtendOffset(offset), inSize); + ReadOnlySpan src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize); - Span dst = new byte[dstStride * height]; + int outSize = dstStride * height; + int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); + Span dst = buffer; + dst = dst.Slice(0, outSize); - LayoutConverter.ConvertBlockLinearToLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src); + LayoutConverter.ConvertBlockLinearToLinear(dst.Slice(dstStart), width, height, dstStride, bytesPerPixel, gobBlocksInY, src); - return dst; + return new RentedBuffer(dst, bufferIndex); } } } diff --git a/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs b/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs index dd64720e9..297a04b6d 100644 --- a/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs +++ b/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs @@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Vic.Image switch (config.OutPixelFormat) { case PixelFormat.A8B8G8R8: - case PixelFormat.X8B8G8R8: + case PixelFormat.X8B8G8R8: WriteA8B8G8R8(rm, input, ref config, ref offsets); break; case PixelFormat.A8R8G8B8: @@ -433,7 +433,7 @@ namespace Ryujinx.Graphics.Vic.Image { if (linear) { - rm.Gmm.Write(ExtendOffset(offset), src); + rm.Gmm.WriteMapped(ExtendOffset(offset), src); return; } @@ -456,7 +456,7 @@ namespace Ryujinx.Graphics.Vic.Image LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src); - rm.Gmm.Write(ExtendOffset(offset), dst); + rm.Gmm.WriteMapped(ExtendOffset(offset), dst); rm.BufferPool.Return(dstIndex); } diff --git a/Ryujinx.Graphics.Vic/Scaler.cs b/Ryujinx.Graphics.Vic/Scaler.cs new file mode 100644 index 000000000..18ae66c4a --- /dev/null +++ b/Ryujinx.Graphics.Vic/Scaler.cs @@ -0,0 +1,124 @@ +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace Ryujinx.Graphics.Vic +{ + static class Scaler + { + public static void DeinterlaceWeave(Span data, ReadOnlySpan prevData, int width, int fieldSize, bool isTopField) + { + // Prev I Curr I Curr P + // TTTTTTTT BBBBBBBB TTTTTTTT + // -------- -------- BBBBBBBB + + if (isTopField) + { + for (int offset = 0; offset < data.Length; offset += fieldSize * 2) + { + prevData.Slice(offset >> 1, width).CopyTo(data.Slice(offset + fieldSize, width)); + } + } + else + { + for (int offset = 0; offset < data.Length; offset += fieldSize * 2) + { + prevData.Slice(offset >> 1, width).CopyTo(data.Slice(offset, width)); + } + } + } + + public static void DeinterlaceBob(Span data, int width, int fieldSize, bool isTopField) + { + // Curr I Curr P + // TTTTTTTT TTTTTTTT + // -------- TTTTTTTT + + if (isTopField) + { + for (int offset = 0; offset < data.Length; offset += fieldSize * 2) + { + data.Slice(offset, width).CopyTo(data.Slice(offset + fieldSize, width)); + } + } + else + { + for (int offset = 0; offset < data.Length; offset += fieldSize * 2) + { + data.Slice(offset + fieldSize, width).CopyTo(data.Slice(offset, width)); + } + } + } + + public unsafe static void DeinterlaceMotionAdaptive( + Span data, + ReadOnlySpan prevData, + ReadOnlySpan nextData, + int width, + int fieldSize, + bool isTopField) + { + // Very simple motion adaptive algorithm. + // If the pixel changed between previous and next frame, use Bob, otherwise use Weave. + // + // Example pseudo code: + // C_even = (P_even == N_even) ? P_even : C_odd + // Where: C is current frame, P is previous frame and N is next frame, and even/odd are the fields. + // + // Note: This does not fully match the hardware algorithm. + // The motion adaptive deinterlacing implemented on hardware is considerably more complex, + // and hard to implement accurately without proper documentation as for example, the + // method used for motion estimation is unknown. + + int start = isTopField ? fieldSize : 0; + int otherFieldOffset = isTopField ? -fieldSize : fieldSize; + + fixed (byte* pData = data, pPrevData = prevData, pNextData = nextData) + { + for (int offset = start; offset < data.Length; offset += fieldSize * 2) + { + int refOffset = (offset - start) >> 1; + int x = 0; + + if (Avx2.IsSupported) + { + for (; x < (width & ~0x1f); x += 32) + { + Vector256 prevPixels = Avx.LoadVector256(pPrevData + refOffset + x); + Vector256 nextPixels = Avx.LoadVector256(pNextData + refOffset + x); + Vector256 bob = Avx.LoadVector256(pData + offset + otherFieldOffset + x); + Vector256 diff = Avx2.CompareEqual(prevPixels, nextPixels); + Avx.Store(pData + offset + x, Avx2.BlendVariable(bob, prevPixels, diff)); + } + } + else if (Sse41.IsSupported) + { + for (; x < (width & ~0xf); x += 16) + { + Vector128 prevPixels = Sse2.LoadVector128(pPrevData + refOffset + x); + Vector128 nextPixels = Sse2.LoadVector128(pNextData + refOffset + x); + Vector128 bob = Sse2.LoadVector128(pData + offset + otherFieldOffset + x); + Vector128 diff = Sse2.CompareEqual(prevPixels, nextPixels); + Sse2.Store(pData + offset + x, Sse41.BlendVariable(bob, prevPixels, diff)); + } + } + + for (; x < width; x++) + { + byte prevPixel = prevData[refOffset + x]; + byte nextPixel = nextData[refOffset + x]; + + if (nextPixel != prevPixel) + { + data[offset + x] = data[offset + otherFieldOffset + x]; + } + else + { + data[offset + x] = prevPixel; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Vic/Types/DeinterlaceMode.cs b/Ryujinx.Graphics.Vic/Types/DeinterlaceMode.cs new file mode 100644 index 000000000..aa0654f01 --- /dev/null +++ b/Ryujinx.Graphics.Vic/Types/DeinterlaceMode.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Vic.Types +{ + enum DeinterlaceMode + { + Weave, + BobField, + Bob, + NewBob, + Disi1, + WeaveLumaBobFieldChroma + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Vic/Types/FrameFormat.cs b/Ryujinx.Graphics.Vic/Types/FrameFormat.cs new file mode 100644 index 000000000..91f5751b4 --- /dev/null +++ b/Ryujinx.Graphics.Vic/Types/FrameFormat.cs @@ -0,0 +1,79 @@ +namespace Ryujinx.Graphics.Vic.Types +{ + enum FrameFormat + { + Progressive, + InterlacedTopFieldFirst, + InterlacedBottomFieldFirst, + TopField, + BottomField, + SubPicProgressive, + SubPicInterlacedTopFieldFirst, + SubPicInterlacedBottomFieldFirst, + SubPicTopField, + SubPicBottomField, + TopFieldChromaBottom, + BottomFieldChromaTop, + SubPicTopFieldChromaBottom, + SubPicBottomFieldChromaTop + } + + static class FrameFormatExtensions + { + public static bool IsField(this FrameFormat frameFormat) + { + switch (frameFormat) + { + case FrameFormat.TopField: + case FrameFormat.BottomField: + case FrameFormat.SubPicTopField: + case FrameFormat.SubPicBottomField: + case FrameFormat.TopFieldChromaBottom: + case FrameFormat.BottomFieldChromaTop: + case FrameFormat.SubPicTopFieldChromaBottom: + case FrameFormat.SubPicBottomFieldChromaTop: + return true; + } + + return false; + } + + public static bool IsInterlaced(this FrameFormat frameFormat) + { + switch (frameFormat) + { + case FrameFormat.InterlacedTopFieldFirst: + case FrameFormat.InterlacedBottomFieldFirst: + case FrameFormat.SubPicInterlacedTopFieldFirst: + case FrameFormat.SubPicInterlacedBottomFieldFirst: + return true; + } + + return false; + } + + public static bool IsInterlacedBottomFirst(this FrameFormat frameFormat) + { + return frameFormat == FrameFormat.InterlacedBottomFieldFirst || + frameFormat == FrameFormat.SubPicInterlacedBottomFieldFirst; + } + + public static bool IsTopField(this FrameFormat frameFormat, bool isLuma) + { + switch (frameFormat) + { + case FrameFormat.TopField: + case FrameFormat.SubPicTopField: + return true; + case FrameFormat.TopFieldChromaBottom: + case FrameFormat.SubPicTopFieldChromaBottom: + return isLuma; + case FrameFormat.BottomFieldChromaTop: + case FrameFormat.SubPicBottomFieldChromaTop: + return !isLuma; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Vic/Types/SlotConfig.cs b/Ryujinx.Graphics.Vic/Types/SlotConfig.cs index 183ee4ac2..373e76f69 100644 --- a/Ryujinx.Graphics.Vic/Types/SlotConfig.cs +++ b/Ryujinx.Graphics.Vic/Types/SlotConfig.cs @@ -27,7 +27,7 @@ public bool PrevMotionFieldEnable => _word0.Extract(13); public bool PpMotionFieldEnable => _word0.Extract(14); public bool CombMotionFieldEnable => _word0.Extract(15); - public int FrameFormat => _word0.Extract(16, 4); + public FrameFormat FrameFormat => (FrameFormat)_word0.Extract(16, 4); public int FilterLengthY => _word0.Extract(20, 2); public int FilterLengthX => _word0.Extract(22, 2); public int Panoramic => _word0.Extract(24, 12); @@ -36,7 +36,7 @@ public int FilterDetail => _word1.Extract(74, 10); public int ChromaNoise => _word1.Extract(84, 10); public int ChromaDetail => _word1.Extract(94, 10); - public int DeinterlaceMode => _word1.Extract(104, 4); + public DeinterlaceMode DeinterlaceMode => (DeinterlaceMode)_word1.Extract(104, 4); public int MotionAccumWeight => _word1.Extract(108, 3); public int NoiseIir => _word1.Extract(111, 11); public int LightLevel => _word1.Extract(122, 4); diff --git a/Ryujinx.Graphics.Vic/VicDevice.cs b/Ryujinx.Graphics.Vic/VicDevice.cs index 21021c58c..537b8ba47 100644 --- a/Ryujinx.Graphics.Vic/VicDevice.cs +++ b/Ryujinx.Graphics.Vic/VicDevice.cs @@ -43,9 +43,9 @@ namespace Ryujinx.Graphics.Vic continue; } - var offsets = _state.State.SetSurfacexSlotx[i][0]; + ref var offsets = ref _state.State.SetSurfacexSlotx[i]; - using Surface src = SurfaceReader.Read(_rm, ref slot.SlotSurfaceConfig, ref offsets); + using Surface src = SurfaceReader.Read(_rm, ref slot.SlotConfig, ref slot.SlotSurfaceConfig, ref offsets); Blender.BlendOne(output, src, ref slot); } diff --git a/Ryujinx.Graphics.Video/FrameField.cs b/Ryujinx.Graphics.Video/FrameField.cs new file mode 100644 index 000000000..2bff0e75f --- /dev/null +++ b/Ryujinx.Graphics.Video/FrameField.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Graphics.Video +{ + public enum FrameField + { + Progressive, + Interlaced + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Video/ISurface.cs b/Ryujinx.Graphics.Video/ISurface.cs index fb66f31a8..7c1661f1f 100644 --- a/Ryujinx.Graphics.Video/ISurface.cs +++ b/Ryujinx.Graphics.Video/ISurface.cs @@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Video Plane UPlane { get; } Plane VPlane { get; } + FrameField Field { get; } + int Width { get; } int Height { get; } int Stride { get; } From 5158cdb308790e58d7e441ed127286ac1ef5ef69 Mon Sep 17 00:00:00 2001 From: Mary Date: Sat, 26 Mar 2022 11:38:35 +0100 Subject: [PATCH 9/9] infra: Put SDL2 headless release inside a GUI-less block in PR (#3218) As title say. --- .github/workflows/nightly_pr_comment.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly_pr_comment.yml b/.github/workflows/nightly_pr_comment.yml index 7145b7b69..36a12ea90 100644 --- a/.github/workflows/nightly_pr_comment.yml +++ b/.github/workflows/nightly_pr_comment.yml @@ -36,15 +36,20 @@ jobs: return core.error(`No artifacts found`); } let body = `Download the artifacts for this pull request:\n`; + let hidden_headless_artifacts = `\n\n
GUI-less (SDL2)\n`; let hidden_debug_artifacts = `\n\n
Only for Developers\n`; for (const art of artifacts) { - if(art.name.includes('Debug')){ + if(art.name.includes('Debug')) { hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; - }else{ + } else if(art.name.includes('headless-sdl2')) { + hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; + } else { body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; } } + hidden_headless_artifacts += `\n
`; hidden_debug_artifacts += `\n
`; + body += hidden_headless_artifacts; body += hidden_debug_artifacts; const {data: comments} = await github.issues.listComments({repo, owner, issue_number});