Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
02714a1291 | ||
|
09c9686498 | ||
|
b6614c6ad5 | ||
|
b1d4b174a6 | ||
|
2b23463daa | ||
|
9dfe81770a | ||
|
52c115a1f8 | ||
|
e20abbf9cc |
@@ -25,7 +25,7 @@
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||
@@ -50,5 +50,7 @@
|
||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3"/>
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@@ -59,11 +59,11 @@ namespace Ryujinx.Ava
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogThemeRestartMessage"],
|
||||
LocaleManager.Instance["DialogThemeRestartSubMessage"],
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["DialogRestartRequiredMessage"]);
|
||||
LocaleManager.Instance[LocaleKeys.DialogThemeRestartMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogThemeRestartSubMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.DialogRestartRequiredMessage]);
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
|
@@ -432,10 +432,10 @@ namespace Ryujinx.Ava
|
||||
if (userError == UserError.NoFirmware)
|
||||
{
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedMessage], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
"");
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
@@ -463,11 +463,11 @@ namespace Ryujinx.Ava
|
||||
_parent.RefreshFirmwareStatus();
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstalledMessage], firmwareVersion.VersionString),
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -869,7 +869,7 @@ namespace Ryujinx.Ava
|
||||
public void UpdateStatus()
|
||||
{
|
||||
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued
|
||||
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance["Docked"] : LocaleManager.Instance["Handheld"];
|
||||
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
|
||||
float scale = GraphicsConfig.ResScale;
|
||||
|
||||
if (scale != 1)
|
||||
@@ -879,11 +879,11 @@ namespace Ryujinx.Ava
|
||||
|
||||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||
Device.EnableDeviceVsync,
|
||||
LocaleManager.Instance["VolumeShort"] + $": {(int)(Device.GetVolume() * 100)}%",
|
||||
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
|
||||
Renderer.IsVulkan ? "Vulkan" : "OpenGL",
|
||||
dockedMode,
|
||||
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
||||
LocaleManager.Instance["Game"] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
||||
$"GPU: {_renderer.GetHardwareInfo().GpuVendor}"));
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ namespace Ryujinx.Ava.Common
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(
|
||||
string.Format(LocaleManager.Instance["DialogMessageCreateSaveErrorMessage"], result.ToStringWithName()));
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageCreateSaveErrorMessage], result.ToStringWithName()));
|
||||
});
|
||||
|
||||
return false;
|
||||
@@ -100,7 +100,7 @@ namespace Ryujinx.Ava.Common
|
||||
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogMessageFindSaveErrorMessage"], result.ToStringWithName()));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageFindSaveErrorMessage], result.ToStringWithName()));
|
||||
});
|
||||
|
||||
return false;
|
||||
@@ -151,7 +151,7 @@ namespace Ryujinx.Ava.Common
|
||||
public static async Task ExtractSection(NcaSectionType ncaSectionType, string titleFilePath,
|
||||
int programIndex = 0)
|
||||
{
|
||||
OpenFolderDialog folderDialog = new() { Title = LocaleManager.Instance["FolderDialogExtractTitle"] };
|
||||
OpenFolderDialog folderDialog = new() { Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] };
|
||||
|
||||
string destination = await folderDialog.ShowAsync(_owner);
|
||||
|
||||
@@ -164,11 +164,11 @@ namespace Ryujinx.Ava.Common
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
string.Format(LocaleManager.Instance["DialogNcaExtractionMessage"], ncaSectionType, Path.GetFileName(titleFilePath)),
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMessage], ncaSectionType, Path.GetFileName(titleFilePath)),
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogCancel"],
|
||||
LocaleManager.Instance["DialogNcaExtractionTitle"]);
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogCancel],
|
||||
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle]);
|
||||
|
||||
if (result == UserResult.Cancel)
|
||||
{
|
||||
@@ -234,7 +234,7 @@ namespace Ryujinx.Ava.Common
|
||||
"Extraction failure. The main NCA was not present in the selected file");
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogNcaExtractionMainNcaNotFoundErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -275,7 +275,7 @@ namespace Ryujinx.Ava.Common
|
||||
$"LibHac returned error code: {resultCode.Value.ErrorCode}");
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogNcaExtractionCheckLogErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
|
||||
});
|
||||
}
|
||||
else if (resultCode.Value.IsSuccess())
|
||||
@@ -283,11 +283,11 @@ namespace Ryujinx.Ava.Common
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(
|
||||
LocaleManager.Instance["DialogNcaExtractionSuccessMessage"],
|
||||
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage],
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
"",
|
||||
LocaleManager.Instance["DialogNcaExtractionTitle"]);
|
||||
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -7,16 +7,16 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
{
|
||||
internal class LocaleExtension : MarkupExtension
|
||||
{
|
||||
public LocaleExtension(string key)
|
||||
public LocaleExtension(LocaleKeys key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
public LocaleKeys Key { get; }
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
string keyToUse = Key;
|
||||
LocaleKeys keyToUse = Key;
|
||||
|
||||
ReflectionBindingExtension binding = new($"[{keyToUse}]")
|
||||
{
|
||||
|
@@ -2,6 +2,7 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -13,17 +14,17 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
{
|
||||
private const string DefaultLanguageCode = "en_US";
|
||||
|
||||
private Dictionary<string, string> _localeStrings;
|
||||
private ConcurrentDictionary<string, object[]> _dynamicValues;
|
||||
private Dictionary<LocaleKeys, string> _localeStrings;
|
||||
private ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
||||
|
||||
public static LocaleManager Instance { get; } = new LocaleManager();
|
||||
public Dictionary<string, string> LocaleStrings { get => _localeStrings; set => _localeStrings = value; }
|
||||
public Dictionary<LocaleKeys, string> LocaleStrings { get => _localeStrings; set => _localeStrings = value; }
|
||||
|
||||
|
||||
public LocaleManager()
|
||||
{
|
||||
_localeStrings = new Dictionary<string, string>();
|
||||
_dynamicValues = new ConcurrentDictionary<string, object[]>();
|
||||
_localeStrings = new Dictionary<LocaleKeys, string>();
|
||||
_dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();
|
||||
|
||||
Load();
|
||||
}
|
||||
@@ -49,7 +50,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
}
|
||||
}
|
||||
|
||||
public string this[string key]
|
||||
public string this[LocaleKeys key]
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -63,7 +64,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
return value;
|
||||
}
|
||||
|
||||
return key;
|
||||
return key.ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -73,7 +74,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateDynamicValue(string key, params object[] values)
|
||||
public void UpdateDynamicValue(LocaleKeys key, params object[] values)
|
||||
{
|
||||
_dynamicValues[key] = values;
|
||||
|
||||
@@ -98,7 +99,10 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
|
||||
foreach (var item in strings)
|
||||
{
|
||||
this[item.Key] = item.Value;
|
||||
if (Enum.TryParse<LocaleKeys>(item.Key, out var key))
|
||||
{
|
||||
this[key] = item.Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
|
@@ -56,7 +56,7 @@ namespace Ryujinx.Ava.Input
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance["AllKeyboards"]);
|
||||
return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance[LocaleKeys.AllKeyboards]);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
|
@@ -84,7 +84,7 @@ namespace Ryujinx.Modules
|
||||
Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedMessage], LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -119,7 +119,7 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], "");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], "");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Ryujinx.Modules
|
||||
Logger.Error?.Print(LogClass.Application, exception.Message);
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdaterFailedToGetVersionMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterFailedToGetVersionMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -165,7 +165,7 @@ namespace Ryujinx.Modules
|
||||
Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from Github!");
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedGithubMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedGithubMessage], LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -177,7 +177,7 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], "");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -210,8 +210,8 @@ namespace Ryujinx.Modules
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
// Show a message asking the user if they want to update
|
||||
var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||
LocaleManager.Instance["RyujinxUpdaterMessage"],
|
||||
var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage],
|
||||
$"{Program.Version} -> {newVersion}");
|
||||
|
||||
if (shouldUpdate)
|
||||
@@ -247,8 +247,8 @@ namespace Ryujinx.Modules
|
||||
|
||||
var taskDialog = new TaskDialog()
|
||||
{
|
||||
Header = LocaleManager.Instance["RyujinxUpdater"],
|
||||
SubHeader = LocaleManager.Instance["UpdaterDownloading"],
|
||||
Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
|
||||
SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading],
|
||||
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
|
||||
Buttons = { },
|
||||
ShowProgressBar = true
|
||||
@@ -272,9 +272,9 @@ namespace Ryujinx.Modules
|
||||
|
||||
if (UpdateSuccessful)
|
||||
{
|
||||
var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||
LocaleManager.Instance["DialogUpdaterCompleteMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterRestartMessage"]);
|
||||
var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterCompleteMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterRestartMessage]);
|
||||
|
||||
if (shouldRestart)
|
||||
{
|
||||
@@ -478,7 +478,7 @@ namespace Ryujinx.Modules
|
||||
private static async void InstallUpdate(TaskDialog taskDialog, string updateFile)
|
||||
{
|
||||
// Extract Update
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterExtracting"];
|
||||
taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterExtracting];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
@@ -556,7 +556,7 @@ namespace Ryujinx.Modules
|
||||
|
||||
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
||||
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterRenaming"];
|
||||
taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterRenaming];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
|
||||
// Replace old files
|
||||
@@ -577,13 +577,13 @@ namespace Ryujinx.Modules
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, string.Format(LocaleManager.Instance["UpdaterRenameFailed"], file));
|
||||
Logger.Warning?.Print(LogClass.Application, string.Format(LocaleManager.Instance[LocaleKeys.UpdaterRenameFailed], file));
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
taskDialog.SubHeader = LocaleManager.Instance["UpdaterAddingFiles"];
|
||||
taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterAddingFiles];
|
||||
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||
});
|
||||
|
||||
@@ -607,8 +607,8 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterArchNotSupportedMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterArchNotSupportedSubMessage"]);
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterArchNotSupportedMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterArchNotSupportedSubMessage]);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -618,8 +618,8 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterNoInternetMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterNoInternetSubMessage"]);
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetSubMessage]);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -629,8 +629,8 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterDirtyBuildMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -642,11 +642,11 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
if (ReleaseInformations.IsFlatHubBuild())
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterFlatpakNotSupportedMessage"]);
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -58,6 +58,7 @@
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -158,4 +159,7 @@
|
||||
<EmbeddedResource Include="Assets\Locales\zh_TW.json" />
|
||||
<EmbeddedResource Include="Assets\Styles\Styles.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="Assets\Locales\en_US.json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@@ -33,15 +33,15 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
? args.PlayerCountMin.ToString()
|
||||
: $"{args.PlayerCountMin}-{args.PlayerCountMax}";
|
||||
|
||||
string key = args.PlayerCountMin == args.PlayerCountMax ? "DialogControllerAppletMessage" : "DialogControllerAppletMessagePlayerRange";
|
||||
LocaleKeys key = args.PlayerCountMin == args.PlayerCountMax ? LocaleKeys.DialogControllerAppletMessage : LocaleKeys.DialogControllerAppletMessagePlayerRange;
|
||||
|
||||
string message = string.Format(LocaleManager.Instance[key],
|
||||
playerCount,
|
||||
args.SupportedStyles,
|
||||
string.Join(", ", args.SupportedPlayers),
|
||||
args.IsDocked ? LocaleManager.Instance["DialogControllerAppletDockModeSet"] : "");
|
||||
args.IsDocked ? LocaleManager.Instance[LocaleKeys.DialogControllerAppletDockModeSet] : "");
|
||||
|
||||
return DisplayMessageDialog(LocaleManager.Instance["DialogControllerAppletTitle"], message);
|
||||
return DisplayMessageDialog(LocaleManager.Instance[LocaleKeys.DialogControllerAppletTitle], message);
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(string title, string message)
|
||||
@@ -62,9 +62,9 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
title,
|
||||
message,
|
||||
"",
|
||||
LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
|
||||
LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel],
|
||||
"",
|
||||
LocaleManager.Instance["SettingsButtonClose"],
|
||||
LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
|
||||
(int)Symbol.Important,
|
||||
deferEvent,
|
||||
async (window) =>
|
||||
@@ -92,7 +92,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogMessageDialogErrorExceptionMessage"], ex));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageDialogErrorExceptionMessage], ex));
|
||||
|
||||
dialogCloseEvent.Set();
|
||||
}
|
||||
@@ -115,7 +115,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await SwkbdAppletDialog.ShowInputDialog(_parent, LocaleManager.Instance["SoftwareKeyboard"], args);
|
||||
var response = await SwkbdAppletDialog.ShowInputDialog(_parent, LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
|
||||
|
||||
if (response.Result == UserResult.Ok)
|
||||
{
|
||||
@@ -126,7 +126,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = true;
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogSoftwareKeyboardErrorExceptionMessage"], ex));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage], ex));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -181,7 +181,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
catch (Exception ex)
|
||||
{
|
||||
dialogCloseEvent.Set();
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogErrorAppletErrorExceptionMessage"], ex));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogErrorAppletErrorExceptionMessage], ex));
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
}
|
||||
else
|
||||
{
|
||||
AddButton(LocaleManager.Instance["InputDialogOk"], 0);
|
||||
AddButton(LocaleManager.Instance[LocaleKeys.InputDialogOk], 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
contentDialog.PrimaryButtonText = args.SubmitText;
|
||||
contentDialog.IsPrimaryButtonEnabled = content._checkLength(content.Message.Length);
|
||||
contentDialog.SecondaryButtonText = "";
|
||||
contentDialog.CloseButtonText = LocaleManager.Instance["InputDialogCancel"];
|
||||
contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel];
|
||||
contentDialog.Content = content;
|
||||
|
||||
TypedEventHandler<ContentDialog, ContentDialogClosedEventArgs> handler = (sender, eventArgs) =>
|
||||
@@ -139,14 +139,14 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
else if (_inputMin > 0 && _inputMax == int.MaxValue)
|
||||
{
|
||||
Error.IsVisible = true;
|
||||
Error.Text = string.Format(LocaleManager.Instance["SwkbdMinCharacters"], _inputMin);
|
||||
Error.Text = string.Format(LocaleManager.Instance[LocaleKeys.SwkbdMinCharacters], _inputMin);
|
||||
|
||||
_checkLength = length => _inputMin <= length;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error.IsVisible = true;
|
||||
Error.Text = string.Format(LocaleManager.Instance["SwkbdMinRangeCharacters"], _inputMin, _inputMax);
|
||||
Error.Text = string.Format(LocaleManager.Instance[LocaleKeys.SwkbdMinRangeCharacters], _inputMin, _inputMax);
|
||||
|
||||
_checkLength = length => _inputMin <= length && length <= _inputMax;
|
||||
}
|
||||
|
@@ -39,9 +39,9 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = title,
|
||||
PrimaryButtonText = LocaleManager.Instance["InputDialogOk"],
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["InputDialogCancel"],
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel],
|
||||
Content = content,
|
||||
PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
|
@@ -65,10 +65,10 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance["UserProfileWindowTitle"],
|
||||
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
||||
PrimaryButtonText = "",
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
|
||||
Content = content,
|
||||
Padding = new Thickness(0)
|
||||
};
|
||||
|
@@ -55,7 +55,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
OpenFileDialog dialog = new();
|
||||
dialog.Filters.Add(new FileDialogFilter
|
||||
{
|
||||
Name = LocaleManager.Instance["AllSupportedFormats"],
|
||||
Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats],
|
||||
Extensions = { "jpg", "jpeg", "png", "bmp" }
|
||||
});
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "JPEG", Extensions = { "jpg", "jpeg" } });
|
||||
|
@@ -62,7 +62,7 @@
|
||||
<Label
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Left"
|
||||
Content="{locale:Locale Descending}" />
|
||||
Content="{locale:Locale OrderDescending}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
@@ -65,14 +65,14 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
if (string.IsNullOrWhiteSpace(TempProfile.Name))
|
||||
{
|
||||
DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance["UserProfileEmptyNameError"]));
|
||||
DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance[LocaleKeys.UserProfileEmptyNameError]));
|
||||
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if (TempProfile.Image == null)
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UserProfileNoImageError"], "");
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UserProfileNoImageError], "");
|
||||
|
||||
isInvalid = true;
|
||||
}
|
||||
|
@@ -170,7 +170,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
secondaryButton,
|
||||
closeButton,
|
||||
iconSymbol,
|
||||
primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok,
|
||||
primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok,
|
||||
deferResetEvent,
|
||||
doWhileDeferred,
|
||||
DeferClose);
|
||||
@@ -188,7 +188,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
|
||||
var deferral = args.GetDeferral();
|
||||
|
||||
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
|
||||
result = primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok;
|
||||
|
||||
sender.PrimaryButtonClick -= DeferClose;
|
||||
|
||||
@@ -281,7 +281,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
UserResult primaryButtonResult = UserResult.Yes)
|
||||
{
|
||||
return await ShowContentDialog(
|
||||
string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance["DialogConfirmationTitle"] : title,
|
||||
string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle] : title,
|
||||
primaryText,
|
||||
secondaryText,
|
||||
acceptButtonText,
|
||||
@@ -299,24 +299,24 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText)
|
||||
{
|
||||
await ShowContentDialog(
|
||||
LocaleManager.Instance["DialogUpdaterTitle"],
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle],
|
||||
primary,
|
||||
secondaryText,
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
(int)Symbol.Important);
|
||||
}
|
||||
|
||||
internal static async Task CreateWarningDialog(string primary, string secondaryText)
|
||||
{
|
||||
await ShowContentDialog(
|
||||
LocaleManager.Instance["DialogWarningTitle"],
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarningTitle],
|
||||
primary,
|
||||
secondaryText,
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
(int)Symbol.Important);
|
||||
}
|
||||
|
||||
@@ -325,12 +325,12 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
Logger.Error?.Print(LogClass.Application, errorMessage);
|
||||
|
||||
await ShowContentDialog(
|
||||
LocaleManager.Instance["DialogErrorTitle"],
|
||||
LocaleManager.Instance["DialogErrorMessage"],
|
||||
LocaleManager.Instance[LocaleKeys.DialogErrorTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogErrorMessage],
|
||||
errorMessage,
|
||||
secondaryErrorMessage,
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
(int)Symbol.Dismiss);
|
||||
}
|
||||
|
||||
@@ -348,9 +348,9 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
title,
|
||||
primary,
|
||||
secondaryText,
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
(int)Symbol.Help,
|
||||
UserResult.Yes);
|
||||
|
||||
@@ -362,17 +362,17 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
internal static async Task<bool> CreateExitDialog()
|
||||
{
|
||||
return await CreateChoiceDialog(
|
||||
LocaleManager.Instance["DialogExitTitle"],
|
||||
LocaleManager.Instance["DialogExitMessage"],
|
||||
LocaleManager.Instance["DialogExitSubMessage"]);
|
||||
LocaleManager.Instance[LocaleKeys.DialogExitTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogExitMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]);
|
||||
}
|
||||
|
||||
internal static async Task<bool> CreateStopEmulationDialog()
|
||||
{
|
||||
return await CreateChoiceDialog(
|
||||
LocaleManager.Instance["DialogStopEmulationTitle"],
|
||||
LocaleManager.Instance["DialogStopEmulationMessage"],
|
||||
LocaleManager.Instance["DialogExitSubMessage"]);
|
||||
LocaleManager.Instance[LocaleKeys.DialogStopEmulationTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogStopEmulationMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]);
|
||||
}
|
||||
|
||||
internal static async Task<string> CreateInputDialog(
|
||||
|
@@ -19,12 +19,12 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
return error switch
|
||||
{
|
||||
UserError.NoKeys => LocaleManager.Instance["UserErrorNoKeys"],
|
||||
UserError.NoFirmware => LocaleManager.Instance["UserErrorNoFirmware"],
|
||||
UserError.FirmwareParsingFailed => LocaleManager.Instance["UserErrorFirmwareParsingFailed"],
|
||||
UserError.ApplicationNotFound => LocaleManager.Instance["UserErrorApplicationNotFound"],
|
||||
UserError.Unknown => LocaleManager.Instance["UserErrorUnknown"],
|
||||
_ => LocaleManager.Instance["UserErrorUndefined"]
|
||||
UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeys],
|
||||
UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmware],
|
||||
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed],
|
||||
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound],
|
||||
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown],
|
||||
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
return error switch
|
||||
{
|
||||
UserError.NoKeys => LocaleManager.Instance["UserErrorNoKeysDescription"],
|
||||
UserError.NoFirmware => LocaleManager.Instance["UserErrorNoFirmwareDescription"],
|
||||
UserError.FirmwareParsingFailed => LocaleManager.Instance["UserErrorFirmwareParsingFailedDescription"],
|
||||
UserError.ApplicationNotFound => LocaleManager.Instance["UserErrorApplicationNotFoundDescription"],
|
||||
UserError.Unknown => LocaleManager.Instance["UserErrorUnknownDescription"],
|
||||
_ => LocaleManager.Instance["UserErrorUndefinedDescription"]
|
||||
UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeysDescription],
|
||||
UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmwareDescription],
|
||||
UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription],
|
||||
UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription],
|
||||
UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription],
|
||||
_ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -73,14 +73,14 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
|
||||
bool isInSetupGuide = IsCoveredBySetupGuide(error);
|
||||
|
||||
string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance["OpenSetupGuideMessage"] : "";
|
||||
string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance[LocaleKeys.OpenSetupGuideMessage] : "";
|
||||
|
||||
var result = await ContentDialogHelper.CreateInfoDialog(
|
||||
string.Format(LocaleManager.Instance["DialogUserErrorDialogMessage"], errorCode, GetErrorTitle(error)),
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogMessage], errorCode, GetErrorTitle(error)),
|
||||
GetErrorDescription(error) + (isInSetupGuide
|
||||
? LocaleManager.Instance["DialogUserErrorDialogInfoMessage"]
|
||||
: ""), setupButtonLabel, LocaleManager.Instance["InputDialogOk"],
|
||||
string.Format(LocaleManager.Instance["DialogUserErrorDialogTitle"], errorCode));
|
||||
? LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogInfoMessage]
|
||||
: ""), setupButtonLabel, LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogTitle], errorCode));
|
||||
|
||||
if (result == UserResult.Ok)
|
||||
{
|
||||
|
@@ -17,12 +17,12 @@ namespace Ryujinx.Ava.UI.Models.Generic
|
||||
string aValue = x.LastPlayed;
|
||||
string bValue = y.LastPlayed;
|
||||
|
||||
if (aValue == LocaleManager.Instance["Never"])
|
||||
if (aValue == LocaleManager.Instance[LocaleKeys.Never])
|
||||
{
|
||||
aValue = DateTime.UnixEpoch.ToString();
|
||||
}
|
||||
|
||||
if (bValue == LocaleManager.Instance["Never"])
|
||||
if (bValue == LocaleManager.Instance[LocaleKeys.Never])
|
||||
{
|
||||
bValue = DateTime.UnixEpoch.ToString();
|
||||
}
|
||||
|
@@ -107,10 +107,10 @@ namespace Ryujinx.Ava.UI.Models
|
||||
|
||||
public async void Delete()
|
||||
{
|
||||
var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DeleteUserSave"],
|
||||
LocaleManager.Instance["IrreversibleActionNote"],
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"], "");
|
||||
var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave],
|
||||
LocaleManager.Instance[LocaleKeys.IrreversibleActionNote],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo], "");
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
|
@@ -11,8 +11,8 @@ namespace Ryujinx.Ava.UI.Models
|
||||
public string Path { get; }
|
||||
|
||||
public string Label => IsNoUpdate
|
||||
? LocaleManager.Instance["NoUpdate"]
|
||||
: string.Format(LocaleManager.Instance["TitleUpdateVersionLabel"], Control.DisplayVersionString.ToString(),
|
||||
? LocaleManager.Instance[LocaleKeys.NoUpdate]
|
||||
: string.Format(LocaleManager.Instance[LocaleKeys.TitleUpdateVersionLabel], Control.DisplayVersionString.ToString(),
|
||||
Path);
|
||||
|
||||
public TitleUpdateModel(ApplicationControlProperty control, string path, bool isNoUpdate = false)
|
||||
|
@@ -344,10 +344,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
if (usageString.Length == 0)
|
||||
{
|
||||
usageString = LocaleManager.Instance["Unknown"] + ".";
|
||||
usageString = LocaleManager.Instance[LocaleKeys.Unknown] + ".";
|
||||
}
|
||||
|
||||
Usage = $"{LocaleManager.Instance["Usage"]} {(writable ? $" ({LocaleManager.Instance["Writable"]})" : "")} : {usageString}";
|
||||
Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageString}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,11 +392,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
return amiiboJsonString;
|
||||
}
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"],
|
||||
LocaleManager.Instance["DialogAmiiboApiFailFetchMessage"],
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||
|
||||
Close();
|
||||
|
||||
@@ -442,11 +442,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
private async void ShowInfoDialog()
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"],
|
||||
LocaleManager.Instance["DialogAmiiboApiConnectErrorMessage"],
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -267,15 +267,15 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
ControllerImage = ProControllerResource;
|
||||
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance["ControllerSettingsPlayer1"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance["ControllerSettingsPlayer2"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance["ControllerSettingsPlayer3"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance["ControllerSettingsPlayer4"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance["ControllerSettingsPlayer5"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance["ControllerSettingsPlayer6"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance["ControllerSettingsPlayer7"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance["ControllerSettingsPlayer8"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance["ControllerSettingsHandheld"]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8]));
|
||||
PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsHandheld]));
|
||||
}
|
||||
|
||||
private void LoadConfiguration(InputConfig inputConfig = null)
|
||||
@@ -406,16 +406,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
if (_playerId == PlayerIndex.Handheld)
|
||||
{
|
||||
Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance["ControllerSettingsControllerTypeHandheld"]));
|
||||
Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeHandheld]));
|
||||
|
||||
Controller = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance["ControllerSettingsControllerTypeProController"]));
|
||||
Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConPair"]));
|
||||
Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConLeft"]));
|
||||
Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConRight"]));
|
||||
Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeProController]));
|
||||
Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConPair]));
|
||||
Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConLeft]));
|
||||
Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConRight]));
|
||||
|
||||
if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1)
|
||||
{
|
||||
@@ -455,7 +455,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Devices.Clear();
|
||||
DeviceList.Clear();
|
||||
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance["ControllerSettingsDeviceDisabled"]));
|
||||
Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
|
||||
|
||||
foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds)
|
||||
{
|
||||
@@ -517,7 +517,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
Directory.CreateDirectory(basePath);
|
||||
}
|
||||
|
||||
ProfilesList.Add((LocaleManager.Instance["ControllerSettingsProfileDefault"]));
|
||||
ProfilesList.Add((LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]));
|
||||
|
||||
foreach (string profile in Directory.GetFiles(basePath, "*.json", SearchOption.AllDirectories))
|
||||
{
|
||||
@@ -526,7 +526,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ProfileName))
|
||||
{
|
||||
ProfileName = LocaleManager.Instance["ControllerSettingsProfileDefault"];
|
||||
ProfileName = LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,7 +687,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
if (ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"])
|
||||
if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
|
||||
{
|
||||
config = LoadDefaultConfiguration();
|
||||
}
|
||||
@@ -717,7 +717,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system.");
|
||||
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogProfileInvalidProfileErrorMessage"], ProfileName));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileErrorMessage], ProfileName));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -749,9 +749,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
if (ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"])
|
||||
if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileDefaultProfileOverwriteErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -784,24 +784,24 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileInvalidProfileNameErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void RemoveProfile()
|
||||
{
|
||||
if (Device == 0 || ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"] || ProfilesList.IndexOf(ProfileName) == -1)
|
||||
if (Device == 0 || ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault] || ProfilesList.IndexOf(ProfileName) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogProfileDeleteProfileTitle"],
|
||||
LocaleManager.Instance["DialogProfileDeleteProfileMessage"],
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
|
@@ -635,14 +635,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
return SortMode switch
|
||||
{
|
||||
ApplicationSort.Title => LocaleManager.Instance["GameListHeaderApplication"],
|
||||
ApplicationSort.Developer => LocaleManager.Instance["GameListHeaderDeveloper"],
|
||||
ApplicationSort.LastPlayed => LocaleManager.Instance["GameListHeaderLastPlayed"],
|
||||
ApplicationSort.TotalTimePlayed => LocaleManager.Instance["GameListHeaderTimePlayed"],
|
||||
ApplicationSort.FileType => LocaleManager.Instance["GameListHeaderFileExtension"],
|
||||
ApplicationSort.FileSize => LocaleManager.Instance["GameListHeaderFileSize"],
|
||||
ApplicationSort.Path => LocaleManager.Instance["GameListHeaderPath"],
|
||||
ApplicationSort.Favorite => LocaleManager.Instance["CommonFavorite"],
|
||||
ApplicationSort.Title => LocaleManager.Instance[LocaleKeys.GameListHeaderApplication],
|
||||
ApplicationSort.Developer => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper],
|
||||
ApplicationSort.LastPlayed => LocaleManager.Instance[LocaleKeys.GameListHeaderLastPlayed],
|
||||
ApplicationSort.TotalTimePlayed => LocaleManager.Instance[LocaleKeys.GameListHeaderTimePlayed],
|
||||
ApplicationSort.FileType => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension],
|
||||
ApplicationSort.FileSize => LocaleManager.Instance[LocaleKeys.GameListHeaderFileSize],
|
||||
ApplicationSort.Path => LocaleManager.Instance[LocaleKeys.GameListHeaderPath],
|
||||
ApplicationSort.Favorite => LocaleManager.Instance[LocaleKeys.CommonFavorite],
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
@@ -771,7 +771,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
StatusBarProgressValue = e.NumAppsLoaded;
|
||||
StatusBarProgressMaximum = e.NumAppsFound;
|
||||
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", StatusBarProgressValue, StatusBarProgressMaximum);
|
||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, StatusBarProgressValue, StatusBarProgressMaximum);
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
@@ -805,7 +805,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
StatusBarProgressMaximum = 0;
|
||||
StatusBarProgressValue = 0;
|
||||
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", 0, 0);
|
||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
|
||||
});
|
||||
|
||||
ReloadGameList();
|
||||
@@ -835,12 +835,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
OpenFileDialog dialog = new()
|
||||
{
|
||||
Title = LocaleManager.Instance["OpenFileDialogTitle"]
|
||||
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle]
|
||||
};
|
||||
|
||||
dialog.Filters.Add(new FileDialogFilter
|
||||
{
|
||||
Name = LocaleManager.Instance["AllSupportedFormats"],
|
||||
Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats],
|
||||
Extensions =
|
||||
{
|
||||
"nsp",
|
||||
@@ -871,7 +871,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
OpenFolderDialog dialog = new()
|
||||
{
|
||||
Title = LocaleManager.Instance["OpenFolderDialogTitle"]
|
||||
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle]
|
||||
};
|
||||
|
||||
string folder = await dialog.ShowAsync(_owner);
|
||||
@@ -1039,11 +1039,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
case PtcLoadingState.Start:
|
||||
case PtcLoadingState.Loading:
|
||||
LoadHeading = LocaleManager.Instance["CompilingPPTC"];
|
||||
LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingPPTC];
|
||||
IsLoadingIndeterminate = false;
|
||||
break;
|
||||
case PtcLoadingState.Loaded:
|
||||
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
|
||||
LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
|
||||
IsLoadingIndeterminate = true;
|
||||
CacheLoadStatus = "";
|
||||
break;
|
||||
@@ -1055,11 +1055,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
case ShaderCacheLoadingState.Start:
|
||||
case ShaderCacheLoadingState.Loading:
|
||||
LoadHeading = LocaleManager.Instance["CompilingShaders"];
|
||||
LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingShaders];
|
||||
IsLoadingIndeterminate = false;
|
||||
break;
|
||||
case ShaderCacheLoadingState.Loaded:
|
||||
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
|
||||
LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
|
||||
IsLoadingIndeterminate = true;
|
||||
CacheLoadStatus = "";
|
||||
break;
|
||||
@@ -1083,7 +1083,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -1166,11 +1166,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
|
||||
|
||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionMessage], selection.TitleName),
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
|
||||
List<FileInfo> cacheFiles = new();
|
||||
|
||||
@@ -1194,7 +1194,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], file.Name, e));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionErrorMessage], file.Name, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1230,11 +1230,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
|
||||
|
||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogShaderDeletionMessage], selection.TitleName),
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
|
||||
List<DirectoryInfo> oldCacheDirectories = new();
|
||||
List<FileInfo> newCacheFiles = new();
|
||||
@@ -1256,7 +1256,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], directory.Name, e));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionErrorMessage], directory.Name, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1269,7 +1269,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["ShaderCachePurgeError"], file.Name, e));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.ShaderCachePurgeError], file.Name, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1337,7 +1337,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -1360,7 +1360,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -1417,32 +1417,32 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
if (firmwareVersion == null)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareNotFoundErrorMessage"], filename));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage], filename));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
string dialogTitle = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallTitle"], firmwareVersion.VersionString);
|
||||
string dialogTitle = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle], firmwareVersion.VersionString);
|
||||
|
||||
SystemVersion currentVersion = _owner.ContentManager.GetCurrentFirmwareVersion();
|
||||
|
||||
string dialogMessage = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallMessage"], firmwareVersion.VersionString);
|
||||
string dialogMessage = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage], firmwareVersion.VersionString);
|
||||
|
||||
if (currentVersion != null)
|
||||
{
|
||||
dialogMessage += string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSubMessage"], currentVersion.VersionString);
|
||||
dialogMessage += string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage], currentVersion.VersionString);
|
||||
}
|
||||
|
||||
dialogMessage += LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallConfirmMessage"];
|
||||
dialogMessage += LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
dialogTitle,
|
||||
dialogMessage,
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
|
||||
UpdateWaitWindow waitingDialog = ContentDialogHelper.CreateWaitingDialog(dialogTitle, LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallWaitMessage"]);
|
||||
UpdateWaitWindow waitingDialog = ContentDialogHelper.CreateWaitingDialog(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
@@ -1463,9 +1463,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
waitingDialog.Close();
|
||||
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString);
|
||||
string message = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage], firmwareVersion.VersionString);
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
|
||||
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance[LocaleKeys.InputDialogOk], "", LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, message);
|
||||
|
||||
@@ -1513,7 +1513,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
public async void InstallFirmwareFromFile()
|
||||
{
|
||||
OpenFileDialog dialog = new() { AllowMultiple = false };
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance["FileDialogAllTypes"], Extensions = { "xci", "zip" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance[LocaleKeys.FileDialogAllTypes], Extensions = { "xci", "zip" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } });
|
||||
|
||||
|
@@ -73,11 +73,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogSettingsBackendThreadingWarningMessage"],
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
LocaleManager.Instance["DialogSettingsBackendThreadingWarningTitle"]);
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -306,11 +306,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
var dialog = new OpenFileDialog()
|
||||
{
|
||||
Title = LocaleManager.Instance["SettingsSelectThemeFileDialogTitle"],
|
||||
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
|
||||
AllowMultiple = false
|
||||
};
|
||||
|
||||
dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance["SettingsXamlThemeFile"] });
|
||||
dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
|
||||
|
||||
var file = await dialog.ShowAsync(_owner);
|
||||
|
||||
|
@@ -149,10 +149,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = string.Format(LocaleManager.Instance["SaveManagerHeading"], userProfile.Name),
|
||||
Title = string.Format(LocaleManager.Instance[LocaleKeys.SaveManagerHeading], userProfile.Name),
|
||||
PrimaryButtonText = "",
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
|
||||
Content = manager,
|
||||
Padding = new Thickness(0)
|
||||
};
|
||||
@@ -180,7 +180,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUserProfileDeletionWarningMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -190,8 +190,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
|
||||
var result =
|
||||
await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogUserProfileDeletionConfirmMessage"], "",
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
||||
await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage], "",
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo], "");
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["MenuBarHelpAbout"];
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.MenuBarHelpAbout];
|
||||
}
|
||||
|
||||
Version = Program.Version;
|
||||
@@ -32,7 +32,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
public string Supporters { get; set; }
|
||||
public string Version { get; set; }
|
||||
|
||||
public string Developers => string.Format(LocaleManager.Instance["AboutPageDeveloperListMore"], "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD«");
|
||||
public string Developers => string.Format(LocaleManager.Instance[LocaleKeys.AboutPageDeveloperListMore], "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD«");
|
||||
|
||||
private void Button_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -46,7 +46,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
if (!NetworkInterface.GetIsNetworkAvailable())
|
||||
{
|
||||
Supporters = LocaleManager.Instance["ConnectionError"];
|
||||
Supporters = LocaleManager.Instance[LocaleKeys.ConnectionError];
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
}
|
||||
catch
|
||||
{
|
||||
Supporters = LocaleManager.Instance["ApiError"];
|
||||
Supporters = LocaleManager.Instance[LocaleKeys.ApiError];
|
||||
}
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() => SupportersTextBlock.Text = Supporters);
|
||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["Amiibo"];
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo];
|
||||
}
|
||||
|
||||
public AmiiboWindow()
|
||||
@@ -30,7 +30,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["Amiibo"];
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -24,14 +24,14 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["CheatWindowTitle"];
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
|
||||
}
|
||||
|
||||
public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName)
|
||||
{
|
||||
LoadedCheats = new AvaloniaList<CheatsList>();
|
||||
|
||||
Heading = string.Format(LocaleManager.Instance["CheatWindowHeading"], titleName, titleId.ToUpper());
|
||||
Heading = string.Format(LocaleManager.Instance[LocaleKeys.CheatWindowHeading], titleName, titleId.ToUpper());
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
DataContext = this;
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["CheatWindowTitle"];
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
|
||||
}
|
||||
|
||||
public void Save()
|
||||
|
@@ -639,14 +639,14 @@
|
||||
Width="20"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Text="{locale:Locale ControllerSettingsRightSL}"
|
||||
Text="{locale:Locale ControllerSettingsLeftSL}"
|
||||
TextAlignment="Center" />
|
||||
<ToggleButton
|
||||
Width="90"
|
||||
Height="27"
|
||||
HorizontalAlignment="Stretch">
|
||||
<TextBlock
|
||||
Text="{Binding Configuration.RightButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
Text="{Binding Configuration.LeftButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
|
@@ -148,11 +148,11 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
_dialogOpen = true;
|
||||
|
||||
var result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogControllerSettingsModifiedConfirmMessage"],
|
||||
LocaleManager.Instance["DialogControllerSettingsModifiedConfirmSubMessage"],
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
|
@@ -43,7 +43,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.DlcWindowTitle]} - {_titleName} ({_titleId:X16})";
|
||||
}
|
||||
|
||||
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||
@@ -73,7 +73,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
DlcDataGrid.SelectionChanged += DlcDataGrid_SelectionChanged;
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.DlcWindowTitle]} - {_titleName} ({_titleId:X16})";
|
||||
|
||||
LoadDownloadableContents();
|
||||
PrintHeading();
|
||||
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
private void PrintHeading()
|
||||
{
|
||||
Heading.Text = string.Format(LocaleManager.Instance["DlcWindowHeading"], _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
|
||||
Heading.Text = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
|
||||
}
|
||||
|
||||
private void LoadDownloadableContents()
|
||||
@@ -133,7 +133,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, containerPath));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, containerPath));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
if (!containsDownloadableContent)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
OpenFileDialog dialog = new OpenFileDialog()
|
||||
{
|
||||
Title = LocaleManager.Instance["SelectDlcDialogTitle"],
|
||||
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
|
||||
AllowMultiple = true
|
||||
};
|
||||
|
||||
|
@@ -179,12 +179,12 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
if (ConfigurationState.Instance.Logger.EnableTrace.Value)
|
||||
{
|
||||
string mainMessage = LocaleManager.Instance["DialogPerformanceCheckLoggingEnabledMessage"];
|
||||
string secondaryMessage = LocaleManager.Instance["DialogPerformanceCheckLoggingEnabledConfirmMessage"];
|
||||
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledMessage];
|
||||
string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage];
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
{
|
||||
@@ -196,13 +196,13 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
|
||||
{
|
||||
string mainMessage = LocaleManager.Instance["DialogPerformanceCheckShaderDumpEnabledMessage"];
|
||||
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledMessage];
|
||||
string secondaryMessage =
|
||||
LocaleManager.Instance["DialogPerformanceCheckShaderDumpEnabledConfirmMessage"];
|
||||
LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage];
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
{
|
||||
@@ -227,11 +227,11 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
if (AppHost != null)
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(
|
||||
LocaleManager.Instance["DialogLoadAppGameAlreadyLoadedMessage"],
|
||||
LocaleManager.Instance["DialogLoadAppGameAlreadyLoadedSubMessage"],
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedSubMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -274,7 +274,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
}
|
||||
|
||||
CanUpdate = false;
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||
|
||||
SwitchToGameControl(startFullscreen);
|
||||
@@ -500,14 +500,14 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
if (version != null)
|
||||
{
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarSystemVersion",
|
||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion,
|
||||
version.VersionString);
|
||||
|
||||
hasApplet = version.Major > 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarSystemVersion", "0.0");
|
||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0");
|
||||
}
|
||||
|
||||
ViewModel.IsAppletMenuActive = hasApplet;
|
||||
|
@@ -45,10 +45,10 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance["ControllerMotionTitle"],
|
||||
PrimaryButtonText = LocaleManager.Instance["ControllerSettingsSave"],
|
||||
Title = LocaleManager.Instance[LocaleKeys.ControllerMotionTitle],
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["ControllerSettingsClose"],
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
|
||||
Content = content
|
||||
};
|
||||
contentDialog.PrimaryButtonClick += (sender, args) =>
|
||||
|
@@ -37,10 +37,10 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance["ControllerRumbleTitle"],
|
||||
PrimaryButtonText = LocaleManager.Instance["ControllerSettingsSave"],
|
||||
Title = LocaleManager.Instance[LocaleKeys.ControllerRumbleTitle],
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["ControllerSettingsClose"],
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
|
||||
Content = content,
|
||||
};
|
||||
|
||||
|
@@ -29,7 +29,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["Settings"]}";
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.Settings]}";
|
||||
|
||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
|
||||
DataContext = ViewModel;
|
||||
|
@@ -43,7 +43,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})";
|
||||
}
|
||||
|
||||
public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||
@@ -73,7 +73,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})";
|
||||
|
||||
LoadUpdates();
|
||||
PrintHeading();
|
||||
@@ -81,7 +81,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
private void PrintHeading()
|
||||
{
|
||||
Heading.Text = string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
|
||||
Heading.Text = string.Format(LocaleManager.Instance[LocaleKeys.GameUpdateWindowHeading], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
|
||||
}
|
||||
|
||||
private void LoadUpdates()
|
||||
@@ -148,7 +148,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdateAddUpdateErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, path));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, path));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -193,7 +193,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
OpenFileDialog dialog = new()
|
||||
{
|
||||
Title = LocaleManager.Instance["SelectUpdateDialogTitle"],
|
||||
Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
|
||||
AllowMultiple = true
|
||||
};
|
||||
|
||||
|
@@ -27,7 +27,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll")]
|
||||
public static partial int GetCurrentThreadId();
|
||||
private static partial int GetCurrentThreadId();
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
@@ -36,7 +36,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static partial bool CloseHandle(IntPtr hObject);
|
||||
private static partial bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
@@ -160,4 +160,4 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
ISampler CreateSampler(SamplerCreateInfo info);
|
||||
ITexture CreateTexture(TextureCreateInfo info, float scale);
|
||||
|
||||
void CreateSync(ulong id);
|
||||
void CreateSync(ulong id, bool strict);
|
||||
|
||||
void DeleteBuffer(BufferHandle buffer);
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
void Initialize(GraphicsDebugLevel logLevel);
|
||||
|
||||
void SetInterruptAction(Action<Action> interruptAction);
|
||||
|
||||
void Screenshot();
|
||||
}
|
||||
}
|
||||
|
@@ -4,15 +4,17 @@
|
||||
{
|
||||
public CommandType CommandType => CommandType.CreateSync;
|
||||
private ulong _id;
|
||||
private bool _strict;
|
||||
|
||||
public void Set(ulong id)
|
||||
public void Set(ulong id, bool strict)
|
||||
{
|
||||
_id = id;
|
||||
_strict = strict;
|
||||
}
|
||||
|
||||
public static void Run(ref CreateSyncCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.CreateSync(command._id);
|
||||
renderer.CreateSync(command._id, command._strict);
|
||||
|
||||
threaded.Sync.AssignSync(command._id);
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
private int _elementSize;
|
||||
private IRenderer _baseRenderer;
|
||||
private Thread _gpuThread;
|
||||
private Thread _backendThread;
|
||||
private bool _disposed;
|
||||
private bool _running;
|
||||
|
||||
@@ -38,6 +39,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
private CircularSpanPool _spanPool;
|
||||
|
||||
private ManualResetEventSlim _invokeRun;
|
||||
private AutoResetEvent _interruptRun;
|
||||
|
||||
private bool _lastSampleCounterClear = true;
|
||||
|
||||
@@ -54,6 +56,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
private int _refProducerPtr;
|
||||
private int _refConsumerPtr;
|
||||
|
||||
private Action _interruptAction;
|
||||
|
||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||
|
||||
internal BufferMap Buffers { get; }
|
||||
@@ -73,6 +77,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_baseRenderer = renderer;
|
||||
|
||||
renderer.ScreenCaptured += (sender, info) => ScreenCaptured?.Invoke(this, info);
|
||||
renderer.SetInterruptAction(Interrupt);
|
||||
|
||||
Pipeline = new ThreadedPipeline(this, renderer.Pipeline);
|
||||
Window = new ThreadedWindow(this, renderer);
|
||||
@@ -82,6 +87,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
|
||||
_galWorkAvailable = new ManualResetEventSlim(false);
|
||||
_invokeRun = new ManualResetEventSlim();
|
||||
_interruptRun = new AutoResetEvent(false);
|
||||
_spanPool = new CircularSpanPool(this, SpanPoolBytes);
|
||||
SpanPool = _spanPool;
|
||||
|
||||
@@ -95,6 +101,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
{
|
||||
_running = true;
|
||||
|
||||
_backendThread = Thread.CurrentThread;
|
||||
|
||||
_gpuThread = new Thread(() => {
|
||||
gpuLoop();
|
||||
_running = false;
|
||||
@@ -116,10 +124,18 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_galWorkAvailable.Wait();
|
||||
_galWorkAvailable.Reset();
|
||||
|
||||
if (Volatile.Read(ref _interruptAction) != null)
|
||||
{
|
||||
_interruptAction();
|
||||
_interruptRun.Set();
|
||||
|
||||
Interlocked.Exchange(ref _interruptAction, null);
|
||||
}
|
||||
|
||||
// The other thread can only increase the command count.
|
||||
// We can assume that if it is above 0, it will stay there or get higher.
|
||||
|
||||
while (_commandCount > 0)
|
||||
while (_commandCount > 0 && Volatile.Read(ref _interruptAction) == null)
|
||||
{
|
||||
int commandPtr = _consumerPtr;
|
||||
|
||||
@@ -281,10 +297,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
return sampler;
|
||||
}
|
||||
|
||||
public void CreateSync(ulong id)
|
||||
public void CreateSync(ulong id, bool strict)
|
||||
{
|
||||
Sync.CreateSyncHandle(id);
|
||||
New<CreateSyncCommand>().Set(id);
|
||||
New<CreateSyncCommand>().Set(id, strict);
|
||||
QueueCommand();
|
||||
}
|
||||
|
||||
@@ -421,6 +437,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_baseRenderer.WaitSync(id);
|
||||
}
|
||||
|
||||
private void Interrupt(Action action)
|
||||
{
|
||||
// Interrupt the backend thread from any external thread and invoke the given action.
|
||||
|
||||
if (Thread.CurrentThread == _backendThread)
|
||||
{
|
||||
// If this is called from the backend thread, the action can run immediately.
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Interlocked.CompareExchange(ref _interruptAction, action, null) != null) { }
|
||||
|
||||
_galWorkAvailable.Set();
|
||||
|
||||
_interruptRun.WaitOne();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInterruptAction(Action<Action> interruptAction)
|
||||
{
|
||||
// Threaded renderer ignores given interrupt action, as it provides its own to the child renderer.
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Dispose must happen from the render thread, after all commands have completed.
|
||||
@@ -440,6 +480,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_frameComplete.Dispose();
|
||||
_galWorkAvailable.Dispose();
|
||||
_invokeRun.Dispose();
|
||||
_interruptRun.Dispose();
|
||||
|
||||
Sync.Dispose();
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
if (_createSyncPending)
|
||||
{
|
||||
_createSyncPending = false;
|
||||
_context.CreateHostSyncIfNeeded(false);
|
||||
_context.CreateHostSyncIfNeeded(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
}
|
||||
else if (operation == SyncpointbOperation.Incr)
|
||||
{
|
||||
_context.CreateHostSyncIfNeeded(true);
|
||||
_context.CreateHostSyncIfNeeded(true, true);
|
||||
_context.Synchronization.IncrementSyncpoint(syncpointId);
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
{
|
||||
_context.Renderer.Pipeline.CommandBufferBarrier();
|
||||
|
||||
_context.CreateHostSyncIfNeeded(false);
|
||||
_context.CreateHostSyncIfNeeded(false, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -250,7 +250,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
uint syncpointId = (uint)argument & 0xFFFF;
|
||||
|
||||
_context.AdvanceSequence();
|
||||
_context.CreateHostSyncIfNeeded(true);
|
||||
_context.CreateHostSyncIfNeeded(true, true);
|
||||
_context.Renderer.UpdateCounters(); // Poll the query counters, the game may want an updated result.
|
||||
_context.Synchronization.IncrementSyncpoint(syncpointId);
|
||||
}
|
||||
|
@@ -316,7 +316,8 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// If no actions are present, a host sync object is not created.
|
||||
/// </summary>
|
||||
/// <param name="syncpoint">True if host sync is being created by a syncpoint</param>
|
||||
public void CreateHostSyncIfNeeded(bool syncpoint)
|
||||
/// <param name="strict">True if the sync should signal as soon as possible</param>
|
||||
public void CreateHostSyncIfNeeded(bool syncpoint, bool strict)
|
||||
{
|
||||
if (BufferMigrations.Count > 0)
|
||||
{
|
||||
@@ -337,7 +338,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
|
||||
if (_pendingSync || (syncpoint && SyncpointActions.Count > 0))
|
||||
{
|
||||
Renderer.CreateSync(SyncNumber);
|
||||
Renderer.CreateSync(SyncNumber, strict);
|
||||
|
||||
SyncNumber++;
|
||||
|
||||
|
@@ -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 = 4106;
|
||||
private const uint CodeGenVersion = 3939;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -106,7 +106,7 @@ namespace Ryujinx.Graphics.Host1x
|
||||
|
||||
private void Method1(int data)
|
||||
{
|
||||
_commandQueue.Add(new MethodCallAction(_currentContextId, (int)_state.State.Method0 * 4, data));
|
||||
_commandQueue.Add(new MethodCallAction(_currentContextId, (int)_state.State.Method0 * sizeof(uint), data));
|
||||
}
|
||||
|
||||
private void Process(CommandAction cmdAction)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
public enum CodecId
|
||||
public enum ApplicationId
|
||||
{
|
||||
Mpeg = 1,
|
||||
Vc1 = 2,
|
||||
@@ -8,6 +8,7 @@
|
||||
Mpeg4 = 4,
|
||||
Vp8 = 5,
|
||||
Hevc = 7,
|
||||
Vp9 = 9
|
||||
Vp9 = 9,
|
||||
HevcParser = 12,
|
||||
}
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
public readonly struct FrameDecodedEventArgs
|
||||
{
|
||||
public CodecId CodecId { get; }
|
||||
public uint LumaOffset { get; }
|
||||
public uint ChromaOffset { get; }
|
||||
|
||||
internal FrameDecodedEventArgs(CodecId codecId, uint lumaOffset, uint chromaOffset)
|
||||
{
|
||||
CodecId = codecId;
|
||||
LumaOffset = lumaOffset;
|
||||
ChromaOffset = chromaOffset;
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,18 +12,18 @@ namespace Ryujinx.Graphics.Nvdec
|
||||
|
||||
public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state)
|
||||
{
|
||||
PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetPictureInfoOffset);
|
||||
PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
|
||||
H264PictureInfo info = pictureInfo.Convert();
|
||||
|
||||
ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetBitstreamOffset, (int)pictureInfo.BitstreamSize);
|
||||
ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize);
|
||||
|
||||
int width = (int)pictureInfo.PicWidthInMbs * MbSizeInPixels;
|
||||
int height = (int)pictureInfo.PicHeightInMbs * MbSizeInPixels;
|
||||
|
||||
int surfaceIndex = (int)pictureInfo.OutputSurfaceIndex;
|
||||
|
||||
uint lumaOffset = state.SetSurfaceLumaOffset[surfaceIndex];
|
||||
uint chromaOffset = state.SetSurfaceChromaOffset[surfaceIndex];
|
||||
uint lumaOffset = state.SetPictureLumaOffset[surfaceIndex];
|
||||
uint chromaOffset = state.SetPictureChromaOffset[surfaceIndex];
|
||||
|
||||
Decoder decoder = context.GetH264Decoder();
|
||||
|
||||
|
@@ -58,24 +58,24 @@ namespace Ryujinx.Graphics.Nvdec
|
||||
|
||||
private void Execute(int data)
|
||||
{
|
||||
Decode((CodecId)_state.State.SetCodecID);
|
||||
Decode((ApplicationId)_state.State.SetApplicationId);
|
||||
}
|
||||
|
||||
private void Decode(CodecId codecId)
|
||||
private void Decode(ApplicationId applicationId)
|
||||
{
|
||||
switch (codecId)
|
||||
switch (applicationId)
|
||||
{
|
||||
case CodecId.H264:
|
||||
case ApplicationId.H264:
|
||||
H264Decoder.Decode(_currentContext, _rm, ref _state.State);
|
||||
break;
|
||||
case CodecId.Vp8:
|
||||
case ApplicationId.Vp8:
|
||||
Vp8Decoder.Decode(_currentContext, _rm, ref _state.State);
|
||||
break;
|
||||
case CodecId.Vp9:
|
||||
case ApplicationId.Vp9:
|
||||
Vp9Decoder.Decode(_rm, ref _state.State);
|
||||
break;
|
||||
default:
|
||||
Logger.Error?.Print(LogClass.Nvdec, $"Unsupported codec \"{codecId}\".");
|
||||
Logger.Error?.Print(LogClass.Nvdec, $"Unsupported codec \"{applicationId}\".");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -2,43 +2,62 @@
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
// Note: Most of those names are not official.
|
||||
struct NvdecRegisters
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Array64<uint> Reserved0;
|
||||
public Array64<uint> Reserved100;
|
||||
public uint SetCodecID;
|
||||
public Array63<uint> Reserved204;
|
||||
public uint Nop;
|
||||
public Array63<uint> Reserved104;
|
||||
public uint SetApplicationId;
|
||||
public uint SetWatchdogTimer;
|
||||
public Array14<uint> Reserved208;
|
||||
public uint SemaphoreA;
|
||||
public uint SemaphoreB;
|
||||
public uint SemaphoreC;
|
||||
public uint CtxSaveArea;
|
||||
public Array44<uint> Reserved254;
|
||||
public uint Execute;
|
||||
public Array63<uint> Reserved304;
|
||||
public uint SetPlatformID;
|
||||
public uint SetPictureInfoOffset;
|
||||
public uint SetBitstreamOffset;
|
||||
public uint SetFrameNumber;
|
||||
public uint SetH264SliceDataOffsetsOffset; // Also used by VC1
|
||||
public uint SetH264MvDumpOffset; // Also used by VC1
|
||||
public uint Unknown418; // Used by VC1
|
||||
public uint Unknown41C;
|
||||
public uint Unknown420; // Used by VC1
|
||||
public uint SetFrameStatsOffset;
|
||||
public uint SetH264LastSurfaceLumaOffset;
|
||||
public uint SetH264LastSurfaceChromaOffset;
|
||||
public Array17<uint> SetSurfaceLumaOffset;
|
||||
public Array17<uint> SetSurfaceChromaOffset;
|
||||
public uint Unknown4B8;
|
||||
public uint Unknown4BC;
|
||||
public uint SemaphoreD;
|
||||
public Array62<uint> Reserved308;
|
||||
public uint SetControlParams;
|
||||
public uint SetDrvPicSetupOffset;
|
||||
public uint SetInBufBaseOffset;
|
||||
public uint SetPictureIndex;
|
||||
public uint SetSliceOffsetsBufOffset; // Also used by VC1
|
||||
public uint SetColocDataOffset; // Also used by VC1
|
||||
public uint SetHistoryOffset; // Used by VC1
|
||||
public uint SetDisplayBufSize;
|
||||
public uint SetHistogramOffset; // Used by VC1
|
||||
public uint SetNvDecStatusOffset;
|
||||
public uint SetDisplayBufLumaOffset;
|
||||
public uint SetDisplayBufChromaOffset;
|
||||
public Array17<uint> SetPictureLumaOffset;
|
||||
public Array17<uint> SetPictureChromaOffset;
|
||||
public uint SetPicScratchBufOffset;
|
||||
public uint SetExternalMvBufferOffset;
|
||||
public uint SetCryptoData0Offset;
|
||||
public uint SetCryptoData1Offset;
|
||||
public Array62<uint> Unknown4C8;
|
||||
public uint SetVp9EntropyProbsOffset;
|
||||
public uint SetVp9BackwardUpdatesOffset;
|
||||
public uint SetVp9LastFrameSegMapOffset;
|
||||
public uint SetVp9CurrFrameSegMapOffset;
|
||||
public uint Unknown5D0;
|
||||
public uint SetVp9LastFrameMvsOffset;
|
||||
public uint SetVp9CurrFrameMvsOffset;
|
||||
public uint Unknown5DC;
|
||||
public Array14<uint> Unknown4C8;
|
||||
public uint H264SetMbHistBufOffset;
|
||||
public Array15<uint> Unknown504;
|
||||
public uint Vp8SetProbDataOffset;
|
||||
public uint Vp8SetHeaderPartitionBufBaseOffset;
|
||||
public Array14<uint> Unknown548;
|
||||
public uint HevcSetScalingListOffset;
|
||||
public uint HevcSetTileSizesOffset;
|
||||
public uint HevcSetFilterBufferOffset;
|
||||
public uint HevcSetSaoBufferOffset;
|
||||
public uint HevcSetSliceInfoBufferOffset;
|
||||
public uint HevcSetSliceGroupIndex;
|
||||
public Array10<uint> Unknown598;
|
||||
public uint Vp9SetProbTabBufOffset;
|
||||
public uint Vp9SetCtxCounterBufOffset;
|
||||
public uint Vp9SetSegmentReadBufOffset;
|
||||
public uint Vp9SetSegmentWriteBufOffset;
|
||||
public uint Vp9SetTileSizeBufOffset;
|
||||
public uint Vp9SetColMvWriteBufOffset;
|
||||
public uint Vp9SetColMvReadBufOffset;
|
||||
public uint Vp9SetFilterBufferOffset;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
}
|
||||
|
@@ -10,8 +10,8 @@ namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state)
|
||||
{
|
||||
PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetPictureInfoOffset);
|
||||
ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetBitstreamOffset, (int)pictureInfo.VLDBufferSize);
|
||||
PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
|
||||
ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.VLDBufferSize);
|
||||
|
||||
Decoder decoder = context.GetVp8Decoder();
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace Ryujinx.Graphics.Nvdec
|
||||
|
||||
Vp8PictureInfo info = pictureInfo.Convert();
|
||||
|
||||
uint lumaOffset = state.SetSurfaceLumaOffset[3];
|
||||
uint chromaOffset = state.SetSurfaceChromaOffset[3];
|
||||
uint lumaOffset = state.SetPictureLumaOffset[3];
|
||||
uint chromaOffset = state.SetPictureChromaOffset[3];
|
||||
|
||||
if (decoder.Decode(ref info, outputSurface, bitstream))
|
||||
{
|
||||
|
@@ -17,18 +17,18 @@ namespace Ryujinx.Graphics.Nvdec
|
||||
|
||||
public unsafe static void Decode(ResourceManager rm, ref NvdecRegisters state)
|
||||
{
|
||||
PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetPictureInfoOffset);
|
||||
EntropyProbs entropy = rm.Gmm.DeviceRead<EntropyProbs>(state.SetVp9EntropyProbsOffset);
|
||||
PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
|
||||
EntropyProbs entropy = rm.Gmm.DeviceRead<EntropyProbs>(state.Vp9SetProbTabBufOffset);
|
||||
|
||||
ISurface Rent(uint lumaOffset, uint chromaOffset, FrameSize size)
|
||||
{
|
||||
return rm.Cache.Get(_decoder, lumaOffset, chromaOffset, size.Width, size.Height);
|
||||
}
|
||||
|
||||
ISurface lastSurface = Rent(state.SetSurfaceLumaOffset[0], state.SetSurfaceChromaOffset[0], pictureInfo.LastFrameSize);
|
||||
ISurface goldenSurface = Rent(state.SetSurfaceLumaOffset[1], state.SetSurfaceChromaOffset[1], pictureInfo.GoldenFrameSize);
|
||||
ISurface altSurface = Rent(state.SetSurfaceLumaOffset[2], state.SetSurfaceChromaOffset[2], pictureInfo.AltFrameSize);
|
||||
ISurface currentSurface = Rent(state.SetSurfaceLumaOffset[3], state.SetSurfaceChromaOffset[3], pictureInfo.CurrentFrameSize);
|
||||
ISurface lastSurface = Rent(state.SetPictureLumaOffset[0], state.SetPictureChromaOffset[0], pictureInfo.LastFrameSize);
|
||||
ISurface goldenSurface = Rent(state.SetPictureLumaOffset[1], state.SetPictureChromaOffset[1], pictureInfo.GoldenFrameSize);
|
||||
ISurface altSurface = Rent(state.SetPictureLumaOffset[2], state.SetPictureChromaOffset[2], pictureInfo.AltFrameSize);
|
||||
ISurface currentSurface = Rent(state.SetPictureLumaOffset[3], state.SetPictureChromaOffset[3], pictureInfo.CurrentFrameSize);
|
||||
|
||||
Vp9PictureInfo info = pictureInfo.Convert();
|
||||
|
||||
@@ -38,31 +38,31 @@ namespace Ryujinx.Graphics.Nvdec
|
||||
|
||||
entropy.Convert(ref info.Entropy);
|
||||
|
||||
ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetBitstreamOffset, (int)pictureInfo.BitstreamSize);
|
||||
ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize);
|
||||
|
||||
ReadOnlySpan<Vp9MvRef> mvsIn = ReadOnlySpan<Vp9MvRef>.Empty;
|
||||
|
||||
if (info.UsePrevInFindMvRefs)
|
||||
{
|
||||
mvsIn = GetMvsInput(rm.Gmm, pictureInfo.CurrentFrameSize, state.SetVp9LastFrameMvsOffset);
|
||||
mvsIn = GetMvsInput(rm.Gmm, pictureInfo.CurrentFrameSize, state.Vp9SetColMvReadBufOffset);
|
||||
}
|
||||
|
||||
int miCols = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Width, 8);
|
||||
int miRows = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Height, 8);
|
||||
|
||||
using var mvsRegion = rm.Gmm.GetWritableRegion(ExtendOffset(state.SetVp9CurrFrameMvsOffset), miRows * miCols * 16);
|
||||
using var mvsRegion = rm.Gmm.GetWritableRegion(ExtendOffset(state.Vp9SetColMvWriteBufOffset), miRows * miCols * 16);
|
||||
|
||||
Span<Vp9MvRef> mvsOut = MemoryMarshal.Cast<byte, Vp9MvRef>(mvsRegion.Memory.Span);
|
||||
|
||||
uint lumaOffset = state.SetSurfaceLumaOffset[3];
|
||||
uint chromaOffset = state.SetSurfaceChromaOffset[3];
|
||||
uint lumaOffset = state.SetPictureLumaOffset[3];
|
||||
uint chromaOffset = state.SetPictureChromaOffset[3];
|
||||
|
||||
if (_decoder.Decode(ref info, currentSurface, bitstream, mvsIn, mvsOut))
|
||||
{
|
||||
SurfaceWriter.Write(rm.Gmm, currentSurface, lumaOffset, chromaOffset);
|
||||
}
|
||||
|
||||
WriteBackwardUpdates(rm.Gmm, state.SetVp9BackwardUpdatesOffset, ref info.BackwardUpdateCounts);
|
||||
WriteBackwardUpdates(rm.Gmm, state.Vp9SetCtxCounterBufOffset, ref info.BackwardUpdateCounts);
|
||||
|
||||
rm.Cache.Put(lastSurface);
|
||||
rm.Cache.Put(goldenSurface);
|
||||
|
@@ -232,7 +232,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
return new Program(programBinary, hasFragmentShader, info.FragmentOutputMap);
|
||||
}
|
||||
|
||||
public void CreateSync(ulong id)
|
||||
public void CreateSync(ulong id, bool strict)
|
||||
{
|
||||
_sync.Create(id);
|
||||
}
|
||||
@@ -247,6 +247,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
return _sync.GetCurrent();
|
||||
}
|
||||
|
||||
public void SetInterruptAction(Action<Action> interruptAction)
|
||||
{
|
||||
// Currently no need for an interrupt action.
|
||||
}
|
||||
|
||||
public void Screenshot()
|
||||
{
|
||||
_window.ScreenCaptureRequested = true;
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
@@ -25,17 +24,6 @@ namespace Ryujinx.Graphics.Shader
|
||||
};
|
||||
}
|
||||
|
||||
public static VariableType ToVariableType(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttributeType.Float => VariableType.F32,
|
||||
AttributeType.Sint => VariableType.S32,
|
||||
AttributeType.Uint => VariableType.U32,
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public static AggregateType ToAggregateType(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
|
@@ -350,19 +350,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetVarTypeName(VariableType type)
|
||||
public static string GetVarTypeName(AggregateType type, bool precise = true)
|
||||
{
|
||||
switch (type)
|
||||
return type switch
|
||||
{
|
||||
case VariableType.Bool: return "bool";
|
||||
case VariableType.F32: return "precise float";
|
||||
case VariableType.F64: return "double";
|
||||
case VariableType.None: return "void";
|
||||
case VariableType.S32: return "int";
|
||||
case VariableType.U32: return "uint";
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid variable type \"{type}\".");
|
||||
AggregateType.Void => "void",
|
||||
AggregateType.Bool => "bool",
|
||||
AggregateType.FP32 => precise ? "precise float" : "float",
|
||||
AggregateType.FP64 => "double",
|
||||
AggregateType.S32 => "int",
|
||||
AggregateType.U32 => "uint",
|
||||
AggregateType.Vector2 | AggregateType.Bool => "bvec2",
|
||||
AggregateType.Vector2 | AggregateType.FP32 => precise ? "precise vec2" : "vec2",
|
||||
AggregateType.Vector2 | AggregateType.FP64 => "dvec2",
|
||||
AggregateType.Vector2 | AggregateType.S32 => "ivec2",
|
||||
AggregateType.Vector2 | AggregateType.U32 => "uvec2",
|
||||
AggregateType.Vector3 | AggregateType.Bool => "bvec3",
|
||||
AggregateType.Vector3 | AggregateType.FP32 => precise ? "precise vec3" : "vec3",
|
||||
AggregateType.Vector3 | AggregateType.FP64 => "dvec3",
|
||||
AggregateType.Vector3 | AggregateType.S32 => "ivec3",
|
||||
AggregateType.Vector3 | AggregateType.U32 => "uvec3",
|
||||
AggregateType.Vector4 | AggregateType.Bool => "bvec4",
|
||||
AggregateType.Vector4 | AggregateType.FP32 => precise ? "precise vec4" : "vec4",
|
||||
AggregateType.Vector4 | AggregateType.FP64 => "dvec4",
|
||||
AggregateType.Vector4 | AggregateType.S32 => "ivec4",
|
||||
AggregateType.Vector4 | AggregateType.U32 => "uvec4",
|
||||
_ => throw new ArgumentException($"Invalid variable type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
private static void DeclareUniforms(CodeGenContext context, BufferDescriptor[] descriptors)
|
||||
|
@@ -126,8 +126,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
else if (node is AstAssignment assignment)
|
||||
{
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, assignment.Source);
|
||||
VariableType dstType = OperandManager.GetNodeDestType(context, assignment.Destination, isAsgDest: true);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, assignment.Source);
|
||||
AggregateType dstType = OperandManager.GetNodeDestType(context, assignment.Destination, isAsgDest: true);
|
||||
|
||||
string dest;
|
||||
|
||||
@@ -158,9 +158,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
private static string GetCondExpr(CodeGenContext context, IAstNode cond)
|
||||
{
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, cond);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, cond);
|
||||
|
||||
return ReinterpretCast(context, cond, srcType, VariableType.Bool);
|
||||
return ReinterpretCast(context, cond, srcType, AggregateType.Bool);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenBallot;
|
||||
@@ -8,6 +9,7 @@ using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenFSI;
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenMemory;
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenPacking;
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenVector;
|
||||
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
@@ -32,12 +34,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
IAstNode src = operation.GetSource(0);
|
||||
|
||||
VariableType type = GetSrcVarType(operation.Inst, 0);
|
||||
AggregateType type = GetSrcVarType(operation.Inst, 0);
|
||||
|
||||
string srcExpr = GetSoureExpr(context, src, type);
|
||||
string zero;
|
||||
|
||||
if (type == VariableType.F64)
|
||||
if (type == AggregateType.FP64)
|
||||
{
|
||||
zero = "0.0";
|
||||
}
|
||||
@@ -95,7 +97,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
VariableType dstType = GetSrcVarType(inst, argIndex);
|
||||
AggregateType dstType = GetSrcVarType(inst, argIndex);
|
||||
|
||||
args += GetSoureExpr(context, operation.GetSource(argIndex), dstType);
|
||||
}
|
||||
@@ -226,6 +228,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
case Instruction.UnpackHalf2x16:
|
||||
return UnpackHalf2x16(context, operation);
|
||||
|
||||
case Instruction.VectorExtract:
|
||||
return VectorExtract(context, operation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
|
||||
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||
@@ -9,7 +10,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
public static string Ballot(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
VariableType dstType = GetSrcVarType(operation.Inst, 0);
|
||||
AggregateType dstType = GetSrcVarType(operation.Inst, 0);
|
||||
|
||||
string arg = GetSoureExpr(context, operation.GetSource(0), dstType);
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion;
|
||||
|
||||
@@ -7,11 +8,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
static class InstGenHelper
|
||||
{
|
||||
private static readonly InstInfo[] InfoTable;
|
||||
private static readonly InstInfo[] _infoTable;
|
||||
|
||||
static InstGenHelper()
|
||||
{
|
||||
InfoTable = new InstInfo[(int)Instruction.Count];
|
||||
_infoTable = new InstInfo[(int)Instruction.Count];
|
||||
|
||||
Add(Instruction.AtomicAdd, InstType.AtomicBinary, "atomicAdd");
|
||||
Add(Instruction.AtomicAnd, InstType.AtomicBinary, "atomicAnd");
|
||||
@@ -132,6 +133,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
Add(Instruction.Truncate, InstType.CallUnary, "trunc");
|
||||
Add(Instruction.UnpackDouble2x32, InstType.Special);
|
||||
Add(Instruction.UnpackHalf2x16, InstType.Special);
|
||||
Add(Instruction.VectorExtract, InstType.Special);
|
||||
Add(Instruction.VoteAll, InstType.CallUnary, "allInvocationsARB");
|
||||
Add(Instruction.VoteAllEqual, InstType.CallUnary, "allInvocationsEqualARB");
|
||||
Add(Instruction.VoteAny, InstType.CallUnary, "anyInvocationARB");
|
||||
@@ -139,15 +141,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
private static void Add(Instruction inst, InstType flags, string opName = null, int precedence = 0)
|
||||
{
|
||||
InfoTable[(int)inst] = new InstInfo(flags, opName, precedence);
|
||||
_infoTable[(int)inst] = new InstInfo(flags, opName, precedence);
|
||||
}
|
||||
|
||||
public static InstInfo GetInstructionInfo(Instruction inst)
|
||||
{
|
||||
return InfoTable[(int)(inst & Instruction.Mask)];
|
||||
return _infoTable[(int)(inst & Instruction.Mask)];
|
||||
}
|
||||
|
||||
public static string GetSoureExpr(CodeGenContext context, IAstNode node, VariableType dstType)
|
||||
public static string GetSoureExpr(CodeGenContext context, IAstNode node, AggregateType dstType)
|
||||
{
|
||||
return ReinterpretCast(context, node, OperandManager.GetNodeDestType(context, node), dstType);
|
||||
}
|
||||
@@ -191,7 +193,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
return false;
|
||||
}
|
||||
|
||||
InstInfo info = InfoTable[(int)(operation.Inst & Instruction.Mask)];
|
||||
InstInfo info = _infoTable[(int)(operation.Inst & Instruction.Mask)];
|
||||
|
||||
if ((info.Type & (InstType.Call | InstType.Special)) != 0)
|
||||
{
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
|
||||
@@ -23,7 +24,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
case Instruction.ImageStore:
|
||||
return "// imageStore(bindless)";
|
||||
case Instruction.ImageLoad:
|
||||
NumberFormatter.TryFormat(0, texOp.Format.GetComponentType(), out string imageConst);
|
||||
AggregateType componentType = texOp.Format.GetComponentType();
|
||||
|
||||
NumberFormatter.TryFormat(0, componentType, out string imageConst);
|
||||
|
||||
AggregateType outputType = texOp.GetVectorType(componentType);
|
||||
|
||||
if ((outputType & AggregateType.ElementCountMask) != 0)
|
||||
{
|
||||
return $"{Declarations.GetVarTypeName(outputType, precise: false)}({imageConst})";
|
||||
}
|
||||
|
||||
return imageConst;
|
||||
default:
|
||||
return NumberFormatter.FormatInt(0);
|
||||
@@ -58,7 +69,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
int srcIndex = isBindless ? 1 : 0;
|
||||
|
||||
string Src(VariableType type)
|
||||
string Src(AggregateType type)
|
||||
{
|
||||
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
|
||||
}
|
||||
@@ -67,7 +78,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (isIndexed)
|
||||
{
|
||||
indexExpr = Src(VariableType.S32);
|
||||
indexExpr = Src(AggregateType.S32);
|
||||
}
|
||||
|
||||
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
|
||||
@@ -113,19 +124,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
for (int index = 0; index < pCount; index++)
|
||||
{
|
||||
elems[index] = Src(VariableType.S32);
|
||||
elems[index] = Src(AggregateType.S32);
|
||||
}
|
||||
|
||||
Append(ApplyScaling("ivec" + pCount + "(" + string.Join(", ", elems) + ")"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Append(Src(VariableType.S32));
|
||||
Append(Src(AggregateType.S32));
|
||||
}
|
||||
|
||||
if (texOp.Inst == Instruction.ImageStore)
|
||||
{
|
||||
VariableType type = texOp.Format.GetComponentType();
|
||||
AggregateType type = texOp.Format.GetComponentType();
|
||||
|
||||
string[] cElems = new string[4];
|
||||
|
||||
@@ -139,8 +150,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
cElems[index] = type switch
|
||||
{
|
||||
VariableType.S32 => NumberFormatter.FormatInt(0),
|
||||
VariableType.U32 => NumberFormatter.FormatUint(0),
|
||||
AggregateType.S32 => NumberFormatter.FormatInt(0),
|
||||
AggregateType.U32 => NumberFormatter.FormatUint(0),
|
||||
_ => NumberFormatter.FormatFloat(0)
|
||||
};
|
||||
}
|
||||
@@ -148,8 +159,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
string prefix = type switch
|
||||
{
|
||||
VariableType.S32 => "i",
|
||||
VariableType.U32 => "u",
|
||||
AggregateType.S32 => "i",
|
||||
AggregateType.U32 => "u",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
@@ -158,7 +169,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (texOp.Inst == Instruction.ImageAtomic)
|
||||
{
|
||||
VariableType type = texOp.Format.GetComponentType();
|
||||
AggregateType type = texOp.Format.GetComponentType();
|
||||
|
||||
if ((texOp.Flags & TextureFlags.AtomicMask) == TextureFlags.CAS)
|
||||
{
|
||||
@@ -176,14 +187,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
texCall += ")";
|
||||
|
||||
if (type != VariableType.S32)
|
||||
if (type != AggregateType.S32)
|
||||
{
|
||||
texCall = "int(" + texCall + ")";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMask(texOp.Index) : "");
|
||||
texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMaskMultiDest(texOp.Index) : "");
|
||||
}
|
||||
|
||||
return texCall;
|
||||
@@ -288,7 +299,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (isIndexed)
|
||||
{
|
||||
indexExpr = GetSoureExpr(context, texOp.GetSource(0), VariableType.S32);
|
||||
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
|
||||
}
|
||||
|
||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||
@@ -303,14 +314,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
for (int index = 0; index < coordsCount; index++)
|
||||
{
|
||||
elems[index] = GetSoureExpr(context, texOp.GetSource(coordsIndex + index), VariableType.F32);
|
||||
elems[index] = GetSoureExpr(context, texOp.GetSource(coordsIndex + index), AggregateType.FP32);
|
||||
}
|
||||
|
||||
coordsExpr = "vec" + coordsCount + "(" + string.Join(", ", elems) + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
coordsExpr = GetSoureExpr(context, texOp.GetSource(coordsIndex), VariableType.F32);
|
||||
coordsExpr = GetSoureExpr(context, texOp.GetSource(coordsIndex), AggregateType.FP32);
|
||||
}
|
||||
|
||||
return $"textureQueryLod({samplerName}, {coordsExpr}){GetMask(texOp.Index)}";
|
||||
@@ -362,9 +373,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
|
||||
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, src2);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, src2);
|
||||
|
||||
string src = TypeConversion.ReinterpretCast(context, src2, srcType, VariableType.U32);
|
||||
string src = TypeConversion.ReinterpretCast(context, src2, srcType, AggregateType.U32);
|
||||
|
||||
return $"{arrayName}[{offsetExpr}] = {src}";
|
||||
}
|
||||
@@ -376,9 +387,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
|
||||
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, src2);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, src2);
|
||||
|
||||
string src = TypeConversion.ReinterpretCast(context, src2, srcType, VariableType.U32);
|
||||
string src = TypeConversion.ReinterpretCast(context, src2, srcType, AggregateType.U32);
|
||||
|
||||
return $"{HelperFunctionNames.StoreShared16}({offsetExpr}, {src})";
|
||||
}
|
||||
@@ -390,9 +401,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
|
||||
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, src2);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, src2);
|
||||
|
||||
string src = TypeConversion.ReinterpretCast(context, src2, srcType, VariableType.U32);
|
||||
string src = TypeConversion.ReinterpretCast(context, src2, srcType, AggregateType.U32);
|
||||
|
||||
return $"{HelperFunctionNames.StoreShared8}({offsetExpr}, {src})";
|
||||
}
|
||||
@@ -406,9 +417,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
string indexExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
|
||||
string offsetExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
|
||||
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, src3);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, src3);
|
||||
|
||||
string src = TypeConversion.ReinterpretCast(context, src3, srcType, VariableType.U32);
|
||||
string src = TypeConversion.ReinterpretCast(context, src3, srcType, AggregateType.U32);
|
||||
|
||||
string sb = GetStorageBufferAccessor(indexExpr, offsetExpr, context.Config.Stage);
|
||||
|
||||
@@ -424,9 +435,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
string indexExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
|
||||
string offsetExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
|
||||
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, src3);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, src3);
|
||||
|
||||
string src = TypeConversion.ReinterpretCast(context, src3, srcType, VariableType.U32);
|
||||
string src = TypeConversion.ReinterpretCast(context, src3, srcType, AggregateType.U32);
|
||||
|
||||
string sb = GetStorageBufferAccessor(indexExpr, offsetExpr, context.Config.Stage);
|
||||
|
||||
@@ -442,9 +453,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
string indexExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
|
||||
string offsetExpr = GetSoureExpr(context, src2, GetSrcVarType(operation.Inst, 1));
|
||||
|
||||
VariableType srcType = OperandManager.GetNodeDestType(context, src3);
|
||||
AggregateType srcType = OperandManager.GetNodeDestType(context, src3);
|
||||
|
||||
string src = TypeConversion.ReinterpretCast(context, src3, srcType, VariableType.U32);
|
||||
string src = TypeConversion.ReinterpretCast(context, src3, srcType, AggregateType.U32);
|
||||
|
||||
string sb = GetStorageBufferAccessor(indexExpr, offsetExpr, context.Config.Stage);
|
||||
|
||||
@@ -469,6 +480,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
|
||||
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
|
||||
|
||||
bool colorIsVector = isGather || !isShadow;
|
||||
|
||||
SamplerType type = texOp.Type & SamplerType.Mask;
|
||||
|
||||
bool is2D = type == SamplerType.Texture2D;
|
||||
@@ -492,7 +505,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
// TODO: Bindless texture support. For now we just return 0.
|
||||
if (isBindless)
|
||||
{
|
||||
return NumberFormatter.FormatFloat(0);
|
||||
string scalarValue = NumberFormatter.FormatFloat(0);
|
||||
|
||||
if (colorIsVector)
|
||||
{
|
||||
AggregateType outputType = texOp.GetVectorType(AggregateType.FP32);
|
||||
|
||||
if ((outputType & AggregateType.ElementCountMask) != 0)
|
||||
{
|
||||
return $"{Declarations.GetVarTypeName(outputType, precise: false)}({scalarValue})";
|
||||
}
|
||||
}
|
||||
|
||||
return scalarValue;
|
||||
}
|
||||
|
||||
string texCall = intCoords ? "texelFetch" : "texture";
|
||||
@@ -521,7 +546,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
int srcIndex = isBindless ? 1 : 0;
|
||||
|
||||
string Src(VariableType type)
|
||||
string Src(AggregateType type)
|
||||
{
|
||||
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
|
||||
}
|
||||
@@ -530,7 +555,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (isIndexed)
|
||||
{
|
||||
indexExpr = Src(VariableType.S32);
|
||||
indexExpr = Src(AggregateType.S32);
|
||||
}
|
||||
|
||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||
@@ -578,7 +603,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
texCall += ", " + str;
|
||||
}
|
||||
|
||||
VariableType coordType = intCoords ? VariableType.S32 : VariableType.F32;
|
||||
AggregateType coordType = intCoords ? AggregateType.S32 : AggregateType.FP32;
|
||||
|
||||
string AssemblePVector(int count)
|
||||
{
|
||||
@@ -590,7 +615,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
if (arrayIndexElem == index)
|
||||
{
|
||||
elems[index] = Src(VariableType.S32);
|
||||
elems[index] = Src(AggregateType.S32);
|
||||
|
||||
if (!intCoords)
|
||||
{
|
||||
@@ -652,20 +677,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
elems[index] = Src(VariableType.F32);
|
||||
elems[index] = Src(AggregateType.FP32);
|
||||
}
|
||||
|
||||
return "vec" + count + "(" + string.Join(", ", elems) + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Src(VariableType.F32);
|
||||
return Src(AggregateType.FP32);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasExtraCompareArg)
|
||||
{
|
||||
Append(Src(VariableType.F32));
|
||||
Append(Src(AggregateType.FP32));
|
||||
}
|
||||
|
||||
if (hasDerivatives)
|
||||
@@ -676,7 +701,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (isMultisample)
|
||||
{
|
||||
Append(Src(VariableType.S32));
|
||||
Append(Src(AggregateType.S32));
|
||||
}
|
||||
else if (hasLodLevel)
|
||||
{
|
||||
@@ -691,14 +716,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
elems[index] = Src(VariableType.S32);
|
||||
elems[index] = Src(AggregateType.S32);
|
||||
}
|
||||
|
||||
return "ivec" + count + "(" + string.Join(", ", elems) + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Src(VariableType.S32);
|
||||
return Src(AggregateType.S32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,17 +743,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (hasLodBias)
|
||||
{
|
||||
Append(Src(VariableType.F32));
|
||||
Append(Src(AggregateType.FP32));
|
||||
}
|
||||
|
||||
// textureGather* optional extra component index,
|
||||
// not needed for shadow samplers.
|
||||
if (isGather && !isShadow)
|
||||
{
|
||||
Append(Src(VariableType.S32));
|
||||
Append(Src(AggregateType.S32));
|
||||
}
|
||||
|
||||
texCall += ")" + (isGather || !isShadow ? GetMask(texOp.Index) : "");
|
||||
texCall += ")" + (colorIsVector ? GetMaskMultiDest(texOp.Index) : "");
|
||||
|
||||
return texCall;
|
||||
}
|
||||
@@ -751,7 +776,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (isIndexed)
|
||||
{
|
||||
indexExpr = GetSoureExpr(context, texOp.GetSource(0), VariableType.S32);
|
||||
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
|
||||
}
|
||||
|
||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||
@@ -804,5 +829,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
return '.' + "rgba".Substring(index, 1);
|
||||
}
|
||||
|
||||
private static string GetMaskMultiDest(int mask)
|
||||
{
|
||||
string swizzle = ".";
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if ((mask & (1 << i)) != 0)
|
||||
{
|
||||
swizzle += "xyzw"[i];
|
||||
}
|
||||
}
|
||||
|
||||
return swizzle;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
|
||||
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
static class InstGenVector
|
||||
{
|
||||
public static string VectorExtract(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
IAstNode vector = operation.GetSource(0);
|
||||
IAstNode index = operation.GetSource(1);
|
||||
|
||||
string vectorExpr = GetSoureExpr(context, vector, OperandManager.GetNodeDestType(context, vector));
|
||||
|
||||
if (index is AstOperand indexOperand && indexOperand.Type == OperandType.Constant)
|
||||
{
|
||||
char elem = "xyzw"[indexOperand.Value];
|
||||
|
||||
return $"{vectorExpr}.{elem}";
|
||||
}
|
||||
else
|
||||
{
|
||||
string indexExpr = GetSoureExpr(context, index, GetSrcVarType(operation.Inst, 1));
|
||||
|
||||
return $"{vectorExpr}[{indexExpr}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
@@ -8,21 +8,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
private const int MaxDecimal = 256;
|
||||
|
||||
public static bool TryFormat(int value, VariableType dstType, out string formatted)
|
||||
public static bool TryFormat(int value, AggregateType dstType, out string formatted)
|
||||
{
|
||||
if (dstType == VariableType.F32)
|
||||
if (dstType == AggregateType.FP32)
|
||||
{
|
||||
return TryFormatFloat(BitConverter.Int32BitsToSingle(value), out formatted);
|
||||
}
|
||||
else if (dstType == VariableType.S32)
|
||||
else if (dstType == AggregateType.S32)
|
||||
{
|
||||
formatted = FormatInt(value);
|
||||
}
|
||||
else if (dstType == VariableType.U32)
|
||||
else if (dstType == AggregateType.U32)
|
||||
{
|
||||
formatted = FormatUint((uint)value);
|
||||
}
|
||||
else if (dstType == VariableType.Bool)
|
||||
else if (dstType == AggregateType.Bool)
|
||||
{
|
||||
formatted = value != 0 ? "true" : "false";
|
||||
}
|
||||
@@ -65,13 +65,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string FormatInt(int value, VariableType dstType)
|
||||
public static string FormatInt(int value, AggregateType dstType)
|
||||
{
|
||||
if (dstType == VariableType.S32)
|
||||
if (dstType == AggregateType.S32)
|
||||
{
|
||||
return FormatInt(value);
|
||||
}
|
||||
else if (dstType == VariableType.U32)
|
||||
else if (dstType == AggregateType.U32)
|
||||
{
|
||||
return FormatUint((uint)value);
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||
|
||||
@@ -17,9 +18,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public VariableType Type { get; }
|
||||
public AggregateType Type { get; }
|
||||
|
||||
public BuiltInAttribute(string name, VariableType type)
|
||||
public BuiltInAttribute(string name, AggregateType type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
@@ -28,64 +29,64 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
private static Dictionary<int, BuiltInAttribute> _builtInAttributes = new Dictionary<int, BuiltInAttribute>()
|
||||
{
|
||||
{ AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", VariableType.S32) },
|
||||
{ AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", VariableType.F32) },
|
||||
{ AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", VariableType.F32) },
|
||||
{ AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", VariableType.F32) },
|
||||
{ AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", VariableType.F32) },
|
||||
{ AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance0, new BuiltInAttribute("gl_ClipDistance[0]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance1, new BuiltInAttribute("gl_ClipDistance[1]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance2, new BuiltInAttribute("gl_ClipDistance[2]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance3, new BuiltInAttribute("gl_ClipDistance[3]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance4, new BuiltInAttribute("gl_ClipDistance[4]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance5, new BuiltInAttribute("gl_ClipDistance[5]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance6, new BuiltInAttribute("gl_ClipDistance[6]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance7, new BuiltInAttribute("gl_ClipDistance[7]", VariableType.F32) },
|
||||
{ AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", VariableType.F32) },
|
||||
{ AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", VariableType.F32) },
|
||||
{ AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", VariableType.F32) },
|
||||
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) },
|
||||
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", VariableType.S32) },
|
||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
||||
{ AttributeConsts.BaseInstance, new BuiltInAttribute("gl_BaseInstanceARB", VariableType.S32) },
|
||||
{ AttributeConsts.BaseVertex, new BuiltInAttribute("gl_BaseVertexARB", VariableType.S32) },
|
||||
{ AttributeConsts.InstanceIndex, new BuiltInAttribute("gl_InstanceIndex", VariableType.S32) },
|
||||
{ AttributeConsts.VertexIndex, new BuiltInAttribute("gl_VertexIndex", VariableType.S32) },
|
||||
{ AttributeConsts.DrawIndex, new BuiltInAttribute("gl_DrawIDARB", VariableType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
||||
{ AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", AggregateType.S32) },
|
||||
{ AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance0, new BuiltInAttribute("gl_ClipDistance[0]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance1, new BuiltInAttribute("gl_ClipDistance[1]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance2, new BuiltInAttribute("gl_ClipDistance[2]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance3, new BuiltInAttribute("gl_ClipDistance[3]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance4, new BuiltInAttribute("gl_ClipDistance[4]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance5, new BuiltInAttribute("gl_ClipDistance[5]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance6, new BuiltInAttribute("gl_ClipDistance[6]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance7, new BuiltInAttribute("gl_ClipDistance[7]", AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", AggregateType.FP32) },
|
||||
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", AggregateType.S32) },
|
||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", AggregateType.S32) },
|
||||
{ AttributeConsts.BaseInstance, new BuiltInAttribute("gl_BaseInstanceARB", AggregateType.S32) },
|
||||
{ AttributeConsts.BaseVertex, new BuiltInAttribute("gl_BaseVertexARB", AggregateType.S32) },
|
||||
{ AttributeConsts.InstanceIndex, new BuiltInAttribute("gl_InstanceIndex", AggregateType.S32) },
|
||||
{ AttributeConsts.VertexIndex, new BuiltInAttribute("gl_VertexIndex", AggregateType.S32) },
|
||||
{ AttributeConsts.DrawIndex, new BuiltInAttribute("gl_DrawIDARB", AggregateType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", AggregateType.Bool) },
|
||||
|
||||
// Special.
|
||||
{ AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
|
||||
{ AttributeConsts.ThreadKill, new BuiltInAttribute("gl_HelperInvocation", VariableType.Bool) },
|
||||
{ AttributeConsts.ThreadIdX, new BuiltInAttribute("gl_LocalInvocationID.x", VariableType.U32) },
|
||||
{ AttributeConsts.ThreadIdY, new BuiltInAttribute("gl_LocalInvocationID.y", VariableType.U32) },
|
||||
{ AttributeConsts.ThreadIdZ, new BuiltInAttribute("gl_LocalInvocationID.z", VariableType.U32) },
|
||||
{ AttributeConsts.CtaIdX, new BuiltInAttribute("gl_WorkGroupID.x", VariableType.U32) },
|
||||
{ AttributeConsts.CtaIdY, new BuiltInAttribute("gl_WorkGroupID.y", VariableType.U32) },
|
||||
{ AttributeConsts.CtaIdZ, new BuiltInAttribute("gl_WorkGroupID.z", VariableType.U32) },
|
||||
{ AttributeConsts.LaneId, new BuiltInAttribute(null, VariableType.U32) },
|
||||
{ AttributeConsts.InvocationId, new BuiltInAttribute("gl_InvocationID", VariableType.S32) },
|
||||
{ AttributeConsts.PrimitiveId, new BuiltInAttribute("gl_PrimitiveID", VariableType.S32) },
|
||||
{ AttributeConsts.PatchVerticesIn, new BuiltInAttribute("gl_PatchVerticesIn", VariableType.S32) },
|
||||
{ AttributeConsts.EqMask, new BuiltInAttribute(null, VariableType.U32) },
|
||||
{ AttributeConsts.GeMask, new BuiltInAttribute(null, VariableType.U32) },
|
||||
{ AttributeConsts.GtMask, new BuiltInAttribute(null, VariableType.U32) },
|
||||
{ AttributeConsts.LeMask, new BuiltInAttribute(null, VariableType.U32) },
|
||||
{ AttributeConsts.LtMask, new BuiltInAttribute(null, VariableType.U32) },
|
||||
{ AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", AggregateType.FP32) },
|
||||
{ AttributeConsts.ThreadKill, new BuiltInAttribute("gl_HelperInvocation", AggregateType.Bool) },
|
||||
{ AttributeConsts.ThreadIdX, new BuiltInAttribute("gl_LocalInvocationID.x", AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdY, new BuiltInAttribute("gl_LocalInvocationID.y", AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdZ, new BuiltInAttribute("gl_LocalInvocationID.z", AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdX, new BuiltInAttribute("gl_WorkGroupID.x", AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdY, new BuiltInAttribute("gl_WorkGroupID.y", AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdZ, new BuiltInAttribute("gl_WorkGroupID.z", AggregateType.U32) },
|
||||
{ AttributeConsts.LaneId, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.InvocationId, new BuiltInAttribute("gl_InvocationID", AggregateType.S32) },
|
||||
{ AttributeConsts.PrimitiveId, new BuiltInAttribute("gl_PrimitiveID", AggregateType.S32) },
|
||||
{ AttributeConsts.PatchVerticesIn, new BuiltInAttribute("gl_PatchVerticesIn", AggregateType.S32) },
|
||||
{ AttributeConsts.EqMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.GeMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.GtMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.LeMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.LtMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
|
||||
// Support uniforms.
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 0, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[0]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 4, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[1]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 8, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[2]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 12, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[3]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[4]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[5]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[6]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[7]", VariableType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 0, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[0]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 4, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[1]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 8, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[2]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 12, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[3]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[4]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[5]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[6]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[7]", AggregateType.Bool) },
|
||||
|
||||
{ AttributeConsts.SupportBlockViewInverseX, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.x", VariableType.F32) },
|
||||
{ AttributeConsts.SupportBlockViewInverseY, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.y", VariableType.F32) }
|
||||
{ AttributeConsts.SupportBlockViewInverseX, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.SupportBlockViewInverseY, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.y", AggregateType.FP32) }
|
||||
};
|
||||
|
||||
private Dictionary<AstOperand, string> _locals;
|
||||
@@ -329,7 +330,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
if (cbIndexable)
|
||||
{
|
||||
return GetUbName(stage, NumberFormatter.FormatInt(slot, VariableType.S32));
|
||||
return GetUbName(stage, NumberFormatter.FormatInt(slot, AggregateType.S32));
|
||||
}
|
||||
|
||||
return $"{GetShaderStagePrefix(stage)}_{DefaultNames.UniformNamePrefix}{slot}_{DefaultNames.UniformNameSuffix}";
|
||||
@@ -404,7 +405,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
return $"{DefaultNames.ArgumentNamePrefix}{argIndex}";
|
||||
}
|
||||
|
||||
public static VariableType GetNodeDestType(CodeGenContext context, IAstNode node, bool isAsgDest = false)
|
||||
public static AggregateType GetNodeDestType(CodeGenContext context, IAstNode node, bool isAsgDest = false)
|
||||
{
|
||||
if (node is AstOperation operation)
|
||||
{
|
||||
@@ -431,12 +432,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
return context.GetFunction(funcId.Value).ReturnType;
|
||||
}
|
||||
else if (operation is AstTextureOperation texOp &&
|
||||
(texOp.Inst == Instruction.ImageLoad ||
|
||||
texOp.Inst == Instruction.ImageStore ||
|
||||
texOp.Inst == Instruction.ImageAtomic))
|
||||
else if (operation.Inst == Instruction.VectorExtract)
|
||||
{
|
||||
return texOp.Format.GetComponentType();
|
||||
return GetNodeDestType(context, operation.GetSource(0)) & ~AggregateType.ElementCountMask;
|
||||
}
|
||||
else if (operation is AstTextureOperation texOp)
|
||||
{
|
||||
if (texOp.Inst == Instruction.ImageLoad ||
|
||||
texOp.Inst == Instruction.ImageStore ||
|
||||
texOp.Inst == Instruction.ImageAtomic)
|
||||
{
|
||||
return texOp.GetVectorType(texOp.Format.GetComponentType());
|
||||
}
|
||||
else if (texOp.Inst == Instruction.TextureSample)
|
||||
{
|
||||
return texOp.GetVectorType(GetDestVarType(operation.Inst));
|
||||
}
|
||||
}
|
||||
|
||||
return GetDestVarType(operation.Inst);
|
||||
@@ -458,7 +469,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
}
|
||||
|
||||
private static VariableType GetOperandVarType(CodeGenContext context, AstOperand operand, bool isAsgDest = false)
|
||||
private static AggregateType GetOperandVarType(CodeGenContext context, AstOperand operand, bool isAsgDest = false)
|
||||
{
|
||||
if (operand.Type == OperandType.Attribute)
|
||||
{
|
||||
@@ -474,7 +485,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
AttributeType type = context.Config.GpuAccessor.QueryAttributeType(location);
|
||||
|
||||
return type.ToVariableType();
|
||||
return type.ToAggregateType();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
@@ -10,8 +11,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
public static string ReinterpretCast(
|
||||
CodeGenContext context,
|
||||
IAstNode node,
|
||||
VariableType srcType,
|
||||
VariableType dstType)
|
||||
AggregateType srcType,
|
||||
AggregateType dstType)
|
||||
{
|
||||
if (node is AstOperand operand && operand.Type == OperandType.Constant)
|
||||
{
|
||||
@@ -26,46 +27,46 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
return ReinterpretCast(expr, node, srcType, dstType);
|
||||
}
|
||||
|
||||
private static string ReinterpretCast(string expr, IAstNode node, VariableType srcType, VariableType dstType)
|
||||
private static string ReinterpretCast(string expr, IAstNode node, AggregateType srcType, AggregateType dstType)
|
||||
{
|
||||
if (srcType == dstType)
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (srcType == VariableType.F32)
|
||||
if (srcType == AggregateType.FP32)
|
||||
{
|
||||
switch (dstType)
|
||||
{
|
||||
case VariableType.Bool: return $"(floatBitsToInt({expr}) != 0)";
|
||||
case VariableType.S32: return $"floatBitsToInt({expr})";
|
||||
case VariableType.U32: return $"floatBitsToUint({expr})";
|
||||
case AggregateType.Bool: return $"(floatBitsToInt({expr}) != 0)";
|
||||
case AggregateType.S32: return $"floatBitsToInt({expr})";
|
||||
case AggregateType.U32: return $"floatBitsToUint({expr})";
|
||||
}
|
||||
}
|
||||
else if (dstType == VariableType.F32)
|
||||
else if (dstType == AggregateType.FP32)
|
||||
{
|
||||
switch (srcType)
|
||||
{
|
||||
case VariableType.Bool: return $"intBitsToFloat({ReinterpretBoolToInt(expr, node, VariableType.S32)})";
|
||||
case VariableType.S32: return $"intBitsToFloat({expr})";
|
||||
case VariableType.U32: return $"uintBitsToFloat({expr})";
|
||||
case AggregateType.Bool: return $"intBitsToFloat({ReinterpretBoolToInt(expr, node, AggregateType.S32)})";
|
||||
case AggregateType.S32: return $"intBitsToFloat({expr})";
|
||||
case AggregateType.U32: return $"uintBitsToFloat({expr})";
|
||||
}
|
||||
}
|
||||
else if (srcType == VariableType.Bool)
|
||||
else if (srcType == AggregateType.Bool)
|
||||
{
|
||||
return ReinterpretBoolToInt(expr, node, dstType);
|
||||
}
|
||||
else if (dstType == VariableType.Bool)
|
||||
else if (dstType == AggregateType.Bool)
|
||||
{
|
||||
expr = InstGenHelper.Enclose(expr, node, Instruction.CompareNotEqual, isLhs: true);
|
||||
|
||||
return $"({expr} != 0)";
|
||||
}
|
||||
else if (dstType == VariableType.S32)
|
||||
else if (dstType == AggregateType.S32)
|
||||
{
|
||||
return $"int({expr})";
|
||||
}
|
||||
else if (dstType == VariableType.U32)
|
||||
else if (dstType == AggregateType.U32)
|
||||
{
|
||||
return $"uint({expr})";
|
||||
}
|
||||
@@ -73,7 +74,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
throw new ArgumentException($"Invalid reinterpret cast from \"{srcType}\" to \"{dstType}\".");
|
||||
}
|
||||
|
||||
private static string ReinterpretBoolToInt(string expr, IAstNode node, VariableType dstType)
|
||||
private static string ReinterpretBoolToInt(string expr, IAstNode node, AggregateType dstType)
|
||||
{
|
||||
string trueExpr = NumberFormatter.FormatInt(IrConsts.True, dstType);
|
||||
string falseExpr = NumberFormatter.FormatInt(IrConsts.False, dstType);
|
||||
|
@@ -241,6 +241,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
throw new NotImplementedException(node.GetType().Name);
|
||||
}
|
||||
|
||||
public Instruction GetWithType(IAstNode node, out AggregateType type)
|
||||
{
|
||||
if (node is AstOperation operation)
|
||||
{
|
||||
var opResult = Instructions.Generate(this, operation);
|
||||
type = opResult.Type;
|
||||
return opResult.Value;
|
||||
}
|
||||
else if (node is AstOperand operand)
|
||||
{
|
||||
switch (operand.Type)
|
||||
{
|
||||
case IrOperandType.LocalVariable:
|
||||
type = operand.VarType;
|
||||
return GetLocal(type, operand);
|
||||
default:
|
||||
throw new ArgumentException($"Invalid operand type \"{operand.Type}\".");
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException(node.GetType().Name);
|
||||
}
|
||||
|
||||
private Instruction GetUndefined(AggregateType type)
|
||||
{
|
||||
return type switch
|
||||
@@ -325,7 +348,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
if (components > 1)
|
||||
{
|
||||
attrOffset &= ~0xf;
|
||||
type = AggregateType.Vector | AggregateType.FP32;
|
||||
type = components switch
|
||||
{
|
||||
2 => AggregateType.Vector2 | AggregateType.FP32,
|
||||
3 => AggregateType.Vector3 | AggregateType.FP32,
|
||||
4 => AggregateType.Vector4 | AggregateType.FP32,
|
||||
_ => AggregateType.FP32
|
||||
};
|
||||
|
||||
attrInfo = new AttributeInfo(attrOffset, (attr - attrOffset) / 4, components, type, false);
|
||||
}
|
||||
}
|
||||
@@ -335,7 +365,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
bool isIndexed = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr));
|
||||
|
||||
if ((type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||
if ((type & (AggregateType.Array | AggregateType.ElementCountMask)) == 0)
|
||||
{
|
||||
if (invocationId != null)
|
||||
{
|
||||
@@ -452,7 +482,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if ((attrInfo.Type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||
if ((attrInfo.Type & (AggregateType.Array | AggregateType.ElementCountMask)) == 0)
|
||||
{
|
||||
return ioVariable;
|
||||
}
|
||||
@@ -533,13 +563,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
public Instruction GetLocal(AggregateType dstType, AstOperand local)
|
||||
{
|
||||
var srcType = local.VarType.Convert();
|
||||
var srcType = local.VarType;
|
||||
return BitcastIfNeeded(dstType, srcType, Load(GetType(srcType), GetLocalPointer(local)));
|
||||
}
|
||||
|
||||
public Instruction GetArgument(AggregateType dstType, AstOperand funcArg)
|
||||
{
|
||||
var srcType = funcArg.VarType.Convert();
|
||||
var srcType = funcArg.VarType;
|
||||
return BitcastIfNeeded(dstType, srcType, Load(GetType(srcType), GetArgumentPointer(funcArg)));
|
||||
}
|
||||
|
||||
@@ -550,13 +580,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
public Instruction GetType(AggregateType type, int length = 1)
|
||||
{
|
||||
if (type.HasFlag(AggregateType.Array))
|
||||
if ((type & AggregateType.Array) != 0)
|
||||
{
|
||||
return TypeArray(GetType(type & ~AggregateType.Array), Constant(TypeU32(), length));
|
||||
}
|
||||
else if (type.HasFlag(AggregateType.Vector))
|
||||
else if ((type & AggregateType.ElementCountMask) != 0)
|
||||
{
|
||||
return TypeVector(GetType(type & ~AggregateType.Vector), length);
|
||||
int vectorLength = (type & AggregateType.ElementCountMask) switch
|
||||
{
|
||||
AggregateType.Vector2 => 2,
|
||||
AggregateType.Vector3 => 3,
|
||||
AggregateType.Vector4 => 4,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
return TypeVector(GetType(type & ~AggregateType.ElementCountMask), vectorLength);
|
||||
}
|
||||
|
||||
return type switch
|
||||
|
@@ -23,11 +23,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
DeclareParameters(context, function.OutArguments, function.InArguments.Length);
|
||||
}
|
||||
|
||||
private static void DeclareParameters(CodeGenContext context, IEnumerable<VariableType> argTypes, int argIndex)
|
||||
private static void DeclareParameters(CodeGenContext context, IEnumerable<AggregateType> argTypes, int argIndex)
|
||||
{
|
||||
foreach (var argType in argTypes)
|
||||
{
|
||||
var argPointerType = context.TypePointer(StorageClass.Function, context.GetType(argType.Convert()));
|
||||
var argPointerType = context.TypePointer(StorageClass.Function, context.GetType(argType));
|
||||
var spvArg = context.FunctionParameter(argPointerType);
|
||||
|
||||
context.DeclareArgument(argIndex++, spvArg);
|
||||
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
foreach (AstOperand local in function.Locals)
|
||||
{
|
||||
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(local.VarType.Convert()));
|
||||
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(local.VarType));
|
||||
var spvLocal = context.Variable(localPointerType, StorageClass.Function);
|
||||
|
||||
context.AddLocalVariable(spvLocal);
|
||||
@@ -62,7 +62,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
for (int i = 0; i < function.InArguments.Length; i++)
|
||||
{
|
||||
var type = function.GetArgumentType(i).Convert();
|
||||
var type = function.GetArgumentType(i);
|
||||
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(type));
|
||||
var spvLocal = context.Variable(localPointerType, StorageClass.Function);
|
||||
|
||||
@@ -303,7 +303,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
var dim = GetDim(descriptor.Type);
|
||||
|
||||
var imageType = context.TypeImage(
|
||||
context.GetType(meta.Format.GetComponentType().Convert()),
|
||||
context.GetType(meta.Format.GetComponentType()),
|
||||
dim,
|
||||
descriptor.Type.HasFlag(SamplerType.Shadow),
|
||||
descriptor.Type.HasFlag(SamplerType.Array),
|
||||
@@ -652,7 +652,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
if (components > 1)
|
||||
{
|
||||
attr &= ~0xf;
|
||||
type = AggregateType.Vector | AggregateType.FP32;
|
||||
type = components switch
|
||||
{
|
||||
2 => AggregateType.Vector2 | AggregateType.FP32,
|
||||
3 => AggregateType.Vector3 | AggregateType.FP32,
|
||||
4 => AggregateType.Vector4 | AggregateType.FP32,
|
||||
_ => AggregateType.FP32
|
||||
};
|
||||
|
||||
hasComponent = false;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using static Spv.Specification;
|
||||
|
||||
@@ -7,20 +6,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
static class EnumConversion
|
||||
{
|
||||
public static AggregateType Convert(this VariableType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
VariableType.None => AggregateType.Void,
|
||||
VariableType.Bool => AggregateType.Bool,
|
||||
VariableType.F32 => AggregateType.FP32,
|
||||
VariableType.F64 => AggregateType.FP64,
|
||||
VariableType.S32 => AggregateType.S32,
|
||||
VariableType.U32 => AggregateType.U32,
|
||||
_ => throw new ArgumentException($"Invalid variable type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public static ExecutionModel Convert(this ShaderStage stage)
|
||||
{
|
||||
return stage switch
|
||||
|
@@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using static Spv.Specification;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
@@ -146,6 +147,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
Add(Instruction.Truncate, GenerateTruncate);
|
||||
Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32);
|
||||
Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16);
|
||||
Add(Instruction.VectorExtract, GenerateVectorExtract);
|
||||
Add(Instruction.VoteAll, GenerateVoteAll);
|
||||
Add(Instruction.VoteAllEqual, GenerateVoteAllEqual);
|
||||
Add(Instruction.VoteAny, GenerateVoteAny);
|
||||
@@ -317,7 +319,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = function.GetArgumentType(i).Convert();
|
||||
var type = function.GetArgumentType(i);
|
||||
var value = context.Get(type, operand);
|
||||
var spvLocal = spvLocals[i];
|
||||
|
||||
@@ -327,7 +329,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
}
|
||||
}
|
||||
|
||||
var retType = function.ReturnType.Convert();
|
||||
var retType = function.ReturnType;
|
||||
var result = context.FunctionCall(context.GetType(retType), spvFunc, args);
|
||||
return new OperationResult(retType, result);
|
||||
}
|
||||
@@ -604,10 +606,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
// TODO: Bindless texture support. For now we just return 0/do nothing.
|
||||
if (isBindless)
|
||||
{
|
||||
return new OperationResult(componentType.Convert(), componentType switch
|
||||
return new OperationResult(componentType, componentType switch
|
||||
{
|
||||
VariableType.S32 => context.Constant(context.TypeS32(), 0),
|
||||
VariableType.U32 => context.Constant(context.TypeU32(), 0u),
|
||||
AggregateType.S32 => context.Constant(context.TypeS32(), 0),
|
||||
AggregateType.U32 => context.Constant(context.TypeU32(), 0u),
|
||||
_ => context.Constant(context.TypeFP32(), 0f),
|
||||
});
|
||||
}
|
||||
@@ -652,13 +654,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
pCoords = Src(AggregateType.S32);
|
||||
}
|
||||
|
||||
SpvInstruction value = Src(componentType.Convert());
|
||||
SpvInstruction value = Src(componentType);
|
||||
|
||||
(var imageType, var imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)];
|
||||
|
||||
var image = context.Load(imageType, imageVariable);
|
||||
|
||||
SpvInstruction resultType = context.GetType(componentType.Convert());
|
||||
SpvInstruction resultType = context.GetType(componentType);
|
||||
SpvInstruction imagePointerType = context.TypePointer(StorageClass.Image, resultType);
|
||||
|
||||
var pointer = context.ImageTexelPointer(imagePointerType, imageVariable, pCoords, context.Constant(context.TypeU32(), 0));
|
||||
@@ -668,10 +670,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
var result = (texOp.Flags & TextureFlags.AtomicMask) switch
|
||||
{
|
||||
TextureFlags.Add => context.AtomicIAdd(resultType, pointer, one, zero, value),
|
||||
TextureFlags.Minimum => componentType == VariableType.S32
|
||||
TextureFlags.Minimum => componentType == AggregateType.S32
|
||||
? context.AtomicSMin(resultType, pointer, one, zero, value)
|
||||
: context.AtomicUMin(resultType, pointer, one, zero, value),
|
||||
TextureFlags.Maximum => componentType == VariableType.S32
|
||||
TextureFlags.Maximum => componentType == AggregateType.S32
|
||||
? context.AtomicSMax(resultType, pointer, one, zero, value)
|
||||
: context.AtomicUMax(resultType, pointer, one, zero, value),
|
||||
TextureFlags.Increment => context.AtomicIIncrement(resultType, pointer, one, zero),
|
||||
@@ -680,11 +682,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
TextureFlags.BitwiseOr => context.AtomicOr(resultType, pointer, one, zero, value),
|
||||
TextureFlags.BitwiseXor => context.AtomicXor(resultType, pointer, one, zero, value),
|
||||
TextureFlags.Swap => context.AtomicExchange(resultType, pointer, one, zero, value),
|
||||
TextureFlags.CAS => context.AtomicCompareExchange(resultType, pointer, one, zero, zero, Src(componentType.Convert()), value),
|
||||
TextureFlags.CAS => context.AtomicCompareExchange(resultType, pointer, one, zero, zero, Src(componentType), value),
|
||||
_ => context.AtomicIAdd(resultType, pointer, one, zero, value),
|
||||
};
|
||||
|
||||
return new OperationResult(componentType.Convert(), result);
|
||||
return new OperationResult(componentType, result);
|
||||
}
|
||||
|
||||
private static OperationResult GenerateImageLoad(CodeGenContext context, AstOperation operation)
|
||||
@@ -698,14 +700,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
// TODO: Bindless texture support. For now we just return 0/do nothing.
|
||||
if (isBindless)
|
||||
{
|
||||
var zero = componentType switch
|
||||
{
|
||||
VariableType.S32 => context.Constant(context.TypeS32(), 0),
|
||||
VariableType.U32 => context.Constant(context.TypeU32(), 0u),
|
||||
_ => context.Constant(context.TypeFP32(), 0f),
|
||||
};
|
||||
|
||||
return new OperationResult(componentType.Convert(), zero);
|
||||
return GetZeroOperationResult(context, texOp, componentType, isVector: true);
|
||||
}
|
||||
|
||||
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
||||
@@ -753,12 +748,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
(var imageType, var imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)];
|
||||
|
||||
var image = context.Load(imageType, imageVariable);
|
||||
var imageComponentType = context.GetType(componentType.Convert());
|
||||
var imageComponentType = context.GetType(componentType);
|
||||
var swizzledResultType = texOp.GetVectorType(componentType);
|
||||
|
||||
var texel = context.ImageRead(context.TypeVector(imageComponentType, 4), image, pCoords, ImageOperandsMask.MaskNone);
|
||||
var result = context.CompositeExtract(imageComponentType, texel, (SpvLiteralInteger)texOp.Index);
|
||||
var result = GetSwizzledResult(context, texel, swizzledResultType, texOp.Index);
|
||||
|
||||
return new OperationResult(componentType.Convert(), result);
|
||||
return new OperationResult(componentType, result);
|
||||
}
|
||||
|
||||
private static OperationResult GenerateImageStore(CodeGenContext context, AstOperation operation)
|
||||
@@ -823,20 +819,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
if (srcIndex < texOp.SourcesCount)
|
||||
{
|
||||
cElems[i] = Src(componentType.Convert());
|
||||
cElems[i] = Src(componentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
cElems[i] = componentType switch
|
||||
{
|
||||
VariableType.S32 => context.Constant(context.TypeS32(), 0),
|
||||
VariableType.U32 => context.Constant(context.TypeU32(), 0u),
|
||||
AggregateType.S32 => context.Constant(context.TypeS32(), 0),
|
||||
AggregateType.U32 => context.Constant(context.TypeU32(), 0u),
|
||||
_ => context.Constant(context.TypeFP32(), 0f),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var texel = context.CompositeConstruct(context.TypeVector(context.GetType(componentType.Convert()), ComponentsCount), cElems);
|
||||
var texel = context.CompositeConstruct(context.TypeVector(context.GetType(componentType), ComponentsCount), cElems);
|
||||
|
||||
(var imageType, var imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)];
|
||||
|
||||
@@ -1238,7 +1234,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
var validLocal = (AstOperand)operation.GetSource(3);
|
||||
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid));
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid));
|
||||
|
||||
return new OperationResult(AggregateType.FP32, result);
|
||||
}
|
||||
@@ -1268,7 +1264,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
var validLocal = (AstOperand)operation.GetSource(3);
|
||||
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid));
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid));
|
||||
|
||||
return new OperationResult(AggregateType.FP32, result);
|
||||
}
|
||||
@@ -1294,7 +1290,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
var validLocal = (AstOperand)operation.GetSource(3);
|
||||
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid));
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid));
|
||||
|
||||
return new OperationResult(AggregateType.FP32, result);
|
||||
}
|
||||
@@ -1324,7 +1320,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
var validLocal = (AstOperand)operation.GetSource(3);
|
||||
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid));
|
||||
context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid));
|
||||
|
||||
return new OperationResult(AggregateType.FP32, result);
|
||||
}
|
||||
@@ -1485,10 +1481,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
|
||||
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
|
||||
|
||||
bool colorIsVector = isGather || !isShadow;
|
||||
|
||||
// TODO: Bindless texture support. For now we just return 0.
|
||||
if (isBindless)
|
||||
{
|
||||
return new OperationResult(AggregateType.FP32, context.Constant(context.TypeFP32(), 0f));
|
||||
return GetZeroOperationResult(context, texOp, AggregateType.FP32, colorIsVector);
|
||||
}
|
||||
|
||||
// This combination is valid, but not available on GLSL.
|
||||
@@ -1705,7 +1703,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
operandsList.Add(sample);
|
||||
}
|
||||
|
||||
bool colorIsVector = isGather || !isShadow;
|
||||
var resultType = colorIsVector ? context.TypeVector(context.TypeFP32(), 4) : context.TypeFP32();
|
||||
|
||||
var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format);
|
||||
@@ -1758,12 +1755,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
result = context.ImageSampleImplicitLod(resultType, image, pCoords, operandsMask, operands);
|
||||
}
|
||||
|
||||
var swizzledResultType = AggregateType.FP32;
|
||||
|
||||
if (colorIsVector)
|
||||
{
|
||||
result = context.CompositeExtract(context.TypeFP32(), result, (SpvLiteralInteger)texOp.Index);
|
||||
swizzledResultType = texOp.GetVectorType(swizzledResultType);
|
||||
|
||||
result = GetSwizzledResult(context, result, swizzledResultType, texOp.Index);
|
||||
}
|
||||
|
||||
return new OperationResult(AggregateType.FP32, result);
|
||||
return new OperationResult(swizzledResultType, result);
|
||||
}
|
||||
|
||||
private static OperationResult GenerateTextureSize(CodeGenContext context, AstOperation operation)
|
||||
@@ -1862,6 +1863,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return new OperationResult(AggregateType.FP32, result);
|
||||
}
|
||||
|
||||
private static OperationResult GenerateVectorExtract(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
var vector = context.GetWithType(operation.GetSource(0), out AggregateType vectorType);
|
||||
var scalarType = vectorType & ~AggregateType.ElementCountMask;
|
||||
var resultType = context.GetType(scalarType);
|
||||
SpvInstruction result;
|
||||
|
||||
if (operation.GetSource(1) is AstOperand indexOperand && indexOperand.Type == OperandType.Constant)
|
||||
{
|
||||
result = context.CompositeExtract(resultType, vector, (SpvLiteralInteger)indexOperand.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = context.Get(AggregateType.S32, operation.GetSource(1));
|
||||
result = context.VectorExtractDynamic(resultType, vector, index);
|
||||
}
|
||||
|
||||
return new OperationResult(scalarType, result);
|
||||
}
|
||||
|
||||
private static OperationResult GenerateVoteAll(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
var execution = context.Constant(context.TypeU32(), Scope.Subgroup);
|
||||
@@ -2044,6 +2065,64 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
context.AddLabel(loopEnd);
|
||||
}
|
||||
|
||||
private static OperationResult GetZeroOperationResult(
|
||||
CodeGenContext context,
|
||||
AstTextureOperation texOp,
|
||||
AggregateType scalarType,
|
||||
bool isVector)
|
||||
{
|
||||
var zero = scalarType switch
|
||||
{
|
||||
AggregateType.S32 => context.Constant(context.TypeS32(), 0),
|
||||
AggregateType.U32 => context.Constant(context.TypeU32(), 0u),
|
||||
_ => context.Constant(context.TypeFP32(), 0f),
|
||||
};
|
||||
|
||||
if (isVector)
|
||||
{
|
||||
AggregateType outputType = texOp.GetVectorType(scalarType);
|
||||
|
||||
if ((outputType & AggregateType.ElementCountMask) != 0)
|
||||
{
|
||||
int componentsCount = BitOperations.PopCount((uint)texOp.Index);
|
||||
|
||||
SpvInstruction[] values = new SpvInstruction[componentsCount];
|
||||
|
||||
values.AsSpan().Fill(zero);
|
||||
|
||||
return new OperationResult(outputType, context.ConstantComposite(context.GetType(outputType), values));
|
||||
}
|
||||
}
|
||||
|
||||
return new OperationResult(scalarType, zero);
|
||||
}
|
||||
|
||||
private static SpvInstruction GetSwizzledResult(CodeGenContext context, SpvInstruction vector, AggregateType swizzledResultType, int mask)
|
||||
{
|
||||
if ((swizzledResultType & AggregateType.ElementCountMask) != 0)
|
||||
{
|
||||
SpvLiteralInteger[] components = new SpvLiteralInteger[BitOperations.PopCount((uint)mask)];
|
||||
|
||||
int componentIndex = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if ((mask & (1 << i)) != 0)
|
||||
{
|
||||
components[componentIndex++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
return context.VectorShuffle(context.GetType(swizzledResultType), vector, vector, components);
|
||||
}
|
||||
else
|
||||
{
|
||||
int componentIndex = (int)BitOperations.TrailingZeroCount(mask);
|
||||
|
||||
return context.CompositeExtract(context.GetType(swizzledResultType), vector, (SpvLiteralInteger)componentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private static SpvInstruction GetStorageElemPointer(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
var sbVariable = context.StorageBuffersArray;
|
||||
|
@@ -104,13 +104,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++)
|
||||
{
|
||||
var function = info.Functions[funcIndex];
|
||||
var retType = context.GetType(function.ReturnType.Convert());
|
||||
var retType = context.GetType(function.ReturnType);
|
||||
|
||||
var funcArgs = new SpvInstruction[function.InArguments.Length + function.OutArguments.Length];
|
||||
|
||||
for (int argIndex = 0; argIndex < funcArgs.Length; argIndex++)
|
||||
{
|
||||
var argType = context.GetType(function.GetArgumentType(argIndex).Convert());
|
||||
var argType = context.GetType(function.GetArgumentType(argIndex));
|
||||
var argPointerType = context.TypePointer(StorageClass.Function, argType);
|
||||
funcArgs[argIndex] = argPointerType;
|
||||
}
|
||||
@@ -387,7 +387,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
if (dest.Type == OperandType.LocalVariable)
|
||||
{
|
||||
var source = context.Get(dest.VarType.Convert(), assignment.Source);
|
||||
var source = context.Get(dest.VarType, assignment.Source);
|
||||
context.Store(context.GetLocalPointer(dest), source);
|
||||
}
|
||||
else if (dest.Type == OperandType.Attribute || dest.Type == OperandType.AttributePerPatch)
|
||||
@@ -407,7 +407,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
}
|
||||
else if (dest.Type == OperandType.Argument)
|
||||
{
|
||||
var source = context.Get(dest.VarType.Convert(), assignment.Source);
|
||||
var source = context.Get(dest.VarType, assignment.Source);
|
||||
context.Store(context.GetArgumentPointer(dest), source);
|
||||
}
|
||||
else
|
||||
|
@@ -1,7 +1,9 @@
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
@@ -217,15 +219,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
return context.Copy(Register(srcB++, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
Operand GetDest()
|
||||
{
|
||||
if (dest >= RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Register(dest++, RegisterType.Gpr);
|
||||
}
|
||||
Operand destOperand = dest != RegisterConsts.RegisterZeroIndex ? Register(dest, RegisterType.Gpr) : null;
|
||||
|
||||
List<Operand> sourcesList = new List<Operand>();
|
||||
|
||||
@@ -291,7 +285,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
flags,
|
||||
imm,
|
||||
0,
|
||||
GetDest(),
|
||||
new[] { destOperand },
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
@@ -371,36 +365,40 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
if (useComponents)
|
||||
{
|
||||
for (int compMask = (int)componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||
{
|
||||
if ((compMask & 1) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Operand[] dests = new Operand[BitOperations.PopCount((uint)componentMask)];
|
||||
|
||||
if (srcB == RegisterConsts.RegisterZeroIndex)
|
||||
int outputIndex = 0;
|
||||
|
||||
for (int i = 0; i < dests.Length; i++)
|
||||
{
|
||||
if (srcB + i >= RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Operand rd = Register(srcB++, RegisterType.Gpr);
|
||||
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.ImageLoad,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
compIndex,
|
||||
rd,
|
||||
sources);
|
||||
|
||||
if (!isBindless)
|
||||
{
|
||||
operation.Format = context.Config.GetTextureFormat(handle);
|
||||
}
|
||||
|
||||
context.Add(operation);
|
||||
dests[outputIndex++] = Register(srcB + i, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
if (outputIndex != dests.Length)
|
||||
{
|
||||
Array.Resize(ref dests, outputIndex);
|
||||
}
|
||||
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.ImageLoad,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
(int)componentMask,
|
||||
dests,
|
||||
sources);
|
||||
|
||||
if (!isBindless)
|
||||
{
|
||||
operation.Format = context.Config.GetTextureFormat(handle);
|
||||
}
|
||||
|
||||
context.Add(operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -412,35 +410,45 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
}
|
||||
|
||||
int components = GetComponents(size);
|
||||
int compMask = (1 << components) - 1;
|
||||
|
||||
for (int compIndex = 0; compIndex < components; compIndex++)
|
||||
Operand[] dests = new Operand[components];
|
||||
|
||||
int outputIndex = 0;
|
||||
|
||||
for (int i = 0; i < dests.Length; i++)
|
||||
{
|
||||
if (srcB == RegisterConsts.RegisterZeroIndex)
|
||||
if (srcB + i >= RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Operand rd = Register(srcB++, RegisterType.Gpr);
|
||||
dests[outputIndex++] = Register(srcB + i, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.ImageLoad,
|
||||
type,
|
||||
GetTextureFormat(size),
|
||||
flags,
|
||||
handle,
|
||||
compIndex,
|
||||
rd,
|
||||
sources);
|
||||
if (outputIndex != dests.Length)
|
||||
{
|
||||
Array.Resize(ref dests, outputIndex);
|
||||
}
|
||||
|
||||
context.Add(operation);
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.ImageLoad,
|
||||
type,
|
||||
GetTextureFormat(size),
|
||||
flags,
|
||||
handle,
|
||||
compMask,
|
||||
dests,
|
||||
sources);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case SuSize.U8: context.Copy(rd, ZeroExtendTo32(context, rd, 8)); break;
|
||||
case SuSize.U16: context.Copy(rd, ZeroExtendTo32(context, rd, 16)); break;
|
||||
case SuSize.S8: context.Copy(rd, SignExtendTo32(context, rd, 8)); break;
|
||||
case SuSize.S16: context.Copy(rd, SignExtendTo32(context, rd, 16)); break;
|
||||
}
|
||||
context.Add(operation);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case SuSize.U8: context.Copy(dests[0], ZeroExtendTo32(context, dests[0], 8)); break;
|
||||
case SuSize.U16: context.Copy(dests[0], ZeroExtendTo32(context, dests[0], 16)); break;
|
||||
case SuSize.S8: context.Copy(dests[0], SignExtendTo32(context, dests[0], 8)); break;
|
||||
case SuSize.S16: context.Copy(dests[0], SignExtendTo32(context, dests[0], 16)); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
@@ -303,42 +304,37 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
}
|
||||
|
||||
Operand[] sources = sourcesList.ToArray();
|
||||
Operand[] dests = new Operand[BitOperations.PopCount((uint)componentMask)];
|
||||
|
||||
Operand GetDest()
|
||||
int outputIndex = 0;
|
||||
|
||||
for (int i = 0; i < dests.Length; i++)
|
||||
{
|
||||
if (rdIndex >= RegisterConsts.RegisterZeroIndex)
|
||||
if (rdIndex + i >= RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
|
||||
return Register(rdIndex++, RegisterType.Gpr);
|
||||
dests[outputIndex++] = Register(rdIndex + i, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
if (outputIndex != dests.Length)
|
||||
{
|
||||
Array.Resize(ref dests, outputIndex);
|
||||
}
|
||||
|
||||
int handle = !isBindless ? imm : 0;
|
||||
|
||||
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||
{
|
||||
if ((compMask & 1) != 0)
|
||||
{
|
||||
Operand dest = GetDest();
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
componentMask,
|
||||
dests,
|
||||
sources);
|
||||
|
||||
if (dest == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
compIndex,
|
||||
dest,
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
}
|
||||
}
|
||||
context.Add(operation);
|
||||
}
|
||||
|
||||
private static void EmitTexs(
|
||||
@@ -624,18 +620,23 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) };
|
||||
Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) };
|
||||
|
||||
int destIncrement = 0;
|
||||
int handle = imm;
|
||||
int componentMask = _maskLut[dest2 == RegisterConsts.RegisterZeroIndex ? 0 : 1, writeMask];
|
||||
|
||||
Operand GetDest()
|
||||
int componentsCount = BitOperations.PopCount((uint)componentMask);
|
||||
|
||||
Operand[] dests = new Operand[componentsCount];
|
||||
|
||||
int outputIndex = 0;
|
||||
|
||||
for (int i = 0; i < componentsCount; i++)
|
||||
{
|
||||
int high = destIncrement >> 1;
|
||||
int low = destIncrement & 1;
|
||||
|
||||
destIncrement++;
|
||||
int high = i >> 1;
|
||||
int low = i & 1;
|
||||
|
||||
if (isF16)
|
||||
{
|
||||
return high != 0
|
||||
dests[outputIndex++] = high != 0
|
||||
? (rd1[low] = Local())
|
||||
: (rd0[low] = Local());
|
||||
}
|
||||
@@ -648,30 +649,26 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
rdIndex += low;
|
||||
}
|
||||
|
||||
return Register(rdIndex, RegisterType.Gpr);
|
||||
dests[outputIndex++] = Register(rdIndex, RegisterType.Gpr);
|
||||
}
|
||||
}
|
||||
|
||||
int handle = imm;
|
||||
int componentMask = _maskLut[dest2 == RegisterConsts.RegisterZeroIndex ? 0 : 1, writeMask];
|
||||
|
||||
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||
if (outputIndex != dests.Length)
|
||||
{
|
||||
if ((compMask & 1) != 0)
|
||||
{
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
compIndex,
|
||||
GetDest(),
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
}
|
||||
Array.Resize(ref dests, outputIndex);
|
||||
}
|
||||
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
componentMask,
|
||||
dests,
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
|
||||
if (isF16)
|
||||
{
|
||||
context.Copy(Register(dest, RegisterType.Gpr), context.PackHalf2x16(rd0[0], rd0[1]));
|
||||
@@ -797,42 +794,37 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
sourcesList.Add(Const((int)component));
|
||||
|
||||
Operand[] sources = sourcesList.ToArray();
|
||||
Operand[] dests = new Operand[BitOperations.PopCount((uint)componentMask)];
|
||||
|
||||
Operand GetDest()
|
||||
int outputIndex = 0;
|
||||
|
||||
for (int i = 0; i < dests.Length; i++)
|
||||
{
|
||||
if (dest >= RegisterConsts.RegisterZeroIndex)
|
||||
if (dest + i >= RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
|
||||
return Register(dest++, RegisterType.Gpr);
|
||||
dests[outputIndex++] = Register(dest + i, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
if (outputIndex != dests.Length)
|
||||
{
|
||||
Array.Resize(ref dests, outputIndex);
|
||||
}
|
||||
|
||||
int handle = imm;
|
||||
|
||||
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||
{
|
||||
if ((compMask & 1) != 0)
|
||||
{
|
||||
Operand destOperand = GetDest();
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
componentMask,
|
||||
dests,
|
||||
sources);
|
||||
|
||||
if (destOperand == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
compIndex,
|
||||
destOperand,
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
}
|
||||
}
|
||||
context.Add(operation);
|
||||
}
|
||||
|
||||
private static void EmitTmml(
|
||||
@@ -951,7 +943,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
flags,
|
||||
handle,
|
||||
compIndex ^ 1, // The instruction component order is the inverse of GLSL's.
|
||||
tempDest,
|
||||
new[] { tempDest },
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
@@ -1071,42 +1063,37 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
}
|
||||
|
||||
Operand[] sources = sourcesList.ToArray();
|
||||
Operand[] dests = new Operand[BitOperations.PopCount((uint)componentMask)];
|
||||
|
||||
Operand GetDest()
|
||||
int outputIndex = 0;
|
||||
|
||||
for (int i = 0; i < dests.Length; i++)
|
||||
{
|
||||
if (dest >= RegisterConsts.RegisterZeroIndex)
|
||||
if (dest + i >= RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
|
||||
return Register(dest++, RegisterType.Gpr);
|
||||
dests[outputIndex++] = Register(dest + i, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
if (outputIndex != dests.Length)
|
||||
{
|
||||
Array.Resize(ref dests, outputIndex);
|
||||
}
|
||||
|
||||
int handle = imm;
|
||||
|
||||
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||
{
|
||||
if ((compMask & 1) != 0)
|
||||
{
|
||||
Operand destOperand = GetDest();
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
componentMask,
|
||||
dests,
|
||||
sources);
|
||||
|
||||
if (destOperand == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
TextureOperation operation = context.CreateTextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
flags,
|
||||
handle,
|
||||
compIndex,
|
||||
destOperand,
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
}
|
||||
}
|
||||
context.Add(operation);
|
||||
}
|
||||
|
||||
private static void EmitTxq(
|
||||
@@ -1188,7 +1175,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
flags,
|
||||
imm,
|
||||
compIndex,
|
||||
destOperand,
|
||||
new[] { destOperand },
|
||||
sources);
|
||||
|
||||
context.Add(operation);
|
||||
|
@@ -134,6 +134,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
Truncate,
|
||||
UnpackDouble2x32,
|
||||
UnpackHalf2x16,
|
||||
VectorExtract,
|
||||
VoteAll,
|
||||
VoteAllEqual,
|
||||
VoteAny,
|
||||
|
@@ -62,18 +62,25 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
Inst = inst;
|
||||
Index = index;
|
||||
|
||||
// The array may be modified externally, so we store a copy.
|
||||
_dests = (Operand[])dests.Clone();
|
||||
|
||||
for (int dstIndex = 0; dstIndex < dests.Length; dstIndex++)
|
||||
if (dests != null)
|
||||
{
|
||||
Operand dest = dests[dstIndex];
|
||||
// The array may be modified externally, so we store a copy.
|
||||
_dests = (Operand[])dests.Clone();
|
||||
|
||||
if (dest != null && dest.Type == OperandType.LocalVariable)
|
||||
for (int dstIndex = 0; dstIndex < dests.Length; dstIndex++)
|
||||
{
|
||||
dest.AsgOp = this;
|
||||
Operand dest = dests[dstIndex];
|
||||
|
||||
if (dest != null && dest.Type == OperandType.LocalVariable)
|
||||
{
|
||||
dest.AsgOp = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dests = Array.Empty<Operand>();
|
||||
}
|
||||
}
|
||||
|
||||
public Operation(Instruction inst, Operand dest, params Operand[] sources) : this(sources)
|
||||
|
@@ -19,8 +19,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
int cbufSlot,
|
||||
int handle,
|
||||
int compIndex,
|
||||
Operand dest,
|
||||
Operand[] sources) : base(inst, compIndex, dest, sources)
|
||||
Operand[] dests,
|
||||
Operand[] sources) : base(inst, compIndex, dests, sources)
|
||||
{
|
||||
Type = type;
|
||||
Format = format;
|
||||
@@ -36,8 +36,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
TextureFlags flags,
|
||||
int handle,
|
||||
int compIndex,
|
||||
Operand dest,
|
||||
Operand[] sources) : this(inst, type, format, flags, DefaultCbufSlot, handle, compIndex, dest, sources)
|
||||
Operand[] dests,
|
||||
Operand[] sources) : this(inst, type, format, flags, DefaultCbufSlot, handle, compIndex, dests, sources)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
@@ -66,7 +66,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
return typeName;
|
||||
}
|
||||
|
||||
public static string ToGlslImageType(this SamplerType type, VariableType componentType)
|
||||
public static string ToGlslImageType(this SamplerType type, AggregateType componentType)
|
||||
{
|
||||
string typeName = (type & SamplerType.Mask) switch
|
||||
{
|
||||
@@ -90,8 +90,8 @@ namespace Ryujinx.Graphics.Shader
|
||||
|
||||
switch (componentType)
|
||||
{
|
||||
case VariableType.U32: typeName = 'u' + typeName; break;
|
||||
case VariableType.S32: typeName = 'i' + typeName; break;
|
||||
case AggregateType.U32: typeName = 'u' + typeName; break;
|
||||
case AggregateType.S32: typeName = 'i' + typeName; break;
|
||||
}
|
||||
|
||||
return typeName;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
@@ -46,7 +47,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
return new AstOperand(OperandType.Constant, value);
|
||||
}
|
||||
|
||||
public static AstOperand Local(VariableType type)
|
||||
public static AstOperand Local(AggregateType type)
|
||||
{
|
||||
AstOperand local = new AstOperand(OperandType.LocalVariable);
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
@@ -10,7 +11,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
public OperandType Type { get; }
|
||||
|
||||
public VariableType VarType { get; set; }
|
||||
public AggregateType VarType { get; set; }
|
||||
|
||||
public int Value { get; }
|
||||
|
||||
@@ -22,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
Defs = new HashSet<IAstNode>();
|
||||
Uses = new HashSet<IAstNode>();
|
||||
|
||||
VarType = VariableType.S32;
|
||||
VarType = AggregateType.S32;
|
||||
}
|
||||
|
||||
public AstOperand(Operand operand) : this()
|
||||
|
@@ -1,4 +1,6 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System.Numerics;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper;
|
||||
|
||||
@@ -56,5 +58,21 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
_sources[index] = source;
|
||||
}
|
||||
|
||||
public AggregateType GetVectorType(AggregateType scalarType)
|
||||
{
|
||||
int componentsCount = BitOperations.PopCount((uint)Index);
|
||||
|
||||
AggregateType type = scalarType;
|
||||
|
||||
switch (componentsCount)
|
||||
{
|
||||
case 2: type |= AggregateType.Vector2; break;
|
||||
case 3: type |= AggregateType.Vector3; break;
|
||||
case 4: type |= AggregateType.Vector4; break;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
@@ -7,11 +8,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
private readonly struct InstInfo
|
||||
{
|
||||
public VariableType DestType { get; }
|
||||
public AggregateType DestType { get; }
|
||||
|
||||
public VariableType[] SrcTypes { get; }
|
||||
public AggregateType[] SrcTypes { get; }
|
||||
|
||||
public InstInfo(VariableType destType, params VariableType[] srcTypes)
|
||||
public InstInfo(AggregateType destType, params AggregateType[] srcTypes)
|
||||
{
|
||||
DestType = destType;
|
||||
SrcTypes = srcTypes;
|
||||
@@ -24,176 +25,173 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
_infoTbl = new InstInfo[(int)Instruction.Count];
|
||||
|
||||
// Inst Destination type Source 1 type Source 2 type Source 3 type Source 4 type
|
||||
Add(Instruction.AtomicAdd, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.AtomicAnd, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.AtomicCompareAndSwap, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.AtomicMaxS32, VariableType.S32, VariableType.S32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.AtomicMaxU32, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.AtomicMinS32, VariableType.S32, VariableType.S32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.AtomicMinU32, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.AtomicOr, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.AtomicSwap, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.AtomicXor, VariableType.U32, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.Absolute, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Add, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Ballot, VariableType.U32, VariableType.Bool);
|
||||
Add(Instruction.BitCount, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.BitfieldExtractS32, VariableType.S32, VariableType.S32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.BitfieldExtractU32, VariableType.U32, VariableType.U32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.BitfieldInsert, VariableType.Int, VariableType.Int, VariableType.Int, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.BitfieldReverse, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.BitwiseAnd, VariableType.Int, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.BitwiseExclusiveOr, VariableType.Int, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.BitwiseNot, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.BitwiseOr, VariableType.Int, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.BranchIfTrue, VariableType.None, VariableType.Bool);
|
||||
Add(Instruction.BranchIfFalse, VariableType.None, VariableType.Bool);
|
||||
Add(Instruction.Call, VariableType.Scalar);
|
||||
Add(Instruction.Ceiling, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Clamp, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.ClampU32, VariableType.U32, VariableType.U32, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.CompareEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.CompareGreater, VariableType.Bool, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.CompareGreaterOrEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.CompareGreaterOrEqualU32, VariableType.Bool, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.CompareGreaterU32, VariableType.Bool, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.CompareLess, VariableType.Bool, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.CompareLessOrEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.CompareLessOrEqualU32, VariableType.Bool, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.CompareLessU32, VariableType.Bool, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.CompareNotEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.ConditionalSelect, VariableType.Scalar, VariableType.Bool, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.ConvertFP32ToFP64, VariableType.F64, VariableType.F32);
|
||||
Add(Instruction.ConvertFP64ToFP32, VariableType.F32, VariableType.F64);
|
||||
Add(Instruction.ConvertFP32ToS32, VariableType.S32, VariableType.F32);
|
||||
Add(Instruction.ConvertFP32ToU32, VariableType.U32, VariableType.F32);
|
||||
Add(Instruction.ConvertFP64ToS32, VariableType.S32, VariableType.F64);
|
||||
Add(Instruction.ConvertFP64ToU32, VariableType.U32, VariableType.F64);
|
||||
Add(Instruction.ConvertS32ToFP32, VariableType.F32, VariableType.S32);
|
||||
Add(Instruction.ConvertS32ToFP64, VariableType.F64, VariableType.S32);
|
||||
Add(Instruction.ConvertU32ToFP32, VariableType.F32, VariableType.U32);
|
||||
Add(Instruction.ConvertU32ToFP64, VariableType.F64, VariableType.U32);
|
||||
Add(Instruction.Cosine, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Ddx, VariableType.F32, VariableType.F32);
|
||||
Add(Instruction.Ddy, VariableType.F32, VariableType.F32);
|
||||
Add(Instruction.Divide, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.ExponentB2, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.FindLSB, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.FindMSBS32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.FindMSBU32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.Floor, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.FusedMultiplyAdd, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.ImageLoad, VariableType.F32);
|
||||
Add(Instruction.ImageStore, VariableType.None);
|
||||
Add(Instruction.ImageAtomic, VariableType.S32);
|
||||
Add(Instruction.IsNan, VariableType.Bool, VariableType.Scalar);
|
||||
Add(Instruction.LoadAttribute, VariableType.F32, VariableType.S32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.LoadConstant, VariableType.F32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.LoadGlobal, VariableType.U32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.LoadLocal, VariableType.U32, VariableType.S32);
|
||||
Add(Instruction.LoadShared, VariableType.U32, VariableType.S32);
|
||||
Add(Instruction.LoadStorage, VariableType.U32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.Lod, VariableType.F32);
|
||||
Add(Instruction.LogarithmB2, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.LogicalAnd, VariableType.Bool, VariableType.Bool, VariableType.Bool);
|
||||
Add(Instruction.LogicalExclusiveOr, VariableType.Bool, VariableType.Bool, VariableType.Bool);
|
||||
Add(Instruction.LogicalNot, VariableType.Bool, VariableType.Bool);
|
||||
Add(Instruction.LogicalOr, VariableType.Bool, VariableType.Bool, VariableType.Bool);
|
||||
Add(Instruction.Maximum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.MaximumU32, VariableType.U32, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.Minimum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.MinimumU32, VariableType.U32, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.Multiply, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.MultiplyHighS32, VariableType.S32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.MultiplyHighU32, VariableType.U32, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.Negate, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.PackDouble2x32, VariableType.F64, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.PackHalf2x16, VariableType.U32, VariableType.F32, VariableType.F32);
|
||||
Add(Instruction.ReciprocalSquareRoot, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Round, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.ShiftLeft, VariableType.Int, VariableType.Int, VariableType.Int);
|
||||
Add(Instruction.ShiftRightS32, VariableType.S32, VariableType.S32, VariableType.Int);
|
||||
Add(Instruction.ShiftRightU32, VariableType.U32, VariableType.U32, VariableType.Int);
|
||||
Add(Instruction.Shuffle, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool);
|
||||
Add(Instruction.ShuffleDown, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool);
|
||||
Add(Instruction.ShuffleUp, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool);
|
||||
Add(Instruction.ShuffleXor, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool);
|
||||
Add(Instruction.Sine, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.SquareRoot, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.StoreAttribute, VariableType.None, VariableType.S32, VariableType.S32, VariableType.F32);
|
||||
Add(Instruction.StoreGlobal, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.StoreLocal, VariableType.None, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.StoreShared, VariableType.None, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.StoreShared16, VariableType.None, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.StoreShared8, VariableType.None, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.StoreStorage, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.StoreStorage16, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.StoreStorage8, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32);
|
||||
Add(Instruction.Subtract, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.SwizzleAdd, VariableType.F32, VariableType.F32, VariableType.F32, VariableType.S32);
|
||||
Add(Instruction.TextureSample, VariableType.F32);
|
||||
Add(Instruction.TextureSize, VariableType.S32, VariableType.S32, VariableType.S32);
|
||||
Add(Instruction.Truncate, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.UnpackDouble2x32, VariableType.U32, VariableType.F64);
|
||||
Add(Instruction.UnpackHalf2x16, VariableType.F32, VariableType.U32);
|
||||
Add(Instruction.VoteAll, VariableType.Bool, VariableType.Bool);
|
||||
Add(Instruction.VoteAllEqual, VariableType.Bool, VariableType.Bool);
|
||||
Add(Instruction.VoteAny, VariableType.Bool, VariableType.Bool);
|
||||
// Inst Destination type Source 1 type Source 2 type Source 3 type Source 4 type
|
||||
Add(Instruction.AtomicAdd, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.AtomicAnd, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.AtomicCompareAndSwap, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.AtomicMaxS32, AggregateType.S32, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.AtomicMaxU32, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.AtomicMinS32, AggregateType.S32, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.AtomicMinU32, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.AtomicOr, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.AtomicSwap, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.AtomicXor, AggregateType.U32, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.Absolute, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.Add, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.Ballot, AggregateType.U32, AggregateType.Bool);
|
||||
Add(Instruction.BitCount, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitfieldExtractS32, AggregateType.S32, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitfieldExtractU32, AggregateType.U32, AggregateType.U32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitfieldInsert, AggregateType.S32, AggregateType.S32, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitfieldReverse, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitwiseAnd, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitwiseExclusiveOr, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitwiseNot, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BitwiseOr, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.BranchIfTrue, AggregateType.Void, AggregateType.Bool);
|
||||
Add(Instruction.BranchIfFalse, AggregateType.Void, AggregateType.Bool);
|
||||
Add(Instruction.Call, AggregateType.Scalar);
|
||||
Add(Instruction.Ceiling, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.Clamp, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.ClampU32, AggregateType.U32, AggregateType.U32, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.CompareEqual, AggregateType.Bool, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.CompareGreater, AggregateType.Bool, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.CompareGreaterOrEqual, AggregateType.Bool, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.CompareGreaterOrEqualU32, AggregateType.Bool, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.CompareGreaterU32, AggregateType.Bool, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.CompareLess, AggregateType.Bool, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.CompareLessOrEqual, AggregateType.Bool, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.CompareLessOrEqualU32, AggregateType.Bool, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.CompareLessU32, AggregateType.Bool, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.CompareNotEqual, AggregateType.Bool, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.ConditionalSelect, AggregateType.Scalar, AggregateType.Bool, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.ConvertFP32ToFP64, AggregateType.FP64, AggregateType.FP32);
|
||||
Add(Instruction.ConvertFP64ToFP32, AggregateType.FP32, AggregateType.FP64);
|
||||
Add(Instruction.ConvertFP32ToS32, AggregateType.S32, AggregateType.FP32);
|
||||
Add(Instruction.ConvertFP32ToU32, AggregateType.U32, AggregateType.FP32);
|
||||
Add(Instruction.ConvertFP64ToS32, AggregateType.S32, AggregateType.FP64);
|
||||
Add(Instruction.ConvertFP64ToU32, AggregateType.U32, AggregateType.FP64);
|
||||
Add(Instruction.ConvertS32ToFP32, AggregateType.FP32, AggregateType.S32);
|
||||
Add(Instruction.ConvertS32ToFP64, AggregateType.FP64, AggregateType.S32);
|
||||
Add(Instruction.ConvertU32ToFP32, AggregateType.FP32, AggregateType.U32);
|
||||
Add(Instruction.ConvertU32ToFP64, AggregateType.FP64, AggregateType.U32);
|
||||
Add(Instruction.Cosine, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.Ddx, AggregateType.FP32, AggregateType.FP32);
|
||||
Add(Instruction.Ddy, AggregateType.FP32, AggregateType.FP32);
|
||||
Add(Instruction.Divide, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.ExponentB2, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.FindLSB, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.FindMSBS32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.FindMSBU32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.Floor, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.FusedMultiplyAdd, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.ImageLoad, AggregateType.FP32);
|
||||
Add(Instruction.ImageStore, AggregateType.Void);
|
||||
Add(Instruction.ImageAtomic, AggregateType.S32);
|
||||
Add(Instruction.IsNan, AggregateType.Bool, AggregateType.Scalar);
|
||||
Add(Instruction.LoadAttribute, AggregateType.FP32, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.LoadConstant, AggregateType.FP32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.LoadGlobal, AggregateType.U32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.LoadLocal, AggregateType.U32, AggregateType.S32);
|
||||
Add(Instruction.LoadShared, AggregateType.U32, AggregateType.S32);
|
||||
Add(Instruction.LoadStorage, AggregateType.U32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.Lod, AggregateType.FP32);
|
||||
Add(Instruction.LogarithmB2, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.LogicalAnd, AggregateType.Bool, AggregateType.Bool, AggregateType.Bool);
|
||||
Add(Instruction.LogicalExclusiveOr, AggregateType.Bool, AggregateType.Bool, AggregateType.Bool);
|
||||
Add(Instruction.LogicalNot, AggregateType.Bool, AggregateType.Bool);
|
||||
Add(Instruction.LogicalOr, AggregateType.Bool, AggregateType.Bool, AggregateType.Bool);
|
||||
Add(Instruction.Maximum, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.MaximumU32, AggregateType.U32, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.Minimum, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.MinimumU32, AggregateType.U32, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.Multiply, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.MultiplyHighS32, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.MultiplyHighU32, AggregateType.U32, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.Negate, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.PackDouble2x32, AggregateType.FP64, AggregateType.U32, AggregateType.U32);
|
||||
Add(Instruction.PackHalf2x16, AggregateType.U32, AggregateType.FP32, AggregateType.FP32);
|
||||
Add(Instruction.ReciprocalSquareRoot, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.Round, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.ShiftLeft, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.ShiftRightS32, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.ShiftRightU32, AggregateType.U32, AggregateType.U32, AggregateType.S32);
|
||||
Add(Instruction.Shuffle, AggregateType.FP32, AggregateType.FP32, AggregateType.U32, AggregateType.U32, AggregateType.Bool);
|
||||
Add(Instruction.ShuffleDown, AggregateType.FP32, AggregateType.FP32, AggregateType.U32, AggregateType.U32, AggregateType.Bool);
|
||||
Add(Instruction.ShuffleUp, AggregateType.FP32, AggregateType.FP32, AggregateType.U32, AggregateType.U32, AggregateType.Bool);
|
||||
Add(Instruction.ShuffleXor, AggregateType.FP32, AggregateType.FP32, AggregateType.U32, AggregateType.U32, AggregateType.Bool);
|
||||
Add(Instruction.Sine, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.SquareRoot, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.StoreAttribute, AggregateType.Void, AggregateType.S32, AggregateType.S32, AggregateType.FP32);
|
||||
Add(Instruction.StoreGlobal, AggregateType.Void, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.StoreLocal, AggregateType.Void, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.StoreShared, AggregateType.Void, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.StoreShared16, AggregateType.Void, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.StoreShared8, AggregateType.Void, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.StoreStorage, AggregateType.Void, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.StoreStorage16, AggregateType.Void, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.StoreStorage8, AggregateType.Void, AggregateType.S32, AggregateType.S32, AggregateType.U32);
|
||||
Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32);
|
||||
Add(Instruction.TextureSample, AggregateType.FP32);
|
||||
Add(Instruction.TextureSize, AggregateType.S32, AggregateType.S32, AggregateType.S32);
|
||||
Add(Instruction.Truncate, AggregateType.Scalar, AggregateType.Scalar);
|
||||
Add(Instruction.UnpackDouble2x32, AggregateType.U32, AggregateType.FP64);
|
||||
Add(Instruction.UnpackHalf2x16, AggregateType.FP32, AggregateType.U32);
|
||||
Add(Instruction.VectorExtract, AggregateType.Scalar, AggregateType.Vector4, AggregateType.S32);
|
||||
Add(Instruction.VoteAll, AggregateType.Bool, AggregateType.Bool);
|
||||
Add(Instruction.VoteAllEqual, AggregateType.Bool, AggregateType.Bool);
|
||||
Add(Instruction.VoteAny, AggregateType.Bool, AggregateType.Bool);
|
||||
}
|
||||
|
||||
private static void Add(Instruction inst, VariableType destType, params VariableType[] srcTypes)
|
||||
private static void Add(Instruction inst, AggregateType destType, params AggregateType[] srcTypes)
|
||||
{
|
||||
_infoTbl[(int)inst] = new InstInfo(destType, srcTypes);
|
||||
}
|
||||
|
||||
public static VariableType GetDestVarType(Instruction inst)
|
||||
public static AggregateType GetDestVarType(Instruction inst)
|
||||
{
|
||||
return GetFinalVarType(_infoTbl[(int)(inst & Instruction.Mask)].DestType, inst);
|
||||
}
|
||||
|
||||
public static VariableType GetSrcVarType(Instruction inst, int index)
|
||||
public static AggregateType GetSrcVarType(Instruction inst, int index)
|
||||
{
|
||||
// TODO: Return correct type depending on source index,
|
||||
// that can improve the decompiler output.
|
||||
if (inst == Instruction.ImageLoad ||
|
||||
inst == Instruction.ImageStore ||
|
||||
if (inst == Instruction.ImageLoad ||
|
||||
inst == Instruction.ImageStore ||
|
||||
inst == Instruction.ImageAtomic ||
|
||||
inst == Instruction.Lod ||
|
||||
inst == Instruction.Lod ||
|
||||
inst == Instruction.TextureSample)
|
||||
{
|
||||
return VariableType.F32;
|
||||
return AggregateType.FP32;
|
||||
}
|
||||
else if (inst == Instruction.Call)
|
||||
{
|
||||
return VariableType.S32;
|
||||
return AggregateType.S32;
|
||||
}
|
||||
|
||||
return GetFinalVarType(_infoTbl[(int)(inst & Instruction.Mask)].SrcTypes[index], inst);
|
||||
}
|
||||
|
||||
private static VariableType GetFinalVarType(VariableType type, Instruction inst)
|
||||
private static AggregateType GetFinalVarType(AggregateType type, Instruction inst)
|
||||
{
|
||||
if (type == VariableType.Scalar)
|
||||
if (type == AggregateType.Scalar)
|
||||
{
|
||||
if ((inst & Instruction.FP32) != 0)
|
||||
{
|
||||
return VariableType.F32;
|
||||
return AggregateType.FP32;
|
||||
}
|
||||
else if ((inst & Instruction.FP64) != 0)
|
||||
{
|
||||
return VariableType.F64;
|
||||
return AggregateType.FP64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return VariableType.S32;
|
||||
return AggregateType.S32;
|
||||
}
|
||||
}
|
||||
else if (type == VariableType.Int)
|
||||
{
|
||||
return VariableType.S32;
|
||||
}
|
||||
else if (type == VariableType.None)
|
||||
else if (type == AggregateType.Void)
|
||||
{
|
||||
throw new ArgumentException($"Invalid operand for instruction \"{inst}\".");
|
||||
}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
static class OperandInfo
|
||||
{
|
||||
public static VariableType GetVarType(AstOperand operand)
|
||||
public static AggregateType GetVarType(AstOperand operand)
|
||||
{
|
||||
if (operand.Type == OperandType.LocalVariable)
|
||||
{
|
||||
@@ -17,16 +18,16 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
}
|
||||
}
|
||||
|
||||
public static VariableType GetVarType(OperandType type)
|
||||
public static AggregateType GetVarType(OperandType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
OperandType.Argument => VariableType.S32,
|
||||
OperandType.Attribute => VariableType.F32,
|
||||
OperandType.AttributePerPatch => VariableType.F32,
|
||||
OperandType.Constant => VariableType.S32,
|
||||
OperandType.ConstantBuffer => VariableType.F32,
|
||||
OperandType.Undefined => VariableType.S32,
|
||||
OperandType.Argument => AggregateType.S32,
|
||||
OperandType.Attribute => AggregateType.FP32,
|
||||
OperandType.AttributePerPatch => AggregateType.FP32,
|
||||
OperandType.Constant => AggregateType.S32,
|
||||
OperandType.ConstantBuffer => AggregateType.FP32,
|
||||
OperandType.Undefined => AggregateType.S32,
|
||||
_ => throw new ArgumentException($"Invalid operand type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
@@ -8,19 +9,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public VariableType ReturnType { get; }
|
||||
public AggregateType ReturnType { get; }
|
||||
|
||||
public VariableType[] InArguments { get; }
|
||||
public VariableType[] OutArguments { get; }
|
||||
public AggregateType[] InArguments { get; }
|
||||
public AggregateType[] OutArguments { get; }
|
||||
|
||||
public HashSet<AstOperand> Locals { get; }
|
||||
|
||||
public StructuredFunction(
|
||||
AstBlock mainBlock,
|
||||
string name,
|
||||
VariableType returnType,
|
||||
VariableType[] inArguments,
|
||||
VariableType[] outArguments)
|
||||
AggregateType returnType,
|
||||
AggregateType[] inArguments,
|
||||
AggregateType[] outArguments)
|
||||
{
|
||||
MainBlock = mainBlock;
|
||||
Name = name;
|
||||
@@ -31,7 +32,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
Locals = new HashSet<AstOperand>();
|
||||
}
|
||||
|
||||
public VariableType GetArgumentType(int index)
|
||||
public AggregateType GetArgumentType(int index)
|
||||
{
|
||||
return index >= InArguments.Length
|
||||
? OutArguments[index - InArguments.Length]
|
||||
|
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
@@ -17,19 +18,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
BasicBlock[] blocks = function.Blocks;
|
||||
|
||||
VariableType returnType = function.ReturnsValue ? VariableType.S32 : VariableType.None;
|
||||
AggregateType returnType = function.ReturnsValue ? AggregateType.S32 : AggregateType.Void;
|
||||
|
||||
VariableType[] inArguments = new VariableType[function.InArgumentsCount];
|
||||
VariableType[] outArguments = new VariableType[function.OutArgumentsCount];
|
||||
AggregateType[] inArguments = new AggregateType[function.InArgumentsCount];
|
||||
AggregateType[] outArguments = new AggregateType[function.OutArgumentsCount];
|
||||
|
||||
for (int i = 0; i < inArguments.Length; i++)
|
||||
{
|
||||
inArguments[i] = VariableType.S32;
|
||||
inArguments[i] = AggregateType.S32;
|
||||
}
|
||||
|
||||
for (int i = 0; i < outArguments.Length; i++)
|
||||
{
|
||||
outArguments[i] = VariableType.S32;
|
||||
outArguments[i] = AggregateType.S32;
|
||||
}
|
||||
|
||||
context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments);
|
||||
@@ -109,8 +110,10 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
}
|
||||
}
|
||||
|
||||
bool vectorDest = IsVectorDestInst(inst);
|
||||
|
||||
int sourcesCount = operation.SourcesCount;
|
||||
int outDestsCount = operation.DestsCount != 0 ? operation.DestsCount - 1 : 0;
|
||||
int outDestsCount = operation.DestsCount != 0 && !vectorDest ? operation.DestsCount - 1 : 0;
|
||||
|
||||
IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount];
|
||||
|
||||
@@ -141,7 +144,52 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
sources);
|
||||
}
|
||||
|
||||
if (operation.Dest != null)
|
||||
int componentsCount = BitOperations.PopCount((uint)operation.Index);
|
||||
|
||||
if (vectorDest && componentsCount > 1)
|
||||
{
|
||||
AggregateType destType = InstructionInfo.GetDestVarType(inst);
|
||||
|
||||
IAstNode source;
|
||||
|
||||
if (operation is TextureOperation texOp)
|
||||
{
|
||||
if (texOp.Inst == Instruction.ImageLoad)
|
||||
{
|
||||
destType = texOp.Format.GetComponentType();
|
||||
}
|
||||
|
||||
source = GetAstTextureOperation(texOp);
|
||||
}
|
||||
else
|
||||
{
|
||||
source = new AstOperation(inst, operation.Index, sources, operation.SourcesCount);
|
||||
}
|
||||
|
||||
AggregateType destElemType = destType;
|
||||
|
||||
switch (componentsCount)
|
||||
{
|
||||
case 2: destType |= AggregateType.Vector2; break;
|
||||
case 3: destType |= AggregateType.Vector3; break;
|
||||
case 4: destType |= AggregateType.Vector4; break;
|
||||
}
|
||||
|
||||
AstOperand destVec = context.NewTemp(destType);
|
||||
|
||||
context.AddNode(new AstAssignment(destVec, source));
|
||||
|
||||
for (int i = 0; i < operation.DestsCount; i++)
|
||||
{
|
||||
AstOperand dest = context.GetOperandDef(operation.GetDest(i));
|
||||
AstOperand index = new AstOperand(OperandType.Constant, i);
|
||||
|
||||
dest.VarType = destElemType;
|
||||
|
||||
context.AddNode(new AstAssignment(dest, new AstOperation(Instruction.VectorExtract, new[] { destVec, index }, 2)));
|
||||
}
|
||||
}
|
||||
else if (operation.Dest != null)
|
||||
{
|
||||
AstOperand dest = context.GetOperandDef(operation.Dest);
|
||||
|
||||
@@ -149,7 +197,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
// logical operations, rather than forcing a cast to int and doing
|
||||
// a bitwise operation with the value, as it is likely to be used as
|
||||
// a bool in the end.
|
||||
if (IsBitwiseInst(inst) && AreAllSourceTypesEqual(sources, VariableType.Bool))
|
||||
if (IsBitwiseInst(inst) && AreAllSourceTypesEqual(sources, AggregateType.Bool))
|
||||
{
|
||||
inst = GetLogicalFromBitwiseInst(inst);
|
||||
}
|
||||
@@ -159,9 +207,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
if (isCondSel || isCopy)
|
||||
{
|
||||
VariableType type = GetVarTypeFromUses(operation.Dest);
|
||||
AggregateType type = GetVarTypeFromUses(operation.Dest);
|
||||
|
||||
if (isCondSel && type == VariableType.F32)
|
||||
if (isCondSel && type == AggregateType.FP32)
|
||||
{
|
||||
inst |= Instruction.FP32;
|
||||
}
|
||||
@@ -259,7 +307,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
}
|
||||
}
|
||||
|
||||
private static VariableType GetVarTypeFromUses(Operand dest)
|
||||
private static AggregateType GetVarTypeFromUses(Operand dest)
|
||||
{
|
||||
HashSet<Operand> visited = new HashSet<Operand>();
|
||||
|
||||
@@ -315,10 +363,10 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
}
|
||||
}
|
||||
|
||||
return VariableType.S32;
|
||||
return AggregateType.S32;
|
||||
}
|
||||
|
||||
private static bool AreAllSourceTypesEqual(IAstNode[] sources, VariableType type)
|
||||
private static bool AreAllSourceTypesEqual(IAstNode[] sources, AggregateType type)
|
||||
{
|
||||
foreach (IAstNode node in sources)
|
||||
{
|
||||
@@ -336,6 +384,16 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsVectorDestInst(Instruction inst)
|
||||
{
|
||||
return inst switch
|
||||
{
|
||||
Instruction.ImageLoad or
|
||||
Instruction.TextureSample => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsBranchInst(Instruction inst)
|
||||
{
|
||||
return inst switch
|
||||
|
@@ -80,9 +80,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
public void EnterFunction(
|
||||
int blocksCount,
|
||||
string name,
|
||||
VariableType returnType,
|
||||
VariableType[] inArguments,
|
||||
VariableType[] outArguments)
|
||||
AggregateType returnType,
|
||||
AggregateType[] inArguments,
|
||||
AggregateType[] outArguments)
|
||||
{
|
||||
_loopTails = new HashSet<BasicBlock>();
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
return gotoTempAsg;
|
||||
}
|
||||
|
||||
AstOperand gotoTemp = NewTemp(VariableType.Bool);
|
||||
AstOperand gotoTemp = NewTemp(AggregateType.Bool);
|
||||
|
||||
gotoTempAsg = Assign(gotoTemp, Const(IrConsts.False));
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
return _gotos.ToArray();
|
||||
}
|
||||
|
||||
private AstOperand NewTemp(VariableType type)
|
||||
public AstOperand NewTemp(AggregateType type)
|
||||
{
|
||||
AstOperand newTemp = Local(type);
|
||||
|
||||
|
@@ -1,14 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
enum VariableType
|
||||
{
|
||||
None,
|
||||
Bool,
|
||||
Scalar,
|
||||
Int,
|
||||
F32,
|
||||
F64,
|
||||
S32,
|
||||
U32
|
||||
}
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
@@ -95,7 +95,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
};
|
||||
}
|
||||
|
||||
public static VariableType GetComponentType(this TextureFormat format)
|
||||
public static AggregateType GetComponentType(this TextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
@@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
case TextureFormat.R16G16B16A16Uint:
|
||||
case TextureFormat.R32G32B32A32Uint:
|
||||
case TextureFormat.R10G10B10A2Uint:
|
||||
return VariableType.U32;
|
||||
return AggregateType.U32;
|
||||
case TextureFormat.R8Sint:
|
||||
case TextureFormat.R16Sint:
|
||||
case TextureFormat.R32Sint:
|
||||
@@ -119,10 +119,10 @@ namespace Ryujinx.Graphics.Shader
|
||||
case TextureFormat.R8G8B8A8Sint:
|
||||
case TextureFormat.R16G16B16A16Sint:
|
||||
case TextureFormat.R32G32B32A32Sint:
|
||||
return VariableType.S32;
|
||||
return AggregateType.S32;
|
||||
}
|
||||
|
||||
return VariableType.F32;
|
||||
return AggregateType.FP32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,14 @@
|
||||
|
||||
ElementTypeMask = 0xff,
|
||||
|
||||
Vector = 1 << 8,
|
||||
Array = 1 << 9
|
||||
ElementCountShift = 8,
|
||||
ElementCountMask = 3 << ElementCountShift,
|
||||
|
||||
Scalar = 0 << ElementCountShift,
|
||||
Vector2 = 1 << ElementCountShift,
|
||||
Vector3 = 2 << ElementCountShift,
|
||||
Vector4 = 3 << ElementCountShift,
|
||||
|
||||
Array = 1 << 10
|
||||
}
|
||||
}
|
||||
|
@@ -9,22 +9,22 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{ AttributeConsts.Layer, new AttributeInfo(AttributeConsts.Layer, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.ViewportIndex, new AttributeInfo(AttributeConsts.ViewportIndex, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.PointSize, new AttributeInfo(AttributeConsts.PointSize, 0, 1, AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 3, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 3, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 3, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 3, AggregateType.Vector4 | AggregateType.FP32) },
|
||||
{ AttributeConsts.InstanceId, new AttributeInfo(AttributeConsts.InstanceId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.VertexId, new AttributeInfo(AttributeConsts.VertexId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.BaseInstance, new AttributeInfo(AttributeConsts.BaseInstance, 0, 1, AggregateType.S32) },
|
||||
@@ -37,21 +37,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
// Special.
|
||||
{ AttributeConsts.FragmentOutputDepth, new AttributeInfo(AttributeConsts.FragmentOutputDepth, 0, 1, AggregateType.FP32) },
|
||||
{ AttributeConsts.ThreadKill, new AttributeInfo(AttributeConsts.ThreadKill, 0, 1, AggregateType.Bool) },
|
||||
{ AttributeConsts.ThreadIdX, new AttributeInfo(AttributeConsts.ThreadIdX, 0, 3, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdY, new AttributeInfo(AttributeConsts.ThreadIdX, 1, 3, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdZ, new AttributeInfo(AttributeConsts.ThreadIdX, 2, 3, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdX, new AttributeInfo(AttributeConsts.CtaIdX, 0, 3, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdY, new AttributeInfo(AttributeConsts.CtaIdX, 1, 3, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdZ, new AttributeInfo(AttributeConsts.CtaIdX, 2, 3, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdX, new AttributeInfo(AttributeConsts.ThreadIdX, 0, 3, AggregateType.Vector3 | AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdY, new AttributeInfo(AttributeConsts.ThreadIdX, 1, 3, AggregateType.Vector3 | AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdZ, new AttributeInfo(AttributeConsts.ThreadIdX, 2, 3, AggregateType.Vector3 | AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdX, new AttributeInfo(AttributeConsts.CtaIdX, 0, 3, AggregateType.Vector3 | AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdY, new AttributeInfo(AttributeConsts.CtaIdX, 1, 3, AggregateType.Vector3 | AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdZ, new AttributeInfo(AttributeConsts.CtaIdX, 2, 3, AggregateType.Vector3 | AggregateType.U32) },
|
||||
{ AttributeConsts.LaneId, new AttributeInfo(AttributeConsts.LaneId, 0, 1, AggregateType.U32) },
|
||||
{ AttributeConsts.InvocationId, new AttributeInfo(AttributeConsts.InvocationId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.PrimitiveId, new AttributeInfo(AttributeConsts.PrimitiveId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.PatchVerticesIn, new AttributeInfo(AttributeConsts.PatchVerticesIn, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.EqMask, new AttributeInfo(AttributeConsts.EqMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.GeMask, new AttributeInfo(AttributeConsts.GeMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.GtMask, new AttributeInfo(AttributeConsts.GtMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.LeMask, new AttributeInfo(AttributeConsts.LeMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.LtMask, new AttributeInfo(AttributeConsts.LtMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
||||
{ AttributeConsts.EqMask, new AttributeInfo(AttributeConsts.EqMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) },
|
||||
{ AttributeConsts.GeMask, new AttributeInfo(AttributeConsts.GeMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) },
|
||||
{ AttributeConsts.GtMask, new AttributeInfo(AttributeConsts.GtMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) },
|
||||
{ AttributeConsts.LeMask, new AttributeInfo(AttributeConsts.LeMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) },
|
||||
{ AttributeConsts.LtMask, new AttributeInfo(AttributeConsts.LtMask, 0, 4, AggregateType.Vector4 | AggregateType.U32) },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<int, AttributeInfo> _builtInAttributesPerPatch = new Dictionary<int, AttributeInfo>()
|
||||
@@ -124,11 +124,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
elemType = AggregateType.FP32;
|
||||
}
|
||||
|
||||
return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector | elemType, false);
|
||||
return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector4 | elemType, false);
|
||||
}
|
||||
else if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
|
||||
{
|
||||
return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector | AggregateType.FP32, false);
|
||||
return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector4 | AggregateType.FP32, false);
|
||||
}
|
||||
else if (value == AttributeConsts.SupportBlockViewInverseX || value == AttributeConsts.SupportBlockViewInverseY)
|
||||
{
|
||||
@@ -149,7 +149,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
if (value >= AttributeConsts.UserAttributePerPatchBase && value < AttributeConsts.UserAttributePerPatchEnd)
|
||||
{
|
||||
int offset = (value - AttributeConsts.UserAttributePerPatchBase) & 0xf;
|
||||
return new AttributeInfo(value - offset, offset >> 2, 4, AggregateType.Vector | AggregateType.FP32, false);
|
||||
return new AttributeInfo(value - offset, offset >> 2, 4, AggregateType.Vector4 | AggregateType.FP32, false);
|
||||
}
|
||||
else if (_builtInAttributesPerPatch.TryGetValue(value, out AttributeInfo info))
|
||||
{
|
||||
|
@@ -109,10 +109,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
TextureFlags flags,
|
||||
int handle,
|
||||
int compIndex,
|
||||
Operand dest,
|
||||
Operand[] dests,
|
||||
params Operand[] sources)
|
||||
{
|
||||
return CreateTextureOperation(inst, type, TextureFormat.Unknown, flags, handle, compIndex, dest, sources);
|
||||
return CreateTextureOperation(inst, type, TextureFormat.Unknown, flags, handle, compIndex, dests, sources);
|
||||
}
|
||||
|
||||
public TextureOperation CreateTextureOperation(
|
||||
@@ -122,7 +122,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
TextureFlags flags,
|
||||
int handle,
|
||||
int compIndex,
|
||||
Operand dest,
|
||||
Operand[] dests,
|
||||
params Operand[] sources)
|
||||
{
|
||||
if (!flags.HasFlag(TextureFlags.Bindless))
|
||||
@@ -130,7 +130,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
Config.SetUsedTexture(inst, type, format, flags, TextureOperation.DefaultCbufSlot, handle);
|
||||
}
|
||||
|
||||
return new TextureOperation(inst, type, format, flags, handle, compIndex, dest, sources);
|
||||
return new TextureOperation(inst, type, format, flags, handle, compIndex, dests, sources);
|
||||
}
|
||||
|
||||
public void FlagAttributeRead(int attribute)
|
||||
|
@@ -385,15 +385,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
int componentIndex = texOp.Index;
|
||||
|
||||
Operand Int(Operand value)
|
||||
{
|
||||
Operand res = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.ConvertFP32ToS32, res, value));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Operand Float(Operand value)
|
||||
{
|
||||
Operand res = Local();
|
||||
@@ -436,7 +427,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
index,
|
||||
coordSize,
|
||||
new[] { coordSize },
|
||||
texSizeSources));
|
||||
|
||||
config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
|
||||
@@ -451,80 +442,53 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
}
|
||||
|
||||
Operand[] dests = new Operand[texOp.DestsCount];
|
||||
|
||||
for (int i = 0; i < texOp.DestsCount; i++)
|
||||
{
|
||||
dests[i] = texOp.GetDest(i);
|
||||
}
|
||||
|
||||
Operand bindlessHandle = isBindless || isIndexed ? sources[0] : null;
|
||||
|
||||
LinkedListNode<INode> oldNode = node;
|
||||
|
||||
// Technically, non-constant texture offsets are not allowed (according to the spec),
|
||||
// however some GPUs does support that.
|
||||
// For GPUs where it is not supported, we can replace the instruction with the following:
|
||||
// For texture*Offset, we replace it by texture*, and add the offset to the P coords.
|
||||
// The offset can be calculated as offset / textureSize(lod), where lod = textureQueryLod(coords).
|
||||
// For texelFetchOffset, we replace it by texelFetch and add the offset to the P coords directly.
|
||||
// For textureGatherOffset, we take advantage of the fact that the operation is already broken down
|
||||
// to read the 4 pixels separately, and just replace it with 4 textureGather with a different offset
|
||||
// for each pixel.
|
||||
if (hasInvalidOffset)
|
||||
// For textureGatherOffset, we split the operation into up to 4 operations, one for each component
|
||||
// that is accessed, where each textureGather operation has a different offset for each pixel.
|
||||
if (hasInvalidOffset && isGather && !isShadow)
|
||||
{
|
||||
if (intCoords)
|
||||
config.SetUsedFeature(FeatureFlags.IntegerSampling);
|
||||
|
||||
Operand[] newSources = new Operand[sources.Length];
|
||||
|
||||
sources.CopyTo(newSources, 0);
|
||||
|
||||
Operand[] texSizes = InsertTextureSize(node, texOp, lodSources, bindlessHandle, coordsCount);
|
||||
|
||||
int destIndex = 0;
|
||||
|
||||
for (int compIndex = 0; compIndex < 4; compIndex++)
|
||||
{
|
||||
for (int index = 0; index < coordsCount; index++)
|
||||
if (((texOp.Index >> compIndex) & 1) == 0)
|
||||
{
|
||||
Operand source = sources[coordsIndex + index];
|
||||
|
||||
Operand coordPlusOffset = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.Add, coordPlusOffset, source, offsets[index]));
|
||||
|
||||
sources[coordsIndex + index] = coordPlusOffset;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config.SetUsedFeature(FeatureFlags.IntegerSampling);
|
||||
|
||||
Operand lod = Local();
|
||||
|
||||
node.List.AddBefore(node, new TextureOperation(
|
||||
Instruction.Lod,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
0,
|
||||
lod,
|
||||
lodSources));
|
||||
|
||||
for (int index = 0; index < coordsCount; index++)
|
||||
{
|
||||
Operand coordSize = Local();
|
||||
|
||||
Operand[] texSizeSources;
|
||||
|
||||
if (isBindless || isIndexed)
|
||||
{
|
||||
texSizeSources = new Operand[] { sources[0], Int(lod) };
|
||||
}
|
||||
else
|
||||
{
|
||||
texSizeSources = new Operand[] { Int(lod) };
|
||||
}
|
||||
|
||||
node.List.AddBefore(node, new TextureOperation(
|
||||
Instruction.TextureSize,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
index,
|
||||
coordSize,
|
||||
texSizeSources));
|
||||
|
||||
config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
|
||||
|
||||
Operand offset = Local();
|
||||
|
||||
Operand intOffset = offsets[index + (hasOffsets ? texOp.Index * coordsCount : 0)];
|
||||
Operand intOffset = offsets[index + (hasOffsets ? compIndex * coordsCount : 0)];
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, offset, Float(intOffset), Float(coordSize)));
|
||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, offset, Float(intOffset), Float(texSizes[index])));
|
||||
|
||||
Operand source = sources[coordsIndex + index];
|
||||
|
||||
@@ -532,45 +496,152 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Add, coordPlusOffset, source, offset));
|
||||
|
||||
sources[coordsIndex + index] = coordPlusOffset;
|
||||
newSources[coordsIndex + index] = coordPlusOffset;
|
||||
}
|
||||
|
||||
TextureOperation newTexOp = new TextureOperation(
|
||||
Instruction.TextureSample,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
1,
|
||||
new[] { dests[destIndex++] },
|
||||
newSources);
|
||||
|
||||
node = node.List.AddBefore(node, newTexOp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasInvalidOffset)
|
||||
{
|
||||
if (intCoords)
|
||||
{
|
||||
for (int index = 0; index < coordsCount; index++)
|
||||
{
|
||||
Operand source = sources[coordsIndex + index];
|
||||
|
||||
Operand coordPlusOffset = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.Add, coordPlusOffset, source, offsets[index]));
|
||||
|
||||
sources[coordsIndex + index] = coordPlusOffset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config.SetUsedFeature(FeatureFlags.IntegerSampling);
|
||||
|
||||
Operand[] texSizes = InsertTextureSize(node, texOp, lodSources, bindlessHandle, coordsCount);
|
||||
|
||||
for (int index = 0; index < coordsCount; index++)
|
||||
{
|
||||
config.SetUsedTexture(Instruction.TextureSize, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, texOp.Handle);
|
||||
|
||||
Operand offset = Local();
|
||||
|
||||
Operand intOffset = offsets[index];
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, offset, Float(intOffset), Float(texSizes[index])));
|
||||
|
||||
Operand source = sources[coordsIndex + index];
|
||||
|
||||
Operand coordPlusOffset = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Add, coordPlusOffset, source, offset));
|
||||
|
||||
sources[coordsIndex + index] = coordPlusOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isGather && !isShadow)
|
||||
{
|
||||
Operand gatherComponent = sources[dstIndex - 1];
|
||||
TextureOperation newTexOp = new TextureOperation(
|
||||
Instruction.TextureSample,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
componentIndex,
|
||||
dests,
|
||||
sources);
|
||||
|
||||
Debug.Assert(gatherComponent.Type == OperandType.Constant);
|
||||
|
||||
componentIndex = gatherComponent.Value;
|
||||
}
|
||||
node = node.List.AddBefore(node, newTexOp);
|
||||
}
|
||||
|
||||
TextureOperation newTexOp = new TextureOperation(
|
||||
Instruction.TextureSample,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
componentIndex,
|
||||
texOp.Dest,
|
||||
sources);
|
||||
node.List.Remove(oldNode);
|
||||
|
||||
for (int index = 0; index < texOp.SourcesCount; index++)
|
||||
{
|
||||
texOp.SetSource(index, null);
|
||||
}
|
||||
|
||||
LinkedListNode<INode> oldNode = node;
|
||||
|
||||
node = node.List.AddBefore(node, newTexOp);
|
||||
|
||||
node.List.Remove(oldNode);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static Operand[] InsertTextureSize(
|
||||
LinkedListNode<INode> node,
|
||||
TextureOperation texOp,
|
||||
Operand[] lodSources,
|
||||
Operand bindlessHandle,
|
||||
int coordsCount)
|
||||
{
|
||||
Operand Int(Operand value)
|
||||
{
|
||||
Operand res = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.ConvertFP32ToS32, res, value));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Operand[] texSizes = new Operand[coordsCount];
|
||||
|
||||
Operand lod = Local();
|
||||
|
||||
node.List.AddBefore(node, new TextureOperation(
|
||||
Instruction.Lod,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
0,
|
||||
new[] { lod },
|
||||
lodSources));
|
||||
|
||||
for (int index = 0; index < coordsCount; index++)
|
||||
{
|
||||
texSizes[index] = Local();
|
||||
|
||||
Operand[] texSizeSources;
|
||||
|
||||
if (bindlessHandle != null)
|
||||
{
|
||||
texSizeSources = new Operand[] { bindlessHandle, Int(lod) };
|
||||
}
|
||||
else
|
||||
{
|
||||
texSizeSources = new Operand[] { Int(lod) };
|
||||
}
|
||||
|
||||
node.List.AddBefore(node, new TextureOperation(
|
||||
Instruction.TextureSize,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.CbufSlot,
|
||||
texOp.Handle,
|
||||
index,
|
||||
new[] { texSizes[index] },
|
||||
texSizeSources));
|
||||
}
|
||||
|
||||
return texSizes;
|
||||
}
|
||||
|
||||
private static LinkedListNode<INode> InsertSnormNormalization(LinkedListNode<INode> node, ShaderConfig config)
|
||||
{
|
||||
TextureOperation texOp = (TextureOperation)node.Value;
|
||||
@@ -604,27 +675,32 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
// Do normalization. We assume SINT formats are being used
|
||||
// as replacement for SNORM (which is not supported).
|
||||
INode[] uses = texOp.Dest.UseOps.ToArray();
|
||||
|
||||
Operation convOp = new Operation(Instruction.ConvertS32ToFP32, Local(), texOp.Dest);
|
||||
Operation normOp = new Operation(Instruction.FP32 | Instruction.Multiply, Local(), convOp.Dest, ConstF(1f / maxPositive));
|
||||
|
||||
node = node.List.AddAfter(node, convOp);
|
||||
node = node.List.AddAfter(node, normOp);
|
||||
|
||||
foreach (INode useOp in uses)
|
||||
for (int i = 0; i < texOp.DestsCount; i++)
|
||||
{
|
||||
if (useOp is not Operation op)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Operand dest = texOp.GetDest(i);
|
||||
|
||||
// Replace all uses of the texture pixel value with the normalized value.
|
||||
for (int index = 0; index < op.SourcesCount; index++)
|
||||
INode[] uses = dest.UseOps.ToArray();
|
||||
|
||||
Operation convOp = new Operation(Instruction.ConvertS32ToFP32, Local(), dest);
|
||||
Operation normOp = new Operation(Instruction.FP32 | Instruction.Multiply, Local(), convOp.Dest, ConstF(1f / maxPositive));
|
||||
|
||||
node = node.List.AddAfter(node, convOp);
|
||||
node = node.List.AddAfter(node, normOp);
|
||||
|
||||
foreach (INode useOp in uses)
|
||||
{
|
||||
if (op.GetSource(index) == texOp.Dest)
|
||||
if (useOp is not Operation op)
|
||||
{
|
||||
op.SetSource(index, normOp.Dest);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace all uses of the texture pixel value with the normalized value.
|
||||
for (int index = 0; index < op.SourcesCount; index++)
|
||||
{
|
||||
if (op.GetSource(index) == dest)
|
||||
{
|
||||
op.SetSource(index, normOp.Dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -116,6 +116,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public void AddInUseWaitable(MultiFenceHolder waitable)
|
||||
{
|
||||
lock (_commandBuffers)
|
||||
{
|
||||
for (int i = 0; i < _totalCommandBuffers; i++)
|
||||
{
|
||||
ref var entry = ref _commandBuffers[i];
|
||||
|
||||
if (entry.InUse)
|
||||
{
|
||||
AddWaitable(i, waitable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddDependency(int cbIndex, CommandBufferScoped dependencyCbs)
|
||||
{
|
||||
Debug.Assert(_commandBuffers[cbIndex].InUse);
|
||||
|
@@ -227,6 +227,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
|
||||
CommandBuffer = (Cbs = Gd.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer;
|
||||
Gd.RegisterFlush();
|
||||
|
||||
// Restore per-command buffer state.
|
||||
|
||||
|
@@ -11,7 +11,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
public ulong ID;
|
||||
public MultiFenceHolder Waitable;
|
||||
public ulong FlushId;
|
||||
public bool Signalled;
|
||||
|
||||
public bool NeedsFlush(ulong currentFlushId)
|
||||
{
|
||||
return (long)(FlushId - currentFlushId) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
private ulong _firstHandle = 0;
|
||||
@@ -19,6 +25,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly VulkanRenderer _gd;
|
||||
private readonly Device _device;
|
||||
private List<SyncHandle> _handles;
|
||||
private ulong FlushId;
|
||||
|
||||
public SyncManager(VulkanRenderer gd, Device device)
|
||||
{
|
||||
@@ -27,17 +34,33 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_handles = new List<SyncHandle>();
|
||||
}
|
||||
|
||||
public void Create(ulong id)
|
||||
public void RegisterFlush()
|
||||
{
|
||||
MultiFenceHolder waitable = new MultiFenceHolder();
|
||||
FlushId++;
|
||||
}
|
||||
|
||||
_gd.FlushAllCommands();
|
||||
_gd.CommandBufferPool.AddWaitable(waitable);
|
||||
public void Create(ulong id, bool strict)
|
||||
{
|
||||
ulong flushId = FlushId;
|
||||
MultiFenceHolder waitable = new MultiFenceHolder();
|
||||
if (strict || _gd.InterruptAction == null)
|
||||
{
|
||||
_gd.FlushAllCommands();
|
||||
_gd.CommandBufferPool.AddWaitable(waitable);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't flush commands, instead wait for the current command buffer to finish.
|
||||
// If this sync is waited on before the command buffer is submitted, interrupt the gpu thread and flush it manually.
|
||||
|
||||
_gd.CommandBufferPool.AddInUseWaitable(waitable);
|
||||
}
|
||||
|
||||
SyncHandle handle = new SyncHandle
|
||||
{
|
||||
ID = id,
|
||||
Waitable = waitable
|
||||
Waitable = waitable,
|
||||
FlushId = flushId
|
||||
};
|
||||
|
||||
lock (_handles)
|
||||
@@ -107,6 +130,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.NeedsFlush(FlushId))
|
||||
{
|
||||
_gd.InterruptAction(() =>
|
||||
{
|
||||
if (result.NeedsFlush(FlushId))
|
||||
{
|
||||
_gd.FlushAllCommands();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool signaled = result.Signalled || result.Waitable.WaitForFences(_gd.Api, _device, 1000000000);
|
||||
if (!signaled)
|
||||
{
|
||||
@@ -132,7 +166,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
first = _handles.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (first == null) break;
|
||||
if (first == null || first.NeedsFlush(FlushId)) break;
|
||||
|
||||
bool signaled = first.Waitable.WaitForFences(_gd.Api, _device, 0);
|
||||
if (signaled)
|
||||
|
@@ -48,6 +48,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
internal DescriptorSetManager DescriptorSetManager { get; private set; }
|
||||
internal PipelineLayoutCache PipelineLayoutCache { get; private set; }
|
||||
internal BackgroundResources BackgroundResources { get; private set; }
|
||||
internal Action<Action> InterruptAction { get; private set; }
|
||||
|
||||
internal BufferManager BufferManager { get; private set; }
|
||||
|
||||
@@ -354,6 +355,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_pipeline?.FlushCommandsImpl();
|
||||
}
|
||||
|
||||
internal void RegisterFlush()
|
||||
{
|
||||
_syncManager.RegisterFlush();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
|
||||
{
|
||||
return BufferManager.GetData(buffer, offset, size);
|
||||
@@ -593,9 +599,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
action();
|
||||
}
|
||||
|
||||
public void CreateSync(ulong id)
|
||||
public void CreateSync(ulong id, bool strict)
|
||||
{
|
||||
_syncManager.Create(id);
|
||||
_syncManager.Create(id, strict);
|
||||
}
|
||||
|
||||
public IProgram LoadProgramBinary(byte[] programBinary, bool isFragment, ShaderInfo info)
|
||||
@@ -613,6 +619,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return _syncManager.GetCurrent();
|
||||
}
|
||||
|
||||
public void SetInterruptAction(Action<Action> interruptAction)
|
||||
{
|
||||
InterruptAction = interruptAction;
|
||||
}
|
||||
|
||||
public void Screenshot()
|
||||
{
|
||||
_window.ScreenCaptureRequested = true;
|
||||
|
@@ -298,6 +298,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(67)] //3.0.0+
|
||||
// IsIlluminanceAvailable() -> bool
|
||||
public ResultCode IsIlluminanceAvailable(ServiceCtx context)
|
||||
{
|
||||
// NOTE: This should call IsAmbientLightSensorAvailable through to Lbl, but there's no situation where we'd want false.
|
||||
context.ResponseData.Write(true);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(68)]
|
||||
// SetAutoSleepDisabled(u8)
|
||||
public ResultCode SetAutoSleepDisabled(ServiceCtx context)
|
||||
@@ -318,6 +330,19 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(71)] //5.0.0+
|
||||
// GetCurrentIlluminanceEx() -> (bool, f32)
|
||||
public ResultCode GetCurrentIlluminanceEx(ServiceCtx context)
|
||||
{
|
||||
// TODO: The light value should be configurable - presumably users using software that takes advantage will want control.
|
||||
context.ResponseData.Write(1); // OverLimit
|
||||
context.ResponseData.Write(10000f); // Lux - 10K lux is ambient light.
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(80)] // 4.0.0+
|
||||
// SetWirelessPriorityMode(s32 wireless_priority_mode)
|
||||
public ResultCode SetWirelessPriorityMode(ServiceCtx context)
|
||||
|
@@ -39,14 +39,10 @@ namespace Ryujinx.Memory.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
[Platform(Exclude = "MacOsX")]
|
||||
public void Test_Alias()
|
||||
{
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
using MemoryBlock backing = new MemoryBlock(0x10000, MemoryAllocationFlags.Mirrorable);
|
||||
using MemoryBlock toAlias = new MemoryBlock(0x10000, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
|
||||
|
||||
@@ -58,14 +54,10 @@ namespace Ryujinx.Memory.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
[Platform(Exclude = "MacOsX")]
|
||||
public void Test_AliasRandom()
|
||||
{
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
using MemoryBlock backing = new MemoryBlock(0x80000, MemoryAllocationFlags.Mirrorable);
|
||||
using MemoryBlock toAlias = new MemoryBlock(0x80000, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
|
||||
|
||||
@@ -94,14 +86,10 @@ namespace Ryujinx.Memory.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
[Platform(Exclude = "MacOsX")]
|
||||
public void Test_AliasMapLeak()
|
||||
{
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
ulong pageSize = 4096;
|
||||
ulong size = 100000 * pageSize; // The mappings limit on Linux is usually around 65K, so let's make sure we are above that.
|
||||
|
||||
|
@@ -379,7 +379,12 @@ namespace Ryujinx.Memory
|
||||
/// <remarks>
|
||||
/// It's an error to use the memory block after disposal.
|
||||
/// </remarks>
|
||||
public void Dispose() => FreeMemory();
|
||||
public void Dispose()
|
||||
{
|
||||
FreeMemory();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~MemoryBlock() => FreeMemory();
|
||||
|
||||
|
@@ -9,6 +9,7 @@ using Ryujinx.Memory.Tests;
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
@@ -57,14 +58,10 @@ namespace Ryujinx.Tests.Memory
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
[Platform(Exclude = "MacOsX")]
|
||||
public void PartialUnmap([Values] bool readOnly)
|
||||
{
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up an address space to test partial unmapping.
|
||||
// Should register the signal handler to deal with this on Windows.
|
||||
ulong vaSize = 0x100000;
|
||||
@@ -78,11 +75,13 @@ namespace Ryujinx.Tests.Memory
|
||||
|
||||
ref var state = ref PartialUnmapState.GetRef();
|
||||
|
||||
Thread testThread = null;
|
||||
bool shouldAccess = true;
|
||||
|
||||
try
|
||||
{
|
||||
// Globally reset the struct for handling partial unmap races.
|
||||
PartialUnmapState.Reset();
|
||||
bool shouldAccess = true;
|
||||
bool error = false;
|
||||
|
||||
// Create a large mapping.
|
||||
@@ -93,8 +92,6 @@ namespace Ryujinx.Tests.Memory
|
||||
memory.Reprotect(0, vaSize, MemoryPermission.Read);
|
||||
}
|
||||
|
||||
Thread testThread;
|
||||
|
||||
if (readOnly)
|
||||
{
|
||||
// Write a value to the physical memory, then try to read it repeately from virtual.
|
||||
@@ -193,6 +190,10 @@ namespace Ryujinx.Tests.Memory
|
||||
}
|
||||
finally
|
||||
{
|
||||
// In case something failed, we want to ensure the test thread is dead before disposing of the memory.
|
||||
shouldAccess = false;
|
||||
testThread?.Join();
|
||||
|
||||
exceptionHandler.Dispose();
|
||||
unusedMainMemory.Dispose();
|
||||
memory.Dispose();
|
||||
@@ -201,13 +202,10 @@ namespace Ryujinx.Tests.Memory
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
[Platform(Exclude = "MacOsX")]
|
||||
public unsafe void PartialUnmapNative()
|
||||
{
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Memory aliasing tests fail on CI at the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up an address space to test partial unmapping.
|
||||
// Should register the signal handler to deal with this on Windows.
|
||||
@@ -284,26 +282,17 @@ namespace Ryujinx.Tests.Memory
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Only test in Windows, as this is only used on Windows and uses Windows APIs for trimming.
|
||||
[Platform("Win")]
|
||||
[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
|
||||
public void ThreadLocalMap()
|
||||
{
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
// Only test in Windows, as this is only used on Windows and uses Windows APIs for trimming.
|
||||
return;
|
||||
}
|
||||
|
||||
PartialUnmapState.Reset();
|
||||
ref var state = ref PartialUnmapState.GetRef();
|
||||
|
||||
bool running = true;
|
||||
var testThread = new Thread(() =>
|
||||
{
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
// Need this here to avoid a warning.
|
||||
return;
|
||||
}
|
||||
|
||||
PartialUnmapState.GetRef().RetryFromAccessViolation();
|
||||
while (running)
|
||||
{
|
||||
@@ -330,14 +319,10 @@ namespace Ryujinx.Tests.Memory
|
||||
}
|
||||
|
||||
[Test]
|
||||
// Only test in Windows, as this is only used on Windows and uses Windows APIs for trimming.
|
||||
[Platform("Win")]
|
||||
public unsafe void ThreadLocalMapNative()
|
||||
{
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
// Only test in Windows, as this is only used on Windows and uses Windows APIs for trimming.
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTranslator();
|
||||
|
||||
PartialUnmapState.Reset();
|
||||
@@ -481,4 +466,4 @@ namespace Ryujinx.Tests.Memory
|
||||
Assert.False(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -68,53 +68,6 @@ namespace Ryujinx.Ui.App.Common
|
||||
_cancellationToken?.Cancel();
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetFilesInDirectory(string directory)
|
||||
{
|
||||
Stack<string> stack = new Stack<string>();
|
||||
|
||||
stack.Push(directory);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
string dir = stack.Pop();
|
||||
string[] content = Array.Empty<string>();
|
||||
|
||||
try
|
||||
{
|
||||
content = Directory.GetFiles(dir, "*");
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Failed to get access to directory: \"{dir}\"");
|
||||
}
|
||||
|
||||
if (content.Length > 0)
|
||||
{
|
||||
foreach (string file in content)
|
||||
{
|
||||
yield return file;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
content = Directory.GetDirectories(dir);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Failed to get access to directory: \"{dir}\"");
|
||||
}
|
||||
|
||||
if (content.Length > 0)
|
||||
{
|
||||
foreach (string subdir in content)
|
||||
{
|
||||
stack.Push(subdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadControlData(IFileSystem controlFs, Span<byte> outProperty)
|
||||
{
|
||||
using var controlFile = new UniqueRef<IFile>();
|
||||
@@ -151,26 +104,28 @@ namespace Ryujinx.Ui.App.Common
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (string app in GetFilesInDirectory(appDir))
|
||||
try
|
||||
{
|
||||
if (_cancellationToken.Token.IsCancellationRequested)
|
||||
foreach (string app in Directory.EnumerateFiles(appDir, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string extension = Path.GetExtension(app).ToLower();
|
||||
|
||||
if ((extension == ".nsp") ||
|
||||
(extension == ".pfs0") ||
|
||||
(extension == ".xci") ||
|
||||
(extension == ".nca") ||
|
||||
(extension == ".nro") ||
|
||||
(extension == ".nso"))
|
||||
{
|
||||
applications.Add(app);
|
||||
numApplicationsFound++;
|
||||
if (_cancellationToken.Token.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string extension = Path.GetExtension(app).ToLower();
|
||||
|
||||
if (!File.GetAttributes(app).HasFlag(FileAttributes.Hidden) && extension is ".nsp" or ".pfs0" or ".xci" or ".nca" or ".nro" or ".nso")
|
||||
{
|
||||
applications.Add(app);
|
||||
numApplicationsFound++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Failed to get access to directory: \"{appDir}\"");
|
||||
}
|
||||
}
|
||||
|
||||
// Loops through applications list, creating a struct and then firing an event containing the struct for each application
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user