Compare commits

..

6 Commits

Author SHA1 Message Date
makigumo
6cb6b15612 Implement p2rc, p2ri, p2rr and r2p.cc shaders (#5031)
* implement P2rC, P2rI, P2rR shaders

* implement R2p.CC shader

* bump CodeGenVersion

* address feedback
2023-05-22 17:32:15 -03:00
gdkchan
2725e40838 Revert "Bump MVK Version (#5057)" (#5061)
This reverts commit c2e4c8f98e.
2023-05-22 17:12:11 -03:00
Isaac Marovitz
c2e4c8f98e Bump MVK Version (#5057) 2023-05-22 14:41:08 -03:00
Isaac Marovitz
b53e7ffd46 Ava UI: Input Menu Redesign (#4990)
* Cleanup

* Remove redundant locales

* Start SVG Fixes…

Better +/- buttons

Fix the grips

Bumpers

Better directional pad

More SVG stuff

Grip adjustments

Final stuff

* Make image bigger

* Border radius

* More cleanup

* Restructure

* Restructure Rumble View

* Use compiled bindings where possible

* Round those pesky corners

* Ack Suggestions

* More suggestions

* Update src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-05-22 01:16:20 +02:00
jhorv
ac66643346 Fix crash in SettingsViewModel when Vulkan isn't available (#4985)
* fix crash when Vulkan isn't available

* add VulkanRenderer.GetPhysicalDevices() overload that provides its own Vk API object and logs on failure

* adjustments per AcK77
2023-05-21 21:39:06 +02:00
jhorv
21e88f17f6 ServerBase thread safety (#4577)
* Add guard against ServerBase.Dispose() being called multiple times. Add reset event to avoid Dispose() being called while the ServerLoop is still running.

* remove unused usings

* rework ServerBase to use one collection each for sessions and ports, and make all accesses thread-safe.

* fix Logger call

* use GetSessionObj(int) instead of using _sessions directly

* move _threadStopped check inside "dispose once" test

* - Replace _threadStopped event with attempt to Join() the ending thread (if that isn't the current thread) instead.

- Use the instance-local _selfProcess and (new) _selfThread variables to avoid suggesting that the current KProcess and KThread could change. Per gdkchan, they can't currently, and this old IPC system will be removed before that changes.

- Re-order Dispose() so that the Interlocked _isDisposed check is the last check before disposing, to increase the likelihood that multiple callers will result in one of them succeeding.

* code style suggestions per AcK77

* add infinite wait for thread termination
2023-05-21 21:28:51 +02:00
20 changed files with 990 additions and 546 deletions

View File

@@ -216,26 +216,17 @@
"ControllerSettingsDPadDown": "Down", "ControllerSettingsDPadDown": "Down",
"ControllerSettingsDPadLeft": "Left", "ControllerSettingsDPadLeft": "Left",
"ControllerSettingsDPadRight": "Right", "ControllerSettingsDPadRight": "Right",
"ControllerSettingsStickButton": "Button",
"ControllerSettingsStickUp": "Up",
"ControllerSettingsStickDown": "Down",
"ControllerSettingsStickLeft": "Left",
"ControllerSettingsStickRight": "Right",
"ControllerSettingsStickStick": "Stick",
"ControllerSettingsStickInvertXAxis": "Invert Stick X",
"ControllerSettingsStickInvertYAxis": "Invert Stick Y",
"ControllerSettingsStickDeadzone": "Deadzone:",
"ControllerSettingsLStick": "Left Stick", "ControllerSettingsLStick": "Left Stick",
"ControllerSettingsLStickButton": "Button",
"ControllerSettingsLStickUp": "Up",
"ControllerSettingsLStickDown": "Down",
"ControllerSettingsLStickLeft": "Left",
"ControllerSettingsLStickRight": "Right",
"ControllerSettingsLStickStick": "Stick",
"ControllerSettingsLStickInvertXAxis": "Invert Stick X",
"ControllerSettingsLStickInvertYAxis": "Invert Stick Y",
"ControllerSettingsLStickDeadzone": "Deadzone:",
"ControllerSettingsRStick": "Right Stick", "ControllerSettingsRStick": "Right Stick",
"ControllerSettingsRStickButton": "Button",
"ControllerSettingsRStickUp": "Up",
"ControllerSettingsRStickDown": "Down",
"ControllerSettingsRStickLeft": "Left",
"ControllerSettingsRStickRight": "Right",
"ControllerSettingsRStickStick": "Stick",
"ControllerSettingsRStickInvertXAxis": "Invert Stick X",
"ControllerSettingsRStickInvertYAxis": "Invert Stick Y",
"ControllerSettingsRStickDeadzone": "Deadzone:",
"ControllerSettingsTriggersLeft": "Triggers Left", "ControllerSettingsTriggersLeft": "Triggers Left",
"ControllerSettingsTriggersRight": "Triggers Right", "ControllerSettingsTriggersRight": "Triggers Right",
"ControllerSettingsTriggersButtonsLeft": "Trigger Buttons Left", "ControllerSettingsTriggersButtonsLeft": "Trigger Buttons Left",

View File

@@ -7,6 +7,7 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Input; using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
@@ -30,7 +31,7 @@ using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {
public class ControllerSettingsViewModel : BaseModel, IDisposable public class ControllerInputViewModel : BaseModel, IDisposable
{ {
private const string Disabled = "disabled"; private const string Disabled = "disabled";
private const string ProControllerResource = "Ryujinx.Ui.Common/Resources/Controller_ProCon.svg"; private const string ProControllerResource = "Ryujinx.Ui.Common/Resources/Controller_ProCon.svg";
@@ -231,7 +232,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public InputConfig Config { get; set; } public InputConfig Config { get; set; }
public ControllerSettingsViewModel(UserControl owner) : this() public ControllerInputViewModel(UserControl owner) : this()
{ {
_owner = owner; _owner = owner;
@@ -258,7 +259,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public ControllerSettingsViewModel() public ControllerInputViewModel()
{ {
PlayerIndexes = new ObservableCollection<PlayerModel>(); PlayerIndexes = new ObservableCollection<PlayerModel>();
Controllers = new ObservableCollection<ControllerModel>(); Controllers = new ObservableCollection<ControllerModel>();
@@ -328,12 +329,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void ShowMotionConfig() public async void ShowMotionConfig()
{ {
await MotionSettingsWindow.Show(this); await MotionInputView.Show(this);
} }
public async void ShowRumbleConfig() public async void ShowRumbleConfig()
{ {
await RumbleSettingsWindow.Show(this); await RumbleInputView.Show(this);
} }
private void LoadInputDriver() private void LoadInputDriver()

View File

@@ -0,0 +1,93 @@
namespace Ryujinx.Ava.UI.ViewModels
{
public class MotionInputViewModel : BaseModel
{
private int _slot;
public int Slot
{
get => _slot;
set
{
_slot = value;
OnPropertyChanged();
}
}
private int _altSlot;
public int AltSlot
{
get => _altSlot;
set
{
_altSlot = value;
OnPropertyChanged();
}
}
private string _dsuServerHost;
public string DsuServerHost
{
get => _dsuServerHost;
set
{
_dsuServerHost = value;
OnPropertyChanged();
}
}
private int _dsuServerPort;
public int DsuServerPort
{
get => _dsuServerPort;
set
{
_dsuServerPort = value;
OnPropertyChanged();
}
}
private bool _mirrorInput;
public bool MirrorInput
{
get => _mirrorInput;
set
{
_mirrorInput = value;
OnPropertyChanged();
}
}
private int _sensitivity;
public int Sensitivity
{
get => _sensitivity;
set
{
_sensitivity = value;
OnPropertyChanged();
}
}
private double _gryoDeadzone;
public double GyroDeadzone
{
get => _gryoDeadzone;
set
{
_gryoDeadzone = value;
OnPropertyChanged();
}
}
private bool _enableCemuHookMotion;
public bool EnableCemuHookMotion
{
get => _enableCemuHookMotion;
set
{
_enableCemuHookMotion = value;
OnPropertyChanged();
}
}
}
}

View File

@@ -0,0 +1,27 @@
namespace Ryujinx.Ava.UI.ViewModels
{
public class RumbleInputViewModel : BaseModel
{
private float _strongRumble;
public float StrongRumble
{
get => _strongRumble;
set
{
_strongRumble = value;
OnPropertyChanged();
}
}
private float _weakRumble;
public float WeakRumble
{
get => _weakRumble;
set
{
_weakRumble = value;
OnPropertyChanged();
}
}
}
}

View File

@@ -311,7 +311,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
_gpuIds = new List<string>(); _gpuIds = new List<string>();
List<string> names = new(); List<string> names = new();
var devices = VulkanRenderer.GetPhysicalDevices(Vk.GetApi()); var devices = VulkanRenderer.GetPhysicalDevices();
if (devices.Length == 0) if (devices.Length == 0)
{ {

View File

@@ -4,7 +4,6 @@ using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
@@ -13,18 +12,18 @@ using Ryujinx.Input;
using Ryujinx.Input.Assigner; using Ryujinx.Input.Assigner;
using System; using System;
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class ControllerSettingsWindow : UserControl public partial class ControllerInputView : UserControl
{ {
private bool _dialogOpen; private bool _dialogOpen;
private ButtonKeyAssigner _currentAssigner; private ButtonKeyAssigner _currentAssigner;
internal ControllerSettingsViewModel ViewModel { get; set; } internal ControllerInputViewModel ViewModel { get; set; }
public ControllerSettingsWindow() public ControllerInputView()
{ {
DataContext = ViewModel = new ControllerSettingsViewModel(this); DataContext = ViewModel = new ControllerInputViewModel(this);
InitializeComponent(); InitializeComponent();

View File

@@ -5,8 +5,11 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:Class="Ryujinx.Ava.UI.Windows.MotionSettingsWindow" x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView"
x:CompileBindings="True"
x:DataType="viewModels:MotionInputViewModel"
Focusable="True"> Focusable="True">
<Grid Margin="10"> <Grid Margin="10">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -14,7 +17,9 @@
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel
Orientation="Horizontal"
HorizontalAlignment="Center">
<TextBlock <TextBlock
Margin="0" Margin="0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -28,11 +33,14 @@
Maximum="100" Maximum="100"
Minimum="0" Minimum="0"
Value="{Binding Sensitivity, Mode=TwoWay}" /> Value="{Binding Sensitivity, Mode=TwoWay}" />
<TextBlock HorizontalAlignment="Center" <TextBlock
Margin="5, 0" HorizontalAlignment="Center"
Text="{Binding Sensitivity, StringFormat=\{0:0\}%}" /> Margin="5, 0"
Text="{Binding Sensitivity, StringFormat=\{0:0\}%}" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel
Orientation="Horizontal"
HorizontalAlignment="Center">
<TextBlock <TextBlock
Margin="0" Margin="0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -51,17 +59,25 @@
Margin="5, 0" Margin="5, 0"
Text="{Binding GyroDeadzone, StringFormat=\{0:0.00\}}" /> Text="{Binding GyroDeadzone, StringFormat=\{0:0.00\}}" />
</StackPanel> </StackPanel>
<Separator Height="1" Margin="0,5" /> <Separator
<CheckBox Margin="5" IsChecked="{Binding EnableCemuHookMotion}"> Height="1"
<TextBlock Margin="0,3,0,0" VerticalAlignment="Center" Margin="0,5" />
Text="{locale:Locale ControllerSettingsMotionUseCemuhookCompatibleMotion}" /> <CheckBox
Margin="5"
IsChecked="{Binding EnableCemuHookMotion}">
<TextBlock
Margin="0,3,0,0"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsMotionUseCemuhookCompatibleMotion}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>
<Border Grid.Row="1" <Border
Padding="20,5" Grid.Row="1"
BorderBrush="{DynamicResource ThemeControlBorderColor}" Padding="20,5"
BorderThickness="1" BorderBrush="{DynamicResource ThemeControlBorderColor}"
HorizontalAlignment="Stretch"> BorderThickness="1"
CornerRadius="5"
HorizontalAlignment="Stretch">
<Grid VerticalAlignment="Top"> <Grid VerticalAlignment="Top">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -109,30 +125,42 @@
<ColumnDefinition /> <ColumnDefinition />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Margin="0,10,0,0" VerticalAlignment="Center" <TextBlock
Text="{locale:Locale ControllerSettingsMotionControllerSlot}" /> Margin="0,10,0,0"
<ui:NumberBox Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"
Name="CemuHookSlotUpDown" Text="{locale:Locale ControllerSettingsMotionControllerSlot}" />
SmallChange="1" <ui:NumberBox
LargeChange="1" Grid.Row="0"
Maximum="4" Grid.Column="1"
Minimum="0" Name="CemuHookSlotUpDown"
Value="{Binding Slot}" /> SmallChange="1"
<TextBlock Margin="0,10,0,0" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" LargeChange="1"
Text="{locale:Locale ControllerSettingsMotionRightJoyConSlot}" /> Maximum="4"
<ui:NumberBox Grid.Row="1" Grid.Column="1" Minimum="0"
Name="CemuHookRightJoyConSlotUpDown" Value="{Binding Slot}" />
SmallChange="1" <TextBlock
LargeChange="1" Margin="0,10,0,0"
Maximum="4" Grid.Row="1"
Minimum="0" Grid.Column="0"
Value="{Binding AltSlot}" /> VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsMotionRightJoyConSlot}" />
<ui:NumberBox
Grid.Row="1"
Grid.Column="1"
Name="CemuHookRightJoyConSlotUpDown"
SmallChange="1"
LargeChange="1"
Maximum="4"
Minimum="0"
Value="{Binding AltSlot}" />
</Grid> </Grid>
</StackPanel> </StackPanel>
<CheckBox HorizontalAlignment="Center" <CheckBox
IsChecked="{Binding MirrorInput, Mode=TwoWay}"> HorizontalAlignment="Center"
<TextBlock HorizontalAlignment="Center" IsChecked="{Binding MirrorInput, Mode=TwoWay}">
Text="{locale:Locale ControllerSettingsMotionMirrorInput}" /> <TextBlock
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsMotionMirrorInput}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -6,44 +6,42 @@ using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class MotionSettingsWindow : UserControl public partial class MotionInputView : UserControl
{ {
private readonly InputConfiguration<GamepadInputId, StickInputId> _viewmodel; private MotionInputViewModel _viewModel;
public MotionSettingsWindow() public MotionInputView()
{ {
InitializeComponent(); InitializeComponent();
DataContext = _viewmodel;
} }
public MotionSettingsWindow(ControllerSettingsViewModel viewmodel) public MotionInputView(ControllerInputViewModel viewModel)
{ {
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
_viewmodel = new InputConfiguration<GamepadInputId, StickInputId>() _viewModel = new MotionInputViewModel
{ {
Slot = config.Slot, Slot = config.Slot,
AltSlot = config.AltSlot, AltSlot = config.AltSlot,
DsuServerHost = config.DsuServerHost, DsuServerHost = config.DsuServerHost,
DsuServerPort = config.DsuServerPort, DsuServerPort = config.DsuServerPort,
MirrorInput = config.MirrorInput, MirrorInput = config.MirrorInput,
EnableMotion = config.EnableMotion,
Sensitivity = config.Sensitivity, Sensitivity = config.Sensitivity,
GyroDeadzone = config.GyroDeadzone, GyroDeadzone = config.GyroDeadzone,
EnableCemuHookMotion = config.EnableCemuHookMotion EnableCemuHookMotion = config.EnableCemuHookMotion
}; };
InitializeComponent(); InitializeComponent();
DataContext = _viewmodel; DataContext = _viewModel;
} }
public static async Task Show(ControllerSettingsViewModel viewmodel) public static async Task Show(ControllerInputViewModel viewModel)
{ {
MotionSettingsWindow content = new MotionSettingsWindow(viewmodel); MotionInputView content = new(viewModel);
ContentDialog contentDialog = new ContentDialog ContentDialog contentDialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.ControllerMotionTitle], Title = LocaleManager.Instance[LocaleKeys.ControllerMotionTitle],
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave], PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
@@ -53,16 +51,15 @@ namespace Ryujinx.Ava.UI.Windows
}; };
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (sender, args) =>
{ {
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
config.Slot = content._viewmodel.Slot; config.Slot = content._viewModel.Slot;
config.EnableMotion = content._viewmodel.EnableMotion; config.Sensitivity = content._viewModel.Sensitivity;
config.Sensitivity = content._viewmodel.Sensitivity; config.GyroDeadzone = content._viewModel.GyroDeadzone;
config.GyroDeadzone = content._viewmodel.GyroDeadzone; config.AltSlot = content._viewModel.AltSlot;
config.AltSlot = content._viewmodel.AltSlot; config.DsuServerHost = content._viewModel.DsuServerHost;
config.DsuServerHost = content._viewmodel.DsuServerHost; config.DsuServerPort = content._viewModel.DsuServerPort;
config.DsuServerPort = content._viewmodel.DsuServerPort; config.EnableCemuHookMotion = content._viewModel.EnableCemuHookMotion;
config.EnableCemuHookMotion = content._viewmodel.EnableCemuHookMotion; config.MirrorInput = content._viewModel.MirrorInput;
config.MirrorInput = content._viewmodel.MirrorInput;
}; };
await contentDialog.ShowAsync(); await contentDialog.ShowAsync();

View File

@@ -4,8 +4,11 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:Class="Ryujinx.Ava.UI.Windows.RumbleSettingsWindow" x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView"
x:DataType="viewModels:RumbleInputViewModel"
x:CompileBindings="True"
Focusable="True"> Focusable="True">
<Grid Margin="10"> <Grid Margin="10">
<Grid.RowDefinitions> <Grid.RowDefinitions>

View File

@@ -6,36 +6,37 @@ using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Views.Input
{ {
public partial class RumbleSettingsWindow : UserControl public partial class RumbleInputView : UserControl
{ {
private readonly InputConfiguration<GamepadInputId, StickInputId> _viewmodel; private RumbleInputViewModel _viewModel;
public RumbleSettingsWindow() public RumbleInputView()
{ {
InitializeComponent(); InitializeComponent();
DataContext = _viewmodel;
} }
public RumbleSettingsWindow(ControllerSettingsViewModel viewmodel) public RumbleInputView(ControllerInputViewModel viewModel)
{ {
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
_viewmodel = new InputConfiguration<GamepadInputId, StickInputId>() _viewModel = new RumbleInputViewModel
{ {
StrongRumble = config.StrongRumble, WeakRumble = config.WeakRumble StrongRumble = config.StrongRumble,
WeakRumble = config.WeakRumble
}; };
InitializeComponent(); InitializeComponent();
DataContext = _viewmodel;
DataContext = _viewModel;
} }
public static async Task Show(ControllerSettingsViewModel viewmodel) public static async Task Show(ControllerInputViewModel viewModel)
{ {
RumbleSettingsWindow content = new RumbleSettingsWindow(viewmodel); RumbleInputView content = new(viewModel);
ContentDialog contentDialog = new ContentDialog ContentDialog contentDialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.ControllerRumbleTitle], Title = LocaleManager.Instance[LocaleKeys.ControllerRumbleTitle],
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave], PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
@@ -46,9 +47,9 @@ namespace Ryujinx.Ava.UI.Windows
contentDialog.PrimaryButtonClick += (sender, args) => contentDialog.PrimaryButtonClick += (sender, args) =>
{ {
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
config.StrongRumble = content._viewmodel.StrongRumble; config.StrongRumble = content._viewModel.StrongRumble;
config.WeakRumble = content._viewmodel.WeakRumble; config.WeakRumble = content._viewModel.WeakRumble;
}; };
await contentDialog.ShowAsync(); await contentDialog.ShowAsync();

View File

@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows" xmlns:views="clr-namespace:Ryujinx.Ava.UI.Views.Input"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d" mc:Ignorable="d"
x:CompileBindings="True" x:CompileBindings="True"
@@ -20,27 +20,49 @@
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"> VerticalScrollBarVisibility="Auto">
<Border Classes="settings"> <Border Classes="settings">
<StackPanel Margin="4" Orientation="Vertical"> <Panel
<StackPanel Orientation="Horizontal"> Margin="10">
<CheckBox Margin="5,0" <Grid>
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}" <Grid.RowDefinitions>
IsChecked="{Binding EnableDockedMode}"> <RowDefinition Height="Auto"/>
<TextBlock VerticalAlignment="Center" <RowDefinition Height="*" />
Text="{locale:Locale SettingsTabInputEnableDockedMode}" /> <RowDefinition Height="Auto" />
</CheckBox> </Grid.RowDefinitions>
<CheckBox Margin="5,0" <views:ControllerInputView
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}" Grid.Row="0"
IsChecked="{Binding EnableKeyboard}"> Name="ControllerSettings" />
<TextBlock Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" /> <StackPanel
</CheckBox> Orientation="Vertical"
<CheckBox Margin="5,0" Grid.Row="2">
ToolTip.Tip="{locale:Locale DirectMouseTooltip}" <Separator
IsChecked="{Binding EnableMouse}"> Margin="0 10"
<TextBlock Text="{locale:Locale SettingsTabInputDirectMouseAccess}" /> Height="1" />
</CheckBox> <StackPanel
</StackPanel> Orientation="Horizontal"
<window:ControllerSettingsWindow Name="ControllerSettings" Margin="0" MinHeight="600" /> Spacing="10">
</StackPanel> <CheckBox
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}"
MinWidth="0"
IsChecked="{Binding EnableDockedMode}">
<TextBlock
Text="{locale:Locale SettingsTabInputEnableDockedMode}" />
</CheckBox>
<CheckBox
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}"
IsChecked="{Binding EnableKeyboard}">
<TextBlock
Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" />
</CheckBox>
<CheckBox
ToolTip.Tip="{locale:Locale DirectMouseTooltip}"
IsChecked="{Binding EnableMouse}">
<TextBlock
Text="{locale:Locale SettingsTabInputDirectMouseAccess}" />
</CheckBox>
</StackPanel>
</StackPanel>
</Grid>
</Panel>
</Border> </Border>
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@@ -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 = 4646; private const uint CodeGenVersion = 5031;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View File

@@ -187,27 +187,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Config.GpuAccessor.Log("Shader instruction Longjmp is not implemented."); context.Config.GpuAccessor.Log("Shader instruction Longjmp is not implemented.");
} }
public static void P2rR(EmitterContext context)
{
InstP2rR op = context.GetOp<InstP2rR>();
context.Config.GpuAccessor.Log("Shader instruction P2rR is not implemented.");
}
public static void P2rI(EmitterContext context)
{
InstP2rI op = context.GetOp<InstP2rI>();
context.Config.GpuAccessor.Log("Shader instruction P2rI is not implemented.");
}
public static void P2rC(EmitterContext context)
{
InstP2rC op = context.GetOp<InstP2rC>();
context.Config.GpuAccessor.Log("Shader instruction P2rC is not implemented.");
}
public static void Pexit(EmitterContext context) public static void Pexit(EmitterContext context)
{ {
InstPexit op = context.GetOp<InstPexit>(); InstPexit op = context.GetOp<InstPexit>();

View File

@@ -209,21 +209,15 @@ namespace Ryujinx.Graphics.Shader.Instructions
return context.ICompareNotEqual(context.BitwiseAnd(value, Const(1 << bit)), Const(0)); return context.ICompareNotEqual(context.BitwiseAnd(value, Const(1 << bit)), Const(0));
} }
if (ccpr) int count = ccpr ? RegisterConsts.FlagsCount : RegisterConsts.PredsCount;
{ RegisterType type = ccpr ? RegisterType.Flag : RegisterType.Predicate;
// TODO: Support Register to condition code flags copy. int shift = (int)byteSel * 8;
context.Config.GpuAccessor.Log("R2P.CC not implemented.");
}
else
{
int shift = (int)byteSel * 8;
for (int bit = 0; bit < RegisterConsts.PredsCount; bit++) for (int bit = 0; bit < count; bit++)
{ {
Operand pred = Register(bit, RegisterType.Predicate); Operand flag = Register(bit, type);
Operand res = context.ConditionalSelect(Test(mask, bit), Test(value, bit + shift), pred); Operand res = context.ConditionalSelect(Test(mask, bit), Test(value, bit + shift), flag);
context.Copy(pred, res); context.Copy(flag, res);
}
} }
} }

View File

@@ -1,7 +1,6 @@
using Ryujinx.Graphics.Shader.Decoders; using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper; using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper;
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -50,5 +49,68 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res); context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res);
context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res); context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res);
} }
public static void P2rC(EmitterContext context)
{
InstP2rC op = context.GetOp<InstP2rC>();
Operand srcA = GetSrcReg(context, op.SrcA);
Operand dest = GetSrcReg(context, op.Dest);
Operand mask = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
EmitP2r(context, srcA, dest, mask, op.ByteSel, op.Ccpr);
}
public static void P2rI(EmitterContext context)
{
InstP2rI op = context.GetOp<InstP2rI>();
Operand srcA = GetSrcReg(context, op.SrcA);
Operand dest = GetSrcReg(context, op.Dest);
Operand mask = GetSrcImm(context, op.Imm20);
EmitP2r(context, srcA, dest, mask, op.ByteSel, op.Ccpr);
}
public static void P2rR(EmitterContext context)
{
InstP2rR op = context.GetOp<InstP2rR>();
Operand srcA = GetSrcReg(context, op.SrcA);
Operand dest = GetSrcReg(context, op.Dest);
Operand mask = GetSrcReg(context, op.SrcB);
EmitP2r(context, srcA, dest, mask, op.ByteSel, op.Ccpr);
}
private static void EmitP2r(
EmitterContext context,
Operand srcA,
Operand dest,
Operand mask,
ByteSel byteSel,
bool ccpr)
{
int count = ccpr ? RegisterConsts.FlagsCount : RegisterConsts.PredsCount;
int shift = (int)byteSel * 8;
mask = context.BitwiseAnd(mask, Const(0xff));
Operand insert = Const(0);
for (int i = 0; i < count; i++)
{
Operand condition = ccpr
? Register(i, RegisterType.Flag)
: Register(i, RegisterType.Predicate);
Operand bit = context.ConditionalSelect(condition, Const(1 << (i + shift)), Const(0));
insert = context.BitwiseOr(insert, bit);
}
Operand maskShifted = context.ShiftLeft(mask, Const(shift));
Operand masked = context.BitwiseAnd(srcA, context.BitwiseNot(maskShifted));
Operand res = context.BitwiseOr(masked, context.BitwiseAnd(insert, maskShifted));
context.Copy(dest, res);
}
} }
} }

View File

@@ -599,6 +599,25 @@ namespace Ryujinx.Graphics.Vulkan
return new HardwareInfo(GpuVendor, GpuRenderer); return new HardwareInfo(GpuVendor, GpuRenderer);
} }
/// <summary>
/// Gets the available Vulkan devices using the default Vulkan API
/// object returned by <see cref="Vk.GetApi()"/>
/// </summary>
/// <returns></returns>
public static DeviceInfo[] GetPhysicalDevices()
{
try
{
return VulkanInitialization.GetSuitablePhysicalDevices(Vk.GetApi());
}
catch (Exception ex)
{
Logger.Error?.PrintMsg(LogClass.Gpu, $"Error querying Vulkan devices: {ex.Message}");
return Array.Empty<DeviceInfo>();
}
}
public static DeviceInfo[] GetPhysicalDevices(Vk api) public static DeviceInfo[] GetPhysicalDevices(Vk api)
{ {
try try

View File

@@ -1,4 +1,5 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel;
@@ -32,13 +33,14 @@ namespace Ryujinx.HLE.HOS.Services
0x01007FFF 0x01007FFF
}; };
private readonly object _handleLock = new(); // The amount of time Dispose() will wait to Join() the thread executing the ServerLoop()
private static readonly TimeSpan ThreadJoinTimeout = TimeSpan.FromSeconds(3);
private readonly KernelContext _context; private readonly KernelContext _context;
private KProcess _selfProcess; private KProcess _selfProcess;
private KThread _selfThread;
private readonly List<int> _sessionHandles = new List<int>(); private readonly ReaderWriterLockSlim _handleLock = new ReaderWriterLockSlim();
private readonly List<int> _portHandles = new List<int>();
private readonly Dictionary<int, IpcService> _sessions = new Dictionary<int, IpcService>(); private readonly Dictionary<int, IpcService> _sessions = new Dictionary<int, IpcService>();
private readonly Dictionary<int, Func<IpcService>> _ports = new Dictionary<int, Func<IpcService>>(); private readonly Dictionary<int, Func<IpcService>> _ports = new Dictionary<int, Func<IpcService>>();
@@ -48,6 +50,8 @@ namespace Ryujinx.HLE.HOS.Services
private readonly MemoryStream _responseDataStream; private readonly MemoryStream _responseDataStream;
private readonly BinaryWriter _responseDataWriter; private readonly BinaryWriter _responseDataWriter;
private int _isDisposed = 0;
public ManualResetEvent InitDone { get; } public ManualResetEvent InitDone { get; }
public string Name { get; } public string Name { get; }
public Func<IpcService> SmObjectFactory { get; } public Func<IpcService> SmObjectFactory { get; }
@@ -79,11 +83,20 @@ namespace Ryujinx.HLE.HOS.Services
private void AddPort(int serverPortHandle, Func<IpcService> objectFactory) private void AddPort(int serverPortHandle, Func<IpcService> objectFactory)
{ {
lock (_handleLock) bool lockTaken = false;
try
{ {
_portHandles.Add(serverPortHandle); lockTaken = _handleLock.TryEnterWriteLock(Timeout.Infinite);
_ports.Add(serverPortHandle, objectFactory);
}
finally
{
if (lockTaken)
{
_handleLock.ExitWriteLock();
}
} }
_ports.Add(serverPortHandle, objectFactory);
} }
public void AddSessionObj(KServerSession serverSession, IpcService obj) public void AddSessionObj(KServerSession serverSession, IpcService obj)
@@ -92,16 +105,62 @@ namespace Ryujinx.HLE.HOS.Services
InitDone.WaitOne(); InitDone.WaitOne();
_selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle); _selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle);
AddSessionObj(serverSessionHandle, obj); AddSessionObj(serverSessionHandle, obj);
} }
public void AddSessionObj(int serverSessionHandle, IpcService obj) public void AddSessionObj(int serverSessionHandle, IpcService obj)
{ {
lock (_handleLock) bool lockTaken = false;
try
{ {
_sessionHandles.Add(serverSessionHandle); lockTaken = _handleLock.TryEnterWriteLock(Timeout.Infinite);
_sessions.Add(serverSessionHandle, obj);
}
finally
{
if (lockTaken)
{
_handleLock.ExitWriteLock();
}
}
}
private IpcService GetSessionObj(int serverSessionHandle)
{
bool lockTaken = false;
try
{
lockTaken = _handleLock.TryEnterReadLock(Timeout.Infinite);
return _sessions[serverSessionHandle];
}
finally
{
if (lockTaken)
{
_handleLock.ExitReadLock();
}
}
}
private bool RemoveSessionObj(int serverSessionHandle, out IpcService obj)
{
bool lockTaken = false;
try
{
lockTaken = _handleLock.TryEnterWriteLock(Timeout.Infinite);
return _sessions.Remove(serverSessionHandle, out obj);
}
finally
{
if (lockTaken)
{
_handleLock.ExitWriteLock();
}
} }
_sessions.Add(serverSessionHandle, obj);
} }
private void Main() private void Main()
@@ -112,6 +171,7 @@ namespace Ryujinx.HLE.HOS.Services
private void ServerLoop() private void ServerLoop()
{ {
_selfProcess = KernelStatic.GetCurrentProcess(); _selfProcess = KernelStatic.GetCurrentProcess();
_selfThread = KernelStatic.GetCurrentThread();
if (SmObjectFactory != null) if (SmObjectFactory != null)
{ {
@@ -122,8 +182,7 @@ namespace Ryujinx.HLE.HOS.Services
InitDone.Set(); InitDone.Set();
KThread thread = KernelStatic.GetCurrentThread(); ulong messagePtr = _selfThread.TlsAddress;
ulong messagePtr = thread.TlsAddress;
_context.Syscall.SetHeapSize(out ulong heapAddr, 0x200000); _context.Syscall.SetHeapSize(out ulong heapAddr, 0x200000);
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0); _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
@@ -134,27 +193,39 @@ namespace Ryujinx.HLE.HOS.Services
while (true) while (true)
{ {
int handleCount;
int portHandleCount; int portHandleCount;
int handleCount;
int[] handles; int[] handles;
lock (_handleLock) bool handleLockTaken = false;
try
{ {
portHandleCount = _portHandles.Count; handleLockTaken = _handleLock.TryEnterReadLock(Timeout.Infinite);
handleCount = portHandleCount + _sessionHandles.Count;
portHandleCount = _ports.Count;
handleCount = portHandleCount + _sessions.Count;
handles = ArrayPool<int>.Shared.Rent(handleCount); handles = ArrayPool<int>.Shared.Rent(handleCount);
_portHandles.CopyTo(handles, 0); _ports.Keys.CopyTo(handles, 0);
_sessionHandles.CopyTo(handles, portHandleCount);
_sessions.Keys.CopyTo(handles, portHandleCount);
}
finally
{
if (handleLockTaken)
{
_handleLock.ExitReadLock();
}
} }
// We still need a timeout here to allow the service to pick up and listen new sessions... // We still need a timeout here to allow the service to pick up and listen new sessions...
var rc = _context.Syscall.ReplyAndReceive(out int signaledIndex, handles.AsSpan(0, handleCount), replyTargetHandle, 1000000L); var rc = _context.Syscall.ReplyAndReceive(out int signaledIndex, handles.AsSpan(0, handleCount), replyTargetHandle, 1000000L);
thread.HandlePostSyscall(); _selfThread.HandlePostSyscall();
if (!thread.Context.Running) if (!_selfThread.Context.Running)
{ {
break; break;
} }
@@ -178,9 +249,20 @@ namespace Ryujinx.HLE.HOS.Services
// We got a new connection, accept the session to allow servicing future requests. // We got a new connection, accept the session to allow servicing future requests.
if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == Result.Success) if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == Result.Success)
{ {
IpcService obj = _ports[handles[signaledIndex]].Invoke(); bool handleWriteLockTaken = false;
try
AddSessionObj(serverSessionHandle, obj); {
handleWriteLockTaken = _handleLock.TryEnterWriteLock(Timeout.Infinite);
IpcService obj = _ports[handles[signaledIndex]].Invoke();
_sessions.Add(serverSessionHandle, obj);
}
finally
{
if (handleWriteLockTaken)
{
_handleLock.ExitWriteLock();
}
}
} }
} }
@@ -197,11 +279,7 @@ namespace Ryujinx.HLE.HOS.Services
private bool Process(int serverSessionHandle, ulong recvListAddr) private bool Process(int serverSessionHandle, ulong recvListAddr)
{ {
KProcess process = KernelStatic.GetCurrentProcess(); IpcMessage request = ReadRequest();
KThread thread = KernelStatic.GetCurrentThread();
ulong messagePtr = thread.TlsAddress;
IpcMessage request = ReadRequest(process, messagePtr);
IpcMessage response = new IpcMessage(); IpcMessage response = new IpcMessage();
@@ -247,15 +325,15 @@ namespace Ryujinx.HLE.HOS.Services
ServiceCtx context = new ServiceCtx( ServiceCtx context = new ServiceCtx(
_context.Device, _context.Device,
process, _selfProcess,
process.CpuMemory, _selfProcess.CpuMemory,
thread, _selfThread,
request, request,
response, response,
_requestDataReader, _requestDataReader,
_responseDataWriter); _responseDataWriter);
_sessions[serverSessionHandle].CallCmifMethod(context); GetSessionObj(serverSessionHandle).CallCmifMethod(context);
response.RawData = _responseDataStream.ToArray(); response.RawData = _responseDataStream.ToArray();
} }
@@ -268,7 +346,7 @@ namespace Ryujinx.HLE.HOS.Services
switch (cmdId) switch (cmdId)
{ {
case 0: case 0:
FillHipcResponse(response, 0, _sessions[serverSessionHandle].ConvertToDomain()); FillHipcResponse(response, 0, GetSessionObj(serverSessionHandle).ConvertToDomain());
break; break;
case 3: case 3:
@@ -278,17 +356,31 @@ namespace Ryujinx.HLE.HOS.Services
// TODO: Whats the difference between IpcDuplicateSession/Ex? // TODO: Whats the difference between IpcDuplicateSession/Ex?
case 2: case 2:
case 4: case 4:
int unknown = _requestDataReader.ReadInt32(); {
_ = _requestDataReader.ReadInt32();
_context.Syscall.CreateSession(out int dupServerSessionHandle, out int dupClientSessionHandle, false, 0); _context.Syscall.CreateSession(out int dupServerSessionHandle, out int dupClientSessionHandle, false, 0);
AddSessionObj(dupServerSessionHandle, _sessions[serverSessionHandle]); bool writeLockTaken = false;
try
{
writeLockTaken = _handleLock.TryEnterWriteLock(Timeout.Infinite);
_sessions[dupServerSessionHandle] = _sessions[serverSessionHandle];
}
finally
{
if (writeLockTaken)
{
_handleLock.ExitWriteLock();
}
}
response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle); response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle);
FillHipcResponse(response, 0); FillHipcResponse(response, 0);
break; break;
}
default: throw new NotImplementedException(cmdId.ToString()); default: throw new NotImplementedException(cmdId.ToString());
} }
@@ -296,13 +388,10 @@ namespace Ryujinx.HLE.HOS.Services
else if (request.Type == IpcMessageType.CmifCloseSession || request.Type == IpcMessageType.TipcCloseSession) else if (request.Type == IpcMessageType.CmifCloseSession || request.Type == IpcMessageType.TipcCloseSession)
{ {
_context.Syscall.CloseHandle(serverSessionHandle); _context.Syscall.CloseHandle(serverSessionHandle);
lock (_handleLock) if (RemoveSessionObj(serverSessionHandle, out var session))
{ {
_sessionHandles.Remove(serverSessionHandle); (session as IDisposable)?.Dispose();
} }
IpcService service = _sessions[serverSessionHandle];
(service as IDisposable)?.Dispose();
_sessions.Remove(serverSessionHandle);
shouldReply = false; shouldReply = false;
} }
// If the type is past 0xF, we are using TIPC // If the type is past 0xF, we are using TIPC
@@ -317,20 +406,20 @@ namespace Ryujinx.HLE.HOS.Services
ServiceCtx context = new ServiceCtx( ServiceCtx context = new ServiceCtx(
_context.Device, _context.Device,
process, _selfProcess,
process.CpuMemory, _selfProcess.CpuMemory,
thread, _selfThread,
request, request,
response, response,
_requestDataReader, _requestDataReader,
_responseDataWriter); _responseDataWriter);
_sessions[serverSessionHandle].CallTipcMethod(context); GetSessionObj(serverSessionHandle).CallTipcMethod(context);
response.RawData = _responseDataStream.ToArray(); response.RawData = _responseDataStream.ToArray();
using var responseStream = response.GetStreamTipc(); using var responseStream = response.GetStreamTipc();
process.CpuMemory.Write(messagePtr, responseStream.GetReadOnlySequence()); _selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence());
} }
else else
{ {
@@ -339,27 +428,24 @@ namespace Ryujinx.HLE.HOS.Services
if (!isTipcCommunication) if (!isTipcCommunication)
{ {
using var responseStream = response.GetStream((long)messagePtr, recvListAddr | ((ulong)PointerBufferSize << 48)); using var responseStream = response.GetStream((long)_selfThread.TlsAddress, recvListAddr | ((ulong)PointerBufferSize << 48));
process.CpuMemory.Write(messagePtr, responseStream.GetReadOnlySequence()); _selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence());
} }
return shouldReply; return shouldReply;
} }
private static IpcMessage ReadRequest(KProcess process, ulong messagePtr) private IpcMessage ReadRequest()
{ {
const int messageSize = 0x100; const int messageSize = 0x100;
byte[] reqData = ArrayPool<byte>.Shared.Rent(messageSize); using IMemoryOwner<byte> reqDataOwner = ByteMemoryPool.Shared.Rent(messageSize);
Span<byte> reqDataSpan = reqData.AsSpan(0, messageSize); Span<byte> reqDataSpan = reqDataOwner.Memory.Span;
reqDataSpan.Clear();
process.CpuMemory.Read(messagePtr, reqDataSpan); _selfProcess.CpuMemory.Read(_selfThread.TlsAddress, reqDataSpan);
IpcMessage request = new IpcMessage(reqDataSpan, (long)messagePtr); IpcMessage request = new IpcMessage(reqDataSpan, (long)_selfThread.TlsAddress);
ArrayPool<byte>.Shared.Return(reqData);
return request; return request;
} }
@@ -392,26 +478,35 @@ namespace Ryujinx.HLE.HOS.Services
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (disposing) if (disposing && _selfThread != null)
{ {
foreach (IpcService service in _sessions.Values) if (_selfThread.HostThread.ManagedThreadId != Environment.CurrentManagedThreadId && _selfThread.HostThread.Join(ThreadJoinTimeout) == false)
{ {
if (service is IDisposable disposableObj) Logger.Warning?.Print(LogClass.Service, $"The ServerBase thread didn't terminate within {ThreadJoinTimeout:g}, waiting longer.");
{
disposableObj.Dispose();
}
service.DestroyAtExit(); _selfThread.HostThread.Join(Timeout.Infinite);
} }
_sessions.Clear(); if (Interlocked.Exchange(ref _isDisposed, 1) == 0)
{
foreach (IpcService service in _sessions.Values)
{
(service as IDisposable)?.Dispose();
_requestDataReader.Dispose(); service.DestroyAtExit();
_requestDataStream.Dispose(); }
_responseDataWriter.Dispose();
_responseDataStream.Dispose();
InitDone.Dispose(); _sessions.Clear();
_ports.Clear();
_handleLock.Dispose();
_requestDataReader.Dispose();
_requestDataStream.Dispose();
_responseDataWriter.Dispose();
_responseDataStream.Dispose();
InitDone.Dispose();
}
} }
} }

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -478,7 +478,7 @@ namespace Ryujinx.Ui.Windows
if (Enum.Parse<GraphicsBackend>(_graphicsBackend.ActiveId) == GraphicsBackend.Vulkan) if (Enum.Parse<GraphicsBackend>(_graphicsBackend.ActiveId) == GraphicsBackend.Vulkan)
{ {
var devices = VulkanRenderer.GetPhysicalDevices(Vk.GetApi()); var devices = VulkanRenderer.GetPhysicalDevices();
string preferredGpuIdFromConfig = ConfigurationState.Instance.Graphics.PreferredGpu.Value; string preferredGpuIdFromConfig = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
string preferredGpuId = preferredGpuIdFromConfig; string preferredGpuId = preferredGpuIdFromConfig;
bool noGpuId = string.IsNullOrEmpty(preferredGpuIdFromConfig); bool noGpuId = string.IsNullOrEmpty(preferredGpuIdFromConfig);