Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
e43390c723 | |||
5af1327068 | |||
88a8d1e567 | |||
bf77d1cab9 | |||
1ca0517c99 | |||
599d485bff | |||
60e16c15b6 | |||
2068445939 | |||
a4fc9f8050 | |||
5437d6cb13 | |||
7539e26144 | |||
1c3697b6a4 | |||
81f848e54f | |||
358a781639 |
@ -58,6 +58,8 @@ namespace Ryujinx.Ava
|
|||||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||||
private const int TargetFps = 60;
|
private const int TargetFps = 60;
|
||||||
|
|
||||||
|
private const float VolumeDelta = 0.05f;
|
||||||
|
|
||||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||||
|
|
||||||
private readonly long _ticksPerFrame;
|
private readonly long _ticksPerFrame;
|
||||||
@ -73,6 +75,7 @@ namespace Ryujinx.Ava
|
|||||||
private bool _isStopped;
|
private bool _isStopped;
|
||||||
private bool _isActive;
|
private bool _isActive;
|
||||||
private long _lastCursorMoveTime;
|
private long _lastCursorMoveTime;
|
||||||
|
private float _newVolume;
|
||||||
private long _ticks = 0;
|
private long _ticks = 0;
|
||||||
|
|
||||||
private KeyboardHotkeyState _prevHotkeyState;
|
private KeyboardHotkeyState _prevHotkeyState;
|
||||||
@ -1003,6 +1006,18 @@ namespace Ryujinx.Ava
|
|||||||
GraphicsConfig.ResScale =
|
GraphicsConfig.ResScale =
|
||||||
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
||||||
break;
|
break;
|
||||||
|
case KeyboardHotkeyState.VolumeUp:
|
||||||
|
_newVolume = MathF.Round((Device.GetVolume() + VolumeDelta), 2);
|
||||||
|
Device.SetVolume(_newVolume);
|
||||||
|
|
||||||
|
_parent.ViewModel.Volume = Device.GetVolume();
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.VolumeDown:
|
||||||
|
_newVolume = MathF.Round((Device.GetVolume() - VolumeDelta), 2);
|
||||||
|
Device.SetVolume(_newVolume);
|
||||||
|
|
||||||
|
_parent.ViewModel.Volume = Device.GetVolume();
|
||||||
|
break;
|
||||||
case KeyboardHotkeyState.None:
|
case KeyboardHotkeyState.None:
|
||||||
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
||||||
break;
|
break;
|
||||||
@ -1068,6 +1083,14 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
state = KeyboardHotkeyState.ResScaleDown;
|
state = KeyboardHotkeyState.ResScaleDown;
|
||||||
}
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeUp))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.VolumeUp;
|
||||||
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeDown))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.VolumeDown;
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -574,12 +574,12 @@
|
|||||||
"Discard": "Discard",
|
"Discard": "Discard",
|
||||||
"UserProfilesSetProfileImage": "Set Profile Image",
|
"UserProfilesSetProfileImage": "Set Profile Image",
|
||||||
"UserProfileEmptyNameError": "Name is required",
|
"UserProfileEmptyNameError": "Name is required",
|
||||||
"UserProfileNoImageError": "Profile image must be set",
|
"UserProfileNoImageError": "Profile image must be set",
|
||||||
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
|
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
|
||||||
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
||||||
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
||||||
"UserProfilesName": "Name:",
|
"UserProfilesName": "Name:",
|
||||||
"UserProfilesUserId" : "User Id:",
|
"UserProfilesUserId": "User Id:",
|
||||||
"SettingsTabGraphicsBackend": "Graphics Backend",
|
"SettingsTabGraphicsBackend": "Graphics Backend",
|
||||||
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
||||||
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
||||||
@ -589,5 +589,8 @@
|
|||||||
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
||||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
|
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
|
||||||
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
||||||
|
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||||
|
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||||
|
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||||
"VolumeShort": "Vol"
|
"VolumeShort": "Vol"
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
Pause,
|
Pause,
|
||||||
ToggleMute,
|
ToggleMute,
|
||||||
ResScaleUp,
|
ResScaleUp,
|
||||||
ResScaleDown
|
ResScaleDown,
|
||||||
|
VolumeUp,
|
||||||
|
VolumeDown
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
using ICSharpCode.SharpZipLib.GZip;
|
using ICSharpCode.SharpZipLib.GZip;
|
||||||
using ICSharpCode.SharpZipLib.Tar;
|
using ICSharpCode.SharpZipLib.Tar;
|
||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
@ -11,11 +13,13 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -40,6 +44,8 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
||||||
|
|
||||||
|
public static bool UpdateSuccessful { get; private set; }
|
||||||
|
|
||||||
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
||||||
{
|
{
|
||||||
if (Running)
|
if (Running)
|
||||||
@ -198,11 +204,18 @@ namespace Ryujinx.Modules
|
|||||||
_buildSize = -1;
|
_buildSize = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
// Show a message asking the user if they want to update
|
// Show a message asking the user if they want to update
|
||||||
UpdaterWindow updateDialog = new(mainWindow, newVersion, _buildUrl);
|
var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||||
await updateDialog.ShowDialog(mainWindow);
|
LocaleManager.Instance["RyujinxUpdaterMessage"],
|
||||||
|
$"{Program.Version} -> {newVersion}");
|
||||||
|
|
||||||
|
if (shouldUpdate)
|
||||||
|
{
|
||||||
|
UpdateRyujinx(mainWindow, _buildUrl);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,8 +229,10 @@ namespace Ryujinx.Modules
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateRyujinx(UpdaterWindow updateDialog, string downloadUrl)
|
public static async void UpdateRyujinx(Window parent, string downloadUrl)
|
||||||
{
|
{
|
||||||
|
UpdateSuccessful = false;
|
||||||
|
|
||||||
// Empty update dir, although it shouldn't ever have anything inside it
|
// Empty update dir, although it shouldn't ever have anything inside it
|
||||||
if (Directory.Exists(UpdateDir))
|
if (Directory.Exists(UpdateDir))
|
||||||
{
|
{
|
||||||
@ -228,25 +243,56 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
||||||
|
|
||||||
// Download the update .zip
|
var taskDialog = new TaskDialog()
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterDownloading"];
|
{
|
||||||
updateDialog.ProgressBar.Value = 0;
|
Header = LocaleManager.Instance["RyujinxUpdater"],
|
||||||
updateDialog.ProgressBar.Maximum = 100;
|
SubHeader = LocaleManager.Instance["UpdaterDownloading"],
|
||||||
|
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
|
||||||
|
Buttons = { },
|
||||||
|
ShowProgressBar = true
|
||||||
|
};
|
||||||
|
|
||||||
Task.Run(() =>
|
taskDialog.XamlRoot = parent;
|
||||||
|
|
||||||
|
taskDialog.Opened += (s, e) =>
|
||||||
{
|
{
|
||||||
if (_buildSize >= 0)
|
if (_buildSize >= 0)
|
||||||
{
|
{
|
||||||
DoUpdateWithMultipleThreads(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithMultipleThreads(taskDialog, downloadUrl, updateFile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
await taskDialog.ShowAsync(true);
|
||||||
|
|
||||||
|
if (UpdateSuccessful)
|
||||||
|
{
|
||||||
|
var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||||
|
LocaleManager.Instance["DialogUpdaterCompleteMessage"],
|
||||||
|
LocaleManager.Instance["DialogUpdaterRestartMessage"]);
|
||||||
|
|
||||||
|
if (shouldRestart)
|
||||||
|
{
|
||||||
|
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
||||||
|
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||||
|
string ryuArg = string.Join(" ", Environment.GetCommandLineArgs().Skip(1).ToArray());
|
||||||
|
|
||||||
|
if (!OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
chmod(ryuExe, Convert.ToUInt32("0777", 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.Start(ryuExe, ryuArg);
|
||||||
|
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoUpdateWithMultipleThreads(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||||
{
|
{
|
||||||
// Multi-Threaded Updater
|
// Multi-Threaded Updater
|
||||||
long chunkSize = _buildSize / ConnectionCount;
|
long chunkSize = _buildSize / ConnectionCount;
|
||||||
@ -290,7 +336,7 @@ namespace Ryujinx.Modules
|
|||||||
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
||||||
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
||||||
|
|
||||||
updateDialog.ProgressBar.Value = totalProgressPercentage / ConnectionCount;
|
taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
|
||||||
};
|
};
|
||||||
|
|
||||||
client.DownloadDataCompleted += (_, args) =>
|
client.DownloadDataCompleted += (_, args) =>
|
||||||
@ -301,6 +347,8 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
webClients[index].Dispose();
|
webClients[index].Dispose();
|
||||||
|
|
||||||
|
taskDialog.Hide();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,14 +368,14 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
InstallUpdate(updateDialog, updateFile);
|
InstallUpdate(taskDialog, updateFile);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, e.Message);
|
Logger.Warning?.Print(LogClass.Application, e.Message);
|
||||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||||
|
|
||||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -348,7 +396,7 @@ namespace Ryujinx.Modules
|
|||||||
webClients[j].CancelAsync();
|
webClients[j].CancelAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -356,7 +404,7 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoUpdateWithSingleThreadWorker(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
private static void DoUpdateWithSingleThreadWorker(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||||
{
|
{
|
||||||
using (HttpClient client = new HttpClient())
|
using (HttpClient client = new HttpClient())
|
||||||
{
|
{
|
||||||
@ -384,19 +432,26 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
byteWritten += readSize;
|
byteWritten += readSize;
|
||||||
|
|
||||||
updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100;
|
taskDialog.SetProgressBarState(GetPercentage(byteWritten, totalBytes), TaskDialogProgressState.Normal);
|
||||||
|
|
||||||
updateFileStream.Write(buffer, 0, readSize);
|
updateFileStream.Write(buffer, 0, readSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallUpdate(updateDialog, updateFile);
|
InstallUpdate(taskDialog, updateFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoUpdateWithSingleThread(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static double GetPercentage(double value, double max)
|
||||||
{
|
{
|
||||||
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile));
|
return max == 0 ? 0 : value / max * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DoUpdateWithSingleThread(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||||
|
{
|
||||||
|
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile));
|
||||||
worker.Name = "Updater.SingleThreadWorker";
|
worker.Name = "Updater.SingleThreadWorker";
|
||||||
worker.Start();
|
worker.Start();
|
||||||
}
|
}
|
||||||
@ -414,11 +469,11 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async void InstallUpdate(UpdaterWindow updateDialog, string updateFile)
|
private static async void InstallUpdate(TaskDialog taskDialog, string updateFile)
|
||||||
{
|
{
|
||||||
// Extract Update
|
// Extract Update
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterExtracting"];
|
taskDialog.SubHeader = LocaleManager.Instance["UpdaterExtracting"];
|
||||||
updateDialog.ProgressBar.Value = 0;
|
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux())
|
if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
@ -426,8 +481,6 @@ namespace Ryujinx.Modules
|
|||||||
using (Stream gzipStream = new GZipInputStream(inStream))
|
using (Stream gzipStream = new GZipInputStream(inStream))
|
||||||
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
|
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Maximum = inStream.Length;
|
|
||||||
|
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
TarEntry tarEntry;
|
TarEntry tarEntry;
|
||||||
@ -450,12 +503,12 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Value += entry.Size;
|
taskDialog.SetProgressBarState(GetPercentage(entry.Size, inStream.Length), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
updateDialog.ProgressBar.Value = inStream.Length;
|
taskDialog.SetProgressBarState(100, TaskDialogProgressState.Normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -463,12 +516,12 @@ namespace Ryujinx.Modules
|
|||||||
using (Stream inStream = File.OpenRead(updateFile))
|
using (Stream inStream = File.OpenRead(updateFile))
|
||||||
using (ZipFile zipFile = new ZipFile(inStream))
|
using (ZipFile zipFile = new ZipFile(inStream))
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Maximum = zipFile.Count;
|
|
||||||
|
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
double count = 0;
|
||||||
foreach (ZipEntry zipEntry in zipFile)
|
foreach (ZipEntry zipEntry in zipFile)
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
if (zipEntry.IsDirectory) continue;
|
if (zipEntry.IsDirectory) continue;
|
||||||
|
|
||||||
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
||||||
@ -485,7 +538,7 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Value++;
|
taskDialog.SetProgressBarState(GetPercentage(count, zipFile.Count), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -497,22 +550,23 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
||||||
|
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterRenaming"];
|
taskDialog.SubHeader = LocaleManager.Instance["UpdaterRenaming"];
|
||||||
updateDialog.ProgressBar.Value = 0;
|
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||||
updateDialog.ProgressBar.Maximum = allFiles.Count;
|
|
||||||
|
|
||||||
// Replace old files
|
// Replace old files
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
double count = 0;
|
||||||
foreach (string file in allFiles)
|
foreach (string file in allFiles)
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Move(file, file + ".ryuold");
|
File.Move(file, file + ".ryuold");
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Value++;
|
taskDialog.SetProgressBarState(GetPercentage(count, allFiles.Count), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -523,23 +577,20 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterAddingFiles"];
|
taskDialog.SubHeader = LocaleManager.Instance["UpdaterAddingFiles"];
|
||||||
updateDialog.ProgressBar.Value = 0;
|
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||||
updateDialog.ProgressBar.Maximum = Directory.GetFiles(UpdatePublishDir, "*", SearchOption.AllDirectories).Length;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, updateDialog);
|
MoveAllFilesOver(UpdatePublishDir, HomeDir, taskDialog);
|
||||||
});
|
});
|
||||||
|
|
||||||
Directory.Delete(UpdateDir, true);
|
Directory.Delete(UpdateDir, true);
|
||||||
|
|
||||||
SetUnixPermissions();
|
SetUnixPermissions();
|
||||||
|
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["DialogUpdaterCompleteMessage"];
|
UpdateSuccessful = true;
|
||||||
updateDialog.SecondaryText.Text = LocaleManager.Instance["DialogUpdaterRestartMessage"];
|
|
||||||
|
|
||||||
updateDialog.ProgressBar.IsVisible = false;
|
taskDialog.Hide();
|
||||||
updateDialog.ButtonBox.IsVisible = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
@ -618,8 +669,9 @@ namespace Ryujinx.Modules
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MoveAllFilesOver(string root, string dest, UpdaterWindow dialog)
|
private static void MoveAllFilesOver(string root, string dest, TaskDialog taskDialog)
|
||||||
{
|
{
|
||||||
|
var total = Directory.GetFiles(root, "*", SearchOption.AllDirectories).Length;
|
||||||
foreach (string directory in Directory.GetDirectories(root))
|
foreach (string directory in Directory.GetDirectories(root))
|
||||||
{
|
{
|
||||||
string dirName = Path.GetFileName(directory);
|
string dirName = Path.GetFileName(directory);
|
||||||
@ -629,16 +681,18 @@ namespace Ryujinx.Modules
|
|||||||
Directory.CreateDirectory(Path.Combine(dest, dirName));
|
Directory.CreateDirectory(Path.Combine(dest, dirName));
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveAllFilesOver(directory, Path.Combine(dest, dirName), dialog);
|
MoveAllFilesOver(directory, Path.Combine(dest, dirName), taskDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double count = 0;
|
||||||
foreach (string file in Directory.GetFiles(root))
|
foreach (string file in Directory.GetFiles(root))
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
|
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
dialog.ProgressBar.Value++;
|
taskDialog.SetProgressBarState(GetPercentage(count, total), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
Title="Ryujinx - About"
|
|
||||||
Width="850"
|
Width="850"
|
||||||
Height="550"
|
Height="550"
|
||||||
MinWidth="500"
|
MinWidth="500"
|
||||||
|
@ -257,6 +257,22 @@
|
|||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
<window:StyleableWindow
|
|
||||||
x:Class="Ryujinx.Ava.Ui.Windows.UpdaterWindow"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
|
||||||
Title="Ryujinx Updater"
|
|
||||||
Width="500"
|
|
||||||
Height="500"
|
|
||||||
MinWidth="500"
|
|
||||||
MinHeight="500"
|
|
||||||
d:DesignHeight="350"
|
|
||||||
d:DesignWidth="400"
|
|
||||||
CanResize="False"
|
|
||||||
SizeToContent="Height"
|
|
||||||
WindowStartupLocation="CenterOwner"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
<Grid
|
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock
|
|
||||||
Name="MainText"
|
|
||||||
Grid.Row="1"
|
|
||||||
Height="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<TextBlock
|
|
||||||
Name="SecondaryText"
|
|
||||||
Grid.Row="2"
|
|
||||||
Height="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<ProgressBar
|
|
||||||
Name="ProgressBar"
|
|
||||||
Grid.Row="3"
|
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
IsVisible="False"
|
|
||||||
Maximum="100"
|
|
||||||
Minimum="0" />
|
|
||||||
<StackPanel
|
|
||||||
Name="ButtonBox"
|
|
||||||
Grid.Row="4"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
IsVisible="False"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Spacing="20">
|
|
||||||
<Button MinWidth="50" Command="{Binding YesPressed}">
|
|
||||||
<TextBlock Text="{locale:Locale InputDialogYes}" TextAlignment="Center" />
|
|
||||||
</Button>
|
|
||||||
<Button MinWidth="50" Command="{Binding NoPressed}">
|
|
||||||
<TextBlock Text="{locale:Locale InputDialogNo}" TextAlignment="Center" />
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</window:StyleableWindow>
|
|
@ -1,73 +0,0 @@
|
|||||||
using Ryujinx.Ava.Common.Locale;
|
|
||||||
using Ryujinx.Modules;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Windows
|
|
||||||
{
|
|
||||||
public partial class UpdaterWindow : StyleableWindow
|
|
||||||
{
|
|
||||||
private readonly string _buildUrl;
|
|
||||||
private readonly MainWindow _mainWindow;
|
|
||||||
private readonly Version _newVersion;
|
|
||||||
private bool _restartQuery;
|
|
||||||
|
|
||||||
public UpdaterWindow()
|
|
||||||
{
|
|
||||||
DataContext = this;
|
|
||||||
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Title = LocaleManager.Instance["RyujinxUpdater"];
|
|
||||||
}
|
|
||||||
|
|
||||||
public UpdaterWindow(MainWindow mainWindow, Version newVersion, string buildUrl) : this()
|
|
||||||
{
|
|
||||||
_mainWindow = mainWindow;
|
|
||||||
_newVersion = newVersion;
|
|
||||||
_buildUrl = buildUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
private static extern int chmod(string path, uint mode);
|
|
||||||
|
|
||||||
public void YesPressed()
|
|
||||||
{
|
|
||||||
if (_restartQuery)
|
|
||||||
{
|
|
||||||
string ryuName = OperatingSystem.IsWindows() ? "Ryujinx.Ava.exe" : "Ryujinx.Ava";
|
|
||||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
|
||||||
string ryuArg = string.Join(" ", Environment.GetCommandLineArgs().AsEnumerable().Skip(1).ToArray());
|
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows())
|
|
||||||
{
|
|
||||||
chmod(ryuExe, 0777);
|
|
||||||
}
|
|
||||||
|
|
||||||
Process.Start(ryuExe, ryuArg);
|
|
||||||
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ButtonBox.IsVisible = false;
|
|
||||||
ProgressBar.IsVisible = true;
|
|
||||||
|
|
||||||
SecondaryText.Text = "";
|
|
||||||
_restartQuery = true;
|
|
||||||
|
|
||||||
Updater.UpdateRyujinx(this, _buildUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NoPressed()
|
|
||||||
{
|
|
||||||
_mainWindow.UpdateMenuItem.IsEnabled = true;
|
|
||||||
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,5 +9,7 @@
|
|||||||
public Key ToggleMute { get; set; }
|
public Key ToggleMute { get; set; }
|
||||||
public Key ResScaleUp { get; set; }
|
public Key ResScaleUp { get; set; }
|
||||||
public Key ResScaleDown { get; set; }
|
public Key ResScaleDown { get; set; }
|
||||||
|
public Key VolumeUp { get; set; }
|
||||||
|
public Key VolumeDown { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
89
Ryujinx.Common/Memory/SpanOrArray.cs
Normal file
89
Ryujinx.Common/Memory/SpanOrArray.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Memory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A struct that can represent both a Span and Array.
|
||||||
|
/// This is useful to keep the Array representation when possible to avoid copies.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Element Type</typeparam>
|
||||||
|
public ref struct SpanOrArray<T> where T : unmanaged
|
||||||
|
{
|
||||||
|
public readonly T[] Array;
|
||||||
|
public readonly ReadOnlySpan<T> Span;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new SpanOrArray from an array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Array to store</param>
|
||||||
|
public SpanOrArray(T[] array)
|
||||||
|
{
|
||||||
|
Array = array;
|
||||||
|
Span = ReadOnlySpan<T>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new SpanOrArray from a readonly span.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Span to store</param>
|
||||||
|
public SpanOrArray(ReadOnlySpan<T> span)
|
||||||
|
{
|
||||||
|
Array = null;
|
||||||
|
Span = span;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return the contained array, or convert the span if necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array containing the data</returns>
|
||||||
|
public T[] ToArray()
|
||||||
|
{
|
||||||
|
return Array ?? Span.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return a ReadOnlySpan from either the array or ReadOnlySpan.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A ReadOnlySpan containing the data</returns>
|
||||||
|
public ReadOnlySpan<T> AsSpan()
|
||||||
|
{
|
||||||
|
return Array ?? Span;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast an array to a SpanOrArray.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Source array</param>
|
||||||
|
public static implicit operator SpanOrArray<T>(T[] array)
|
||||||
|
{
|
||||||
|
return new SpanOrArray<T>(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast a ReadOnlySpan to a SpanOrArray.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">Source ReadOnlySpan</param>
|
||||||
|
public static implicit operator SpanOrArray<T>(ReadOnlySpan<T> span)
|
||||||
|
{
|
||||||
|
return new SpanOrArray<T>(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast a Span to a SpanOrArray.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">Source Span</param>
|
||||||
|
public static implicit operator SpanOrArray<T>(Span<T> span)
|
||||||
|
{
|
||||||
|
return new SpanOrArray<T>(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast a SpanOrArray to a ReadOnlySpan
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="spanOrArray">Source SpanOrArray</param>
|
||||||
|
public static implicit operator ReadOnlySpan<T>(SpanOrArray<T> spanOrArray)
|
||||||
|
{
|
||||||
|
return spanOrArray.AsSpan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
@ -17,9 +18,9 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
ReadOnlySpan<byte> GetData();
|
ReadOnlySpan<byte> GetData();
|
||||||
ReadOnlySpan<byte> GetData(int layer, int level);
|
ReadOnlySpan<byte> GetData(int layer, int level);
|
||||||
|
|
||||||
void SetData(ReadOnlySpan<byte> data);
|
void SetData(SpanOrArray<byte> data);
|
||||||
void SetData(ReadOnlySpan<byte> data, int layer, int level);
|
void SetData(SpanOrArray<byte> data, int layer, int level);
|
||||||
void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region);
|
void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region);
|
||||||
void SetStorage(BufferRange buffer);
|
void SetStorage(BufferRange buffer);
|
||||||
void Release();
|
void Release();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
|
||||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -107,19 +108,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data.ToArray()));
|
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data.ToArray()));
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level);
|
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level, region);
|
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level, region);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
|
@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
|
|
||||||
if (target != null)
|
if (target != null)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<byte> data;
|
byte[] data;
|
||||||
if (srcLinear)
|
if (srcLinear)
|
||||||
{
|
{
|
||||||
data = LayoutConverter.ConvertLinearStridedToLinear(
|
data = LayoutConverter.ConvertLinearStridedToLinear(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
@ -136,11 +137,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public LinkedListNode<Texture> CacheNode { get; set; }
|
public LinkedListNode<Texture> CacheNode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event to fire when texture data is disposed.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<Texture> Disposed;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Physical memory ranges where the texture data is located.
|
/// Physical memory ranges where the texture data is located.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -720,9 +716,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data = ConvertToHostCompatibleFormat(data);
|
SpanOrArray<byte> result = ConvertToHostCompatibleFormat(data);
|
||||||
|
|
||||||
HostTexture.SetData(data);
|
HostTexture.SetData(result);
|
||||||
|
|
||||||
_hasData = true;
|
_hasData = true;
|
||||||
}
|
}
|
||||||
@ -731,7 +727,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// Uploads new texture data to the host GPU.
|
/// Uploads new texture data to the host GPU.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">New data</param>
|
/// <param name="data">New data</param>
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
BlacklistScale();
|
BlacklistScale();
|
||||||
|
|
||||||
@ -750,7 +746,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="data">New data</param>
|
/// <param name="data">New data</param>
|
||||||
/// <param name="layer">Target layer</param>
|
/// <param name="layer">Target layer</param>
|
||||||
/// <param name="level">Target level</param>
|
/// <param name="level">Target level</param>
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
BlacklistScale();
|
BlacklistScale();
|
||||||
|
|
||||||
@ -786,7 +782,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="level">Mip level to convert</param>
|
/// <param name="level">Mip level to convert</param>
|
||||||
/// <param name="single">True to convert a single slice</param>
|
/// <param name="single">True to convert a single slice</param>
|
||||||
/// <returns>Converted data</returns>
|
/// <returns>Converted data</returns>
|
||||||
public ReadOnlySpan<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
|
public SpanOrArray<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
|
||||||
{
|
{
|
||||||
int width = Info.Width;
|
int width = Info.Width;
|
||||||
int height = Info.Height;
|
int height = Info.Height;
|
||||||
@ -799,9 +795,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
height = Math.Max(height >> level, 1);
|
height = Math.Max(height >> level, 1);
|
||||||
depth = Math.Max(depth >> level, 1);
|
depth = Math.Max(depth >> level, 1);
|
||||||
|
|
||||||
|
SpanOrArray<byte> result;
|
||||||
|
|
||||||
if (Info.IsLinear)
|
if (Info.IsLinear)
|
||||||
{
|
{
|
||||||
data = LayoutConverter.ConvertLinearStridedToLinear(
|
result = LayoutConverter.ConvertLinearStridedToLinear(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
Info.FormatInfo.BlockWidth,
|
Info.FormatInfo.BlockWidth,
|
||||||
@ -813,7 +811,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data = LayoutConverter.ConvertBlockLinearToLinear(
|
result = LayoutConverter.ConvertBlockLinearToLinear(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
depth,
|
depth,
|
||||||
@ -836,7 +834,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
|
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
|
||||||
{
|
{
|
||||||
if (!AstcDecoder.TryDecodeToRgba8P(
|
if (!AstcDecoder.TryDecodeToRgba8P(
|
||||||
data.ToArray(),
|
result.ToArray(),
|
||||||
Info.FormatInfo.BlockWidth,
|
Info.FormatInfo.BlockWidth,
|
||||||
Info.FormatInfo.BlockHeight,
|
Info.FormatInfo.BlockHeight,
|
||||||
width,
|
width,
|
||||||
@ -856,11 +854,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
decoded = BCnEncoder.EncodeBC7(decoded, width, height, depth, levels, layers);
|
decoded = BCnEncoder.EncodeBC7(decoded, width, height, depth, levels, layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
data = decoded;
|
result = decoded;
|
||||||
}
|
}
|
||||||
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
||||||
{
|
{
|
||||||
data = PixelConverter.ConvertR4G4ToR4G4B4A4(data);
|
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
|
||||||
}
|
}
|
||||||
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
||||||
{
|
{
|
||||||
@ -868,36 +866,36 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
case Format.Bc1RgbaSrgb:
|
case Format.Bc1RgbaSrgb:
|
||||||
case Format.Bc1RgbaUnorm:
|
case Format.Bc1RgbaUnorm:
|
||||||
data = BCnDecoder.DecodeBC1(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC1(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
case Format.Bc2Srgb:
|
case Format.Bc2Srgb:
|
||||||
case Format.Bc2Unorm:
|
case Format.Bc2Unorm:
|
||||||
data = BCnDecoder.DecodeBC2(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC2(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
case Format.Bc3Srgb:
|
case Format.Bc3Srgb:
|
||||||
case Format.Bc3Unorm:
|
case Format.Bc3Unorm:
|
||||||
data = BCnDecoder.DecodeBC3(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC3(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
case Format.Bc4Snorm:
|
case Format.Bc4Snorm:
|
||||||
case Format.Bc4Unorm:
|
case Format.Bc4Unorm:
|
||||||
data = BCnDecoder.DecodeBC4(data, width, height, depth, levels, layers, Format == Format.Bc4Snorm);
|
result = BCnDecoder.DecodeBC4(result, width, height, depth, levels, layers, Format == Format.Bc4Snorm);
|
||||||
break;
|
break;
|
||||||
case Format.Bc5Snorm:
|
case Format.Bc5Snorm:
|
||||||
case Format.Bc5Unorm:
|
case Format.Bc5Unorm:
|
||||||
data = BCnDecoder.DecodeBC5(data, width, height, depth, levels, layers, Format == Format.Bc5Snorm);
|
result = BCnDecoder.DecodeBC5(result, width, height, depth, levels, layers, Format == Format.Bc5Snorm);
|
||||||
break;
|
break;
|
||||||
case Format.Bc6HSfloat:
|
case Format.Bc6HSfloat:
|
||||||
case Format.Bc6HUfloat:
|
case Format.Bc6HUfloat:
|
||||||
data = BCnDecoder.DecodeBC6(data, width, height, depth, levels, layers, Format == Format.Bc6HSfloat);
|
result = BCnDecoder.DecodeBC6(result, width, height, depth, levels, layers, Format == Format.Bc6HSfloat);
|
||||||
break;
|
break;
|
||||||
case Format.Bc7Srgb:
|
case Format.Bc7Srgb:
|
||||||
case Format.Bc7Unorm:
|
case Format.Bc7Unorm:
|
||||||
data = BCnDecoder.DecodeBC7(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC7(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1445,7 +1443,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
DisposeTextures();
|
DisposeTextures();
|
||||||
|
|
||||||
HostTexture = hostTexture;
|
HostTexture = hostTexture;
|
||||||
InvalidatedSequence++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1600,6 +1597,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void DisposeTextures()
|
private void DisposeTextures()
|
||||||
{
|
{
|
||||||
|
InvalidatedSequence++;
|
||||||
|
|
||||||
_currentData = null;
|
_currentData = null;
|
||||||
HostTexture.Release();
|
HostTexture.Release();
|
||||||
|
|
||||||
@ -1634,8 +1633,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
DisposeTextures();
|
DisposeTextures();
|
||||||
|
|
||||||
Disposed?.Invoke(this);
|
|
||||||
|
|
||||||
if (Group.Storage == this)
|
if (Group.Storage == this)
|
||||||
{
|
{
|
||||||
Group.Dispose();
|
Group.Dispose();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Cpu.Tracking;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Cpu.Tracking;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
@ -348,9 +349,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
|
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
|
||||||
|
|
||||||
data = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true);
|
SpanOrArray<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true);
|
||||||
|
|
||||||
Storage.SetData(data, info.BaseLayer, info.BaseLevel);
|
Storage.SetData(result, info.BaseLayer, info.BaseLevel);
|
||||||
|
|
||||||
offsetIndex++;
|
offsetIndex++;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3728;
|
private const uint CodeGenVersion = 3732;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@ -123,7 +123,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
/// <param name="releaseCallback">Texture release callback</param>
|
/// <param name="releaseCallback">Texture release callback</param>
|
||||||
/// <param name="userObj">User defined object passed to the release callback</param>
|
/// <param name="userObj">User defined object passed to the release callback</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
|
/// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
|
||||||
public void EnqueueFrameThreadSafe(
|
/// <returns>True if the frame was added to the queue, false otherwise</returns>
|
||||||
|
public bool EnqueueFrameThreadSafe(
|
||||||
ulong pid,
|
ulong pid,
|
||||||
ulong address,
|
ulong address,
|
||||||
int width,
|
int width,
|
||||||
@ -140,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
{
|
{
|
||||||
if (!_context.PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
|
if (!_context.PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);
|
FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);
|
||||||
@ -184,6 +185,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
acquireCallback,
|
acquireCallback,
|
||||||
releaseCallback,
|
releaseCallback,
|
||||||
userObj));
|
userObj));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -48,17 +49,19 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
return GetData();
|
return GetData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
Buffer.SetData(_buffer, _bufferOffset, data.Slice(0, Math.Min(data.Length, _bufferSize)));
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
|
Buffer.SetData(_buffer, _bufferOffset, dataSpan.Slice(0, Math.Min(dataSpan.Length, _bufferSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -317,32 +318,36 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
if (Format == Format.S8UintD24Unorm)
|
if (Format == Format.S8UintD24Unorm)
|
||||||
{
|
{
|
||||||
data = FormatConverter.ConvertS8D24ToD24S8(data);
|
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = data)
|
fixed (byte* ptr = dataSpan)
|
||||||
{
|
{
|
||||||
ReadFrom((IntPtr)ptr, data.Length);
|
ReadFrom((IntPtr)ptr, dataSpan.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
if (Format == Format.S8UintD24Unorm)
|
if (Format == Format.S8UintD24Unorm)
|
||||||
{
|
{
|
||||||
data = FormatConverter.ConvertS8D24ToD24S8(data);
|
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = data)
|
fixed (byte* ptr = dataSpan)
|
||||||
{
|
{
|
||||||
int width = Math.Max(Info.Width >> level, 1);
|
int width = Math.Max(Info.Width >> level, 1);
|
||||||
int height = Math.Max(Info.Height >> level, 1);
|
int height = Math.Max(Info.Height >> level, 1);
|
||||||
@ -352,11 +357,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
if (Format == Format.S8UintD24Unorm)
|
if (Format == Format.S8UintD24Unorm)
|
||||||
{
|
{
|
||||||
data = FormatConverter.ConvertS8D24ToD24S8(data);
|
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
||||||
@ -364,7 +371,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = data)
|
fixed (byte* ptr = dataSpan)
|
||||||
{
|
{
|
||||||
ReadFrom2D(
|
ReadFrom2D(
|
||||||
(IntPtr)ptr,
|
(IntPtr)ptr,
|
||||||
|
@ -257,7 +257,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
|
DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
|
||||||
|
|
||||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
|
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling) && scaleElements != 0)
|
||||||
{
|
{
|
||||||
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
|
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
|
@ -279,16 +279,16 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2, InstEmit.SuatomB2, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
|
Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2, InstEmit.SuatomB2, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
|
||||||
Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB, InstEmit.SuatomCasB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.SPd);
|
Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB, InstEmit.SuatomCasB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.SPd);
|
||||||
Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas, InstEmit.SuatomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.SPd);
|
Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas, InstEmit.SuatomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.SPd);
|
||||||
Add("111010110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
Add("1110101100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||||
Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD, InstEmit.SuldD, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD, InstEmit.SuldD, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
||||||
Add("11101011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
Add("1110101100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||||
Add("11101011000x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
Add("1110101100001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
||||||
Add("111010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
|
Add("1110101101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
|
||||||
Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured, InstEmit.Sured, InstProps.Rd | InstProps.Ra);
|
Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured, InstEmit.Sured, InstProps.Rd | InstProps.Ra);
|
||||||
Add("111010110011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB, InstEmit.SustDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
Add("1110101100110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB, InstEmit.SustDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||||
Add("1110101100111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustD, InstEmit.SustD, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
Add("1110101100111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustD, InstEmit.SustD, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
||||||
Add("11101011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB, InstEmit.SustB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
Add("1110101100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB, InstEmit.SustB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||||
Add("11101011001x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
Add("1110101100101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
||||||
Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync, InstEmit.Sync, InstProps.Bra);
|
Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync, InstEmit.Sync, InstProps.Bra);
|
||||||
Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex, InstEmit.Tex, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
|
Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex, InstEmit.Tex, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
|
||||||
Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
|
Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
|
||||||
|
@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
{
|
{
|
||||||
InstSuldB op = context.GetOp<InstSuldB>();
|
InstSuldB op = context.GetOp<InstSuldB>();
|
||||||
|
|
||||||
EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: true);
|
EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, op.SrcC, useComponents: true, false, isBindless: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Suld(EmitterContext context)
|
public static void Suld(EmitterContext context)
|
||||||
|
@ -93,7 +93,7 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Span<byte> ConvertBlockLinearToLinear(
|
public static byte[] ConvertBlockLinearToLinear(
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int depth,
|
int depth,
|
||||||
@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
blockHeight,
|
blockHeight,
|
||||||
bytesPerPixel);
|
bytesPerPixel);
|
||||||
|
|
||||||
Span<byte> output = new byte[outSize];
|
byte[] output = new byte[outSize];
|
||||||
|
|
||||||
int outOffs = 0;
|
int outOffs = 0;
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Span<byte> ConvertLinearStridedToLinear(
|
public static byte[] ConvertLinearStridedToLinear(
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int blockWidth,
|
int blockWidth,
|
||||||
@ -262,14 +262,15 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);
|
int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);
|
||||||
lineSize = Math.Min(lineSize, outStride);
|
lineSize = Math.Min(lineSize, outStride);
|
||||||
|
|
||||||
Span<byte> output = new byte[h * outStride];
|
byte[] output = new byte[h * outStride];
|
||||||
|
Span<byte> outSpan = output;
|
||||||
|
|
||||||
int outOffs = 0;
|
int outOffs = 0;
|
||||||
int inOffs = 0;
|
int inOffs = 0;
|
||||||
|
|
||||||
for (int y = 0; y < h; y++)
|
for (int y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
data.Slice(inOffs, lineSize).CopyTo(output.Slice(outOffs, lineSize));
|
data.Slice(inOffs, lineSize).CopyTo(outSpan.Slice(outOffs, lineSize));
|
||||||
|
|
||||||
inOffs += stride;
|
inOffs += stride;
|
||||||
outOffs += outStride;
|
outOffs += outStride;
|
||||||
|
@ -109,12 +109,34 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (isWrite)
|
if (isWrite)
|
||||||
{
|
{
|
||||||
_cachedConvertedBuffers.Clear();
|
SignalWrite(0, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _buffer;
|
return _buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, int offset, int size, bool isWrite = false)
|
||||||
|
{
|
||||||
|
if (isWrite)
|
||||||
|
{
|
||||||
|
SignalWrite(offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SignalWrite(int offset, int size)
|
||||||
|
{
|
||||||
|
if (offset == 0 && size == Size)
|
||||||
|
{
|
||||||
|
_cachedConvertedBuffers.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_cachedConvertedBuffers.ClearRange(offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BufferHandle GetHandle()
|
public BufferHandle GetHandle()
|
||||||
{
|
{
|
||||||
var handle = _bufferHandle;
|
var handle = _bufferHandle;
|
||||||
@ -183,6 +205,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
data.Slice(0, dataSize).CopyTo(new Span<byte>((void*)(_map + offset), dataSize));
|
data.Slice(0, dataSize).CopyTo(new Span<byte>((void*)(_map + offset), dataSize));
|
||||||
|
|
||||||
|
SignalWrite(offset, dataSize);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +264,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
endRenderPass?.Invoke();
|
endRenderPass?.Invoke();
|
||||||
|
|
||||||
var dstBuffer = GetBuffer(cbs.CommandBuffer, true).Get(cbs, dstOffset, data.Length).Value;
|
var dstBuffer = GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true).Get(cbs, dstOffset, data.Length).Value;
|
||||||
|
|
||||||
InsertBufferBarrier(
|
InsertBufferBarrier(
|
||||||
_gd,
|
_gd,
|
||||||
@ -364,7 +388,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
|
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
|
||||||
{
|
{
|
||||||
var key = new I8ToI16CacheKey();
|
var key = new I8ToI16CacheKey(_gd);
|
||||||
|
|
||||||
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
||||||
{
|
{
|
||||||
@ -373,6 +397,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_gd.PipelineInternal.EndRenderPass();
|
_gd.PipelineInternal.EndRenderPass();
|
||||||
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
|
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
|
||||||
|
|
||||||
|
key.SetBuffer(holder.GetBuffer());
|
||||||
|
|
||||||
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,6 +443,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_gd.PipelineInternal.EndRenderPass();
|
_gd.PipelineInternal.EndRenderPass();
|
||||||
_gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount);
|
_gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount);
|
||||||
|
|
||||||
|
key.SetBuffer(holder.GetBuffer());
|
||||||
|
|
||||||
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private readonly IdList<BufferHolder> _buffers;
|
private readonly IdList<BufferHolder> _buffers;
|
||||||
|
|
||||||
|
public int BufferCount { get; private set; }
|
||||||
|
|
||||||
public StagingBuffer StagingBuffer { get; }
|
public StagingBuffer StagingBuffer { get; }
|
||||||
|
|
||||||
public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device)
|
public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device)
|
||||||
@ -56,6 +58,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return BufferHandle.Null;
|
return BufferHandle.Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BufferCount++;
|
||||||
|
|
||||||
ulong handle64 = (uint)_buffers.Add(holder);
|
ulong handle64 = (uint)_buffers.Add(holder);
|
||||||
|
|
||||||
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
||||||
@ -120,6 +124,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, BufferHandle handle, int offset, int size, bool isWrite)
|
||||||
|
{
|
||||||
|
if (TryGetBuffer(handle, out var holder))
|
||||||
|
{
|
||||||
|
return holder.GetBuffer(commandBuffer, offset, size, isWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
|
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
|
||||||
{
|
{
|
||||||
if (TryGetBuffer(handle, out var holder))
|
if (TryGetBuffer(handle, out var holder))
|
||||||
|
@ -24,6 +24,11 @@
|
|||||||
|
|
||||||
public void Add(int cbIndex, int offset, int size)
|
public void Add(int cbIndex, int offset, int size)
|
||||||
{
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
|
// Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
|
||||||
if (offset + size > _size)
|
if (offset + size > _size)
|
||||||
{
|
{
|
||||||
@ -39,6 +44,11 @@
|
|||||||
|
|
||||||
public bool OverlapsWith(int cbIndex, int offset, int size)
|
public bool OverlapsWith(int cbIndex, int offset, int size)
|
||||||
{
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int cbBase = cbIndex * _bitsPerCb;
|
int cbBase = cbIndex * _bitsPerCb;
|
||||||
int start = cbBase + offset / _granularity;
|
int start = cbBase + offset / _granularity;
|
||||||
int end = cbBase + (offset + size - 1) / _granularity;
|
int end = cbBase + (offset + size - 1) / _granularity;
|
||||||
|
@ -25,6 +25,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return other is I8ToI16CacheKey;
|
return other is I8ToI16CacheKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetBuffer(Auto<DisposableBuffer> buffer)
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_gd.PipelineInternal.DirtyIndexBuffer(_buffer);
|
_gd.PipelineInternal.DirtyIndexBuffer(_buffer);
|
||||||
@ -160,6 +165,44 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClearRange(int offset, int size)
|
||||||
|
{
|
||||||
|
if (_ranges != null && _ranges.Count > 0)
|
||||||
|
{
|
||||||
|
int end = offset + size;
|
||||||
|
|
||||||
|
List<ulong> toRemove = null;
|
||||||
|
|
||||||
|
foreach (KeyValuePair<ulong, List<Entry>> range in _ranges)
|
||||||
|
{
|
||||||
|
(int rOffset, int rSize) = UnpackRange(range.Key);
|
||||||
|
|
||||||
|
int rEnd = rOffset + rSize;
|
||||||
|
|
||||||
|
if (rEnd > offset && rOffset < end)
|
||||||
|
{
|
||||||
|
List<Entry> entries = range.Value;
|
||||||
|
|
||||||
|
foreach (Entry entry in entries)
|
||||||
|
{
|
||||||
|
entry.Key.Dispose();
|
||||||
|
entry.Value.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
(toRemove ??= new List<ulong>()).Add(range.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toRemove != null)
|
||||||
|
{
|
||||||
|
foreach (ulong range in toRemove)
|
||||||
|
{
|
||||||
|
_ranges.Remove(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<Entry> GetEntries(int offset, int size)
|
private List<Entry> GetEntries(int offset, int size)
|
||||||
{
|
{
|
||||||
if (_ranges == null)
|
if (_ranges == null)
|
||||||
@ -184,6 +227,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return (uint)offset | ((ulong)size << 32);
|
return (uint)offset | ((ulong)size << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static (int offset, int size) UnpackRange(ulong range)
|
||||||
|
{
|
||||||
|
return ((int)range, (int)(range >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
protected readonly AutoFlushCounter AutoFlush;
|
protected readonly AutoFlushCounter AutoFlush;
|
||||||
|
|
||||||
private PipelineDynamicState _dynamicState;
|
protected PipelineDynamicState DynamicState;
|
||||||
private PipelineState _newState;
|
private PipelineState _newState;
|
||||||
private bool _stateDirty;
|
private bool _stateDirty;
|
||||||
private GAL.PrimitiveTopology _topology;
|
private GAL.PrimitiveTopology _topology;
|
||||||
@ -150,7 +150,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, true).Get(Cbs, offset, size).Value;
|
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, offset, size, true).Get(Cbs, offset, size).Value;
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
Gd,
|
Gd,
|
||||||
@ -238,8 +238,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
var src = Gd.BufferManager.GetBuffer(CommandBuffer, source, false);
|
var src = Gd.BufferManager.GetBuffer(CommandBuffer, source, srcOffset, size, false);
|
||||||
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, true);
|
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, dstOffset, size, true);
|
||||||
|
|
||||||
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
|
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
|
||||||
}
|
}
|
||||||
@ -388,7 +388,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var oldDepthTestEnable = _newState.DepthTestEnable;
|
var oldDepthTestEnable = _newState.DepthTestEnable;
|
||||||
var oldDepthWriteEnable = _newState.DepthWriteEnable;
|
var oldDepthWriteEnable = _newState.DepthWriteEnable;
|
||||||
var oldTopology = _newState.Topology;
|
var oldTopology = _newState.Topology;
|
||||||
var oldViewports = _dynamicState.Viewports;
|
var oldViewports = DynamicState.Viewports;
|
||||||
var oldViewportsCount = _newState.ViewportsCount;
|
var oldViewportsCount = _newState.ViewportsCount;
|
||||||
|
|
||||||
_newState.CullMode = CullModeFlags.CullModeNone;
|
_newState.CullMode = CullModeFlags.CullModeNone;
|
||||||
@ -411,9 +411,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
||||||
_newState.Topology = oldTopology;
|
_newState.Topology = oldTopology;
|
||||||
|
|
||||||
_dynamicState.Viewports = oldViewports;
|
DynamicState.Viewports = oldViewports;
|
||||||
_dynamicState.ViewportsCount = (int)oldViewportsCount;
|
DynamicState.ViewportsCount = (int)oldViewportsCount;
|
||||||
_dynamicState.SetViewportsDirty();
|
DynamicState.SetViewportsDirty();
|
||||||
|
|
||||||
_newState.ViewportsCount = oldViewportsCount;
|
_newState.ViewportsCount = oldViewportsCount;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
@ -448,8 +448,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ResumeTransformFeedbackInternal();
|
ResumeTransformFeedbackInternal();
|
||||||
DrawCount++;
|
DrawCount++;
|
||||||
|
|
||||||
var buffer = Gd.BufferManager.GetBuffer(CommandBuffer, indirectBuffer.Handle, true).Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
var buffer = Gd.BufferManager
|
||||||
var countBuffer = Gd.BufferManager.GetBuffer(CommandBuffer, parameterBuffer.Handle, true).Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
.GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, true)
|
||||||
|
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
||||||
|
|
||||||
|
var countBuffer = Gd.BufferManager
|
||||||
|
.GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
|
||||||
|
.Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
||||||
|
|
||||||
Gd.DrawIndirectCountApi.CmdDrawIndirectCount(
|
Gd.DrawIndirectCountApi.CmdDrawIndirectCount(
|
||||||
CommandBuffer,
|
CommandBuffer,
|
||||||
@ -478,8 +483,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ResumeTransformFeedbackInternal();
|
ResumeTransformFeedbackInternal();
|
||||||
DrawCount++;
|
DrawCount++;
|
||||||
|
|
||||||
var buffer = Gd.BufferManager.GetBuffer(CommandBuffer, indirectBuffer.Handle, true).Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
var buffer = Gd.BufferManager
|
||||||
var countBuffer = Gd.BufferManager.GetBuffer(CommandBuffer, parameterBuffer.Handle, true).Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
.GetBuffer(CommandBuffer, indirectBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
|
||||||
|
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
||||||
|
|
||||||
|
var countBuffer = Gd.BufferManager
|
||||||
|
.GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
|
||||||
|
.Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
||||||
|
|
||||||
Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount(
|
Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount(
|
||||||
CommandBuffer,
|
CommandBuffer,
|
||||||
@ -535,7 +545,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
|
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
|
||||||
{
|
{
|
||||||
_dynamicState.SetDepthBias(factor, units, clamp);
|
DynamicState.SetDepthBias(factor, units, clamp);
|
||||||
|
|
||||||
_newState.DepthBiasEnable = enables != 0;
|
_newState.DepthBiasEnable = enables != 0;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
@ -753,10 +763,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var offset = new Offset2D(region.X, region.Y);
|
var offset = new Offset2D(region.X, region.Y);
|
||||||
var extent = new Extent2D((uint)region.Width, (uint)region.Height);
|
var extent = new Extent2D((uint)region.Width, (uint)region.Height);
|
||||||
|
|
||||||
_dynamicState.SetScissor(i, new Rect2D(offset, extent));
|
DynamicState.SetScissor(i, new Rect2D(offset, extent));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dynamicState.ScissorsCount = count;
|
DynamicState.ScissorsCount = count;
|
||||||
|
|
||||||
_newState.ScissorsCount = (uint)count;
|
_newState.ScissorsCount = (uint)count;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
@ -764,7 +774,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void SetStencilTest(StencilTestDescriptor stencilTest)
|
public void SetStencilTest(StencilTestDescriptor stencilTest)
|
||||||
{
|
{
|
||||||
_dynamicState.SetStencilMasks(
|
DynamicState.SetStencilMasks(
|
||||||
(uint)stencilTest.BackFuncMask,
|
(uint)stencilTest.BackFuncMask,
|
||||||
(uint)stencilTest.BackMask,
|
(uint)stencilTest.BackMask,
|
||||||
(uint)stencilTest.BackFuncRef,
|
(uint)stencilTest.BackFuncRef,
|
||||||
@ -813,7 +823,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (range.Handle != BufferHandle.Null)
|
if (range.Handle != BufferHandle.Null)
|
||||||
{
|
{
|
||||||
_transformFeedbackBuffers[i] = new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, true), range.Offset, range.Size);
|
_transformFeedbackBuffers[i] =
|
||||||
|
new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, range.Offset, range.Size, true), range.Offset, range.Size);
|
||||||
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
|
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -975,7 +986,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
var viewport = viewports[i];
|
var viewport = viewports[i];
|
||||||
|
|
||||||
_dynamicState.SetViewport(i, new Silk.NET.Vulkan.Viewport(
|
DynamicState.SetViewport(i, new Silk.NET.Vulkan.Viewport(
|
||||||
viewport.Region.X,
|
viewport.Region.X,
|
||||||
viewport.Region.Y,
|
viewport.Region.Y,
|
||||||
viewport.Region.Width == 0f ? 1f : viewport.Region.Width,
|
viewport.Region.Width == 0f ? 1f : viewport.Region.Width,
|
||||||
@ -984,7 +995,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Clamp(viewport.DepthFar)));
|
Clamp(viewport.DepthFar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dynamicState.ViewportsCount = count;
|
DynamicState.ViewportsCount = count;
|
||||||
|
|
||||||
float disableTransformF = disableTransform ? 1.0f : 0.0f;
|
float disableTransformF = disableTransform ? 1.0f : 0.0f;
|
||||||
if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform)
|
if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform)
|
||||||
@ -1063,7 +1074,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
||||||
|
|
||||||
_descriptorSetUpdater.SignalCommandBufferChange();
|
_descriptorSetUpdater.SignalCommandBufferChange();
|
||||||
_dynamicState.ForceAllDirty();
|
DynamicState.ForceAllDirty();
|
||||||
_currentPipelineHandle = 0;
|
_currentPipelineHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1201,7 +1212,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
||||||
{
|
{
|
||||||
_dynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||||
|
|
||||||
// Commit changes to the support buffer before drawing.
|
// Commit changes to the support buffer before drawing.
|
||||||
SupportBufferUpdater.Commit();
|
SupportBufferUpdater.Commit();
|
||||||
|
@ -204,6 +204,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
SignalCommandBufferChange();
|
SignalCommandBufferChange();
|
||||||
|
|
||||||
|
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FlushCommandsImpl()
|
public void FlushCommandsImpl()
|
||||||
|
@ -64,6 +64,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
};
|
};
|
||||||
|
|
||||||
samplerCreateInfo.PNext = &customBorderColor;
|
samplerCreateInfo.PNext = &customBorderColor;
|
||||||
|
samplerCreateInfo.BorderColor = BorderColor.FloatCustomExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.Api.CreateSampler(device, samplerCreateInfo, null, out var sampler).ThrowOnError();
|
gd.Api.CreateSampler(device, samplerCreateInfo, null, out var sampler).ThrowOnError();
|
||||||
|
@ -87,7 +87,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private void PushDataImpl(CommandBufferScoped cbs, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
|
private void PushDataImpl(CommandBufferScoped cbs, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
var srcBuffer = _buffer.GetBuffer();
|
var srcBuffer = _buffer.GetBuffer();
|
||||||
var dstBuffer = dst.GetBuffer();
|
var dstBuffer = dst.GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true);
|
||||||
|
|
||||||
int offset = _freeOffset;
|
int offset = _freeOffset;
|
||||||
int capacity = BufferSize - offset;
|
int capacity = BufferSize - offset;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -16,6 +17,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private Auto<DisposableBufferView> _bufferView;
|
private Auto<DisposableBufferView> _bufferView;
|
||||||
private Dictionary<GAL.Format, Auto<DisposableBufferView>> _selfManagedViews;
|
private Dictionary<GAL.Format, Auto<DisposableBufferView>> _selfManagedViews;
|
||||||
|
|
||||||
|
private int _bufferCount;
|
||||||
|
|
||||||
public int Width { get; }
|
public int Width { get; }
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
|
|
||||||
@ -88,17 +91,17 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_bufferView = null;
|
_bufferView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
_gd.SetBufferData(_bufferHandle, _offset, data);
|
_gd.SetBufferData(_bufferHandle, _offset, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
@ -107,7 +110,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (_bufferHandle == buffer.Handle &&
|
if (_bufferHandle == buffer.Handle &&
|
||||||
_offset == buffer.Offset &&
|
_offset == buffer.Offset &&
|
||||||
_size == buffer.Size)
|
_size == buffer.Size &&
|
||||||
|
_bufferCount == _gd.BufferManager.BufferCount)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -115,6 +119,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_bufferHandle = buffer.Handle;
|
_bufferHandle = buffer.Handle;
|
||||||
_offset = buffer.Offset;
|
_offset = buffer.Offset;
|
||||||
_size = buffer.Size;
|
_size = buffer.Size;
|
||||||
|
_bufferCount = _gd.BufferManager.BufferCount;
|
||||||
|
|
||||||
ReleaseImpl();
|
ReleaseImpl();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -873,17 +874,17 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return GetDataFromBuffer(result, size, result);
|
return GetDataFromBuffer(result, size, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
|
SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
SetData(data, layer, level, 1, 1, singleSlice: true);
|
SetData(data, layer, level, 1, 1, singleSlice: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
SetData(data, layer, level, 1, 1, singleSlice: true, region);
|
SetData(data, layer, level, 1, 1, singleSlice: true, region);
|
||||||
}
|
}
|
||||||
|
@ -38,18 +38,17 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
|
|||||||
// Read() -> (u32, buffer<nn::bcat::DeliveryCacheDirectoryEntry, 6>)
|
// Read() -> (u32, buffer<nn::bcat::DeliveryCacheDirectoryEntry, 6>)
|
||||||
public ResultCode Read(ServiceCtx context)
|
public ResultCode Read(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong position = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
ulong size = context.Request.ReceiveBuff[0].Size;
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _base.Get.Read(out int entriesRead, MemoryMarshal.Cast<byte, DeliveryCacheDirectoryEntry>(region.Memory.Span));
|
||||||
|
|
||||||
Result result = _base.Get.Read(out int entriesRead, MemoryMarshal.Cast<byte, DeliveryCacheDirectoryEntry>(data));
|
context.ResponseData.Write(entriesRead);
|
||||||
|
|
||||||
context.Memory.Write(position, data);
|
return (ResultCode)result.Value;
|
||||||
|
}
|
||||||
context.ResponseData.Write(entriesRead);
|
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(2)]
|
[CommandHipc(2)]
|
||||||
|
@ -38,20 +38,19 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
|
|||||||
// Read(u64) -> (u64, buffer<bytes, 6>)
|
// Read(u64) -> (u64, buffer<bytes, 6>)
|
||||||
public ResultCode Read(ServiceCtx context)
|
public ResultCode Read(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong position = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
ulong size = context.Request.ReceiveBuff[0].Size;
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
long offset = context.RequestData.ReadInt64();
|
long offset = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _base.Get.Read(out long bytesRead, offset, region.Memory.Span);
|
||||||
|
|
||||||
Result result = _base.Get.Read(out long bytesRead, offset, data);
|
context.ResponseData.Write(bytesRead);
|
||||||
|
|
||||||
context.Memory.Write(position, data);
|
return (ResultCode)result.Value;
|
||||||
|
}
|
||||||
context.ResponseData.Write(bytesRead);
|
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(2)]
|
[CommandHipc(2)]
|
||||||
|
@ -50,18 +50,17 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
|
|||||||
// EnumerateDeliveryCacheDirectory() -> (u32, buffer<nn::bcat::DirectoryName, 6>)
|
// EnumerateDeliveryCacheDirectory() -> (u32, buffer<nn::bcat::DirectoryName, 6>)
|
||||||
public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context)
|
public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong position = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
ulong size = context.Request.ReceiveBuff[0].Size;
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _base.Get.EnumerateDeliveryCacheDirectory(out int count, MemoryMarshal.Cast<byte, DirectoryName>(region.Memory.Span));
|
||||||
|
|
||||||
Result result = _base.Get.EnumerateDeliveryCacheDirectory(out int count, MemoryMarshal.Cast<byte, DirectoryName>(data));
|
context.ResponseData.Write(count);
|
||||||
|
|
||||||
context.Memory.Write(position, data);
|
return (ResultCode)result.Value;
|
||||||
|
}
|
||||||
context.ResponseData.Write(count);
|
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -17,17 +17,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
|||||||
// Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries)
|
// Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries)
|
||||||
public ResultCode Read(ServiceCtx context)
|
public ResultCode Read(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong bufferPosition = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
byte[] entryBuffer = new byte[bufferLen];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _baseDirectory.Get.Read(out long entriesRead, new OutBuffer(region.Memory.Span));
|
||||||
|
|
||||||
Result result = _baseDirectory.Get.Read(out long entriesRead, new OutBuffer(entryBuffer));
|
context.ResponseData.Write(entriesRead);
|
||||||
|
|
||||||
context.Memory.Write(bufferPosition, entryBuffer);
|
return (ResultCode)result.Value;
|
||||||
context.ResponseData.Write(entriesRead);
|
}
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(1)]
|
[CommandHipc(1)]
|
||||||
|
@ -19,7 +19,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
|||||||
// Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf)
|
// Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf)
|
||||||
public ResultCode Read(ServiceCtx context)
|
public ResultCode Read(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong position = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
ReadOption readOption = context.RequestData.ReadStruct<ReadOption>();
|
ReadOption readOption = context.RequestData.ReadStruct<ReadOption>();
|
||||||
context.RequestData.BaseStream.Position += 4;
|
context.RequestData.BaseStream.Position += 4;
|
||||||
@ -27,15 +28,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
|||||||
long offset = context.RequestData.ReadInt64();
|
long offset = context.RequestData.ReadInt64();
|
||||||
long size = context.RequestData.ReadInt64();
|
long size = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
byte[] data = new byte[context.Request.ReceiveBuff[0].Size];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _baseFile.Get.Read(out long bytesRead, offset, new OutBuffer(region.Memory.Span), size, readOption);
|
||||||
|
|
||||||
Result result = _baseFile.Get.Read(out long bytesRead, offset, new OutBuffer(data), size, readOption);
|
context.ResponseData.Write(bytesRead);
|
||||||
|
|
||||||
context.Memory.Write(position, data);
|
return (ResultCode)result.Value;
|
||||||
|
}
|
||||||
context.ResponseData.Write(bytesRead);
|
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(1)]
|
[CommandHipc(1)]
|
||||||
|
@ -197,13 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
|||||||
context.ResponseData.Write(timestamp.Created);
|
context.ResponseData.Write(timestamp.Created);
|
||||||
context.ResponseData.Write(timestamp.Modified);
|
context.ResponseData.Write(timestamp.Modified);
|
||||||
context.ResponseData.Write(timestamp.Accessed);
|
context.ResponseData.Write(timestamp.Accessed);
|
||||||
|
context.ResponseData.Write(1L); // Is valid?
|
||||||
byte[] data = new byte[8];
|
|
||||||
|
|
||||||
// is valid?
|
|
||||||
data[0] = 1;
|
|
||||||
|
|
||||||
context.ResponseData.Write(data);
|
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
return (ResultCode)result.Value;
|
||||||
}
|
}
|
||||||
|
@ -23,21 +23,21 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
|||||||
|
|
||||||
if (context.Request.ReceiveBuff.Count > 0)
|
if (context.Request.ReceiveBuff.Count > 0)
|
||||||
{
|
{
|
||||||
IpcBuffDesc buffDesc = context.Request.ReceiveBuff[0];
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
// Use smaller length to avoid overflows.
|
// Use smaller length to avoid overflows.
|
||||||
if (size > buffDesc.Size)
|
if (size > bufferLen)
|
||||||
{
|
{
|
||||||
size = buffDesc.Size;
|
size = bufferLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
|
||||||
|
|
||||||
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(data), (long)size);
|
return (ResultCode)result.Value;
|
||||||
|
}
|
||||||
context.Memory.Write(buffDesc.Position, data);
|
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
|
@ -500,16 +500,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||||||
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
|
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
|
||||||
SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>();
|
SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>();
|
||||||
|
|
||||||
ulong bufferPosition = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
byte[] infoBuffer = new byte[bufferLen];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _baseFileSystemProxy.Get.FindSaveDataWithFilter(out long count, new OutBuffer(region.Memory.Span), spaceId, in filter);
|
||||||
|
if (result.IsFailure()) return (ResultCode)result.Value;
|
||||||
|
|
||||||
Result result = _baseFileSystemProxy.Get.FindSaveDataWithFilter(out long count, new OutBuffer(infoBuffer), spaceId, in filter);
|
context.ResponseData.Write(count);
|
||||||
if (result.IsFailure()) return (ResultCode)result.Value;
|
}
|
||||||
|
|
||||||
context.Memory.Write(bufferPosition, infoBuffer);
|
|
||||||
context.ResponseData.Write(count);
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||||||
// ReadSaveDataInfo() -> (u64, buffer<unknown, 6>)
|
// ReadSaveDataInfo() -> (u64, buffer<unknown, 6>)
|
||||||
public ResultCode ReadSaveDataInfo(ServiceCtx context)
|
public ResultCode ReadSaveDataInfo(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong bufferPosition = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
byte[] infoBuffer = new byte[bufferLen];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
|
Result result = _baseReader.Get.Read(out long readCount, new OutBuffer(region.Memory.Span));
|
||||||
|
|
||||||
Result result = _baseReader.Get.Read(out long readCount, new OutBuffer(infoBuffer));
|
context.ResponseData.Write(readCount);
|
||||||
|
|
||||||
context.Memory.Write(bufferPosition, infoBuffer);
|
return (ResultCode)result.Value;
|
||||||
context.ResponseData.Write(readCount);
|
}
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -3,7 +3,6 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
||||||
{
|
{
|
||||||
@ -11,13 +10,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||||||
{
|
{
|
||||||
private const int FlagNotFreedYet = 1;
|
private const int FlagNotFreedYet = 1;
|
||||||
|
|
||||||
private static ConcurrentDictionary<ulong, IdDictionary> _maps = new ConcurrentDictionary<ulong, IdDictionary>();
|
private static NvMapIdDictionary _maps = new NvMapIdDictionary();
|
||||||
|
|
||||||
public NvMapDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner)
|
public NvMapDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner)
|
||||||
{
|
{
|
||||||
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
|
|
||||||
|
|
||||||
dict.Add(0, new NvMapHandle());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
|
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
|
||||||
@ -232,19 +228,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||||||
|
|
||||||
private int CreateHandleFromMap(NvMapHandle map)
|
private int CreateHandleFromMap(NvMapHandle map)
|
||||||
{
|
{
|
||||||
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
|
return _maps.Add(map);
|
||||||
|
|
||||||
return dict.Add(map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DeleteMapWithHandle(ulong pid, int handle)
|
private static bool DeleteMapWithHandle(ulong pid, int handle)
|
||||||
{
|
{
|
||||||
if (_maps.TryGetValue(pid, out IdDictionary dict))
|
return _maps.Delete(handle) != null;
|
||||||
{
|
|
||||||
return dict.Delete(handle) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void IncrementMapRefCount(ulong pid, int handle)
|
public static void IncrementMapRefCount(ulong pid, int handle)
|
||||||
@ -277,12 +266,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||||||
|
|
||||||
public static NvMapHandle GetMapFromHandle(ulong pid, int handle)
|
public static NvMapHandle GetMapFromHandle(ulong pid, int handle)
|
||||||
{
|
{
|
||||||
if (_maps.TryGetValue(pid, out IdDictionary dict))
|
return _maps.Get(handle);
|
||||||
{
|
|
||||||
return dict.GetData<NvMapHandle>(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
||||||
|
{
|
||||||
|
class NvMapIdDictionary
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<int, NvMapHandle> _nvmapHandles;
|
||||||
|
private int _id;
|
||||||
|
|
||||||
|
public ICollection<NvMapHandle> Values => _nvmapHandles.Values;
|
||||||
|
|
||||||
|
public NvMapIdDictionary()
|
||||||
|
{
|
||||||
|
_nvmapHandles = new ConcurrentDictionary<int, NvMapHandle>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Add(NvMapHandle handle)
|
||||||
|
{
|
||||||
|
int id = Interlocked.Add(ref _id, 4);
|
||||||
|
|
||||||
|
if (id != 0 && _nvmapHandles.TryAdd(id, handle))
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("NvMap ID overflow.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvMapHandle Get(int id)
|
||||||
|
{
|
||||||
|
if (_nvmapHandles.TryGetValue(id, out NvMapHandle handle))
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NvMapHandle Delete(int id)
|
||||||
|
{
|
||||||
|
if (_nvmapHandles.TryRemove(id, out NvMapHandle handle))
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<NvMapHandle> Clear()
|
||||||
|
{
|
||||||
|
ICollection<NvMapHandle> values = _nvmapHandles.Values;
|
||||||
|
|
||||||
|
_nvmapHandles.Clear();
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -235,6 +235,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
shouldBlockAfterOperation = true;
|
shouldBlockAfterOperation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Socket.IsBound)
|
||||||
|
{
|
||||||
|
receiveSize = -1;
|
||||||
|
|
||||||
|
return LinuxError.EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
receiveSize = Socket.ReceiveFrom(buffer[..size], ConvertBsdSocketFlags(flags), ref temp);
|
receiveSize = Socket.ReceiveFrom(buffer[..size], ConvertBsdSocketFlags(flags), ref temp);
|
||||||
|
|
||||||
remoteEndPoint = (IPEndPoint)temp;
|
remoteEndPoint = (IPEndPoint)temp;
|
||||||
@ -519,4 +526,4 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -142,14 +142,13 @@ namespace Ryujinx.HLE.HOS.Services.Ssl.SslService
|
|||||||
// GetHostName(buffer<bytes, 6>) -> u32
|
// GetHostName(buffer<bytes, 6>) -> u32
|
||||||
public ResultCode GetHostName(ServiceCtx context)
|
public ResultCode GetHostName(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong hostNameDataPosition = context.Request.ReceiveBuff[0].Position;
|
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
|
||||||
ulong hostNameDataSize = context.Request.ReceiveBuff[0].Size;
|
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
byte[] hostNameData = new byte[hostNameDataSize];
|
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
|
||||||
|
{
|
||||||
Encoding.ASCII.GetBytes(_hostName, hostNameData);
|
Encoding.ASCII.GetBytes(_hostName, region.Memory.Span);
|
||||||
|
}
|
||||||
context.Memory.Write(hostNameDataPosition, hostNameData);
|
|
||||||
|
|
||||||
context.ResponseData.Write((uint)_hostName.Length);
|
context.ResponseData.Write((uint)_hostName.Length);
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
Item = item
|
Item = item
|
||||||
};
|
};
|
||||||
|
|
||||||
_device.Gpu.Window.EnqueueFrameThreadSafe(
|
if (_device.Gpu.Window.EnqueueFrameThreadSafe(
|
||||||
layer.Owner,
|
layer.Owner,
|
||||||
frameBufferAddress,
|
frameBufferAddress,
|
||||||
frameBufferWidth,
|
frameBufferWidth,
|
||||||
@ -466,20 +466,25 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
crop,
|
crop,
|
||||||
AcquireBuffer,
|
AcquireBuffer,
|
||||||
ReleaseBuffer,
|
ReleaseBuffer,
|
||||||
textureCallbackInformation);
|
textureCallbackInformation))
|
||||||
|
|
||||||
if (item.Fence.FenceCount == 0)
|
|
||||||
{
|
{
|
||||||
_device.Gpu.Window.SignalFrameReady();
|
if (item.Fence.FenceCount == 0)
|
||||||
_device.Gpu.GPFifo.Interrupt();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item.Fence.RegisterCallback(_device.Gpu, (x) =>
|
|
||||||
{
|
{
|
||||||
_device.Gpu.Window.SignalFrameReady();
|
_device.Gpu.Window.SignalFrameReady();
|
||||||
_device.Gpu.GPFifo.Interrupt();
|
_device.Gpu.GPFifo.Interrupt();
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Fence.RegisterCallback(_device.Gpu, (x) =>
|
||||||
|
{
|
||||||
|
_device.Gpu.Window.SignalFrameReady();
|
||||||
|
_device.Gpu.GPFifo.Interrupt();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReleaseBuffer(textureCallbackInformation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ namespace Ryujinx.HLE
|
|||||||
|
|
||||||
public void SetVolume(float volume)
|
public void SetVolume(float volume)
|
||||||
{
|
{
|
||||||
System.SetVolume(volume);
|
System.SetVolume(Math.Clamp(volume, 0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetVolume()
|
public float GetVolume()
|
||||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 40;
|
public const int CurrentVersion = 41;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the configuration file format
|
/// Version of the configuration file format
|
||||||
|
@ -677,7 +677,9 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
ShowUi = Key.F4,
|
ShowUi = Key.F4,
|
||||||
Pause = Key.F5,
|
Pause = Key.F5,
|
||||||
ResScaleUp = Key.Unbound,
|
ResScaleUp = Key.Unbound,
|
||||||
ResScaleDown = Key.Unbound
|
ResScaleDown = Key.Unbound,
|
||||||
|
VolumeUp = Key.Unbound,
|
||||||
|
VolumeDown = Key.Unbound
|
||||||
};
|
};
|
||||||
Hid.InputConfig.Value = new List<InputConfig>
|
Hid.InputConfig.Value = new List<InputConfig>
|
||||||
{
|
{
|
||||||
@ -1156,6 +1158,24 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 41)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 41.");
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
||||||
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
|
ShowUi = configurationFileFormat.Hotkeys.ShowUi,
|
||||||
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
|
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
|
||||||
|
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
|
||||||
|
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
|
||||||
|
VolumeUp = Key.Unbound,
|
||||||
|
VolumeDown = Key.Unbound
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||||
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
||||||
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
||||||
|
@ -35,6 +35,7 @@ namespace Ryujinx.Ui
|
|||||||
private const int SwitchPanelHeight = 720;
|
private const int SwitchPanelHeight = 720;
|
||||||
private const int TargetFps = 60;
|
private const int TargetFps = 60;
|
||||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||||
|
private const float VolumeDelta = 0.05f;
|
||||||
|
|
||||||
public ManualResetEvent WaitEvent { get; set; }
|
public ManualResetEvent WaitEvent { get; set; }
|
||||||
public NpadManager NpadManager { get; }
|
public NpadManager NpadManager { get; }
|
||||||
@ -57,6 +58,7 @@ namespace Ryujinx.Ui
|
|||||||
private readonly long _ticksPerFrame;
|
private readonly long _ticksPerFrame;
|
||||||
|
|
||||||
private long _ticks = 0;
|
private long _ticks = 0;
|
||||||
|
private float _newVolume;
|
||||||
|
|
||||||
private readonly Stopwatch _chrono;
|
private readonly Stopwatch _chrono;
|
||||||
|
|
||||||
@ -643,6 +645,20 @@ namespace Ryujinx.Ui
|
|||||||
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentHotkeyState.HasFlag(KeyboardHotkeyState.VolumeUp) &&
|
||||||
|
!_prevHotkeyState.HasFlag(KeyboardHotkeyState.VolumeUp))
|
||||||
|
{
|
||||||
|
_newVolume = MathF.Round((Device.GetVolume() + VolumeDelta), 2);
|
||||||
|
Device.SetVolume(_newVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentHotkeyState.HasFlag(KeyboardHotkeyState.VolumeDown) &&
|
||||||
|
!_prevHotkeyState.HasFlag(KeyboardHotkeyState.VolumeDown))
|
||||||
|
{
|
||||||
|
_newVolume = MathF.Round((Device.GetVolume() - VolumeDelta), 2);
|
||||||
|
Device.SetVolume(_newVolume);
|
||||||
|
}
|
||||||
|
|
||||||
_prevHotkeyState = currentHotkeyState;
|
_prevHotkeyState = currentHotkeyState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,7 +691,9 @@ namespace Ryujinx.Ui
|
|||||||
Pause = 1 << 3,
|
Pause = 1 << 3,
|
||||||
ToggleMute = 1 << 4,
|
ToggleMute = 1 << 4,
|
||||||
ResScaleUp = 1 << 5,
|
ResScaleUp = 1 << 5,
|
||||||
ResScaleDown = 1 << 6
|
ResScaleDown = 1 << 6,
|
||||||
|
VolumeUp = 1 << 7,
|
||||||
|
VolumeDown = 1 << 8
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyboardHotkeyState GetHotkeyState()
|
private KeyboardHotkeyState GetHotkeyState()
|
||||||
@ -717,6 +735,16 @@ namespace Ryujinx.Ui
|
|||||||
state |= KeyboardHotkeyState.ResScaleDown;
|
state |= KeyboardHotkeyState.ResScaleDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeUp))
|
||||||
|
{
|
||||||
|
state |= KeyboardHotkeyState.VolumeUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeDown))
|
||||||
|
{
|
||||||
|
state |= KeyboardHotkeyState.VolumeDown;
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user