diff --git a/src/Ryujinx.Common/Configuration/DirtyHacks.cs b/src/Ryujinx.Common/Configuration/DirtyHack.cs similarity index 53% rename from src/Ryujinx.Common/Configuration/DirtyHacks.cs rename to src/Ryujinx.Common/Configuration/DirtyHack.cs index e52c96cf1..6e21fe44e 100644 --- a/src/Ryujinx.Common/Configuration/DirtyHacks.cs +++ b/src/Ryujinx.Common/Configuration/DirtyHack.cs @@ -6,18 +6,19 @@ using System.Linq; namespace Ryujinx.Common.Configuration { [Flags] - public enum DirtyHacks : byte + public enum DirtyHack : byte { Xc2MenuSoftlockFix = 1, - ShaderCompilationThreadSleep = 2 + ShaderTranslationDelay = 2 } - public record EnabledDirtyHack(DirtyHacks Hack, int Value) + public readonly struct EnabledDirtyHack(DirtyHack hack, int value) { - public static readonly byte[] PackedFormat = [8, 32]; - - private uint[] Raw => [(uint)Hack, (uint)Value.CoerceAtLeast(0)]; - + public DirtyHack Hack => hack; + public int Value => value; + + + public ulong Pack() => Raw.PackBitFields(PackedFormat); public static EnabledDirtyHack Unpack(ulong packedHack) @@ -26,16 +27,20 @@ namespace Ryujinx.Common.Configuration if (unpackedFields is not [var hack, var value]) throw new ArgumentException(nameof(packedHack)); - return new EnabledDirtyHack((DirtyHacks)hack, (int)value); + return new EnabledDirtyHack((DirtyHack)hack, (int)value); } + + private uint[] Raw => [(uint)Hack, (uint)Value.CoerceAtLeast(0)]; + + public static readonly byte[] PackedFormat = [8, 32]; } - public class DirtyHackCollection : Dictionary + public class DirtyHacks : Dictionary { - public DirtyHackCollection(IEnumerable hacks) + public DirtyHacks(IEnumerable hacks) => hacks.ForEach(edh => Add(edh.Hack, edh.Value)); - public DirtyHackCollection(ulong[] packedHacks) : this(packedHacks.Select(EnabledDirtyHack.Unpack)) {} + public DirtyHacks(ulong[] packedHacks) : this(packedHacks.Select(EnabledDirtyHack.Unpack)) {} public ulong[] PackEntries() => Entries.Select(it => it.Pack()).ToArray(); @@ -45,11 +50,11 @@ namespace Ryujinx.Common.Configuration .Select(it => new EnabledDirtyHack(it.Key, it.Value)) .ToArray(); - public static implicit operator DirtyHackCollection(EnabledDirtyHack[] hacks) => new(hacks); - public static implicit operator DirtyHackCollection(ulong[] packedHacks) => new(packedHacks); + public static implicit operator DirtyHacks(EnabledDirtyHack[] hacks) => new(hacks); + public static implicit operator DirtyHacks(ulong[] packedHacks) => new(packedHacks); - public new int this[DirtyHacks hack] => TryGetValue(hack, out var value) ? value : -1; + public new int this[DirtyHack hack] => TryGetValue(hack, out var value) ? value : -1; - public bool IsEnabled(DirtyHacks hack) => ContainsKey(hack); + public bool IsEnabled(DirtyHack hack) => ContainsKey(hack); } } diff --git a/src/Ryujinx.Graphics.Gpu/GpuContext.cs b/src/Ryujinx.Graphics.Gpu/GpuContext.cs index 84bc0b9a9..f7e8f1bf8 100644 --- a/src/Ryujinx.Graphics.Gpu/GpuContext.cs +++ b/src/Ryujinx.Graphics.Gpu/GpuContext.cs @@ -92,7 +92,11 @@ namespace Ryujinx.Graphics.Gpu /// internal SupportBufferUpdater SupportBufferUpdater { get; } - internal DirtyHackCollection DirtyHacks { get; } + /// + /// Enabled dirty hacks. + /// Used for workarounds to emulator bugs we can't fix/don't know how to fix yet. + /// + internal DirtyHacks DirtyHacks { get; } /// @@ -117,7 +121,7 @@ namespace Ryujinx.Graphics.Gpu /// Creates a new instance of the GPU emulation context. /// /// Host renderer - public GpuContext(IRenderer renderer, DirtyHackCollection hackCollection) + public GpuContext(IRenderer renderer, DirtyHacks hacks) { Renderer = renderer; @@ -140,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu SupportBufferUpdater = new SupportBufferUpdater(renderer); - DirtyHacks = hackCollection; + DirtyHacks = hacks; _firstTimestamp = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds); } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs index 9aa96a76f..910e9aea0 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs @@ -367,8 +367,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache { try { - if (_context.DirtyHacks.IsEnabled(DirtyHacks.ShaderCompilationThreadSleep)) - Thread.Sleep(_context.DirtyHacks[DirtyHacks.ShaderCompilationThreadSleep]); + if (_context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay)) + Thread.Sleep(_context.DirtyHacks[DirtyHack.ShaderTranslationDelay]); AsyncProgramTranslation asyncTranslation = new(guestShaders, specState, programIndex, isCompute); _asyncTranslationQueue.Add(asyncTranslation, _cancellationToken); diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs index ac5dc04e9..3d197ac19 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IStorage.cs @@ -39,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true); Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size); - if (context.Device.DirtyHacks.IsEnabled(DirtyHacks.Xc2MenuSoftlockFix) && TitleIDs.CurrentApplication.Value == Xc2TitleId) + if (context.Device.DirtyHacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix) && TitleIDs.CurrentApplication.Value == Xc2TitleId) { // Add a load-bearing sleep to avoid XC2 softlock // https://web.archive.org/web/20240728045136/https://github.com/Ryujinx/Ryujinx/issues/2357 diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index 127e532e2..25e65354f 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -40,7 +40,7 @@ namespace Ryujinx.HLE public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable; - public DirtyHackCollection DirtyHacks { get; } + public DirtyHacks DirtyHacks { get; } public Switch(HLEConfiguration configuration) { @@ -57,7 +57,7 @@ namespace Ryujinx.HLE : MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Mirrorable; #pragma warning disable IDE0055 // Disable formatting - DirtyHacks = new DirtyHackCollection(Configuration.Hacks); + DirtyHacks = new DirtyHacks(Configuration.Hacks); AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver); Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags); Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks); diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs index 828ceba57..551e3ab8e 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs @@ -752,12 +752,12 @@ namespace Ryujinx.Ava.Utilities.Configuration Hacks.ShowDirtyHacks.Value = configurationFileFormat.ShowDirtyHacks; { - DirtyHackCollection hacks = new (configurationFileFormat.DirtyHacks ?? []); + DirtyHacks hacks = new (configurationFileFormat.DirtyHacks ?? []); - Hacks.Xc2MenuSoftlockFix.Value = hacks.IsEnabled(DirtyHacks.Xc2MenuSoftlockFix); + Hacks.Xc2MenuSoftlockFix.Value = hacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix); - Hacks.EnableShaderTranslationDelay.Value = hacks.IsEnabled(DirtyHacks.ShaderCompilationThreadSleep); - Hacks.ShaderTranslationDelay.Value = hacks[DirtyHacks.ShaderCompilationThreadSleep].CoerceAtLeast(0); + Hacks.EnableShaderTranslationDelay.Value = hacks.IsEnabled(DirtyHack.ShaderTranslationDelay); + Hacks.ShaderTranslationDelay.Value = hacks[DirtyHack.ShaderTranslationDelay].CoerceAtLeast(0); } if (configurationFileUpdated) diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs index 2a91bf65b..4fc25addb 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs @@ -666,14 +666,14 @@ namespace Ryujinx.Ava.Utilities.Configuration List enabledHacks = []; if (Xc2MenuSoftlockFix) - Apply(DirtyHacks.Xc2MenuSoftlockFix); + Apply(DirtyHack.Xc2MenuSoftlockFix); if (EnableShaderTranslationDelay) - Apply(DirtyHacks.ShaderCompilationThreadSleep, ShaderTranslationDelay); + Apply(DirtyHack.ShaderTranslationDelay, ShaderTranslationDelay); return enabledHacks.ToArray(); - void Apply(DirtyHacks hack, int value = 0) + void Apply(DirtyHack hack, int value = 0) { enabledHacks.Add(new EnabledDirtyHack(hack, value)); }