Compare commits

..

15 Commits

Author SHA1 Message Date
Andrey Sukharev
3868a00206 Use source generated regular expressions (#4005) 2022-12-04 00:43:23 +00:00
mageven
933e5144a9 Query Available RAM on macOS (#4000) 2022-12-04 00:25:07 +00:00
Ac_K
73a42c85c4 Add crowdin badge and information in readme (#3990)
* Add crowdin bagde and informations in readme.

* Update README.md

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Update README.md

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2022-12-02 23:57:38 +01:00
Ac_K
39ba11054b Update Crowdin configuration file 2022-12-02 15:22:21 +01:00
Ac_K
c250e3392c Fix using in Ava 2022-12-02 15:08:57 +01:00
Ac_K
e56b069081 Update Crowdin configuration file 2022-12-02 14:54:56 +01:00
merry
204c031fef SDL2Driver: Invoke dispatcher on main thread (#3818) 2022-12-02 14:37:22 +01:00
Emmanuel Hansen
d9053bbe37 Avalonia - Save Manager (#3476)
* Add save manager to account selector

* add fallback to app metadata for titlename if app is not in gamelist

* Allow recovering lost accounts
2022-12-02 13:16:43 +00:00
Mary-nyan
c25e8427aa amadeus: Fix wrong SendCommands logic (#3969)
* amadeus: Fix wrong SendCommands logic

Might help with audio desync, might cause audio stutters, will see!

* Address gdkchan's comment
2022-12-02 13:01:19 +00:00
Isaac Marovitz
21a081b185 Add back locales removed in #3955 (#3983)
Add back `SettingsButtonSave` & `SettingsButtonClose` removed in #3955

Fixes #3982
2022-12-02 12:46:18 +00:00
Isaac Marovitz
b540ea80d1 Ava GUI: Make Dialogue More Intuitive (#3955)
* Adjust button position and locales

* Shortcuts + Highlight default action

* Update Locales - Corrections Welcome

* Move `Apply` button back to right side

* OS Reactive Button layout

* Fix reversed boolean :)

* Fix accented button styling
2022-12-02 03:31:21 +01:00
Mary
d692a9b83e Revert "nuget: bump SixLabors.ImageSharp from 1.0.4 to 2.1.3 (#3976)"
This reverts commit 9677ddaa5d.

SixLabors.ImageShar switched to a shady and vague license starting with 2.x
without mentioning it on their changelog.

As a result we are staying on 1.x (licensed under Apache-2) and will
seak an alternative package.
2022-12-01 23:06:55 +01:00
dependabot[bot]
9677ddaa5d nuget: bump SixLabors.ImageSharp from 1.0.4 to 2.1.3 (#3976)
* nuget: bump SixLabors.ImageSharp from 1.0.4 to 2.1.3

Bumps [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) from 1.0.4 to 2.1.3.
- [Release notes](https://github.com/SixLabors/ImageSharp/releases)
- [Commits](https://github.com/SixLabors/ImageSharp/compare/v1.0.4...v2.1.3)

---
updated-dependencies:
- dependency-name: SixLabors.ImageSharp
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update for 2.x changes

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mary <mary@mary.zone>
2022-12-01 21:54:41 +00:00
Mary-nyan
ce92e8cd04 chore: Update Silk.NET to 2.16.0 (#3953) 2022-12-01 19:11:56 +01:00
Isaac Marovitz
456fc04007 Better SDL2 Audio Init Error Logging (#3967)
* Better SDL2 Audio Init Error Logging

* Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs

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

* Update Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs

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

* Update SDL2HardwareDeviceDriver.cs

* Update SDL2HardwareDeviceDriver.cs

Co-authored-by: Mary-nyan <thog@protonmail.com>
Co-authored-by: Ac_K <Acoustik666@gmail.com>
2022-12-01 17:53:13 +01:00
75 changed files with 1242 additions and 423 deletions

View File

@@ -21,6 +21,10 @@
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
alt="">
</a>
<a href="https://crwd.in/ryujinx">
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
alt="">
</a>
<a href="https://discord.com/invite/VkQYXAZ">
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
alt="Discord">
@@ -48,6 +52,8 @@ See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ry
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
## Latest build
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**

View File

@@ -1,5 +1,6 @@
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using Ryujinx.SDL2.Common;
using System;
@@ -112,6 +113,9 @@ namespace Ryujinx.Audio.Backends.SDL2
if (device == 0)
{
Logger.Error?.Print(LogClass.Application,
$"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
return 0;
}
@@ -119,6 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
if (!isValid)
{
Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
SDL_CloseAudioDevice(device);
return 0;

View File

@@ -116,6 +116,11 @@ namespace Ryujinx.Audio.Renderer.Dsp
};
}
public bool HasRemainingCommands(int sessionId)
{
return _sessionCommandList[sessionId] != null;
}
public void Signal()
{
_mailbox.SendMessage(MailboxMessage.RenderStart);

View File

@@ -670,14 +670,21 @@ namespace Ryujinx.Audio.Renderer.Server
{
_terminationEvent.Reset();
GenerateCommandList(out CommandList commands);
if (!_manager.Processor.HasRemainingCommands(_sessionId))
{
GenerateCommandList(out CommandList commands);
_manager.Processor.Send(_sessionId,
commands,
GetMaxAllocatedTimeForDsp(),
_appletResourceId);
_manager.Processor.Send(_sessionId,
commands,
GetMaxAllocatedTimeForDsp(),
_appletResourceId);
_systemEvent.Signal();
_systemEvent.Signal();
}
else
{
_isDspRunningBehind = true;
}
}
else
{

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Direkter Tastaturzugriff",
"SettingsButtonSave": "Speichern",
"SettingsButtonClose": "Schließen",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Abbrechen",
"SettingsButtonApply": "Übernehmen",
"ControllerSettingsPlayer": "Spieler",
"ControllerSettingsPlayer1": "Spieler 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Άμεση Πρόσβαση στο Πληκτρολόγιο",
"SettingsButtonSave": "Αποθήκευση",
"SettingsButtonClose": "Κλείσιμο",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Ακύρωση",
"SettingsButtonApply": "Εφαρμογή",
"ControllerSettingsPlayer": "Παίχτης",
"ControllerSettingsPlayer1": "Παίχτης 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Direct Keyboard Access",
"SettingsButtonSave": "Save",
"SettingsButtonClose": "Close",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Cancel",
"SettingsButtonApply": "Apply",
"ControllerSettingsPlayer": "Player",
"ControllerSettingsPlayer1": "Player 1",
@@ -594,7 +596,18 @@
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
"VolumeShort": "Vol",
"SettingsEnableMacroHLE": "Enable Macro HLE",
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure."
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
"VolumeShort": "Vol",
"UserProfilesManageSaves": "Manage Saves",
"DeleteUserSave": "Do you want to delete user save for this game?",
"IrreversibleActionNote": "This action is not reversible.",
"SaveManagerHeading": "Manage Saves for {0}",
"SaveManagerTitle": "Save Manager",
"Name": "Name",
"Size": "Size",
"Search": "Search",
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
"Recover": "Recover",
"UserProfilesRecoverHeading" : "Saves were found for the following accounts"
}

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Acceso directo al teclado",
"SettingsButtonSave": "Guardar",
"SettingsButtonClose": "Cerrar",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Cancelar",
"SettingsButtonApply": "Aplicar",
"ControllerSettingsPlayer": "Jugador",
"ControllerSettingsPlayer1": "Jugador 1",

View File

@@ -161,6 +161,8 @@
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
"SettingsButtonSave": "Enregistrer",
"SettingsButtonClose": "Fermer",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Annuler",
"SettingsButtonApply": "Appliquer",
"ControllerSettingsPlayer": "Joueur",
"ControllerSettingsPlayer1": "Joueur 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
"SettingsButtonSave": "Salva",
"SettingsButtonClose": "Chiudi",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Cancella",
"SettingsButtonApply": "Applica",
"ControllerSettingsPlayer": "Giocatore",
"ControllerSettingsPlayer1": "Giocatore 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "キーボード直接アクセス",
"SettingsButtonSave": "セーブ",
"SettingsButtonClose": "閉じる",
"SettingsButtonOk": "オーケー",
"SettingsButtonCancel": "キャンセル",
"SettingsButtonApply": "適用",
"ControllerSettingsPlayer": "プレイヤー",
"ControllerSettingsPlayer1": "プレイヤー 1",

View File

@@ -167,6 +167,8 @@
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
"SettingsButtonSave": "구하다",
"SettingsButtonClose": "출구",
"SettingsButtonOk": "좋아",
"SettingsButtonCancel": "취소",
"SettingsButtonApply": "적용하다",
"ControllerSettingsPlayer": "플레이어",
"ControllerSettingsPlayer1": "플레이어 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Bezpośredni Dostęp do Klawiatury",
"SettingsButtonSave": "Zapisz",
"SettingsButtonClose": "Zamknij",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Anuluj",
"SettingsButtonApply": "Zastosuj",
"ControllerSettingsPlayer": "Gracz",
"ControllerSettingsPlayer1": "Gracz 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Acesso direto ao teclado",
"SettingsButtonSave": "Salvar",
"SettingsButtonClose": "Fechar",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Cancelar",
"SettingsButtonApply": "Aplicar",
"ControllerSettingsPlayer": "Jogador",
"ControllerSettingsPlayer1": "Jogador 1",

View File

@@ -167,6 +167,8 @@
"SettingsTabInputDirectKeyboardAccess": "Прямой доступ с клавиатуры",
"SettingsButtonSave": "Сохранить",
"SettingsButtonClose": "Закрыть",
"SettingsButtonOk": "OK",
"SettingsButtonCancel": "Отмена",
"SettingsButtonApply": "Применить",
"ControllerSettingsPlayer": "Игрок",
"ControllerSettingsPlayer1": "Игрок 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "Doğrudan Klavye Erişimi",
"SettingsButtonSave": "Kaydet",
"SettingsButtonClose": "Kapat",
"SettingsButtonOk": "Tamam",
"SettingsButtonCancel": "İptal",
"SettingsButtonApply": "Uygula",
"ControllerSettingsPlayer": "Oyuncu",
"ControllerSettingsPlayer1": "Oyuncu 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "直通键盘控制",
"SettingsButtonSave": "保存",
"SettingsButtonClose": "关闭",
"SettingsButtonOk": "批准",
"SettingsButtonCancel": "取消",
"SettingsButtonApply": "应用",
"ControllerSettingsPlayer": "玩家",
"ControllerSettingsPlayer1": "玩家 1",

View File

@@ -168,6 +168,8 @@
"SettingsTabInputDirectKeyboardAccess": "直通鍵盤控制",
"SettingsButtonSave": "儲存",
"SettingsButtonClose": "關閉",
"SettingsButtonOk": "嘛好",
"SettingsButtonCancel": "取消",
"SettingsButtonApply": "套用",
"ControllerSettingsPlayer": "玩家",
"ControllerSettingsPlayer1": "玩家 1",

View File

@@ -41,6 +41,9 @@
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="{StaticResource ControlFillColorSecondary}" />
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>

View File

@@ -1,7 +1,6 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
<Design.PreviewWith>
<Border Height="2000" Padding="20">
@@ -269,13 +268,15 @@
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
<sys:Double x:Key="ScrollBarThickness">15</sys:Double>
<sys:Double x:Key="FontSizeSmall">8</sys:Double>
<sys:Double x:Key="FontSizeNormal">10</sys:Double>
<sys:Double x:Key="FontSize">12</sys:Double>
<sys:Double x:Key="FontSizeLarge">15</sys:Double>
<sys:Double x:Key="ControlContentThemeFontSize">13</sys:Double>
<x:Double x:Key="ScrollBarThickness">15</x:Double>
<x:Double x:Key="FontSizeSmall">8</x:Double>
<x:Double x:Key="FontSizeNormal">10</x:Double>
<x:Double x:Key="FontSize">12</x:Double>
<x:Double x:Key="FontSizeLarge">15</x:Double>
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
<x:Double x:Key="MenuItemHeight">26</x:Double>
<x:Double x:Key="TabItemMinHeight">28</x:Double>
<x:Double x:Key="ContentDialogMaxWidth">600</x:Double>
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
</Styles.Resources>
</Styles>

View File

@@ -113,6 +113,11 @@ namespace Ryujinx.Ava.Common
return;
}
OpenSaveDir(saveDataId);
}
public static void OpenSaveDir(ulong saveDataId)
{
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
if (!Directory.Exists(saveRootPath))

View File

@@ -1,5 +1,6 @@
using ARMeilleure.Translation.PTC;
using Avalonia;
using Avalonia.Threading;
using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
@@ -8,6 +9,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.System;
using Ryujinx.Common.SystemInfo;
using Ryujinx.Modules;
using Ryujinx.SDL2.Common;
using Ryujinx.Ui.Common;
using Ryujinx.Ui.Common.Configuration;
using Ryujinx.Ui.Common.Helper;
@@ -94,6 +96,9 @@ namespace Ryujinx.Ava
// Initialize Discord integration.
DiscordIntegrationModule.Initialize();
// Initialize SDL2 driver
SDL2Driver.MainThreadDispatcher = action => Dispatcher.UIThread.InvokeAsync(action, DispatcherPriority.Input);
ReloadConfig();
ForceDpiAware.Windows();
@@ -219,4 +224,4 @@ namespace Ryujinx.Ava
Logger.Shutdown();
}
}
}
}

View File

@@ -33,9 +33,9 @@
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageReference Include="SPB" Version="0.0.4-build28" />
<PackageReference Include="SharpZipLib" Version="1.4.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />

View File

@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using FluentAvalonia.UI.Controls;
using LibHac;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.ViewModels;
using Ryujinx.HLE.FileSystem;
@@ -14,6 +15,8 @@ namespace Ryujinx.Ava.Ui.Controls
{
public AccountManager AccountManager { get; }
public ContentManager ContentManager { get; }
public VirtualFileSystem VirtualFileSystem { get; }
public HorizonClient HorizonClient { get; }
public UserProfileViewModel ViewModel { get; set; }
public NavigationDialogHost()
@@ -22,10 +25,12 @@ namespace Ryujinx.Ava.Ui.Controls
}
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
VirtualFileSystem virtualFileSystem)
VirtualFileSystem virtualFileSystem, HorizonClient horizonClient)
{
AccountManager = accountManager;
ContentManager = contentManager;
VirtualFileSystem = virtualFileSystem;
HorizonClient = horizonClient;
ViewModel = new UserProfileViewModel(this);
@@ -54,9 +59,10 @@ namespace Ryujinx.Ava.Ui.Controls
ContentFrame.Navigate(sourcePageType, parameter);
}
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager, VirtualFileSystem ownerVirtualFileSystem)
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager,
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
{
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem);
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
ContentDialog contentDialog = new ContentDialog
{
Title = LocaleManager.Instance["UserProfileWindowTitle"],

View File

@@ -0,0 +1,102 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Height="400"
Width="550"
x:Class="Ryujinx.Ava.Ui.Controls.SaveManager">
<UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
<Label Content="{locale:Locale CommonSort}" VerticalAlignment="Center" />
<ComboBox SelectedIndex="{Binding SortIndex}" Width="100">
<ComboBoxItem>
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
Content="{locale:Locale Name}" />
</ComboBoxItem>
<ComboBoxItem>
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
Content="{locale:Locale Size}" />
</ComboBoxItem>
</ComboBox>
<ComboBox SelectedIndex="{Binding OrderIndex}" Width="150">
<ComboBoxItem>
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
Content="{locale:Locale OrderAscending}" />
</ComboBoxItem>
<ComboBoxItem>
<Label VerticalAlignment="Center" HorizontalContentAlignment="Left"
Content="{locale:Locale Descending}" />
</ComboBoxItem>
</ComboBox>
</StackPanel>
<Grid Grid.Column="1" HorizontalAlignment="Stretch" Margin="10,0, 0, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="{locale:Locale Search}" VerticalAlignment="Center"/>
<TextBox Margin="5,0,0,0" Grid.Column="1" HorizontalAlignment="Stretch" Text="{Binding Search}"/>
</Grid>
</Grid>
<Border Grid.Row="1" Margin="0,5" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListBox Name="SaveList" Items="{Binding View}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="models:SaveModel">
<Grid HorizontalAlignment="Stretch" Margin="0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<Border Height="42" Margin="2" Width="42" Padding="10"
IsVisible="{Binding !InGameList}">
<ui:SymbolIcon Symbol="Help" FontSize="30" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<Image IsVisible="{Binding InGameList}"
Margin="2"
Width="42"
Height="42"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<TextBlock MaxLines="3" Width="320" Margin="5" TextWrapping="Wrap"
Text="{Binding Title}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Grid.Column="1" Spacing="10" HorizontalAlignment="Right"
Orientation="Horizontal">
<Label Content="{Binding SizeString}" IsVisible="{Binding SizeAvailable}"
VerticalAlignment="Center" HorizontalAlignment="Right" />
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
MinWidth="0" MinHeight="0" Name="OpenLocation" Command="{Binding OpenLocation}">
<ui:SymbolIcon Symbol="OpenFolder" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Button>
<Button VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10"
MinWidth="0" MinHeight="0" Name="Delete" Command="{Binding Delete}">
<ui:SymbolIcon Symbol="Delete" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Button>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,160 @@
using Avalonia.Controls;
using DynamicData;
using DynamicData.Binding;
using LibHac;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Shim;
using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.Models;
using Ryujinx.HLE.FileSystem;
using Ryujinx.Ui.App.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
namespace Ryujinx.Ava.Ui.Controls
{
public partial class SaveManager : UserControl
{
private readonly UserProfile _userProfile;
private readonly HorizonClient _horizonClient;
private readonly VirtualFileSystem _virtualFileSystem;
private int _sortIndex;
private int _orderIndex;
private ObservableCollection<SaveModel> _view = new ObservableCollection<SaveModel>();
private string _search;
public ObservableCollection<SaveModel> Saves { get; set; } = new ObservableCollection<SaveModel>();
public ObservableCollection<SaveModel> View
{
get => _view;
set => _view = value;
}
public int SortIndex
{
get => _sortIndex;
set
{
_sortIndex = value;
Sort();
}
}
public int OrderIndex
{
get => _orderIndex;
set
{
_orderIndex = value;
Sort();
}
}
public string Search
{
get => _search;
set
{
_search = value;
Sort();
}
}
public SaveManager()
{
InitializeComponent();
}
public SaveManager(UserProfile userProfile, HorizonClient horizonClient, VirtualFileSystem virtualFileSystem)
{
_userProfile = userProfile;
_horizonClient = horizonClient;
_virtualFileSystem = virtualFileSystem;
InitializeComponent();
DataContext = this;
Task.Run(LoadSaves);
}
public void LoadSaves()
{
Saves.Clear();
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
new UserId((ulong)_userProfile.UserId.High, (ulong)_userProfile.UserId.Low), saveDataId: default, index: default);
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
_horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
while (true)
{
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
if (readCount == 0)
{
break;
}
for (int i = 0; i < readCount; i++)
{
var save = saveDataInfo[i];
if (save.ProgramId.Value != 0)
{
var saveModel = new SaveModel(save, _horizonClient, _virtualFileSystem);
Saves.Add(saveModel);
saveModel.DeleteAction = () => { Saves.Remove(saveModel); };
}
Sort();
}
}
}
private void Sort()
{
Saves.AsObservableChangeSet()
.Filter(Filter)
.Sort(GetComparer())
.Bind(out var view).AsObservableList();
_view.Clear();
_view.AddRange(view);
}
private IComparer<SaveModel> GetComparer()
{
switch (SortIndex)
{
case 0:
return OrderIndex == 0
? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
: SortExpressionComparer<SaveModel>.Descending(save => save.Title);
case 1:
return OrderIndex == 0
? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
: SortExpressionComparer<SaveModel>.Descending(save => save.Size);
default:
return null;
}
}
private bool Filter(object arg)
{
if (arg is SaveModel save)
{
return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower());
}
return false;
}
}
}

View File

@@ -10,6 +10,7 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
Margin="0"
MinWidth="500"
Padding="0"
mc:Ignorable="d">
<UserControl.Resources>
@@ -63,7 +64,7 @@
HorizontalAlignment="Stretch"
MaxLength="{Binding MaxProfileNameLength}"
Text="{Binding Name}" />
<TextBlock Text="{Locale:Locale UserProfilesUserId}" />
<TextBlock Name="IdText" Text="{Locale:Locale UserProfilesUserId}" />
<TextBlock Name="IdLabel" Text="{Binding UserId}" />
</StackPanel>
<StackPanel

View File

@@ -36,15 +36,8 @@ namespace Ryujinx.Ava.Ui.Controls
case NavigationMode.New:
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
_isNewUser = args.isNewUser;
if (!_isNewUser)
{
_profile = args.profile;
TempProfile = new TempProfile(_profile);
}
else
{
TempProfile = new TempProfile();
}
_profile = args.profile;
TempProfile = new TempProfile(_profile);
_parent = args.parent;
break;
@@ -53,7 +46,8 @@ namespace Ryujinx.Ava.Ui.Controls
DataContext = TempProfile;
AddPictureButton.IsVisible = _isNewUser;
IdLabel.IsVisible = !_isNewUser;
IdLabel.IsVisible = _profile != null;
IdText.IsVisible = _profile != null;
ChangePictureButton.IsVisible = !_isNewUser;
}
}
@@ -87,7 +81,7 @@ namespace Ryujinx.Ava.Ui.Controls
return;
}
if (_profile != null)
if (_profile != null && !_isNewUser)
{
_profile.Name = TempProfile.Name;
_profile.Image = TempProfile.Image;
@@ -97,7 +91,7 @@ namespace Ryujinx.Ava.Ui.Controls
}
else if (_isNewUser)
{
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image);
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image, TempProfile.UserId);
}
else
{

View File

@@ -0,0 +1,70 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
MinWidth="500"
MinHeight="400"
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
x:Class="Ryujinx.Ava.Ui.Controls.UserRecoverer">
<Design.DataContext>
<viewModels:UserProfileViewModel />
</Design.DataContext>
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0"
Margin="5"
Height="30"
Width="50"
MinWidth="50"
HorizontalAlignment="Left"
Command="{Binding GoBack}">
<ui:SymbolIcon Symbol="Back"/>
</Button>
<TextBlock Grid.Row="1"
Text="{Locale:Locale UserProfilesRecoverHeading}"/>
<ListBox
Margin="5"
Grid.Row="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Items="{Binding LostProfiles}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ClipToBounds="True"
CornerRadius="5">
<Grid Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding UserId}"
TextAlignment="Left"
TextWrapping="Wrap" />
<Button Grid.Column="1"
HorizontalAlignment="Right"
Command="{Binding Recover}"
CommandParameter="{Binding}"
Content="{Locale:Locale Recover}"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>

View File

@@ -0,0 +1,44 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
using Ryujinx.Ava.Ui.Models;
using Ryujinx.Ava.Ui.ViewModels;
namespace Ryujinx.Ava.Ui.Controls
{
public partial class UserRecoverer : UserControl
{
private UserProfileViewModel _viewModel;
private NavigationDialogHost _parent;
public UserRecoverer()
{
InitializeComponent();
AddHandler(Frame.NavigatedToEvent, (s, e) =>
{
NavigatedTo(e);
}, RoutingStrategies.Direct);
}
private void NavigatedTo(NavigationEventArgs arg)
{
if (Program.PreviewerDetached)
{
switch (arg.NavigationMode)
{
case NavigationMode.New:
var args = ((NavigationDialogHost parent, UserProfileViewModel viewModel))arg.Parameter;
_viewModel = args.viewModel;
_parent = args.parent;
break;
}
DataContext = _viewModel;
}
}
}
}

View File

@@ -10,6 +10,7 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
d:DesignHeight="450"
MinWidth="500"
d:DesignWidth="800"
mc:Ignorable="d">
<UserControl.Resources>
@@ -25,6 +26,7 @@
</Grid.RowDefinitions>
<ListBox
Margin="5"
MaxHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
DoubleTapped="ProfilesList_DoubleTapped"
@@ -88,21 +90,56 @@
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel
<Grid
Grid.Row="1"
Margin="10,0"
HorizontalAlignment="Center"
Orientation="Horizontal"
Spacing="10">
<Button Command="{Binding AddUser}" Content="{Locale:Locale UserProfilesAddNewProfile}" />
HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button
HorizontalAlignment="Stretch"
Grid.Row="0"
Grid.Column="0"
Margin="2"
Command="{Binding AddUser}"
Content="{Locale:Locale UserProfilesAddNewProfile}" />
<Button
HorizontalAlignment="Stretch"
Grid.Row="0"
Margin="2"
Grid.Column="1"
Command="{Binding EditUser}"
Content="{Locale:Locale UserProfilesEditProfile}"
IsEnabled="{Binding IsSelectedProfiledEditable}" />
<Button
HorizontalAlignment="Stretch"
Grid.Row="1"
Grid.Column="0"
Margin="2"
Content="{Locale:Locale UserProfilesManageSaves}"
Command="{Binding ManageSaves}" />
<Button
HorizontalAlignment="Stretch"
Grid.Row="1"
Grid.Column="1"
Margin="2"
Command="{Binding DeleteUser}"
Content="{Locale:Locale UserProfilesDeleteSelectedProfile}"
IsEnabled="{Binding IsSelectedProfileDeletable}" />
</StackPanel>
<Button
HorizontalAlignment="Stretch"
Grid.Row="2"
Grid.ColumnSpan="2"
Grid.Column="0"
Margin="2"
Command="{Binding RecoverLostAccounts}"
Content="{Locale:Locale UserProfilesRecoverLostAccounts}" />
</Grid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,122 @@
using LibHac;
using LibHac.Fs;
using LibHac.Fs.Shim;
using LibHac.Ncm;
using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.Controls;
using Ryujinx.Ava.Ui.ViewModels;
using Ryujinx.Ava.Ui.Windows;
using Ryujinx.HLE.FileSystem;
using Ryujinx.Ui.App.Common;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Ryujinx.Ava.Ui.Models
{
public class SaveModel : BaseModel
{
private readonly HorizonClient _horizonClient;
private long _size;
public Action DeleteAction { get; set; }
public ulong SaveId { get; }
public ProgramId TitleId { get; }
public string TitleIdString => $"{TitleId.Value:X16}";
public UserId UserId { get; }
public bool InGameList { get; }
public string Title { get; }
public byte[] Icon { get; }
public long Size
{
get => _size; set
{
_size = value;
SizeAvailable = true;
OnPropertyChanged();
OnPropertyChanged(nameof(SizeString));
OnPropertyChanged(nameof(SizeAvailable));
}
}
public bool SizeAvailable { get; set; }
public string SizeString => $"{((float)_size * 0.000000954):0.###}MB";
public SaveModel(SaveDataInfo info, HorizonClient horizonClient, VirtualFileSystem virtualFileSystem)
{
_horizonClient = horizonClient;
SaveId = info.SaveDataId;
TitleId = info.ProgramId;
UserId = info.UserId;
var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.TitleId.ToUpper() == TitleIdString);
InGameList = appData != null;
if (InGameList)
{
Icon = appData.Icon;
Title = appData.TitleName;
}
else
{
var appMetadata = MainWindow.MainWindowViewModel.ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
Title = appMetadata.Title ?? TitleIdString;
}
Task.Run(() =>
{
var saveRoot = System.IO.Path.Combine(virtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
long total_size = GetDirectorySize(saveRoot);
long GetDirectorySize(string path)
{
long size = 0;
if (Directory.Exists(path))
{
var directories = Directory.GetDirectories(path);
foreach (var directory in directories)
{
size += GetDirectorySize(directory);
}
var files = Directory.GetFiles(path);
foreach (var file in files)
{
size += new FileInfo(file).Length;
}
}
return size;
}
Size = total_size;
});
}
public void OpenLocation()
{
ApplicationHelper.OpenSaveDir(SaveId);
}
public async void Delete()
{
var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DeleteUserSave"],
LocaleManager.Instance["IrreversibleActionNote"],
LocaleManager.Instance["InputDialogYes"],
LocaleManager.Instance["InputDialogNo"], "");
if (result == UserResult.Yes)
{
_horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, SaveId);
DeleteAction?.Invoke();
}
}
}
}

View File

@@ -45,9 +45,12 @@ namespace Ryujinx.Ava.Ui.Models
{
_profile = profile;
Image = profile.Image;
Name = profile.Name;
UserId = profile.UserId;
if (_profile != null)
{
Image = profile.Image;
Name = profile.Name;
UserId = profile.UserId;
}
}
public TempProfile(){}

View File

@@ -1,3 +1,4 @@
using Ryujinx.Ava.Ui.Controls;
using Ryujinx.Ava.Ui.ViewModels;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Profile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
@@ -7,6 +8,7 @@ namespace Ryujinx.Ava.Ui.Models
public class UserProfile : BaseModel
{
private readonly Profile _profile;
private readonly NavigationDialogHost _owner;
private byte[] _image;
private string _name;
private UserId _userId;
@@ -41,9 +43,10 @@ namespace Ryujinx.Ava.Ui.Models
}
}
public UserProfile(Profile profile)
public UserProfile(Profile profile, NavigationDialogHost owner)
{
_profile = profile;
_owner = owner;
Image = profile.Image;
Name = profile.Name;
@@ -57,5 +60,10 @@ namespace Ryujinx.Ava.Ui.Models
OnPropertyChanged(nameof(IsOpened));
OnPropertyChanged(nameof(Name));
}
public void Recover(UserProfile userProfile)
{
_owner.Navigate(typeof(UserEditor), (_owner, userProfile, true));
}
}
}

View File

@@ -76,6 +76,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
private bool _showAll;
private string _lastScannedAmiiboId;
private ReadOnlyObservableCollection<ApplicationData> _appsObservableList;
public ApplicationLibrary ApplicationLibrary => _owner.ApplicationLibrary;
public string TitleName { get; internal set; }
@@ -103,8 +104,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void Initialize()
{
_owner.ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
_owner.ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
Ptc.PtcStateChanged -= ProgressHandler;
Ptc.PtcStateChanged += ProgressHandler;
@@ -817,7 +818,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
Thread thread = new(() =>
{
_owner.ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs.Value, ConfigurationState.Instance.System.Language);
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs.Value, ConfigurationState.Instance.System.Language);
_isLoading = false;
})
@@ -1005,7 +1006,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
public async void ManageProfiles()
{
await NavigationDialogHost.Show(_owner.AccountManager, _owner.ContentManager, _owner.VirtualFileSystem);
await NavigationDialogHost.Show(_owner.AccountManager, _owner.ContentManager, _owner.VirtualFileSystem, _owner.LibHacHorizonManager.RyujinxClient);
}
public async void OpenAboutWindow()
@@ -1098,7 +1099,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
selection.Favorite = !selection.Favorite;
_owner.ApplicationLibrary.LoadAndSaveMetaData(selection.TitleId, appMetadata =>
ApplicationLibrary.LoadAndSaveMetaData(selection.TitleId, appMetadata =>
{
appMetadata.Favorite = selection.Favorite;
});

View File

@@ -118,7 +118,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
OnPropertyChanged();
}
}
public bool IsMacOS
{
get => OperatingSystem.IsMacOS();
}
public bool EnableDiscordIntegration { get; set; }
public bool CheckUpdatesOnStart { get; set; }
public bool ShowConfirmExit { get; set; }
@@ -474,11 +479,40 @@ namespace Ryujinx.Ava.Ui.ViewModels
MainWindow.UpdateGraphicsConfig();
_previousVolumeLevel = Volume;
if (_owner is SettingsWindow owner)
{
owner.ControllerSettings?.SaveCurrentProfile();
}
if (_owner.Owner is MainWindow window && _directoryChanged)
{
window.ViewModel.LoadApplications();
}
_directoryChanged = false;
}
public void RevertIfNotSaved()
{
Program.ReloadConfig();
}
public void ApplyButton()
{
SaveSettings();
}
public void OkButton()
{
SaveSettings();
_owner.Close();
}
public void CancelButton()
{
RevertIfNotSaved();
_owner.Close();
}
}
}

View File

@@ -1,8 +1,14 @@
using Avalonia;
using Avalonia.Threading;
using FluentAvalonia.UI.Controls;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Shim;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.Controls;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
@@ -19,6 +25,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
public UserProfileViewModel()
{
Profiles = new ObservableCollection<UserProfile>();
LostProfiles = new ObservableCollection<UserProfile>();
}
public UserProfileViewModel(NavigationDialogHost owner) : this()
@@ -30,6 +37,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
public ObservableCollection<UserProfile> Profiles { get; set; }
public ObservableCollection<UserProfile> LostProfiles { get; set; }
public UserProfile SelectedProfile
{
get => _selectedProfile;
@@ -65,12 +74,13 @@ namespace Ryujinx.Ava.Ui.ViewModels
public void LoadProfiles()
{
Profiles.Clear();
LostProfiles.Clear();
var profiles = _owner.AccountManager.GetAllUsers().OrderByDescending(x => x.AccountState == AccountState.Open);
foreach (var profile in profiles)
{
Profiles.Add(new UserProfile(profile));
Profiles.Add(new UserProfile(profile, _owner));
}
SelectedProfile = Profiles.FirstOrDefault(x => x.UserId == _owner.AccountManager.LastOpenedUser.UserId);
@@ -84,6 +94,42 @@ namespace Ryujinx.Ava.Ui.ViewModels
_owner.AccountManager.OpenUser(_selectedProfile.UserId);
}
}
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
default, saveDataId: default, index: default);
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
_owner.HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new HashSet<HLE.HOS.Services.Account.Acc.UserId>();
while (true)
{
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
if (readCount == 0)
{
break;
}
for (int i = 0; i < readCount; i++)
{
var save = saveDataInfo[i];
var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
if (Profiles.FirstOrDefault( x=> x.UserId == id) == null)
{
lostAccounts.Add(id);
}
}
}
foreach(var account in lostAccounts)
{
LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), _owner));
}
}
public void AddUser()
@@ -93,6 +139,25 @@ namespace Ryujinx.Ava.Ui.ViewModels
_owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true));
}
public async void ManageSaves()
{
UserProfile userProfile = _highlightedProfile ?? SelectedProfile;
SaveManager manager = new SaveManager(userProfile, _owner.HorizonClient, _owner.VirtualFileSystem);
ContentDialog contentDialog = new ContentDialog
{
Title = string.Format(LocaleManager.Instance["SaveManagerHeading"], userProfile.Name),
PrimaryButtonText = "",
SecondaryButtonText = "",
CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
Content = manager,
Padding = new Thickness(0)
};
await contentDialog.ShowAsync();
}
public void EditUser()
{
_owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false));
@@ -134,5 +199,15 @@ namespace Ryujinx.Ava.Ui.ViewModels
LoadProfiles();
}
public void GoBack()
{
_owner.GoBack();
}
public void RecoverLostAccounts()
{
_owner.Navigate(typeof(UserRecoverer), (this._owner, this));
}
}
}

View File

@@ -36,6 +36,7 @@ namespace Ryujinx.Ava.Ui.Windows
{
public partial class MainWindow : StyleableWindow
{
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
private bool _canUpdate;
private bool _isClosing;
private bool _isLoading;
@@ -81,6 +82,8 @@ namespace Ryujinx.Ava.Ui.Windows
{
ViewModel = new MainWindowViewModel(this);
MainWindowViewModel = ViewModel;
DataContext = ViewModel;
InitializeComponent();

View File

@@ -955,16 +955,25 @@
Icon="Document" />
</ui:NavigationView.MenuItems>
</ui:NavigationView>
<StackPanel
<ReversibleStackPanel
Grid.Row="2"
Margin="10"
Spacing="10"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="{locale:Locale SettingsButtonSave}" Click="SaveButton_Clicked" />
<Button Content="{locale:Locale SettingsButtonClose}" Click="CloseButton_Clicked" />
<Button Content="{locale:Locale SettingsButtonApply}"
Click="ApplyButton_Clicked" />
</StackPanel>
HorizontalAlignment="Right"
ReverseOrder="{ReflectionBinding IsMacOS}">
<Button
HotKey="Enter"
Classes="accent"
Content="{locale:Locale SettingsButtonOk}"
Command="{ReflectionBinding OkButton}" />
<Button
HotKey="Escape"
Content="{locale:Locale SettingsButtonCancel}"
Command="{ReflectionBinding CancelButton}" />
<Button
Content="{locale:Locale SettingsButtonApply}"
Command="{ReflectionBinding ApplyButton}" />
</ReversibleStackPanel>
</Grid>
</window:StyleableWindow>

View File

@@ -199,36 +199,6 @@ namespace Ryujinx.Ava.Ui.Windows
}
}
private void SaveButton_Clicked(object sender, RoutedEventArgs e)
{
SaveSettings();
Close();
}
private void CloseButton_Clicked(object sender, RoutedEventArgs e)
{
ViewModel.RevertIfNotSaved();
Close();
}
private void ApplyButton_Clicked(object sender, RoutedEventArgs e)
{
SaveSettings();
}
private void SaveSettings()
{
ViewModel.SaveSettings();
ControllerSettings?.SaveCurrentProfile();
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
{
window.ViewModel.LoadApplications();
}
ViewModel.DirectoryChanged = false;
}
protected override void OnClosed(EventArgs e)
{
ControllerSettings.Dispose();

View File

@@ -28,9 +28,39 @@ namespace Ryujinx.Common.SystemInfo
CpuName = $"{cpuName} ; {LogicalCoreCount} logical";
RamTotal = totalRAM;
RamAvailable = GetVMInfoAvailableMemory();
}
[DllImport("libSystem.dylib", CharSet = CharSet.Ansi, SetLastError = true)]
static ulong GetVMInfoAvailableMemory()
{
var port = mach_host_self();
uint pageSize = 0;
var result = host_page_size(port, ref pageSize);
if (result != 0)
{
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_page_size() error = {result}");
return 0;
}
const int flavor = 4; // HOST_VM_INFO64
uint count = (uint)(Marshal.SizeOf<VMStatistics64>() / sizeof(int)); // HOST_VM_INFO64_COUNT
VMStatistics64 stats = new();
result = host_statistics64(port, flavor, ref stats, ref count);
if (result != 0)
{
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_statistics64() error = {result}");
return 0;
}
return (ulong)(stats.FreeCount + stats.InactiveCount) * pageSize;
}
private const string SystemLibraryName = "libSystem.dylib";
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
@@ -85,5 +115,43 @@ namespace Ryujinx.Common.SystemInfo
return res;
}
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern uint mach_host_self();
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int host_page_size(uint host, ref uint out_page_size);
[StructLayout(LayoutKind.Sequential, Pack = 8)]
struct VMStatistics64
{
public uint FreeCount;
public uint ActiveCount;
public uint InactiveCount;
public uint WireCount;
public ulong ZeroFillCount;
public ulong Reactivations;
public ulong Pageins;
public ulong Pageouts;
public ulong Faults;
public ulong CowFaults;
public ulong Lookups;
public ulong Hits;
public ulong Purges;
public uint PurgeableCount;
public uint SpeculativeCount;
public ulong Decompressions;
public ulong Compressions;
public ulong Swapins;
public ulong Swapouts;
public uint CompressorPageCount;
public uint ThrottledCount;
public uint ExternalPageCount;
public uint InternalPageCount;
public ulong TotalUncompressedPagesInCompressor;
}
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
}
}

View File

@@ -12,12 +12,12 @@ namespace Ryujinx.Graphics.Vulkan
private const int MaxUpdateBufferSize = 0x10000;
public const AccessFlags DefaultAccessFlags =
AccessFlags.AccessIndirectCommandReadBit |
AccessFlags.AccessShaderReadBit |
AccessFlags.AccessShaderWriteBit |
AccessFlags.AccessTransferReadBit |
AccessFlags.AccessTransferWriteBit |
AccessFlags.AccessUniformReadBit;
AccessFlags.IndirectCommandReadBit |
AccessFlags.ShaderReadBit |
AccessFlags.ShaderWriteBit |
AccessFlags.TransferReadBit |
AccessFlags.TransferWriteBit |
AccessFlags.UniformReadBit;
private readonly VulkanRenderer _gd;
private readonly Device _device;
@@ -87,9 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
_gd.Api.CmdPipelineBarrier(
commandBuffer,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
DependencyFlags.DependencyDeviceGroupBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.AllCommandsBit,
DependencyFlags.DeviceGroupBit,
1,
memoryBarrier,
0,
@@ -273,9 +273,9 @@ namespace Ryujinx.Graphics.Vulkan
cbs.CommandBuffer,
dstBuffer,
BufferHolder.DefaultAccessFlags,
AccessFlags.AccessTransferWriteBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
dstOffset,
data.Length);
@@ -293,10 +293,10 @@ namespace Ryujinx.Graphics.Vulkan
_gd,
cbs.CommandBuffer,
dstBuffer,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
BufferHolder.DefaultAccessFlags,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
dstOffset,
data.Length);
@@ -320,9 +320,9 @@ namespace Ryujinx.Graphics.Vulkan
cbs.CommandBuffer,
dstBuffer,
BufferHolder.DefaultAccessFlags,
AccessFlags.AccessTransferWriteBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
dstOffset,
size);
@@ -334,10 +334,10 @@ namespace Ryujinx.Graphics.Vulkan
gd,
cbs.CommandBuffer,
dstBuffer,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
BufferHolder.DefaultAccessFlags,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
dstOffset,
size);
}

View File

@@ -10,28 +10,28 @@ namespace Ryujinx.Graphics.Vulkan
class BufferManager : IDisposable
{
private const MemoryPropertyFlags DefaultBufferMemoryFlags =
MemoryPropertyFlags.MemoryPropertyHostVisibleBit |
MemoryPropertyFlags.MemoryPropertyHostCoherentBit |
MemoryPropertyFlags.MemoryPropertyHostCachedBit;
MemoryPropertyFlags.HostVisibleBit |
MemoryPropertyFlags.HostCoherentBit |
MemoryPropertyFlags.HostCachedBit;
private const MemoryPropertyFlags DeviceLocalBufferMemoryFlags =
MemoryPropertyFlags.MemoryPropertyDeviceLocalBit;
MemoryPropertyFlags.DeviceLocalBit;
private const MemoryPropertyFlags FlushableDeviceLocalBufferMemoryFlags =
MemoryPropertyFlags.MemoryPropertyHostVisibleBit |
MemoryPropertyFlags.MemoryPropertyHostCoherentBit |
MemoryPropertyFlags.MemoryPropertyDeviceLocalBit;
MemoryPropertyFlags.HostVisibleBit |
MemoryPropertyFlags.HostCoherentBit |
MemoryPropertyFlags.DeviceLocalBit;
private const BufferUsageFlags DefaultBufferUsageFlags =
BufferUsageFlags.BufferUsageTransferSrcBit |
BufferUsageFlags.BufferUsageTransferDstBit |
BufferUsageFlags.BufferUsageUniformTexelBufferBit |
BufferUsageFlags.BufferUsageStorageTexelBufferBit |
BufferUsageFlags.BufferUsageUniformBufferBit |
BufferUsageFlags.BufferUsageStorageBufferBit |
BufferUsageFlags.BufferUsageIndexBufferBit |
BufferUsageFlags.BufferUsageVertexBufferBit |
BufferUsageFlags.BufferUsageTransformFeedbackBufferBitExt;
BufferUsageFlags.TransferSrcBit |
BufferUsageFlags.TransferDstBit |
BufferUsageFlags.UniformTexelBufferBit |
BufferUsageFlags.StorageTexelBufferBit |
BufferUsageFlags.UniformBufferBit |
BufferUsageFlags.StorageBufferBit |
BufferUsageFlags.IndexBufferBit |
BufferUsageFlags.VertexBufferBit |
BufferUsageFlags.TransformFeedbackBufferBitExt;
private readonly PhysicalDevice _physicalDevice;
private readonly Device _device;
@@ -76,11 +76,11 @@ namespace Ryujinx.Graphics.Vulkan
if (forConditionalRendering && gd.Capabilities.SupportsConditionalRendering)
{
usage |= BufferUsageFlags.BufferUsageConditionalRenderingBitExt;
usage |= BufferUsageFlags.ConditionalRenderingBitExt;
}
else if (gd.Capabilities.SupportsIndirectParameters)
{
usage |= BufferUsageFlags.BufferUsageIndirectBufferBit;
usage |= BufferUsageFlags.IndirectBufferBit;
}
var bufferCreateInfo = new BufferCreateInfo()

View File

@@ -71,8 +71,8 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.CommandPoolCreateInfo,
QueueFamilyIndex = queueFamilyIndex,
Flags = CommandPoolCreateFlags.CommandPoolCreateTransientBit |
CommandPoolCreateFlags.CommandPoolCreateResetCommandBufferBit
Flags = CommandPoolCreateFlags.TransientBit |
CommandPoolCreateFlags.ResetCommandBufferBit
};
api.CreateCommandPool(device, commandPoolCreateInfo, null, out _pool).ThrowOnError();

View File

@@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Vulkan
}
else if (texture is TextureView view)
{
view.Storage.InsertBarrier(cbs, AccessFlags.AccessShaderReadBit, stage.ConvertToPipelineStageFlags());
view.Storage.InsertBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
_textureRefs[binding] = view.GetImageView();
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();

View File

@@ -12,12 +12,12 @@ namespace Ryujinx.Graphics.Vulkan
{
return stage switch
{
ShaderStage.Vertex => ShaderStageFlags.ShaderStageVertexBit,
ShaderStage.Geometry => ShaderStageFlags.ShaderStageGeometryBit,
ShaderStage.TessellationControl => ShaderStageFlags.ShaderStageTessellationControlBit,
ShaderStage.TessellationEvaluation => ShaderStageFlags.ShaderStageTessellationEvaluationBit,
ShaderStage.Fragment => ShaderStageFlags.ShaderStageFragmentBit,
ShaderStage.Compute => ShaderStageFlags.ShaderStageComputeBit,
ShaderStage.Vertex => ShaderStageFlags.VertexBit,
ShaderStage.Geometry => ShaderStageFlags.GeometryBit,
ShaderStage.TessellationControl => ShaderStageFlags.TessellationControlBit,
ShaderStage.TessellationEvaluation => ShaderStageFlags.TessellationEvaluationBit,
ShaderStage.Fragment => ShaderStageFlags.FragmentBit,
ShaderStage.Compute => ShaderStageFlags.ComputeBit,
_ => LogInvalidAndReturn(stage, nameof(ShaderStage), (ShaderStageFlags)0)
};
}
@@ -26,12 +26,12 @@ namespace Ryujinx.Graphics.Vulkan
{
return stage switch
{
ShaderStage.Vertex => PipelineStageFlags.PipelineStageVertexShaderBit,
ShaderStage.Geometry => PipelineStageFlags.PipelineStageGeometryShaderBit,
ShaderStage.TessellationControl => PipelineStageFlags.PipelineStageTessellationControlShaderBit,
ShaderStage.TessellationEvaluation => PipelineStageFlags.PipelineStageTessellationEvaluationShaderBit,
ShaderStage.Fragment => PipelineStageFlags.PipelineStageFragmentShaderBit,
ShaderStage.Compute => PipelineStageFlags.PipelineStageComputeShaderBit,
ShaderStage.Vertex => PipelineStageFlags.VertexShaderBit,
ShaderStage.Geometry => PipelineStageFlags.GeometryShaderBit,
ShaderStage.TessellationControl => PipelineStageFlags.TessellationControlShaderBit,
ShaderStage.TessellationEvaluation => PipelineStageFlags.TessellationEvaluationShaderBit,
ShaderStage.Fragment => PipelineStageFlags.FragmentShaderBit,
ShaderStage.Compute => PipelineStageFlags.ComputeShaderBit,
_ => LogInvalidAndReturn(stage, nameof(ShaderStage), (PipelineStageFlags)0)
};
}
@@ -112,10 +112,10 @@ namespace Ryujinx.Graphics.Vulkan
{
return face switch
{
Face.Back => CullModeFlags.CullModeBackBit,
Face.Front => CullModeFlags.CullModeFrontBit,
Face.FrontAndBack => CullModeFlags.CullModeFrontAndBack,
_ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.CullModeBackBit)
Face.Back => CullModeFlags.BackBit,
Face.Front => CullModeFlags.FrontBit,
Face.FrontAndBack => CullModeFlags.FrontAndBack,
_ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.BackBit)
};
}
@@ -223,14 +223,14 @@ namespace Ryujinx.Graphics.Vulkan
{
Target.Texture1D or
Target.Texture1DArray or
Target.TextureBuffer => ImageType.ImageType1D,
Target.TextureBuffer => ImageType.Type1D,
Target.Texture2D or
Target.Texture2DArray or
Target.Texture2DMultisample or
Target.Cubemap or
Target.CubemapArray => ImageType.ImageType2D,
Target.Texture3D => ImageType.ImageType3D,
_ => LogInvalidAndReturn(target, nameof(Target), ImageType.ImageType2D)
Target.CubemapArray => ImageType.Type2D,
Target.Texture3D => ImageType.Type3D,
_ => LogInvalidAndReturn(target, nameof(Target), ImageType.Type2D)
};
}
@@ -238,14 +238,14 @@ namespace Ryujinx.Graphics.Vulkan
{
return target switch
{
Target.Texture1D => ImageViewType.ImageViewType1D,
Target.Texture2D or Target.Texture2DMultisample => ImageViewType.ImageViewType2D,
Target.Texture3D => ImageViewType.ImageViewType3D,
Target.Texture1DArray => ImageViewType.ImageViewType1DArray,
Target.Texture2DArray => ImageViewType.ImageViewType2DArray,
Target.Cubemap => ImageViewType.Cube,
Target.CubemapArray => ImageViewType.CubeArray,
_ => LogInvalidAndReturn(target, nameof(Target), ImageViewType.ImageViewType2D)
Target.Texture1D => ImageViewType.Type1D,
Target.Texture2D or Target.Texture2DMultisample => ImageViewType.Type2D,
Target.Texture3D => ImageViewType.Type3D,
Target.Texture1DArray => ImageViewType.Type1DArray,
Target.Texture2DArray => ImageViewType.Type2DArray,
Target.Cubemap => ImageViewType.TypeCube,
Target.CubemapArray => ImageViewType.TypeCubeArray,
_ => LogInvalidAndReturn(target, nameof(Target), ImageViewType.Type2D)
};
}
@@ -253,12 +253,12 @@ namespace Ryujinx.Graphics.Vulkan
{
return format switch
{
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.ImageAspectDepthBit,
GAL.Format.S8Uint => ImageAspectFlags.ImageAspectStencilBit,
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.DepthBit,
GAL.Format.S8Uint => ImageAspectFlags.StencilBit,
GAL.Format.D24UnormS8Uint or
GAL.Format.D32FloatS8Uint or
GAL.Format.S8UintD24Unorm => ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit,
_ => ImageAspectFlags.ImageAspectColorBit
GAL.Format.S8UintD24Unorm => ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit,
_ => ImageAspectFlags.ColorBit
};
}
@@ -266,12 +266,12 @@ namespace Ryujinx.Graphics.Vulkan
{
return format switch
{
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.ImageAspectDepthBit,
GAL.Format.S8Uint => ImageAspectFlags.ImageAspectStencilBit,
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.DepthBit,
GAL.Format.S8Uint => ImageAspectFlags.StencilBit,
GAL.Format.D24UnormS8Uint or
GAL.Format.D32FloatS8Uint or
GAL.Format.S8UintD24Unorm => depthStencilMode == DepthStencilMode.Stencil ? ImageAspectFlags.ImageAspectStencilBit : ImageAspectFlags.ImageAspectDepthBit,
_ => ImageAspectFlags.ImageAspectColorBit
GAL.Format.S8UintD24Unorm => depthStencilMode == DepthStencilMode.Stencil ? ImageAspectFlags.StencilBit : ImageAspectFlags.DepthBit,
_ => ImageAspectFlags.ColorBit
};
}

View File

@@ -83,22 +83,22 @@ namespace Ryujinx.Graphics.Vulkan
{
var format = FormatTable.GetFormat(srcFormat);
var requiredFeatures = FormatFeatureFlags.FormatFeatureSampledImageBit |
FormatFeatureFlags.FormatFeatureTransferSrcBit |
FormatFeatureFlags.FormatFeatureTransferDstBit;
var requiredFeatures = FormatFeatureFlags.SampledImageBit |
FormatFeatureFlags.TransferSrcBit |
FormatFeatureFlags.TransferDstBit;
if (srcFormat.IsDepthOrStencil())
{
requiredFeatures |= FormatFeatureFlags.FormatFeatureDepthStencilAttachmentBit;
requiredFeatures |= FormatFeatureFlags.DepthStencilAttachmentBit;
}
else if (srcFormat.IsRtColorCompatible())
{
requiredFeatures |= FormatFeatureFlags.FormatFeatureColorAttachmentBit;
requiredFeatures |= FormatFeatureFlags.ColorAttachmentBit;
}
if (srcFormat.IsImageCompatible())
{
requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit;
requiredFeatures |= FormatFeatureFlags.StorageImageBit;
}
if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
@@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan
{
var format = FormatTable.GetFormat(srcFormat);
if (!BufferFormatSupports(FormatFeatureFlags.FormatFeatureVertexBufferBit, srcFormat) ||
if (!BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, srcFormat) ||
(IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported))
{
// The format is not supported. Can we convert it to an alternative format?

View File

@@ -190,14 +190,14 @@ namespace Ryujinx.Graphics.Vulkan
for (int index = 0; index < _colors.Length; index++)
{
_colors[index].Storage.SetModification(
AccessFlags.AccessColorAttachmentWriteBit,
PipelineStageFlags.PipelineStageColorAttachmentOutputBit);
AccessFlags.ColorAttachmentWriteBit,
PipelineStageFlags.ColorAttachmentOutputBit);
}
}
_depthStencil?.Storage.SetModification(
AccessFlags.AccessDepthStencilAttachmentWriteBit,
PipelineStageFlags.PipelineStageColorAttachmentOutputBit);
AccessFlags.DepthStencilAttachmentWriteBit,
PipelineStageFlags.ColorAttachmentOutputBit);
}
}
}

View File

@@ -349,8 +349,8 @@ namespace Ryujinx.Graphics.Vulkan
var srcBuffer = srcBufferAuto.Get(cbs, srcOffset, size).Value;
var dstBuffer = dstBufferAuto.Get(cbs, 0, newSize).Value;
var access = supportsUint8 ? AccessFlags.AccessShaderWriteBit : AccessFlags.AccessTransferWriteBit;
var stage = supportsUint8 ? PipelineStageFlags.PipelineStageComputeShaderBit : PipelineStageFlags.PipelineStageTransferBit;
var access = supportsUint8 ? AccessFlags.ShaderWriteBit : AccessFlags.TransferWriteBit;
var stage = supportsUint8 ? PipelineStageFlags.ComputeShaderBit : PipelineStageFlags.TransferBit;
BufferHolder.InsertBufferBarrier(
gd,
@@ -358,7 +358,7 @@ namespace Ryujinx.Graphics.Vulkan
dstBuffer,
BufferHolder.DefaultAccessFlags,
access,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.AllCommandsBit,
stage,
0,
newSize);
@@ -420,7 +420,7 @@ namespace Ryujinx.Graphics.Vulkan
access,
BufferHolder.DefaultAccessFlags,
stage,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.AllCommandsBit,
0,
newSize);
}
@@ -484,9 +484,9 @@ namespace Ryujinx.Graphics.Vulkan
cbs.CommandBuffer,
dstBuffer,
BufferHolder.DefaultAccessFlags,
AccessFlags.AccessTransferWriteBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
0,
convertedCount * outputIndexSize);
@@ -499,10 +499,10 @@ namespace Ryujinx.Graphics.Vulkan
gd,
cbs.CommandBuffer,
dstBuffer,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
BufferHolder.DefaultAccessFlags,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
0,
convertedCount * outputIndexSize);
}
@@ -548,10 +548,10 @@ namespace Ryujinx.Graphics.Vulkan
cbs.CommandBuffer,
src.GetImage().Get(cbs).Value,
TextureStorage.DefaultAccessMask,
AccessFlags.AccessShaderReadBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageComputeShaderBit,
ImageAspectFlags.ImageAspectColorBit,
AccessFlags.ShaderReadBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.ComputeShaderBit,
ImageAspectFlags.ColorBit,
src.FirstLayer + srcLayer,
src.FirstLevel,
depth,
@@ -610,11 +610,11 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api,
cbs.CommandBuffer,
dst.GetImage().Get(cbs).Value,
AccessFlags.AccessShaderWriteBit,
AccessFlags.ShaderWriteBit,
TextureStorage.DefaultAccessMask,
PipelineStageFlags.PipelineStageComputeShaderBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
ImageAspectFlags.ImageAspectColorBit,
PipelineStageFlags.ComputeShaderBit,
PipelineStageFlags.AllCommandsBit,
ImageAspectFlags.ColorBit,
dst.FirstLayer + dstLayer,
dst.FirstLevel,
depth,
@@ -770,9 +770,9 @@ namespace Ryujinx.Graphics.Vulkan
cbs.CommandBuffer,
srcIndirectBuffer.GetBuffer().Get(cbs, srcIndirectBufferOffset, indirectDataSize).Value,
BufferHolder.DefaultAccessFlags,
AccessFlags.AccessShaderReadBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageComputeShaderBit,
AccessFlags.ShaderReadBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.ComputeShaderBit,
srcIndirectBufferOffset,
indirectDataSize);
@@ -786,10 +786,10 @@ namespace Ryujinx.Graphics.Vulkan
gd,
cbs.CommandBuffer,
patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
AccessFlags.AccessShaderWriteBit,
AccessFlags.AccessIndirectCommandReadBit,
PipelineStageFlags.PipelineStageComputeShaderBit,
PipelineStageFlags.PipelineStageDrawIndirectBit,
AccessFlags.ShaderWriteBit,
AccessFlags.IndirectCommandReadBit,
PipelineStageFlags.ComputeShaderBit,
PipelineStageFlags.DrawIndirectBit,
ParamsIndirectDispatchOffset,
ParamsIndirectDispatchSize);
@@ -798,9 +798,9 @@ namespace Ryujinx.Graphics.Vulkan
cbs.CommandBuffer,
dstBuffer,
BufferHolder.DefaultAccessFlags,
AccessFlags.AccessTransferWriteBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
0,
convertedCount * outputIndexSize);
@@ -814,10 +814,10 @@ namespace Ryujinx.Graphics.Vulkan
gd,
cbs.CommandBuffer,
dstBuffer,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
BufferHolder.DefaultAccessFlags,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
0,
convertedCount * outputIndexSize);

View File

@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.Vulkan
return default;
}
bool map = flags.HasFlag(MemoryPropertyFlags.MemoryPropertyHostVisibleBit);
bool map = flags.HasFlag(MemoryPropertyFlags.HostVisibleBit);
return Allocate(memoryTypeIndex, requirements.Size, requirements.Alignment, map);
}

View File

@@ -128,14 +128,14 @@ namespace Ryujinx.Graphics.Vulkan
MemoryBarrier memoryBarrier = new MemoryBarrier()
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit,
DstAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit
SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit
};
Gd.Api.CmdPipelineBarrier(
CommandBuffer,
PipelineStageFlags.PipelineStageFragmentShaderBit,
PipelineStageFlags.PipelineStageFragmentShaderBit,
PipelineStageFlags.FragmentShaderBit,
PipelineStageFlags.FragmentShaderBit,
0,
1,
memoryBarrier,
@@ -161,9 +161,9 @@ namespace Ryujinx.Graphics.Vulkan
Cbs.CommandBuffer,
dst,
BufferHolder.DefaultAccessFlags,
AccessFlags.AccessTransferWriteBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
offset,
size);
@@ -173,10 +173,10 @@ namespace Ryujinx.Graphics.Vulkan
Gd,
Cbs.CommandBuffer,
dst,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
BufferHolder.DefaultAccessFlags,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
offset,
size);
}
@@ -196,7 +196,7 @@ namespace Ryujinx.Graphics.Vulkan
BeginRenderPass();
var clearValue = new ClearValue(new ClearColorValue(color.Red, color.Green, color.Blue, color.Alpha));
var attachment = new ClearAttachment(ImageAspectFlags.ImageAspectColorBit, (uint)index, clearValue);
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
@@ -219,11 +219,11 @@ namespace Ryujinx.Graphics.Vulkan
BeginRenderPass();
var clearValue = new ClearValue(null, new ClearDepthStencilValue(depthValue, (uint)stencilValue));
var flags = depthMask ? ImageAspectFlags.ImageAspectDepthBit : 0;
var flags = depthMask ? ImageAspectFlags.DepthBit : 0;
if (stencilMask != 0)
{
flags |= ImageAspectFlags.ImageAspectStencilBit;
flags |= ImageAspectFlags.StencilBit;
}
var attachment = new ClearAttachment(flags, 0, clearValue);
@@ -238,13 +238,13 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = BufferHolder.DefaultAccessFlags,
DstAccessMask = AccessFlags.AccessIndirectCommandReadBit
DstAccessMask = AccessFlags.IndirectCommandReadBit
};
Gd.Api.CmdPipelineBarrier(
CommandBuffer,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageDrawIndirectBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.DrawIndirectBit,
0,
1,
memoryBarrier,
@@ -624,7 +624,7 @@ namespace Ryujinx.Graphics.Vulkan
var oldViewports = DynamicState.Viewports;
var oldViewportsCount = _newState.ViewportsCount;
_newState.CullMode = CullModeFlags.CullModeNone;
_newState.CullMode = CullModeFlags.None;
_newState.StencilTestEnable = false;
_newState.DepthTestEnable = false;
_newState.DepthWriteEnable = false;
@@ -737,7 +737,7 @@ namespace Ryujinx.Graphics.Vulkan
public void SetFaceCulling(bool enable, Face face)
{
_newState.CullMode = enable ? face.Convert() : CullModeFlags.CullModeNone;
_newState.CullMode = enable ? face.Convert() : CullModeFlags.None;
SignalStateChange();
}
@@ -1200,14 +1200,14 @@ namespace Ryujinx.Graphics.Vulkan
MemoryBarrier memoryBarrier = new MemoryBarrier()
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit,
DstAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit
SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit
};
Gd.Api.CmdPipelineBarrier(
CommandBuffer,
PipelineStageFlags.PipelineStageFragmentShaderBit,
PipelineStageFlags.PipelineStageFragmentShaderBit,
PipelineStageFlags.FragmentShaderBit,
PipelineStageFlags.FragmentShaderBit,
0,
1,
memoryBarrier,

View File

@@ -6,8 +6,8 @@ namespace Ryujinx.Graphics.Vulkan
{
static class PipelineConverter
{
private const AccessFlags SubpassSrcAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessColorAttachmentWriteBit;
private const AccessFlags SubpassDstAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessShaderReadBit;
private const AccessFlags SubpassSrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ColorAttachmentWriteBit;
private const AccessFlags SubpassDstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ShaderReadBit;
public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device)
{
@@ -129,8 +129,8 @@ namespace Ryujinx.Graphics.Vulkan
return new SubpassDependency(
0,
0,
PipelineStageFlags.PipelineStageAllGraphicsBit,
PipelineStageFlags.PipelineStageAllGraphicsBit,
PipelineStageFlags.AllGraphicsBit,
PipelineStageFlags.AllGraphicsBit,
SubpassSrcAccessMask,
SubpassDstAccessMask,
0);
@@ -143,8 +143,8 @@ namespace Ryujinx.Graphics.Vulkan
null,
0,
0,
PipelineStageFlags.PipelineStageAllGraphicsBit,
PipelineStageFlags.PipelineStageAllGraphicsBit,
PipelineStageFlags.AllGraphicsBit,
PipelineStageFlags.AllGraphicsBit,
SubpassSrcAccessMask,
SubpassDstAccessMask,
0);
@@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Vulkan
// It is assumed that Dynamic State is enabled when this conversion is used.
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.CullModeNone;
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.None;
pipeline.DepthBoundsTestEnable = false; // Not implemented.

View File

@@ -145,12 +145,12 @@ namespace Ryujinx.Graphics.Vulkan
private void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)
{
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.StencilFaceBackBit, _backCompareMask);
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.StencilFaceBackBit, _backWriteMask);
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.StencilFaceBackBit, _backReference);
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.StencilFaceFrontBit, _frontCompareMask);
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.StencilFaceFrontBit, _frontWriteMask);
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.StencilFaceFrontBit, _frontReference);
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask);
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask);
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceBackBit, _backReference);
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontCompareMask);
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontWriteMask);
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference);
}
private void RecordViewport(Vk api, CommandBuffer commandBuffer)

View File

@@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan
if (Gd.Capabilities.SupportsConditionalRendering)
{
var buffer = evt.GetBuffer().Get(Cbs, 0, sizeof(long)).Value;
var flags = isEqual ? ConditionalRenderingFlagsEXT.ConditionalRenderingInvertedBitExt : 0;
var flags = isEqual ? ConditionalRenderingFlagsEXT.InvertedBitExt : 0;
var conditionalRenderingBeginInfo = new ConditionalRenderingBeginInfoEXT()
{

View File

@@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.Vulkan
static class PipelineLayoutFactory
{
private const ShaderStageFlags SupportBufferStages =
ShaderStageFlags.ShaderStageVertexBit |
ShaderStageFlags.ShaderStageFragmentBit |
ShaderStageFlags.ShaderStageComputeBit;
ShaderStageFlags.VertexBit |
ShaderStageFlags.FragmentBit |
ShaderStageFlags.ComputeBit;
public static unsafe DescriptorSetLayout[] Create(VulkanRenderer gd, Device device, uint stages, bool usePd, out PipelineLayout layout)
{
@@ -42,11 +42,11 @@ namespace Ryujinx.Graphics.Vulkan
var stageFlags = stage switch
{
1 => ShaderStageFlags.ShaderStageFragmentBit,
2 => ShaderStageFlags.ShaderStageGeometryBit,
3 => ShaderStageFlags.ShaderStageTessellationControlBit,
4 => ShaderStageFlags.ShaderStageTessellationEvaluationBit,
_ => ShaderStageFlags.ShaderStageVertexBit | ShaderStageFlags.ShaderStageComputeBit
1 => ShaderStageFlags.FragmentBit,
2 => ShaderStageFlags.GeometryBit,
3 => ShaderStageFlags.TessellationControlBit,
4 => ShaderStageFlags.TessellationEvaluationBit,
_ => ShaderStageFlags.VertexBit | ShaderStageFlags.ComputeBit
};
void Set(DescriptorSetLayoutBinding* bindings, int maxPerStage, DescriptorType type, int start, int skip)
@@ -93,7 +93,7 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.DescriptorSetLayoutCreateInfo,
PBindings = uLayoutBindings,
BindingCount = (uint)uCount,
Flags = usePd ? DescriptorSetLayoutCreateFlags.DescriptorSetLayoutCreatePushDescriptorBitKhr : 0
Flags = usePd ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : 0
};
var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()

View File

@@ -41,7 +41,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
if (_isSupported)
{
QueryPipelineStatisticFlags flags = type == CounterType.PrimitivesGenerated ?
QueryPipelineStatisticFlags.QueryPipelineStatisticGeometryShaderPrimitivesBit : 0;
QueryPipelineStatisticFlags.GeometryShaderPrimitivesBit : 0;
var queryPoolCreateInfo = new QueryPoolCreateInfo()
{
@@ -175,11 +175,11 @@ namespace Ryujinx.Graphics.Vulkan.Queries
{
var buffer = _buffer.GetBuffer(cbs.CommandBuffer, true).Get(cbs, 0, sizeof(long)).Value;
QueryResultFlags flags = QueryResultFlags.QueryResultWaitBit;
QueryResultFlags flags = QueryResultFlags.ResultWaitBit;
if (!_result32Bit)
{
flags |= QueryResultFlags.QueryResult64Bit;
flags |= QueryResultFlags.Result64Bit;
}
_api.CmdCopyQueryPoolResults(

View File

@@ -15,9 +15,9 @@
<ItemGroup>
<PackageReference Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.5" />
<PackageReference Include="shaderc.net" Version="0.1.0" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />

View File

@@ -82,14 +82,14 @@ namespace Ryujinx.Graphics.Vulkan
stages |= 1u << shader.StageFlags switch
{
ShaderStageFlags.ShaderStageFragmentBit => 1,
ShaderStageFlags.ShaderStageGeometryBit => 2,
ShaderStageFlags.ShaderStageTessellationControlBit => 3,
ShaderStageFlags.ShaderStageTessellationEvaluationBit => 4,
ShaderStageFlags.FragmentBit => 1,
ShaderStageFlags.GeometryBit => 2,
ShaderStageFlags.TessellationControlBit => 3,
ShaderStageFlags.TessellationEvaluationBit => 4,
_ => 0
};
if (shader.StageFlags == ShaderStageFlags.ShaderStageComputeBit)
if (shader.StageFlags == ShaderStageFlags.ComputeBit)
{
IsCompute = true;
}

View File

@@ -60,9 +60,9 @@ namespace Ryujinx.Graphics.Vulkan
commandBuffer,
srcImage,
TextureStorage.DefaultAccessMask,
AccessFlags.AccessTransferReadBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
srcAspectFlags,
srcLayer,
srcLevel,
@@ -103,10 +103,10 @@ namespace Ryujinx.Graphics.Vulkan
api,
commandBuffer,
dstImage,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
TextureStorage.DefaultAccessMask,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
dstAspectFlags,
dstLayer,
dstLevel,
@@ -285,9 +285,9 @@ namespace Ryujinx.Graphics.Vulkan
commandBuffer,
srcImage,
TextureStorage.DefaultAccessMask,
AccessFlags.AccessTransferReadBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
srcAspect,
srcViewLayer + srcLayer,
srcViewLevel + srcLevel,
@@ -345,10 +345,10 @@ namespace Ryujinx.Graphics.Vulkan
api,
commandBuffer,
dstImage,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
TextureStorage.DefaultAccessMask,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
dstAspect,
dstViewLayer + dstLayer,
dstViewLevel + dstLevel,
@@ -370,8 +370,8 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.SubpassDescriptionDepthStencilResolve,
PDepthStencilResolveAttachment = &dsResolveAttachmentReference,
DepthResolveMode = ResolveModeFlags.ResolveModeSampleZeroBit,
StencilResolveMode = ResolveModeFlags.ResolveModeSampleZeroBit
DepthResolveMode = ResolveModeFlags.SampleZeroBit,
StencilResolveMode = ResolveModeFlags.SampleZeroBit
};
var subpass = new SubpassDescription2()

View File

@@ -12,22 +12,22 @@ namespace Ryujinx.Graphics.Vulkan
class TextureStorage : IDisposable
{
private const MemoryPropertyFlags DefaultImageMemoryFlags =
MemoryPropertyFlags.MemoryPropertyDeviceLocalBit;
MemoryPropertyFlags.DeviceLocalBit;
private const ImageUsageFlags DefaultUsageFlags =
ImageUsageFlags.ImageUsageSampledBit |
ImageUsageFlags.ImageUsageTransferSrcBit |
ImageUsageFlags.ImageUsageTransferDstBit;
ImageUsageFlags.SampledBit |
ImageUsageFlags.TransferSrcBit |
ImageUsageFlags.TransferDstBit;
public const AccessFlags DefaultAccessMask =
AccessFlags.AccessShaderReadBit |
AccessFlags.AccessShaderWriteBit |
AccessFlags.AccessColorAttachmentReadBit |
AccessFlags.AccessColorAttachmentWriteBit |
AccessFlags.AccessDepthStencilAttachmentReadBit |
AccessFlags.AccessDepthStencilAttachmentWriteBit |
AccessFlags.AccessTransferReadBit |
AccessFlags.AccessTransferWriteBit;
AccessFlags.ShaderReadBit |
AccessFlags.ShaderWriteBit |
AccessFlags.ColorAttachmentReadBit |
AccessFlags.ColorAttachmentWriteBit |
AccessFlags.DepthStencilAttachmentReadBit |
AccessFlags.DepthStencilAttachmentWriteBit |
AccessFlags.TransferReadBit |
AccessFlags.TransferWriteBit;
private readonly VulkanRenderer _gd;
@@ -83,32 +83,32 @@ namespace Ryujinx.Graphics.Vulkan
if (info.Format.IsDepthOrStencil())
{
usage |= ImageUsageFlags.ImageUsageDepthStencilAttachmentBit;
usage |= ImageUsageFlags.DepthStencilAttachmentBit;
}
else if (info.Format.IsRtColorCompatible())
{
usage |= ImageUsageFlags.ImageUsageColorAttachmentBit;
usage |= ImageUsageFlags.ColorAttachmentBit;
}
if (info.Format.IsImageCompatible())
{
usage |= ImageUsageFlags.ImageUsageStorageBit;
usage |= ImageUsageFlags.StorageBit;
}
var flags = ImageCreateFlags.ImageCreateMutableFormatBit;
var flags = ImageCreateFlags.CreateMutableFormatBit;
// This flag causes mipmapped texture arrays to break on AMD GCN, so for that copy dependencies are forced for aliasing as cube.
bool isCube = info.Target == Target.Cubemap || info.Target == Target.CubemapArray;
bool cubeCompatible = gd.IsAmdGcn ? isCube : (info.Width == info.Height && layers >= 6);
if (type == ImageType.ImageType2D && cubeCompatible)
if (type == ImageType.Type2D && cubeCompatible)
{
flags |= ImageCreateFlags.ImageCreateCubeCompatibleBit;
flags |= ImageCreateFlags.CreateCubeCompatibleBit;
}
if (type == ImageType.ImageType3D)
if (type == ImageType.Type3D)
{
flags |= ImageCreateFlags.ImageCreate2DArrayCompatibleBit;
flags |= ImageCreateFlags.Create2DArrayCompatibleBit;
}
var imageCreateInfo = new ImageCreateInfo()
@@ -290,8 +290,8 @@ namespace Ryujinx.Graphics.Vulkan
_gd.Api.CmdPipelineBarrier(
cbs.CommandBuffer,
PipelineStageFlags.PipelineStageTopOfPipeBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TopOfPipeBit,
PipelineStageFlags.AllCommandsBit,
0,
0,
null,
@@ -308,9 +308,9 @@ namespace Ryujinx.Graphics.Vulkan
public static SampleCountFlags ConvertToSampleCountFlags(uint samples)
{
if (samples == 0 || samples > (uint)SampleCountFlags.SampleCount64Bit)
if (samples == 0 || samples > (uint)SampleCountFlags.Count64Bit)
{
return SampleCountFlags.SampleCount1Bit;
return SampleCountFlags.Count1Bit;
}
// Round up to the nearest power of two.
@@ -428,7 +428,7 @@ namespace Ryujinx.Graphics.Vulkan
public void InsertBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
{
if (_lastModificationAccess != AccessFlags.AccessNoneKhr)
if (_lastModificationAccess != AccessFlags.NoneKhr)
{
ImageAspectFlags aspectFlags;
@@ -436,20 +436,20 @@ namespace Ryujinx.Graphics.Vulkan
{
if (_info.Format == GAL.Format.S8Uint)
{
aspectFlags = ImageAspectFlags.ImageAspectStencilBit;
aspectFlags = ImageAspectFlags.StencilBit;
}
else if (_info.Format == GAL.Format.D16Unorm || _info.Format == GAL.Format.D32Float)
{
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
aspectFlags = ImageAspectFlags.DepthBit;
}
else
{
aspectFlags = ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit;
aspectFlags = ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
}
}
else
{
aspectFlags = ImageAspectFlags.ImageAspectColorBit;
aspectFlags = ImageAspectFlags.ColorBit;
}
TextureView.InsertImageBarrier(
@@ -466,7 +466,7 @@ namespace Ryujinx.Graphics.Vulkan
_info.GetLayers(),
_info.Levels);
_lastModificationAccess = AccessFlags.AccessNoneKhr;
_lastModificationAccess = AccessFlags.NoneKhr;
}
}

View File

@@ -126,7 +126,7 @@ namespace Ryujinx.Graphics.Vulkan
{
subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
_imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.ImageViewType2DArray);
_imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray);
}
Valid = true;
@@ -322,8 +322,8 @@ namespace Ryujinx.Graphics.Vulkan
return;
}
else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.BlitSrcBit, srcFormat) &&
_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.BlitDstBit, dstFormat))
{
TextureCopy.Blit(
_gd.Api,
@@ -402,8 +402,8 @@ namespace Ryujinx.Graphics.Vulkan
layers,
levels,
linearFilter,
ImageAspectFlags.ImageAspectColorBit,
ImageAspectFlags.ImageAspectColorBit);
ImageAspectFlags.ColorBit,
ImageAspectFlags.ColorBit);
}
private static void BlitDepthStencilWithBuffer(
@@ -471,10 +471,10 @@ namespace Ryujinx.Graphics.Vulkan
gd,
cbs.CommandBuffer,
srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
AccessFlags.AccessTransferWriteBit,
AccessFlags.AccessTransferReadBit,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
0,
srcSize);
@@ -498,10 +498,10 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api,
cbs.CommandBuffer,
srcTemp.GetImage().Get(cbs).Value,
AccessFlags.AccessTransferWriteBit,
AccessFlags.AccessTransferReadBit,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
aspectFlags,
0,
0,
@@ -531,10 +531,10 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api,
cbs.CommandBuffer,
dstTemp.GetImage().Get(cbs).Value,
AccessFlags.AccessTransferWriteBit,
AccessFlags.AccessTransferReadBit,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
aspectFlags,
0,
0,
@@ -561,10 +561,10 @@ namespace Ryujinx.Graphics.Vulkan
gd,
cbs.CommandBuffer,
dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
AccessFlags.AccessTransferWriteBit,
AccessFlags.AccessTransferReadBit,
PipelineStageFlags.PipelineStageTransferBit,
PipelineStageFlags.PipelineStageTransferBit,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
0,
dstSize);
@@ -585,8 +585,8 @@ namespace Ryujinx.Graphics.Vulkan
false);
}
SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.ImageAspectDepthBit);
SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.ImageAspectStencilBit);
SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.DepthBit);
SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.StencilBit);
}
public static unsafe void InsertImageBarrier(
@@ -631,7 +631,7 @@ namespace Ryujinx.Graphics.Vulkan
private bool SupportsBlitFromD32FS8ToD32FAndS8()
{
var formatFeatureFlags = FormatFeatureFlags.FormatFeatureBlitSrcBit | FormatFeatureFlags.FormatFeatureBlitDstBit;
var formatFeatureFlags = FormatFeatureFlags.BlitSrcBit | FormatFeatureFlags.BlitDstBit;
return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
_gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
}
@@ -903,9 +903,9 @@ namespace Ryujinx.Graphics.Vulkan
var aspectFlags = Info.Format.ConvertAspectFlags();
if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
if (aspectFlags == (ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit))
{
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
aspectFlags = ImageAspectFlags.DepthBit;
}
var sl = new ImageSubresourceLayers(
@@ -962,9 +962,9 @@ namespace Ryujinx.Graphics.Vulkan
{
var aspectFlags = Info.Format.ConvertAspectFlags();
if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
if (aspectFlags == (ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit))
{
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
aspectFlags = ImageAspectFlags.DepthBit;
}
var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);

View File

@@ -11,9 +11,10 @@ namespace Ryujinx.Graphics.Vulkan
Unknown
}
static class VendorUtils
static partial class VendorUtils
{
public static Regex AmdGcnRegex = new Regex(@"Radeon (((HD|R(5|7|9|X)) )?((M?[2-6]\d{2}(\D|$))|([7-8]\d{3}(\D|$))|Fury|Nano))|(Pro Duo)");
[GeneratedRegex("Radeon (((HD|R(5|7|9|X)) )?((M?[2-6]\\d{2}(\\D|$))|([7-8]\\d{3}(\\D|$))|Fury|Nano))|(Pro Duo)")]
public static partial Regex AmdGcnRegex();
public static Vendor FromId(uint id)
{

View File

@@ -159,20 +159,20 @@ namespace Ryujinx.Graphics.Vulkan
}
}
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt))
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt))
{
Logger.Error?.Print(LogClass.Gpu, msg);
//throw new Exception(msg);
}
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt))
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.WarningBitExt))
{
Logger.Warning?.Print(LogClass.Gpu, msg);
}
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityInfoBitExt))
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.InfoBitExt))
{
Logger.Info?.Print(LogClass.Gpu, msg);
}
else // if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityVerboseBitExt))
else // if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt))
{
Logger.Debug?.Print(LogClass.Gpu, msg);
}
@@ -317,7 +317,7 @@ namespace Ryujinx.Graphics.Vulkan
internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
{
const QueueFlags RequiredFlags = QueueFlags.QueueGraphicsBit | QueueFlags.QueueComputeBit;
const QueueFlags RequiredFlags = QueueFlags.GraphicsBit | QueueFlags.ComputeBit;
var khrSurface = new KhrSurface(api.Context);
@@ -561,24 +561,24 @@ namespace Ryujinx.Graphics.Vulkan
var filterLogType = logLevel switch
{
GraphicsDebugLevel.Error => DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt,
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt |
DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypePerformanceBitExt,
GraphicsDebugLevel.All => DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeGeneralBitExt |
DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt |
DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypePerformanceBitExt,
GraphicsDebugLevel.Error => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt,
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt |
DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt,
GraphicsDebugLevel.All => DebugUtilsMessageTypeFlagsEXT.GeneralBitExt |
DebugUtilsMessageTypeFlagsEXT.ValidationBitExt |
DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt,
_ => throw new ArgumentException($"Invalid log level \"{logLevel}\".")
};
var filterLogSeverity = logLevel switch
{
GraphicsDebugLevel.Error => DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt,
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt |
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt,
GraphicsDebugLevel.All => DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityInfoBitExt |
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt |
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityVerboseBitExt |
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt,
GraphicsDebugLevel.Error => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt,
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt |
DebugUtilsMessageSeverityFlagsEXT.WarningBitExt,
GraphicsDebugLevel.All => DebugUtilsMessageSeverityFlagsEXT.InfoBitExt |
DebugUtilsMessageSeverityFlagsEXT.WarningBitExt |
DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt |
DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt,
_ => throw new ArgumentException($"Invalid log level \"{logLevel}\".")
};

View File

@@ -341,11 +341,11 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe Capabilities GetCapabilities()
{
FormatFeatureFlags compressedFormatFeatureFlags =
FormatFeatureFlags.FormatFeatureSampledImageBit |
FormatFeatureFlags.FormatFeatureSampledImageFilterLinearBit |
FormatFeatureFlags.FormatFeatureBlitSrcBit |
FormatFeatureFlags.FormatFeatureTransferSrcBit |
FormatFeatureFlags.FormatFeatureTransferDstBit;
FormatFeatureFlags.SampledImageBit |
FormatFeatureFlags.SampledImageFilterLinearBit |
FormatFeatureFlags.BlitSrcBit |
FormatFeatureFlags.TransferSrcBit |
FormatFeatureFlags.TransferDstBit;
bool supportsBc123CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
GAL.Format.Bc1RgbaSrgb,
@@ -471,7 +471,7 @@ namespace Ryujinx.Graphics.Vulkan
GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName);
GpuVersion = $"Vulkan v{ParseStandardVulkanVersion(properties.ApiVersion)}, Driver v{ParseDriverVersion(ref properties)}";
IsAmdGcn = Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex.IsMatch(GpuRenderer);
IsAmdGcn = Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer);
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
}

View File

@@ -109,11 +109,11 @@ namespace Ryujinx.Graphics.Vulkan
ImageFormat = surfaceFormat.Format,
ImageColorSpace = surfaceFormat.ColorSpace,
ImageExtent = extent,
ImageUsage = ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit,
ImageUsage = ImageUsageFlags.ColorAttachmentBit | ImageUsageFlags.TransferDstBit,
ImageSharingMode = SharingMode.Exclusive,
ImageArrayLayers = 1,
PreTransform = capabilities.CurrentTransform,
CompositeAlpha = CompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr,
CompositeAlpha = CompositeAlphaFlagsKHR.OpaqueBitKhr,
PresentMode = ChooseSwapPresentMode(presentModes, _vsyncEnabled),
Clipped = true,
OldSwapchain = oldSwapchain
@@ -146,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
ComponentSwizzle.B,
ComponentSwizzle.A);
var aspectFlags = ImageAspectFlags.ImageAspectColorBit;
var aspectFlags = ImageAspectFlags.ColorBit;
var subresourceRange = new ImageSubresourceRange(aspectFlags, 0, 1, 0, 1);
@@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.ImageViewCreateInfo,
Image = swapchainImage,
ViewType = ImageViewType.ImageViewType2D,
ViewType = ImageViewType.Type2D,
Format = format,
Components = componentMapping,
SubresourceRange = subresourceRange
@@ -168,12 +168,12 @@ namespace Ryujinx.Graphics.Vulkan
{
if (availableFormats.Length == 1 && availableFormats[0].Format == VkFormat.Undefined)
{
return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.ColorspaceSrgbNonlinearKhr);
return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.PaceSrgbNonlinearKhr);
}
foreach (var format in availableFormats)
{
if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.ColorspaceSrgbNonlinearKhr)
if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr)
{
return format;
}
@@ -184,21 +184,21 @@ namespace Ryujinx.Graphics.Vulkan
private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, bool vsyncEnabled)
{
if (!vsyncEnabled && availablePresentModes.Contains(PresentModeKHR.PresentModeImmediateKhr))
if (!vsyncEnabled && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr))
{
return PresentModeKHR.PresentModeImmediateKhr;
return PresentModeKHR.ImmediateKhr;
}
else if (availablePresentModes.Contains(PresentModeKHR.PresentModeMailboxKhr))
else if (availablePresentModes.Contains(PresentModeKHR.MailboxKhr))
{
return PresentModeKHR.PresentModeMailboxKhr;
return PresentModeKHR.MailboxKhr;
}
else if (availablePresentModes.Contains(PresentModeKHR.PresentModeFifoKhr))
else if (availablePresentModes.Contains(PresentModeKHR.FifoKhr))
{
return PresentModeKHR.PresentModeFifoKhr;
return PresentModeKHR.FifoKhr;
}
else
{
return PresentModeKHR.PresentModeFifoKhr;
return PresentModeKHR.FifoKhr;
}
}
@@ -254,7 +254,7 @@ namespace Ryujinx.Graphics.Vulkan
cbs.CommandBuffer,
swapchainImage,
0,
AccessFlags.AccessTransferWriteBit,
AccessFlags.TransferWriteBit,
ImageLayout.Undefined,
ImageLayout.General);
@@ -339,7 +339,7 @@ namespace Ryujinx.Graphics.Vulkan
_gd.CommandBufferPool.Return(
cbs,
stackalloc[] { _imageAvailableSemaphore },
stackalloc[] { PipelineStageFlags.PipelineStageColorAttachmentOutputBit },
stackalloc[] { PipelineStageFlags.ColorAttachmentOutputBit },
stackalloc[] { _renderFinishedSemaphore });
// TODO: Present queue.
@@ -373,7 +373,7 @@ namespace Ryujinx.Graphics.Vulkan
ImageLayout srcLayout,
ImageLayout dstLayout)
{
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ImageAspectColorBit, 0, 1, 0, 1);
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ColorBit, 0, 1, 0, 1);
var barrier = new ImageMemoryBarrier()
{
@@ -390,8 +390,8 @@ namespace Ryujinx.Graphics.Vulkan
_gd.Api.CmdPipelineBarrier(
commandBuffer,
PipelineStageFlags.PipelineStageTopOfPipeBit,
PipelineStageFlags.PipelineStageAllCommandsBit,
PipelineStageFlags.TopOfPipeBit,
PipelineStageFlags.AllCommandsBit,
0,
0,
null,

View File

@@ -18,7 +18,7 @@ using System.Text.RegularExpressions;
namespace Ryujinx.HLE.HOS.Applets.Error
{
internal class ErrorApplet : IApplet
internal partial class ErrorApplet : IApplet
{
private const long ErrorMessageBinaryTitleId = 0x0100000000000801;
@@ -30,6 +30,9 @@ namespace Ryujinx.HLE.HOS.Applets.Error
public event EventHandler AppletStateChanged;
[GeneratedRegex(@"[^\u0000\u0009\u000A\u000D\u0020-\uFFFF]..")]
private static partial Regex CleanTextRegex();
public ErrorApplet(Horizon horizon)
{
_horizon = horizon;
@@ -101,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
private static string CleanText(string value)
{
return Regex.Replace(value, @"[^\u0000\u0009\u000A\u000D\u0020-\uFFFF]..", "").Replace("\0", "");
return CleanTextRegex().Replace(value, "").Replace("\0", "");
}
private string GetMessageText(uint module, uint description, string key)

View File

@@ -2,18 +2,30 @@
namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Proxy
{
static class DnsBlacklist
static partial class DnsBlacklist
{
const RegexOptions RegexOpts = RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled;
const RegexOptions RegexOpts = RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture;
private static readonly Regex[] BlockedHosts = new Regex[]
{
new Regex(@"^(.*)\-lp1\.(n|s)\.n\.srv\.nintendo\.net$", RegexOpts),
new Regex(@"^(.*)\-lp1\.lp1\.t\.npln\.srv\.nintendo\.net$", RegexOpts),
new Regex(@"^(.*)\-lp1\.(znc|p)\.srv\.nintendo\.net$", RegexOpts),
new Regex(@"^(.*)\-sb\-api\.accounts\.nintendo\.com$", RegexOpts),
new Regex(@"^(.*)\-sb\.accounts\.nintendo\.com$", RegexOpts),
new Regex(@"^accounts\.nintendo\.com$", RegexOpts)
[GeneratedRegex(@"^(.*)\-lp1\.(n|s)\.n\.srv\.nintendo\.net$", RegexOpts)]
private static partial Regex BlockedHost1();
[GeneratedRegex(@"^(.*)\-lp1\.lp1\.t\.npln\.srv\.nintendo\.net$", RegexOpts)]
private static partial Regex BlockedHost2();
[GeneratedRegex(@"^(.*)\-lp1\.(znc|p)\.srv\.nintendo\.net$", RegexOpts)]
private static partial Regex BlockedHost3();
[GeneratedRegex(@"^(.*)\-sb\-api\.accounts\.nintendo\.com$", RegexOpts)]
private static partial Regex BlockedHost4();
[GeneratedRegex(@"^(.*)\-sb\.accounts\.nintendo\.com$", RegexOpts)]
private static partial Regex BlockedHost5();
[GeneratedRegex(@"^accounts\.nintendo\.com$", RegexOpts)]
private static partial Regex BlockedHost6();
private static readonly Regex[] BlockedHosts = {
BlockedHost1(),
BlockedHost2(),
BlockedHost3(),
BlockedHost4(),
BlockedHost5(),
BlockedHost6()
};
public static bool IsHostBlocked(string host)

View File

@@ -9,7 +9,7 @@ using System.Text.RegularExpressions;
namespace Ryujinx.HLE.Loaders.Executables
{
class NsoExecutable : IExecutable
partial class NsoExecutable : IExecutable
{
public byte[] Program { get; }
public Span<byte> Text => Program.AsSpan((int)TextOffset, (int)TextSize);
@@ -29,6 +29,13 @@ namespace Ryujinx.HLE.Loaders.Executables
public string Name;
public Array32<byte> BuildId;
[GeneratedRegex(@"[a-z]:[\\/][ -~]{5,}\.nss", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)]
private static partial Regex ModuleRegex();
[GeneratedRegex(@"sdk_version: ([0-9.]*)")]
private static partial Regex FsSdkRegex();
[GeneratedRegex(@"SDK MW[ -~]*")]
private static partial Regex SdkMwRegex();
public NsoExecutable(IStorage inStorage, string name = null)
{
NsoReader reader = new NsoReader();
@@ -83,7 +90,7 @@ namespace Ryujinx.HLE.Loaders.Executables
if (string.IsNullOrEmpty(modulePath))
{
Match moduleMatch = Regex.Match(rawTextBuffer, @"[a-z]:[\\/][ -~]{5,}\.nss", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
Match moduleMatch = ModuleRegex().Match(rawTextBuffer);
if (moduleMatch.Success)
{
modulePath = moduleMatch.Value;
@@ -92,13 +99,13 @@ namespace Ryujinx.HLE.Loaders.Executables
stringBuilder.AppendLine($" Module: {modulePath}");
Match fsSdkMatch = Regex.Match(rawTextBuffer, @"sdk_version: ([0-9.]*)", RegexOptions.Compiled);
Match fsSdkMatch = FsSdkRegex().Match(rawTextBuffer);
if (fsSdkMatch.Success)
{
stringBuilder.AppendLine($" FS SDK Version: {fsSdkMatch.Value.Replace("sdk_version: ", "")}");
}
MatchCollection sdkMwMatches = Regex.Matches(rawTextBuffer, @"SDK MW[ -~]*", RegexOptions.Compiled);
MatchCollection sdkMwMatches = SdkMwRegex().Matches(rawTextBuffer);
if (sdkMwMatches.Count != 0)
{
string libHeader = " SDK Libraries: ";

View File

@@ -638,16 +638,7 @@ namespace Ryujinx.Headless.SDL2
Translator.IsReadyForTranslation.Reset();
Thread windowThread = new Thread(() =>
{
ExecutionEntrypoint();
})
{
Name = "GUI.WindowThread"
};
windowThread.Start();
windowThread.Join();
ExecutionEntrypoint();
return true;
}

View File

@@ -168,14 +168,6 @@ namespace Ryujinx.Headless.SDL2
public void Render()
{
InitializeWindowRenderer();
Device.Gpu.Renderer.Initialize(_glLogLevel);
InitializeRenderer();
_gpuVendorName = GetGpuVendorName();
Device.Gpu.Renderer.RunLoop(() =>
{
Device.Gpu.SetGpuThread();
@@ -323,6 +315,14 @@ namespace Ryujinx.Headless.SDL2
InitializeWindow();
InitializeWindowRenderer();
Device.Gpu.Renderer.Initialize(_glLogLevel);
InitializeRenderer();
_gpuVendorName = GetGpuVendorName();
Thread renderLoopThread = new Thread(Render)
{
Name = "GUI.RenderLoop"

View File

@@ -28,6 +28,8 @@ namespace Ryujinx.SDL2.Common
}
}
public static Action<Action> MainThreadDispatcher { get; set; }
private const uint SdlInitFlags = SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO | SDL_INIT_VIDEO;
private bool _isRunning;
@@ -69,7 +71,7 @@ namespace Ryujinx.SDL2.Common
if (SDL_Init(SdlInitFlags) != 0)
{
string errorMessage = $"SDL2 initlaization failed with error \"{SDL_GetError()}\"";
string errorMessage = $"SDL2 initialization failed with error \"{SDL_GetError()}\"";
Logger.Error?.Print(LogClass.Application, errorMessage);
@@ -154,10 +156,13 @@ namespace Ryujinx.SDL2.Common
while (_isRunning)
{
while (SDL_PollEvent(out SDL_Event evnt) != 0)
MainThreadDispatcher?.Invoke(() =>
{
HandleSDLEvent(ref evnt);
}
while (SDL_PollEvent(out SDL_Event evnt) != 0)
{
HandleSDLEvent(ref evnt);
}
});
waitHandle.Wait(WaitTimeMs);
}

View File

@@ -444,7 +444,10 @@ namespace Ryujinx.Ui.App.Common
continue;
}
ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId);
ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId, appMetadata =>
{
appMetadata.Title = titleName;
});
if (appMetadata.LastPlayed != "Never" && !DateTime.TryParse(appMetadata.LastPlayed, out _))
{

View File

@@ -2,6 +2,7 @@
{
public class ApplicationMetadata
{
public string Title { get; set; }
public bool Favorite { get; set; }
public double TimePlayed { get; set; }
public string LastPlayed { get; set; } = "Never";

View File

@@ -7,6 +7,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.System;
using Ryujinx.Common.SystemInfo;
using Ryujinx.Modules;
using Ryujinx.SDL2.Common;
using Ryujinx.Ui;
using Ryujinx.Ui.Common;
using Ryujinx.Ui.Common.Configuration;
@@ -111,6 +112,15 @@ namespace Ryujinx
// Initialize Discord integration.
DiscordIntegrationModule.Initialize();
// Initialize SDL2 driver
SDL2Driver.MainThreadDispatcher = action =>
{
Gtk.Application.Invoke(delegate
{
action();
});
};
// Sets ImageSharp Jpeg Encoder Quality.
SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()
{

3
crowdin.yml Normal file
View File

@@ -0,0 +1,3 @@
files:
- source: /**/Assets/Locales/en_US.json
translation: /**/Assets/Locales/%locale_with_underscore%.json