Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5e9678c8fa | ||
|
773e239db7 | ||
|
42750a74f8 | ||
|
3ab0a71c7b | ||
|
6e784e0aca | ||
|
5a0aa074b6 | ||
|
93aa40f1fb | ||
|
bedee64af5 | ||
|
86931cc3f1 | ||
|
2be8b6ea45 | ||
|
f95b7c5877 |
@@ -14,6 +14,13 @@ tab_width = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
|
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -3,10 +3,6 @@ name: Build job
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: pr-builds-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
@@ -54,7 +50,11 @@ jobs:
|
||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
|
||||
- name: Test
|
||||
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
uses: TSRBerry/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
timeout-minutes: 10
|
||||
retry-codes: 139
|
||||
|
||||
- name: Publish Ryujinx
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
|
||||
@@ -141,4 +141,4 @@ jobs:
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_ava/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request'
|
||||
|
28
.github/workflows/checks.yml
vendored
28
.github/workflows/checks.yml
vendored
@@ -40,23 +40,23 @@ jobs:
|
||||
run: |
|
||||
dotnet format whitespace --verify-no-changes --report ./whitespace-report.json -v d
|
||||
|
||||
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
|
||||
# so in that case we'll try again (3 tries max).
|
||||
- name: Run dotnet format style
|
||||
run: |
|
||||
dotnet format style --severity info --verify-no-changes --report ./style-report.json -v d
|
||||
uses: TSRBerry/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet format style --severity info --verify-no-changes --report ./style-report.json -v d
|
||||
timeout-minutes: 5
|
||||
retry-codes: 139
|
||||
|
||||
# For some reason this step sometimes fails with exit code 139 (segfault?),
|
||||
# so should that be the case we'll try again (3 tries max).
|
||||
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
|
||||
# so in that case we'll try again (3 tries max).
|
||||
- name: Run dotnet format analyzers
|
||||
run: |
|
||||
attempt=0
|
||||
exit_code=139
|
||||
until [ $attempt -ge 3 ] || [ $exit_code -ne 139 ]; do
|
||||
((attempt+=1))
|
||||
exit_code=0
|
||||
echo "Attempt: ${attempt}/3"
|
||||
dotnet format analyzers --severity info --verify-no-changes --report ./analyzers-report.json -v d || exit_code=$?
|
||||
done
|
||||
exit $exit_code
|
||||
uses: TSRBerry/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet format analyzers --severity info --verify-no-changes --report ./analyzers-report.json -v d
|
||||
timeout-minutes: 5
|
||||
retry-codes: 139
|
||||
|
||||
- name: Upload report
|
||||
if: failure()
|
||||
|
1
.github/workflows/pr_triage.yml
vendored
1
.github/workflows/pr_triage.yml
vendored
@@ -28,6 +28,7 @@ jobs:
|
||||
dot: true
|
||||
|
||||
- name: Assign reviewers
|
||||
if: ! github.event.pull_request.draft
|
||||
run: |
|
||||
pip3 install PyGithub
|
||||
python3 .github/update_reviewers.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
|
@@ -330,6 +330,7 @@ namespace ARMeilleure.Decoders
|
||||
SetA64("011111100x110000110010xxxxxxxxxx", InstName.Fmaxnmp_S, InstEmit.Fmaxnmp_S, OpCodeSimd.Create);
|
||||
SetA64("0>1011100<1xxxxx110001xxxxxxxxxx", InstName.Fmaxnmp_V, InstEmit.Fmaxnmp_V, OpCodeSimdReg.Create);
|
||||
SetA64("0110111000110000110010xxxxxxxxxx", InstName.Fmaxnmv_V, InstEmit.Fmaxnmv_V, OpCodeSimd.Create);
|
||||
SetA64("011111100x110000111110xxxxxxxxxx", InstName.Fmaxp_S, InstEmit.Fmaxp_S, OpCodeSimd.Create);
|
||||
SetA64("0>1011100<1xxxxx111101xxxxxxxxxx", InstName.Fmaxp_V, InstEmit.Fmaxp_V, OpCodeSimdReg.Create);
|
||||
SetA64("0110111000110000111110xxxxxxxxxx", InstName.Fmaxv_V, InstEmit.Fmaxv_V, OpCodeSimd.Create);
|
||||
SetA64("000111100x1xxxxx010110xxxxxxxxxx", InstName.Fmin_S, InstEmit.Fmin_S, OpCodeSimdReg.Create);
|
||||
@@ -339,6 +340,7 @@ namespace ARMeilleure.Decoders
|
||||
SetA64("011111101x110000110010xxxxxxxxxx", InstName.Fminnmp_S, InstEmit.Fminnmp_S, OpCodeSimd.Create);
|
||||
SetA64("0>1011101<1xxxxx110001xxxxxxxxxx", InstName.Fminnmp_V, InstEmit.Fminnmp_V, OpCodeSimdReg.Create);
|
||||
SetA64("0110111010110000110010xxxxxxxxxx", InstName.Fminnmv_V, InstEmit.Fminnmv_V, OpCodeSimd.Create);
|
||||
SetA64("011111101x110000111110xxxxxxxxxx", InstName.Fminp_S, InstEmit.Fminp_S, OpCodeSimd.Create);
|
||||
SetA64("0>1011101<1xxxxx111101xxxxxxxxxx", InstName.Fminp_V, InstEmit.Fminp_V, OpCodeSimdReg.Create);
|
||||
SetA64("0110111010110000111110xxxxxxxxxx", InstName.Fminv_V, InstEmit.Fminv_V, OpCodeSimd.Create);
|
||||
SetA64("010111111xxxxxxx0001x0xxxxxxxxxx", InstName.Fmla_Se, InstEmit.Fmla_Se, OpCodeSimdRegElemF.Create);
|
||||
|
@@ -883,6 +883,31 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmaxp_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FmaxpS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse2ScalarPairwiseOpF(context, (op1, op2) =>
|
||||
{
|
||||
return EmitSse41ProcessNaNsOpF(context, (op1, op2) =>
|
||||
{
|
||||
return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: true);
|
||||
}, scalar: true, op1, op2);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarPairwiseOpF(context, (op1, op2) =>
|
||||
{
|
||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmaxp_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
@@ -1081,6 +1106,31 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fminp_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FminpS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse2ScalarPairwiseOpF(context, (op1, op2) =>
|
||||
{
|
||||
return EmitSse41ProcessNaNsOpF(context, (op1, op2) =>
|
||||
{
|
||||
return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: false);
|
||||
}, scalar: true, op1, op2);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarPairwiseOpF(context, (op1, op2) =>
|
||||
{
|
||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fminp_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
|
@@ -228,6 +228,7 @@ namespace ARMeilleure.Instructions
|
||||
Fmaxnmp_S,
|
||||
Fmaxnmp_V,
|
||||
Fmaxnmv_V,
|
||||
Fmaxp_S,
|
||||
Fmaxp_V,
|
||||
Fmaxv_V,
|
||||
Fmin_S,
|
||||
@@ -237,6 +238,7 @@ namespace ARMeilleure.Instructions
|
||||
Fminnmp_S,
|
||||
Fminnmp_V,
|
||||
Fminnmv_V,
|
||||
Fminp_S,
|
||||
Fminp_V,
|
||||
Fminv_V,
|
||||
Fmla_Se,
|
||||
|
@@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 5343; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 5518; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
|
@@ -27,6 +27,26 @@ namespace ARMeilleure.Translation.PTC
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Dictionary<TKey, TValue> DeserializeAndUpdateDictionary<TKey, TValue>(Stream stream, Func<Stream, TValue> valueFunc, Func<TKey, TValue, (TKey, TValue)> updateFunc) where TKey : struct
|
||||
{
|
||||
Dictionary<TKey, TValue> dictionary = new();
|
||||
|
||||
int count = DeserializeStructure<int>(stream);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
TKey key = DeserializeStructure<TKey>(stream);
|
||||
TValue value = valueFunc(stream);
|
||||
|
||||
(key, value) = updateFunc(key, value);
|
||||
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static List<T> DeserializeList<T>(Stream stream) where T : struct
|
||||
{
|
||||
|
@@ -9,10 +9,13 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
@@ -20,7 +23,11 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
||||
|
||||
private const uint InternalVersion = 1866; //! Not to be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 5518; //! Not to be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private static readonly uint[] _migrateInternalVersions = {
|
||||
1866,
|
||||
};
|
||||
|
||||
private const int SaveInterval = 30; // Seconds.
|
||||
|
||||
@@ -28,7 +35,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
private readonly Ptc _ptc;
|
||||
|
||||
private readonly System.Timers.Timer _timer;
|
||||
private readonly Timer _timer;
|
||||
|
||||
private readonly ulong _outerHeaderMagic;
|
||||
|
||||
@@ -51,7 +58,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
_ptc = ptc;
|
||||
|
||||
_timer = new System.Timers.Timer((double)SaveInterval * 1000d);
|
||||
_timer = new Timer(SaveInterval * 1000d);
|
||||
_timer.Elapsed += PreSave;
|
||||
|
||||
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
||||
@@ -168,7 +175,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outerHeader.InfoFileVersion != InternalVersion)
|
||||
if (outerHeader.InfoFileVersion != InternalVersion && !_migrateInternalVersions.Contains(outerHeader.InfoFileVersion))
|
||||
{
|
||||
InvalidateCompressedStream(compressedStream);
|
||||
|
||||
@@ -211,7 +218,19 @@ namespace ARMeilleure.Translation.PTC
|
||||
return false;
|
||||
}
|
||||
|
||||
ProfiledFuncs = Deserialize(stream);
|
||||
switch (outerHeader.InfoFileVersion)
|
||||
{
|
||||
case InternalVersion:
|
||||
ProfiledFuncs = Deserialize(stream);
|
||||
break;
|
||||
case 1866:
|
||||
ProfiledFuncs = Deserialize(stream, (address, profile) => (address + 0x500000UL, profile));
|
||||
break;
|
||||
default:
|
||||
Logger.Error?.Print(LogClass.Ptc, $"No migration path for {nameof(outerHeader.InfoFileVersion)} '{outerHeader.InfoFileVersion}'. Discarding cache.");
|
||||
InvalidateCompressedStream(compressedStream);
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Assert(stream.Position == stream.Length);
|
||||
|
||||
@@ -225,9 +244,14 @@ namespace ARMeilleure.Translation.PTC
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Dictionary<ulong, FuncProfile> Deserialize(Stream stream)
|
||||
private static Dictionary<ulong, FuncProfile> Deserialize(Stream stream, Func<ulong, FuncProfile, (ulong, FuncProfile)> migrateEntryFunc = null)
|
||||
{
|
||||
return DeserializeDictionary<ulong, FuncProfile>(stream, (stream) => DeserializeStructure<FuncProfile>(stream));
|
||||
if (migrateEntryFunc != null)
|
||||
{
|
||||
return DeserializeAndUpdateDictionary(stream, DeserializeStructure<FuncProfile>, migrateEntryFunc);
|
||||
}
|
||||
|
||||
return DeserializeDictionary<ulong, FuncProfile>(stream, DeserializeStructure<FuncProfile>);
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
|
||||
@@ -240,7 +264,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
compressedStream.SetLength(0L);
|
||||
}
|
||||
|
||||
private void PreSave(object source, System.Timers.ElapsedEventArgs e)
|
||||
private void PreSave(object source, ElapsedEventArgs e)
|
||||
{
|
||||
_waitEvent.Reset();
|
||||
|
||||
@@ -277,7 +301,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L);
|
||||
|
||||
stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
||||
stream.Seek(Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
@@ -288,7 +312,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
Debug.Assert(stream.Position == stream.Length);
|
||||
|
||||
stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
||||
stream.Seek(Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
|
||||
Hash128 hash = XXHash128.ComputeHash(GetReadOnlySpan(stream));
|
||||
|
||||
stream.Seek(0L, SeekOrigin.Begin);
|
||||
@@ -332,7 +356,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
private static void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
|
||||
{
|
||||
SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
|
||||
SerializeDictionary(stream, profiledFuncs, SerializeStructure);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 29*/)]
|
||||
|
@@ -186,6 +186,7 @@ namespace Ryujinx.Ava
|
||||
ConfigurationState.Instance.Graphics.AntiAliasing.Event += UpdateAntiAliasing;
|
||||
ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter;
|
||||
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
|
||||
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
|
||||
|
||||
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
|
||||
|
||||
@@ -229,6 +230,11 @@ namespace Ryujinx.Ava
|
||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||
}
|
||||
|
||||
private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool> e)
|
||||
{
|
||||
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||
}
|
||||
|
||||
private void ShowCursor()
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
@@ -461,6 +467,7 @@ namespace Ryujinx.Ava
|
||||
ConfigurationState.Instance.Graphics.ScalingFilter.Event -= UpdateScalingFilter;
|
||||
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event -= UpdateScalingFilterLevel;
|
||||
ConfigurationState.Instance.Graphics.AntiAliasing.Event -= UpdateAntiAliasing;
|
||||
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event -= UpdateColorSpacePassthrough;
|
||||
|
||||
_topLevel.PointerMoved -= TopLevel_PointerEnterOrMoved;
|
||||
_topLevel.PointerEnter -= TopLevel_PointerEnterOrMoved;
|
||||
@@ -887,6 +894,7 @@ namespace Ryujinx.Ava
|
||||
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)ConfigurationState.Instance.Graphics.AntiAliasing.Value);
|
||||
_renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||
|
||||
Width = (int)RendererHost.Bounds.Width;
|
||||
Height = (int)RendererHost.Bounds.Height;
|
||||
|
@@ -620,6 +620,8 @@
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||
"SettingsEnableColorSpacePassthrough": "Color Space Passthrough",
|
||||
"SettingsEnableColorSpacePassthroughTooltip": "Directs the Vulkan backend to pass through color information without specifying a color space. For users with wide gamut displays, this may result in more vibrant colors, at the cost of color correctness.",
|
||||
"VolumeShort": "Vol",
|
||||
"UserProfilesManageSaves": "Manage Saves",
|
||||
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||
|
@@ -145,6 +145,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
public bool EnableShaderCache { get; set; }
|
||||
public bool EnableTextureRecompression { get; set; }
|
||||
public bool EnableMacroHLE { get; set; }
|
||||
public bool EnableColorSpacePassthrough { get; set; }
|
||||
public bool EnableFileLog { get; set; }
|
||||
public bool EnableStub { get; set; }
|
||||
public bool EnableInfo { get; set; }
|
||||
@@ -419,6 +420,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
EnableShaderCache = config.Graphics.EnableShaderCache;
|
||||
EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
|
||||
EnableMacroHLE = config.Graphics.EnableMacroHLE;
|
||||
EnableColorSpacePassthrough = config.Graphics.EnableColorSpacePassthrough;
|
||||
ResolutionScale = config.Graphics.ResScale == -1 ? 4 : config.Graphics.ResScale - 1;
|
||||
CustomResolutionScale = config.Graphics.ResScaleCustom;
|
||||
MaxAnisotropy = config.Graphics.MaxAnisotropy == -1 ? 0 : (int)(MathF.Log2(config.Graphics.MaxAnisotropy));
|
||||
@@ -506,6 +508,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
|
||||
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
|
||||
config.Graphics.EnableMacroHLE.Value = EnableMacroHLE;
|
||||
config.Graphics.EnableColorSpacePassthrough.Value = EnableColorSpacePassthrough;
|
||||
config.Graphics.ResScale.Value = ResolutionScale == 4 ? -1 : ResolutionScale + 1;
|
||||
config.Graphics.ResScaleCustom.Value = CustomResolutionScale;
|
||||
config.Graphics.MaxAnisotropy.Value = MaxAnisotropy == 0 ? -1 : MathF.Pow(2, MaxAnisotropy);
|
||||
|
@@ -73,6 +73,10 @@
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableColorSpacePassthrough}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
|
@@ -13,5 +13,6 @@ namespace Ryujinx.Graphics.GAL
|
||||
void SetAntiAliasing(AntiAliasing antialiasing);
|
||||
void SetScalingFilter(ScalingFilter type);
|
||||
void SetScalingFilterLevel(float level);
|
||||
void SetColorSpacePassthrough(bool colorSpacePassThroughEnabled);
|
||||
}
|
||||
}
|
||||
|
@@ -38,5 +38,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
public void SetScalingFilter(ScalingFilter type) { }
|
||||
|
||||
public void SetScalingFilterLevel(float level) { }
|
||||
|
||||
public void SetColorSpacePassthrough(bool colorSpacePassthroughEnabled) { }
|
||||
}
|
||||
}
|
||||
|
@@ -342,5 +342,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Y negate enabled state.
|
||||
/// </summary>
|
||||
/// <param name="enabled">True if Y negate of the fragment coordinates is enabled</param>
|
||||
public void SetYNegateEnabled(bool enabled)
|
||||
{
|
||||
if (enabled != _graphics.YNegateEnabled)
|
||||
{
|
||||
_graphics.YNegateEnabled = enabled;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
private ProgramPipelineState _pipeline;
|
||||
|
||||
private bool _fsReadsFragCoord;
|
||||
private bool _vsUsesDrawParameters;
|
||||
private bool _vtgWritesRtLayer;
|
||||
private byte _vsClipDistancesWritten;
|
||||
@@ -330,7 +331,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
UpdateShaderState();
|
||||
}
|
||||
|
||||
_channel.BufferManager.CommitGraphicsBindings();
|
||||
_channel.BufferManager.CommitGraphicsBindings(_drawState.DrawIndexed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -692,12 +693,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
var face = _state.State.FaceState;
|
||||
|
||||
bool disableTransform = _state.State.ViewportTransformEnable == 0;
|
||||
bool yNegate = yControl.HasFlag(YControl.NegateY);
|
||||
|
||||
UpdateFrontFace(yControl, face.FrontFace);
|
||||
UpdateDepthMode();
|
||||
|
||||
bool flipY = yControl.HasFlag(YControl.NegateY);
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
||||
|
||||
for (int index = 0; index < Constants.TotalViewports; index++)
|
||||
@@ -719,7 +719,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
float scaleX = MathF.Abs(transform.ScaleX);
|
||||
float scaleY = transform.ScaleY;
|
||||
|
||||
if (flipY)
|
||||
if (yNegate)
|
||||
{
|
||||
scaleY = -scaleY;
|
||||
}
|
||||
@@ -771,8 +771,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_channel.TextureManager.RenderTargetScale,
|
||||
disableTransform);
|
||||
|
||||
// Viewport size is only used on the shader when YNegate is enabled,
|
||||
// and if the fragment shader accesses gl_FragCoord,
|
||||
// so there's no need to update it in other cases.
|
||||
if (yNegate && _fsReadsFragCoord)
|
||||
{
|
||||
UpdateSupportBufferViewportSize();
|
||||
}
|
||||
|
||||
_currentSpecState.SetViewportTransformDisable(disableTransform);
|
||||
_currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
|
||||
_currentSpecState.SetYNegateEnabled(yNegate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1415,9 +1424,41 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_currentProgramInfo[stageIndex] = info;
|
||||
}
|
||||
|
||||
if (gs.Shaders[5]?.Info.UsesFragCoord == true)
|
||||
{
|
||||
// Make sure we update the viewport size on the support buffer if it will be consumed on the new shader.
|
||||
|
||||
if (!_fsReadsFragCoord && _state.State.YControl.HasFlag(YControl.NegateY))
|
||||
{
|
||||
UpdateSupportBufferViewportSize();
|
||||
}
|
||||
|
||||
_fsReadsFragCoord = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fsReadsFragCoord = false;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the viewport size on the support buffer for fragment shader access.
|
||||
/// </summary>
|
||||
private void UpdateSupportBufferViewportSize()
|
||||
{
|
||||
ref var transform = ref _state.State.ViewportTransform[0];
|
||||
|
||||
float scaleX = MathF.Abs(transform.ScaleX);
|
||||
float scaleY = transform.ScaleY;
|
||||
|
||||
float width = scaleX * 2;
|
||||
float height = scaleY * 2;
|
||||
|
||||
_context.SupportBufferUpdater.SetViewportSize(width, MathF.Abs(height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates bindings consumed by the shader on the texture and buffer managers.
|
||||
/// </summary>
|
||||
|
@@ -67,6 +67,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// Enables or disables recompression of compressed textures that are not natively supported by the host.
|
||||
/// </summary>
|
||||
public static bool EnableTextureRecompression = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables color space passthrough, if available.
|
||||
/// </summary>
|
||||
public static bool EnableColorSpacePassthrough = false;
|
||||
}
|
||||
#pragma warning restore CA2211
|
||||
}
|
||||
|
@@ -515,24 +515,32 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// Ensures that the graphics engine bindings are visible to the host GPU.
|
||||
/// Note: this actually performs the binding using the host graphics API.
|
||||
/// </summary>
|
||||
public void CommitGraphicsBindings()
|
||||
/// <param name="indexed">True if the index buffer is in use</param>
|
||||
public void CommitGraphicsBindings(bool indexed)
|
||||
{
|
||||
var bufferCache = _channel.MemoryManager.Physical.BufferCache;
|
||||
|
||||
if (_indexBufferDirty || _rebind)
|
||||
if (indexed)
|
||||
{
|
||||
_indexBufferDirty = false;
|
||||
|
||||
if (_indexBuffer.Address != 0)
|
||||
if (_indexBufferDirty || _rebind)
|
||||
{
|
||||
BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
_indexBufferDirty = false;
|
||||
|
||||
_context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
|
||||
if (_indexBuffer.Address != 0)
|
||||
{
|
||||
BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
|
||||
_context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
|
||||
}
|
||||
}
|
||||
else if (_indexBuffer.Address != 0)
|
||||
{
|
||||
bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
}
|
||||
}
|
||||
else if (_indexBuffer.Address != 0)
|
||||
else if (_rebind)
|
||||
{
|
||||
bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
|
||||
_indexBufferDirty = true;
|
||||
}
|
||||
|
||||
uint vbEnableMask = _vertexBuffersEnableMask;
|
||||
|
@@ -112,6 +112,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
MarkDirty(SupportBuffer.ViewportInverseOffset, SupportBuffer.FieldSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the viewport size vector.
|
||||
/// </summary>
|
||||
/// <param name="data">Viewport size vector</param>
|
||||
private void UpdateViewportSize(Vector4<float> data)
|
||||
{
|
||||
_data.ViewportSize = data;
|
||||
|
||||
MarkDirty(SupportBuffer.ViewportSizeOffset, SupportBuffer.FieldSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the scale of all output render targets (they should all have the same scale).
|
||||
/// </summary>
|
||||
@@ -192,6 +203,25 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the viewport size, used to invert the fragment coordinates Y value.
|
||||
/// </summary>
|
||||
/// <param name="viewportWidth">Value used as viewport width</param>
|
||||
/// <param name="viewportHeight">Value used as viewport height</param>
|
||||
public void SetViewportSize(float viewportWidth, float viewportHeight)
|
||||
{
|
||||
if (_data.ViewportSize.X != viewportWidth || _data.ViewportSize.Y != viewportHeight)
|
||||
{
|
||||
UpdateViewportSize(new Vector4<float>
|
||||
{
|
||||
X = viewportWidth,
|
||||
Y = viewportHeight,
|
||||
Z = 1,
|
||||
W = 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Submits all pending buffer updates to the GPU.
|
||||
/// </summary>
|
||||
|
@@ -247,6 +247,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
return _oldSpecState.GraphicsState.ViewportTransformDisable;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryYNegateEnabled()
|
||||
{
|
||||
return _oldSpecState.GraphicsState.YNegateEnabled;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterTexture(int handle, int cbufSlot)
|
||||
{
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 5266;
|
||||
private const uint CodeGenVersion = 5529;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
@@ -140,6 +140,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// </summary>
|
||||
public ShaderStage Stage;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the fragment shader accesses the fragment coordinate built-in variable.
|
||||
/// </summary>
|
||||
public bool UsesFragCoord;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the shader accesses the Instance ID built-in variable.
|
||||
/// </summary>
|
||||
@@ -781,6 +786,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
ShaderIdentification.None,
|
||||
0,
|
||||
dataInfo.Stage,
|
||||
dataInfo.UsesFragCoord,
|
||||
dataInfo.UsesInstanceId,
|
||||
dataInfo.UsesDrawParameters,
|
||||
dataInfo.UsesRtLayer,
|
||||
@@ -807,6 +813,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
TexturesCount = (ushort)info.Textures.Count,
|
||||
ImagesCount = (ushort)info.Images.Count,
|
||||
Stage = info.Stage,
|
||||
UsesFragCoord = info.UsesFragCoord,
|
||||
UsesInstanceId = info.UsesInstanceId,
|
||||
UsesDrawParameters = info.UsesDrawParameters,
|
||||
UsesRtLayer = info.UsesRtLayer,
|
||||
|
@@ -113,6 +113,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return _state.GraphicsState.AttributeTypes[location];
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryEarlyZForce()
|
||||
{
|
||||
_state.SpecializationState?.RecordEarlyZForce();
|
||||
return _state.GraphicsState.EarlyZForce;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public AttributeType QueryFragmentOutputType(int location)
|
||||
{
|
||||
@@ -275,19 +282,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return _state.TransformFeedbackDescriptors[bufferIndex].Stride;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryEarlyZForce()
|
||||
{
|
||||
_state.SpecializationState?.RecordEarlyZForce();
|
||||
return _state.GraphicsState.EarlyZForce;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryViewportTransformDisable()
|
||||
{
|
||||
return _state.GraphicsState.ViewportTransformDisable;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryYNegateEnabled()
|
||||
{
|
||||
return _state.GraphicsState.YNegateEnabled;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterTexture(int handle, int cbufSlot)
|
||||
{
|
||||
|
@@ -97,6 +97,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
public bool DualSourceBlendEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether Y negate of the fragment coordinates is enabled.
|
||||
/// </summary>
|
||||
public bool YNegateEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GPU graphics state.
|
||||
/// </summary>
|
||||
@@ -116,7 +121,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
|
||||
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
||||
/// <param name="fragmentOutputTypes">Type of the fragment shader outputs</param>
|
||||
/// <param name="dualSourceBlendEnable">Type of the vertex attributes consumed by the shader</param>
|
||||
/// <param name="dualSourceBlendEnable">Indicates whether dual source blend is enabled</param>
|
||||
/// <param name="yNegateEnabled">Indicates whether Y negate of the fragment coordinates is enabled</param>
|
||||
public GpuChannelGraphicsState(
|
||||
bool earlyZForce,
|
||||
PrimitiveTopology topology,
|
||||
@@ -134,7 +140,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
bool hasConstantBufferDrawParameters,
|
||||
bool hasUnalignedStorageBuffer,
|
||||
ref Array8<AttributeType> fragmentOutputTypes,
|
||||
bool dualSourceBlendEnable)
|
||||
bool dualSourceBlendEnable,
|
||||
bool yNegateEnabled)
|
||||
{
|
||||
EarlyZForce = earlyZForce;
|
||||
Topology = topology;
|
||||
@@ -153,6 +160,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||
FragmentOutputTypes = fragmentOutputTypes;
|
||||
DualSourceBlendEnable = dualSourceBlendEnable;
|
||||
YNegateEnabled = yNegateEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -540,6 +540,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graphicsState.YNegateEnabled != GraphicsState.YNegateEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
||||
}
|
||||
|
||||
|
@@ -307,6 +307,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_updateScalingFilter = true;
|
||||
}
|
||||
|
||||
public void SetColorSpacePassthrough(bool colorSpacePassthroughEnabled) { }
|
||||
|
||||
private void UpdateEffect()
|
||||
{
|
||||
if (_updateEffect)
|
||||
|
@@ -188,10 +188,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryEarlyZForce())
|
||||
if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
context.AppendLine("layout(early_fragment_tests) in;");
|
||||
context.AppendLine();
|
||||
if (context.Config.GpuAccessor.QueryEarlyZForce())
|
||||
{
|
||||
context.AppendLine("layout (early_fragment_tests) in;");
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.Properties.OriginUpperLeft)
|
||||
{
|
||||
context.AppendLine("layout (origin_upper_left) in vec4 gl_FragCoord;");
|
||||
context.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0)
|
||||
|
@@ -251,7 +251,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
context.AddExecutionMode(spvFunc, context.Config.Options.TargetApi == TargetApi.Vulkan
|
||||
context.AddExecutionMode(spvFunc, context.Config.Properties.OriginUpperLeft
|
||||
? ExecutionMode.OriginUpperLeft
|
||||
: ExecutionMode.OriginLowerLeft);
|
||||
|
||||
|
@@ -178,6 +178,15 @@ namespace Ryujinx.Graphics.Shader
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries if host state forces early depth testing.
|
||||
/// </summary>
|
||||
/// <returns>True if early depth testing is forced</returns>
|
||||
bool QueryEarlyZForce()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries whenever the current draw has written the base vertex and base instance into Constant Buffer 0.
|
||||
/// </summary>
|
||||
@@ -534,19 +543,19 @@ namespace Ryujinx.Graphics.Shader
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries if host state forces early depth testing.
|
||||
/// Queries if host state disables the viewport transform.
|
||||
/// </summary>
|
||||
/// <returns>True if early depth testing is forced</returns>
|
||||
bool QueryEarlyZForce()
|
||||
/// <returns>True if the viewport transform is disabled</returns>
|
||||
bool QueryViewportTransformDisable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries if host state disables the viewport transform.
|
||||
/// Queries Y negate enable state.
|
||||
/// </summary>
|
||||
/// <returns>True if the viewport transform is disabled</returns>
|
||||
bool QueryViewportTransformDisable()
|
||||
/// <returns>True if Y negate of the fragment coordinates is enabled, false otherwise</returns>
|
||||
bool QueryYNegateEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@@ -161,6 +161,18 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
// FragCoord X/Y must be divided by the render target scale, if resolution scaling is active,
|
||||
// because the shader code is not expecting scaled values.
|
||||
res = context.FPDivide(res, context.Load(StorageKind.ConstantBuffer, SupportBuffer.Binding, Const((int)SupportBufferField.RenderScale), Const(0)));
|
||||
|
||||
if (op.Imm10 == AttributeConsts.PositionY && context.Config.Options.TargetApi != TargetApi.OpenGL)
|
||||
{
|
||||
// If YNegate is enabled, we need to flip the fragment coordinates vertically, unless
|
||||
// the API supports changing the origin (only OpenGL does).
|
||||
if (context.Config.GpuAccessor.QueryYNegateEnabled())
|
||||
{
|
||||
Operand viewportHeight = context.Load(StorageKind.ConstantBuffer, 0, Const((int)SupportBufferField.ViewportSize), Const(1));
|
||||
|
||||
res = context.FPSubtract(viewportHeight, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (op.Imm10 == AttributeConsts.FrontFacing && context.Config.GpuAccessor.QueryHostHasFrontFacingBug())
|
||||
{
|
||||
|
@@ -162,8 +162,10 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
if (op.Ccc == Ccc.T)
|
||||
{
|
||||
context.PrepareForReturn();
|
||||
context.Return();
|
||||
if (context.PrepareForReturn())
|
||||
{
|
||||
context.Return();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -174,8 +176,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
Operand lblSkip = Label();
|
||||
context.BranchIfFalse(lblSkip, cond);
|
||||
context.PrepareForReturn();
|
||||
context.Return();
|
||||
|
||||
if (context.PrepareForReturn())
|
||||
{
|
||||
context.Return();
|
||||
}
|
||||
|
||||
context.MarkLabel(lblSkip);
|
||||
}
|
||||
}
|
||||
|
@@ -218,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
return context.Copy(Register(srcB++, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
Operand d = dest != RegisterConsts.RegisterZeroIndex ? Register(dest, RegisterType.Gpr) : null;
|
||||
Operand d = Register(dest, RegisterType.Gpr);
|
||||
|
||||
List<Operand> sourcesList = new();
|
||||
|
||||
@@ -304,6 +304,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
bool byteAddress,
|
||||
bool isBindless)
|
||||
{
|
||||
if (srcB == RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
|
||||
|
||||
SamplerType type = ConvertSamplerType(dimensions);
|
||||
|
@@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
public ShaderIdentification Identification { get; }
|
||||
public int GpLayerInputAttribute { get; }
|
||||
public ShaderStage Stage { get; }
|
||||
public bool UsesFragCoord { get; }
|
||||
public bool UsesInstanceId { get; }
|
||||
public bool UsesDrawParameters { get; }
|
||||
public bool UsesRtLayer { get; }
|
||||
@@ -27,6 +28,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
ShaderIdentification identification,
|
||||
int gpLayerInputAttribute,
|
||||
ShaderStage stage,
|
||||
bool usesFragCoord,
|
||||
bool usesInstanceId,
|
||||
bool usesDrawParameters,
|
||||
bool usesRtLayer,
|
||||
@@ -41,6 +43,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
Identification = identification;
|
||||
GpLayerInputAttribute = gpLayerInputAttribute;
|
||||
Stage = stage;
|
||||
UsesFragCoord = usesFragCoord;
|
||||
UsesInstanceId = usesInstanceId;
|
||||
UsesDrawParameters = usesDrawParameters;
|
||||
UsesRtLayer = usesRtLayer;
|
||||
|
@@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
|
||||
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
||||
|
||||
public readonly bool OriginUpperLeft;
|
||||
|
||||
public ShaderProperties()
|
||||
{
|
||||
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
||||
@@ -28,6 +30,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
_sharedMemories = new Dictionary<int, MemoryDefinition>();
|
||||
}
|
||||
|
||||
public ShaderProperties(bool originUpperLeft) : this()
|
||||
{
|
||||
OriginUpperLeft = originUpperLeft;
|
||||
}
|
||||
|
||||
public void AddOrUpdateConstantBuffer(int binding, BufferDefinition definition)
|
||||
{
|
||||
_constantBuffers[binding] = definition;
|
||||
|
@@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
FragmentAlphaTest,
|
||||
FragmentIsBgra,
|
||||
ViewportInverse,
|
||||
ViewportSize,
|
||||
FragmentRenderScaleCount,
|
||||
RenderScale,
|
||||
}
|
||||
@@ -33,6 +34,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
public static readonly int FragmentAlphaTestOffset;
|
||||
public static readonly int FragmentIsBgraOffset;
|
||||
public static readonly int ViewportInverseOffset;
|
||||
public static readonly int ViewportSizeOffset;
|
||||
public static readonly int FragmentRenderScaleCountOffset;
|
||||
public static readonly int GraphicsRenderScaleOffset;
|
||||
public static readonly int ComputeRenderScaleOffset;
|
||||
@@ -56,6 +58,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
FragmentAlphaTestOffset = OffsetOf(ref instance, ref instance.FragmentAlphaTest);
|
||||
FragmentIsBgraOffset = OffsetOf(ref instance, ref instance.FragmentIsBgra);
|
||||
ViewportInverseOffset = OffsetOf(ref instance, ref instance.ViewportInverse);
|
||||
ViewportSizeOffset = OffsetOf(ref instance, ref instance.ViewportSize);
|
||||
FragmentRenderScaleCountOffset = OffsetOf(ref instance, ref instance.FragmentRenderScaleCount);
|
||||
GraphicsRenderScaleOffset = OffsetOf(ref instance, ref instance.RenderScale);
|
||||
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
|
||||
@@ -68,6 +71,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
new StructureField(AggregateType.U32, "s_alpha_test"),
|
||||
new StructureField(AggregateType.Array | AggregateType.U32, "s_is_bgra", FragmentIsBgraCount),
|
||||
new StructureField(AggregateType.Vector4 | AggregateType.FP32, "s_viewport_inverse"),
|
||||
new StructureField(AggregateType.Vector4 | AggregateType.FP32, "s_viewport_size"),
|
||||
new StructureField(AggregateType.S32, "s_frag_scale_count"),
|
||||
new StructureField(AggregateType.Array | AggregateType.FP32, "s_render_scale", RenderScaleMaxCount),
|
||||
});
|
||||
@@ -76,6 +80,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
public Vector4<int> FragmentAlphaTest;
|
||||
public Array8<Vector4<int>> FragmentIsBgra;
|
||||
public Vector4<float> ViewportInverse;
|
||||
public Vector4<float> ViewportSize;
|
||||
public Vector4<int> FragmentRenderScaleCount;
|
||||
|
||||
// Render scale max count: 1 + 64 + 8. First scale is fragment output scale, others are textures/image inputs.
|
||||
|
@@ -304,11 +304,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
PrepareForVertexReturn();
|
||||
}
|
||||
|
||||
public void PrepareForReturn()
|
||||
public bool PrepareForReturn()
|
||||
{
|
||||
if (IsNonMain)
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Config.LastInVertexPipeline &&
|
||||
@@ -383,13 +383,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
AlphaTestOp alphaTestOp = Config.GpuAccessor.QueryAlphaTestCompare();
|
||||
|
||||
if (alphaTestOp != AlphaTestOp.Always && (Config.OmapTargets & 8) != 0)
|
||||
if (alphaTestOp != AlphaTestOp.Always)
|
||||
{
|
||||
if (alphaTestOp == AlphaTestOp.Never)
|
||||
{
|
||||
this.Discard();
|
||||
}
|
||||
else
|
||||
else if ((Config.OmapTargets & 8) != 0)
|
||||
{
|
||||
Instruction comparator = alphaTestOp switch
|
||||
{
|
||||
@@ -415,6 +415,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
}
|
||||
|
||||
// We don't need to output anything if alpha test always fails.
|
||||
if (alphaTestOp == AlphaTestOp.Never)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int regIndexBase = 0;
|
||||
|
||||
for (int rtIndex = 0; rtIndex < 8; rtIndex++)
|
||||
@@ -462,6 +468,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void GenerateAlphaToCoverageDitherDiscard()
|
||||
|
@@ -429,6 +429,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return context.Add(Instruction.FP32 | Instruction.SquareRoot, Local(), a);
|
||||
}
|
||||
|
||||
public static Operand FPSubtract(this EmitterContext context, Operand a, Operand b, Instruction fpType = Instruction.FP32)
|
||||
{
|
||||
return context.Add(fpType | Instruction.Subtract, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand FPTruncate(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
|
||||
{
|
||||
return context.Add(fpType | Instruction.Truncate, Local(), a);
|
||||
|
@@ -123,7 +123,20 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||
|
||||
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
|
||||
ShaderProperties properties;
|
||||
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage.Fragment:
|
||||
bool originUpperLeft = options.TargetApi == TargetApi.Vulkan || gpuAccessor.QueryYNegateEnabled();
|
||||
properties = new ShaderProperties(originUpperLeft);
|
||||
break;
|
||||
default:
|
||||
properties = new ShaderProperties();
|
||||
break;
|
||||
}
|
||||
|
||||
ResourceManager = new ResourceManager(stage, gpuAccessor, properties);
|
||||
|
||||
if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
|
||||
{
|
||||
@@ -135,7 +148,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
BufferDefinition tfeInfoBuffer = new(BufferLayout.Std430, 1, Constants.TfeInfoBinding, "tfe_info", tfeInfoStruct);
|
||||
|
||||
Properties.AddOrUpdateStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
|
||||
properties.AddOrUpdateStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
|
||||
|
||||
StructureType tfeDataStruct = new(new StructureField[]
|
||||
{
|
||||
@@ -146,7 +159,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
int binding = Constants.TfeBufferBaseBinding + i;
|
||||
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
|
||||
Properties.AddOrUpdateStorageBuffer(binding, tfeDataBuffer);
|
||||
properties.AddOrUpdateStorageBuffer(binding, tfeDataBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -615,6 +628,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
identification,
|
||||
GpLayerInputAttribute,
|
||||
Stage,
|
||||
UsedFeatures.HasFlag(FeatureFlags.FragCoordXY),
|
||||
UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
||||
UsedFeatures.HasFlag(FeatureFlags.DrawParameters),
|
||||
UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
||||
|
@@ -42,6 +42,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
"VK_NV_viewport_array2",
|
||||
"VK_EXT_depth_clip_control",
|
||||
"VK_KHR_portability_subset", // As per spec, we should enable this if present.
|
||||
"VK_EXT_4444_formats",
|
||||
};
|
||||
|
||||
private static readonly string[] _requiredExtensions = {
|
||||
|
@@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private int _width;
|
||||
private int _height;
|
||||
private bool _vsyncEnabled;
|
||||
private bool _vsyncModeChanged;
|
||||
private bool _swapchainIsDirty;
|
||||
private VkFormat _format;
|
||||
private AntiAliasing _currentAntiAliasing;
|
||||
private bool _updateEffect;
|
||||
@@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private float _scalingFilterLevel;
|
||||
private bool _updateScalingFilter;
|
||||
private ScalingFilter _currentScalingFilter;
|
||||
private bool _colorSpacePassthroughEnabled;
|
||||
|
||||
public unsafe Window(VulkanRenderer gd, SurfaceKHR surface, PhysicalDevice physicalDevice, Device device)
|
||||
{
|
||||
@@ -60,7 +61,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private void RecreateSwapchain()
|
||||
{
|
||||
var oldSwapchain = _swapchain;
|
||||
_vsyncModeChanged = false;
|
||||
_swapchainIsDirty = false;
|
||||
|
||||
for (int i = 0; i < _swapchainImageViews.Length; i++)
|
||||
{
|
||||
@@ -106,7 +107,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
imageCount = capabilities.MaxImageCount;
|
||||
}
|
||||
|
||||
var surfaceFormat = ChooseSwapSurfaceFormat(surfaceFormats);
|
||||
var surfaceFormat = ChooseSwapSurfaceFormat(surfaceFormats, _colorSpacePassthroughEnabled);
|
||||
|
||||
var extent = ChooseSwapExtent(capabilities);
|
||||
|
||||
@@ -178,22 +179,40 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return new Auto<DisposableImageView>(new DisposableImageView(_gd.Api, _device, imageView));
|
||||
}
|
||||
|
||||
private static SurfaceFormatKHR ChooseSwapSurfaceFormat(SurfaceFormatKHR[] availableFormats)
|
||||
private static SurfaceFormatKHR ChooseSwapSurfaceFormat(SurfaceFormatKHR[] availableFormats, bool colorSpacePassthroughEnabled)
|
||||
{
|
||||
if (availableFormats.Length == 1 && availableFormats[0].Format == VkFormat.Undefined)
|
||||
{
|
||||
return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.PaceSrgbNonlinearKhr);
|
||||
}
|
||||
|
||||
foreach (var format in availableFormats)
|
||||
var formatToReturn = availableFormats[0];
|
||||
if (colorSpacePassthroughEnabled)
|
||||
{
|
||||
if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr)
|
||||
foreach (var format in availableFormats)
|
||||
{
|
||||
return format;
|
||||
if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.SpacePassThroughExt)
|
||||
{
|
||||
formatToReturn = format;
|
||||
break;
|
||||
}
|
||||
else if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr)
|
||||
{
|
||||
formatToReturn = format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return availableFormats[0];
|
||||
else
|
||||
{
|
||||
foreach (var format in availableFormats)
|
||||
{
|
||||
if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr)
|
||||
{
|
||||
formatToReturn = format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return formatToReturn;
|
||||
}
|
||||
|
||||
private static CompositeAlphaFlagsKHR ChooseCompositeAlpha(CompositeAlphaFlagsKHR supportedFlags)
|
||||
@@ -259,7 +278,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (acquireResult == Result.ErrorOutOfDateKhr ||
|
||||
acquireResult == Result.SuboptimalKhr ||
|
||||
_vsyncModeChanged)
|
||||
_swapchainIsDirty)
|
||||
{
|
||||
RecreateSwapchain();
|
||||
}
|
||||
@@ -443,6 +462,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_updateScalingFilter = true;
|
||||
}
|
||||
|
||||
public override void SetColorSpacePassthrough(bool colorSpacePassthroughEnabled)
|
||||
{
|
||||
_colorSpacePassthroughEnabled = colorSpacePassthroughEnabled;
|
||||
_swapchainIsDirty = true;
|
||||
}
|
||||
|
||||
private void UpdateEffect()
|
||||
{
|
||||
if (_updateEffect)
|
||||
@@ -559,7 +584,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public override void ChangeVSyncMode(bool vsyncEnabled)
|
||||
{
|
||||
_vsyncEnabled = vsyncEnabled;
|
||||
_vsyncModeChanged = true;
|
||||
_swapchainIsDirty = true;
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
|
@@ -14,5 +14,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public abstract void SetAntiAliasing(AntiAliasing effect);
|
||||
public abstract void SetScalingFilter(ScalingFilter scalerType);
|
||||
public abstract void SetScalingFilterLevel(float scale);
|
||||
public abstract void SetColorSpacePassthrough(bool colorSpacePassthroughEnabled);
|
||||
}
|
||||
}
|
||||
|
@@ -89,9 +89,6 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
||||
Logger.Warning?.Print(LogClass.Ptc, "Detected unsupported ExeFs modifications. PTC disabled.");
|
||||
}
|
||||
|
||||
// We allow it for nx-hbloader because it can be used to launch homebrew.
|
||||
bool allowCodeMemoryForJit = programId == 0x010000000000100DUL || isHomebrew;
|
||||
|
||||
string programName = "";
|
||||
|
||||
if (!isHomebrew && programId > 0x010000000000FFFF)
|
||||
@@ -119,7 +116,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
||||
metaLoader,
|
||||
nacpData,
|
||||
enablePtc,
|
||||
allowCodeMemoryForJit,
|
||||
true,
|
||||
programName,
|
||||
metaLoader.GetProgramId(),
|
||||
null,
|
||||
|
@@ -28,6 +28,11 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
{
|
||||
static class ProcessLoaderHelper
|
||||
{
|
||||
// NOTE: If you want to change this value make sure to increment the InternalVersion of Ptc and PtcProfiler.
|
||||
// You also need to add a new migration path and adjust the existing ones.
|
||||
// TODO: Remove this workaround when ASLR is implemented.
|
||||
private const ulong CodeStartOffset = 0x500000UL;
|
||||
|
||||
public static LibHac.Result RegisterProgramMapInfo(Switch device, PartitionFileSystem partitionFileSystem)
|
||||
{
|
||||
ulong applicationId = 0;
|
||||
@@ -242,7 +247,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
ulong argsStart = 0;
|
||||
uint argsSize = 0;
|
||||
ulong codeStart = (meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL;
|
||||
ulong codeStart = ((meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL) + CodeStartOffset;
|
||||
uint codeSize = 0;
|
||||
|
||||
var buildIds = executables.Select(e => (e switch
|
||||
|
@@ -764,7 +764,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
0x7E30D820u, // FADDP S0, V1.2S
|
||||
0x7E30C820u, // FMAXNMP S0, V1.2S
|
||||
0x7E30F820u, // FMAXP S0, V1.2S
|
||||
0x7EB0C820u, // FMINNMP S0, V1.2S
|
||||
0x7EB0F820u, // FMINP S0, V1.2S
|
||||
};
|
||||
}
|
||||
|
||||
@@ -774,7 +776,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
0x7E70D820u, // FADDP D0, V1.2D
|
||||
0x7E70C820u, // FMAXNMP D0, V1.2D
|
||||
0x7E70F820u, // FMAXP D0, V1.2D
|
||||
0x7EF0C820u, // FMINNMP D0, V1.2D
|
||||
0x7EF0F820u, // FMINP D0, V1.2D
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
/// <summary>
|
||||
/// The current version of the file format
|
||||
/// </summary>
|
||||
public const int CurrentVersion = 47;
|
||||
public const int CurrentVersion = 48;
|
||||
|
||||
/// <summary>
|
||||
/// Version of the configuration file format
|
||||
@@ -186,6 +186,11 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
/// </summary>
|
||||
public bool EnableMacroHLE { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables color space passthrough, if available.
|
||||
/// </summary>
|
||||
public bool EnableColorSpacePassthrough { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables profiled translation cache persistency
|
||||
/// </summary>
|
||||
|
@@ -485,6 +485,11 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> EnableMacroHLE { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables color space passthrough, if available.
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> EnableColorSpacePassthrough { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Graphics backend
|
||||
/// </summary>
|
||||
@@ -535,6 +540,8 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
PreferredGpu.Event += static (sender, e) => LogValueChange(e, nameof(PreferredGpu));
|
||||
EnableMacroHLE = new ReactiveObject<bool>();
|
||||
EnableMacroHLE.Event += static (sender, e) => LogValueChange(e, nameof(EnableMacroHLE));
|
||||
EnableColorSpacePassthrough = new ReactiveObject<bool>();
|
||||
EnableColorSpacePassthrough.Event += static (sender, e) => LogValueChange(e, nameof(EnableColorSpacePassthrough));
|
||||
AntiAliasing = new ReactiveObject<AntiAliasing>();
|
||||
AntiAliasing.Event += static (sender, e) => LogValueChange(e, nameof(AntiAliasing));
|
||||
ScalingFilter = new ReactiveObject<ScalingFilter>();
|
||||
@@ -667,6 +674,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
EnableShaderCache = Graphics.EnableShaderCache,
|
||||
EnableTextureRecompression = Graphics.EnableTextureRecompression,
|
||||
EnableMacroHLE = Graphics.EnableMacroHLE,
|
||||
EnableColorSpacePassthrough = Graphics.EnableColorSpacePassthrough,
|
||||
EnablePtc = System.EnablePtc,
|
||||
EnableInternetAccess = System.EnableInternetAccess,
|
||||
EnableFsIntegrityChecks = System.EnableFsIntegrityChecks,
|
||||
@@ -772,6 +780,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
Graphics.EnableShaderCache.Value = true;
|
||||
Graphics.EnableTextureRecompression.Value = false;
|
||||
Graphics.EnableMacroHLE.Value = true;
|
||||
Graphics.EnableColorSpacePassthrough.Value = false;
|
||||
Graphics.AntiAliasing.Value = AntiAliasing.None;
|
||||
Graphics.ScalingFilter.Value = ScalingFilter.Bilinear;
|
||||
Graphics.ScalingFilterLevel.Value = 80;
|
||||
@@ -1391,6 +1400,15 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
configurationFileUpdated = true;
|
||||
}
|
||||
|
||||
if (configurationFileFormat.Version < 48)
|
||||
{
|
||||
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 48.");
|
||||
|
||||
configurationFileFormat.EnableColorSpacePassthrough = false;
|
||||
|
||||
configurationFileUpdated = true;
|
||||
}
|
||||
|
||||
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
||||
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
||||
@@ -1426,6 +1444,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
|
||||
Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
|
||||
Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE;
|
||||
Graphics.EnableColorSpacePassthrough.Value = configurationFileFormat.EnableColorSpacePassthrough;
|
||||
System.EnablePtc.Value = configurationFileFormat.EnablePtc;
|
||||
System.EnableInternetAccess.Value = configurationFileFormat.EnableInternetAccess;
|
||||
System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
|
||||
|
Reference in New Issue
Block a user