Compare commits

...

2 Commits

Author SHA1 Message Date
a01a06cd3f 2 unmerged PRs from original Ryujinx:
Implement shader compile counter (currently not translated, will change, need to pull changes.)
Remove event logic in favor of a single init function.
Thanks @MutantAura
2024-10-24 14:14:17 -05:00
7618ef134d misc: Code cleanups. 2024-10-24 14:14:17 -05:00
23 changed files with 146 additions and 149 deletions

View File

@ -41,10 +41,12 @@ namespace Ryujinx.Common
} }
} }
public static implicit operator T(ReactiveObject<T> obj) public static implicit operator T(ReactiveObject<T> obj) => obj.Value;
{ }
return obj.Value;
} public static class ReactiveObjectHelper
{
public static void Toggle(this ReactiveObject<bool> rBoolean) => rBoolean.Value = !rBoolean.Value;
} }
public class ReactiveEventArgs<T>(T oldValue, T newValue) public class ReactiveEventArgs<T>(T oldValue, T newValue)

View File

@ -14,6 +14,8 @@ namespace Ryujinx.Graphics.GAL
IWindow Window { get; } IWindow Window { get; }
uint ProgramCount { get; }
void BackgroundContextAction(Action action, bool alwaysBackground = false); void BackgroundContextAction(Action action, bool alwaysBackground = false);
BufferHandle CreateBuffer(int size, BufferAccess access = BufferAccess.Default); BufferHandle CreateBuffer(int size, BufferAccess access = BufferAccess.Default);

View File

@ -55,6 +55,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading
private int _refProducerPtr; private int _refProducerPtr;
private int _refConsumerPtr; private int _refConsumerPtr;
public uint ProgramCount { get; set; } = 0;
private Action _interruptAction; private Action _interruptAction;
private readonly object _interruptLock = new(); private readonly object _interruptLock = new();
@ -307,6 +309,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Programs.Add(request); Programs.Add(request);
ProgramCount++;
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request)); New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
QueueCommand(); QueueCommand();

View File

@ -29,6 +29,8 @@ namespace Ryujinx.Graphics.OpenGL
private readonly Sync _sync; private readonly Sync _sync;
public uint ProgramCount { get; set; } = 0;
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured; public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
internal PersistentBuffers PersistentBuffers { get; } internal PersistentBuffers PersistentBuffers { get; }
@ -94,6 +96,8 @@ namespace Ryujinx.Graphics.OpenGL
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info) public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
{ {
ProgramCount++;
return new Program(shaders, info.FragmentOutputMap); return new Program(shaders, info.FragmentOutputMap);
} }

View File

@ -27,6 +27,8 @@ namespace Ryujinx.Graphics.Vulkan
private bool _initialized; private bool _initialized;
public uint ProgramCount { get; set; } = 0;
internal FormatCapabilities FormatCapabilities { get; private set; } internal FormatCapabilities FormatCapabilities { get; private set; }
internal HardwareCapabilities Capabilities; internal HardwareCapabilities Capabilities;
@ -544,6 +546,8 @@ namespace Ryujinx.Graphics.Vulkan
public IProgram CreateProgram(ShaderSource[] sources, ShaderInfo info) public IProgram CreateProgram(ShaderSource[] sources, ShaderInfo info)
{ {
ProgramCount++;
bool isCompute = sources.Length == 1 && sources[0].Stage == ShaderStage.Compute; bool isCompute = sources.Length == 1 && sources[0].Stage == ShaderStage.Compute;
if (info.State.HasValue || isCompute) if (info.State.HasValue || isCompute)

View File

@ -85,7 +85,9 @@ namespace Ryujinx.HLE.Loaders.Processes
} }
// TODO: LibHac npdm currently doesn't support version field. // TODO: LibHac npdm currently doesn't support version field.
string version = ProgramId > 0x0100000000007FFF ? DisplayVersion : device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?"; string version = ProgramId > 0x0100000000007FFF
? DisplayVersion
: device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?";
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {Name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]"); Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {Name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]");

View File

@ -119,12 +119,10 @@ namespace Ryujinx.Headless.SDL2
} }
} }
IGamepad gamepad; IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
bool isKeyboard = true; bool isKeyboard = true;
gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
if (gamepad == null) if (gamepad == null)
{ {
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId); gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);

View File

@ -325,12 +325,12 @@ namespace Ryujinx.UI.Common.Configuration
public ReactiveObject<bool> EnableDockedMode { get; private set; } public ReactiveObject<bool> EnableDockedMode { get; private set; }
/// <summary> /// <summary>
/// Enables or disables profiled translation cache persistency /// Enables or disables persistent profiled translation cache
/// </summary> /// </summary>
public ReactiveObject<bool> EnablePtc { get; private set; } public ReactiveObject<bool> EnablePtc { get; private set; }
/// <summary> /// <summary>
/// Enables or disables low-power profiled translation cache persistency loading /// Enables or disables low-power persistent profiled translation cache loading
/// </summary> /// </summary>
public ReactiveObject<bool> EnableLowPowerPtc { get; private set; } public ReactiveObject<bool> EnableLowPowerPtc { get; private set; }

View File

@ -73,7 +73,7 @@ namespace Ryujinx.UI.Common
{ {
Assets = new Assets Assets = new Assets
{ {
LargeImageKey = _discordGameAssetKeys.Contains(procRes.ProgramIdText.ToLower()) ? procRes.ProgramIdText : "game", LargeImageKey = _discordGameAssetKeys.Contains(procRes.ProgramIdText) ? procRes.ProgramIdText : "game",
LargeImageText = TruncateToByteLength($"{appMeta.Title} | {procRes.DisplayVersion}"), LargeImageText = TruncateToByteLength($"{appMeta.Title} | {procRes.DisplayVersion}"),
SmallImageKey = "ryujinx", SmallImageKey = "ryujinx",
SmallImageText = TruncateToByteLength(_description) SmallImageText = TruncateToByteLength(_description)
@ -121,8 +121,8 @@ namespace Ryujinx.UI.Common
} }
private static readonly string[] _discordGameAssetKeys = private static readonly string[] _discordGameAssetKeys =
[ [
"01002da013484000", // The Legend of Zelda: Skyward Sword HD "01002da013484000", // The Legend of Zelda: Skyward Sword HD
"01007ef00011e000", // The Legend of Zelda: Breath of the Wild "01007ef00011e000", // The Legend of Zelda: Breath of the Wild
"0100f2c0115b6000", // The Legend of Zelda: Tears of the Kingdom "0100f2c0115b6000", // The Legend of Zelda: Tears of the Kingdom
"01008cf01baac000", // The Legend of Zelda: Echoes of Wisdom "01008cf01baac000", // The Legend of Zelda: Echoes of Wisdom
@ -131,9 +131,15 @@ namespace Ryujinx.UI.Common
"0100000000010000", // SUPER MARIO ODYSSEY "0100000000010000", // SUPER MARIO ODYSSEY
"010015100b514000", // Super Mario Bros. Wonder "010015100b514000", // Super Mario Bros. Wonder
"0100152000022000", // Mario Kart 8 Deluxe "0100152000022000", // Mario Kart 8 Deluxe
"01006fe013472000", // Mario Party Superstars
"0100965017338000", // Super Mario Party Jamboree
"010049900f546000", // Super Mario 3D All-Stars "010049900f546000", // Super Mario 3D All-Stars
"010028600ebda000", // Super Mario 3D World + Bowser's Fury "010028600ebda000", // Super Mario 3D World + Bowser's Fury
"0100ecd018ebe000", // Paper Mario: The Thousand-Year Door "0100ecd018ebe000", // Paper Mario: The Thousand-Year Door
"010019401051c000", // Mario Strikers League
"0100ea80032ea000", // Super Mario Bros. U Deluxe
"0100bc0018138000", // Super Mario RPG
"0100bde00862a000", // Mario Tennis Aces
"010048701995e000", // Luigi's Mansion 2 HD "010048701995e000", // Luigi's Mansion 2 HD
"0100dca0064a6000", // Luigi's Mansion 3 "0100dca0064a6000", // Luigi's Mansion 3
@ -149,14 +155,21 @@ namespace Ryujinx.UI.Common
"0100f4c009322000", // Pikmin 3 Deluxe "0100f4c009322000", // Pikmin 3 Deluxe
"0100b7c00933a000", // Pikmin 4 "0100b7c00933a000", // Pikmin 4
"01004ad014bf0000", // Sonic Frontiers
"01004d300c5ae000", // Kirby and the Forgotten Land
"01006b601380e000", // Kirby's Return to Dreamland Deluxe
"01007e3006dda000", // Kirby Star Allies
"0100c2500fc20000", // Splatoon 3 "0100c2500fc20000", // Splatoon 3
"0100ba0018500000", // Splatoon 3: Splatfest World Premiere "0100ba0018500000", // Splatoon 3: Splatfest World Premiere
"01000a10041ea000", // The Elder Scrolls V: Skyrim "01000a10041ea000", // The Elder Scrolls V: Skyrim
"01007820196a6000", // Red Dead Redemption "01007820196a6000", // Red Dead Redemption
"01008c8012920000", // Dying Light Platinum Edition
"0100744001588000", // Cars 3: Driven to Win "0100744001588000", // Cars 3: Driven to Win
"0100c1f0051b6000", // Donkey Kong Country: Tropical Freeze
"01002b00111a2000", // Hyrule Warriors: Age of Calamity "01002b00111a2000", // Hyrule Warriors: Age of Calamity
"01006f8002326000", // Animal Crossing: New Horizons "01006f8002326000", // Animal Crossing: New Horizons
"01004d300c5ae000", // Kirby and the Forgotten Land
"0100853015e86000", // No Man's Sky "0100853015e86000", // No Man's Sky
"01008d100d43e000", // Saints Row IV "01008d100d43e000", // Saints Row IV
"0100de600beee000", // Saints Row: The Third - The Full Package "0100de600beee000", // Saints Row: The Third - The Full Package

View File

@ -103,6 +103,10 @@ namespace Ryujinx.Ava
private CursorStates _cursorState = !ConfigurationState.Instance.Hid.EnableMouse.Value ? private CursorStates _cursorState = !ConfigurationState.Instance.Hid.EnableMouse.Value ?
CursorStates.CursorIsVisible : CursorStates.CursorIsHidden; CursorStates.CursorIsVisible : CursorStates.CursorIsHidden;
private DateTime _lastShaderReset;
private uint _displayCount;
private uint _previousCount = 0;
private bool _isStopped; private bool _isStopped;
private bool _isActive; private bool _isActive;
private bool _renderingStarted; private bool _renderingStarted;
@ -120,7 +124,6 @@ namespace Ryujinx.Ava
private readonly object _lockObject = new(); private readonly object _lockObject = new();
public event EventHandler AppExit; public event EventHandler AppExit;
public event EventHandler<StatusInitEventArgs> StatusInitEvent;
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent; public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
public VirtualFileSystem VirtualFileSystem { get; } public VirtualFileSystem VirtualFileSystem { get; }
@ -511,8 +514,7 @@ namespace Ryujinx.Ava
} }
_isStopped = true; _isStopped = true;
_isActive = false; Stop();
DiscordIntegrationModule.SwitchToMainState();
} }
public void DisposeContext() public void DisposeContext()
@ -1043,14 +1045,14 @@ namespace Ryujinx.Ava
public void InitStatus() public void InitStatus()
{ {
StatusInitEvent?.Invoke(this, new StatusInitEventArgs( _viewModel.BackendText = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch {
{ GraphicsBackend.Vulkan => "Vulkan",
GraphicsBackend.Vulkan => "Vulkan", GraphicsBackend.OpenGl => "OpenGL",
GraphicsBackend.OpenGl => "OpenGL", _ => throw new NotImplementedException()
_ => throw new NotImplementedException() };
},
$"GPU: {_renderer.GetHardwareInfo().GpuDriver}")); _viewModel.GpuNameText = $"GPU: {_renderer.GetHardwareInfo().GpuDriver}";
} }
public void UpdateStatus() public void UpdateStatus()
@ -1058,6 +1060,8 @@ namespace Ryujinx.Ava
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued. // Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued.
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld]; string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
UpdateShaderCount();
if (GraphicsConfig.ResScale != 1) if (GraphicsConfig.ResScale != 1)
{ {
dockedMode += $" ({GraphicsConfig.ResScale}x)"; dockedMode += $" ({GraphicsConfig.ResScale}x)";
@ -1069,7 +1073,8 @@ namespace Ryujinx.Ava
dockedMode, dockedMode,
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %")); $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
_displayCount));
} }
public async Task ShowExitPrompt() public async Task ShowExitPrompt()
@ -1095,6 +1100,24 @@ namespace Ryujinx.Ava
} }
} }
private void UpdateShaderCount()
{
// If there is a mismatch between total program compile and previous count
// this means new shaders have been compiled and should be displayed.
if (_renderer.ProgramCount != _previousCount)
{
_displayCount += _renderer.ProgramCount - _previousCount;
_lastShaderReset = DateTime.Now;
_previousCount = _renderer.ProgramCount;
}
// Check if 5s has passed since any new shaders were compiled.
// If yes, reset the counter.
else if (_lastShaderReset.AddSeconds(5) <= DateTime.Now)
{
_displayCount = 0;
}
}
private bool UpdateFrame() private bool UpdateFrame()
{ {
if (!_isActive) if (!_isActive)

View File

@ -68,7 +68,7 @@ namespace Ryujinx.Ava.Common
Logger.Warning?.Print(LogClass.Application, "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games."); Logger.Warning?.Print(LogClass.Application, "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
} }
Uid user = new((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low); Uid user = _accountManager.LastOpenedUser.UserId.ToLibHacUid();
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new ApplicationId(titleId), in control, in user); result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new ApplicationId(titleId), in control, in user);
if (result.IsFailure()) if (result.IsFailure())

View File

@ -37,14 +37,9 @@ namespace Ryujinx.Ava.UI.Applet
public ControllerAppletDialog(MainWindow mainWindow, ControllerAppletUIArgs args) public ControllerAppletDialog(MainWindow mainWindow, ControllerAppletUIArgs args)
{ {
if (args.PlayerCountMin == args.PlayerCountMax) PlayerCount = args.PlayerCountMin == args.PlayerCountMax
{ ? args.PlayerCountMin.ToString()
PlayerCount = args.PlayerCountMin.ToString(); : $"{args.PlayerCountMin} - {args.PlayerCountMax}";
}
else
{
PlayerCount = $"{args.PlayerCountMin} - {args.PlayerCountMax}";
}
SupportsProController = (args.SupportedStyles & ControllerType.ProController) != 0; SupportsProController = (args.SupportedStyles & ControllerType.ProController) != 0;
SupportsLeftJoycon = (args.SupportedStyles & ControllerType.JoyconLeft) != 0; SupportsLeftJoycon = (args.SupportedStyles & ControllerType.JoyconLeft) != 0;

View File

@ -13,19 +13,19 @@ namespace Ryujinx.Ava.UI.Helpers
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
if (value == null) switch (value)
{ {
return null; case null:
return null;
case byte[] buffer when targetType == typeof(IImage):
{
MemoryStream mem = new(buffer);
return new Bitmap(mem);
}
default:
throw new NotSupportedException();
} }
if (value is byte[] buffer && targetType == typeof(IImage))
{
MemoryStream mem = new(buffer);
return new Bitmap(mem);
}
throw new NotSupportedException();
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

View File

@ -41,11 +41,7 @@ namespace Ryujinx.Ava.UI.Helpers
if (_isWaitingForInput) if (_isWaitingForInput)
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() => Cancel());
{
Cancel();
});
return; return;
} }

View File

@ -22,22 +22,11 @@ namespace Ryujinx.Ava.UI.Helpers
_key = key; _key = key;
} }
public string this[string key] public string this[string key] =>
{ _glyphs.TryGetValue(Enum.Parse<Glyph>(key), out var val)
get ? val
{ : string.Empty;
if (_glyphs.TryGetValue(Enum.Parse<Glyph>(key), out var val))
{
return val;
}
return string.Empty; public override object ProvideValue(IServiceProvider serviceProvider) => this[_key];
}
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this[_key];
}
} }
} }

View File

@ -1,44 +0,0 @@
using Avalonia.Data.Converters;
using Avalonia.Markup.Xaml;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.UI.Common.Helper;
using System;
using System.Globalization;
namespace Ryujinx.Ava.UI.Helpers
{
/// <summary>
/// This <see cref="IValueConverter"/> makes sure that the string "Never" that's returned by <see cref="ValueFormatUtils.FormatDateTime"/> is properly localized in the Avalonia UI.
/// After the Avalonia UI has been made the default and the GTK UI is removed, <see cref="ValueFormatUtils"/> should be updated to directly return a localized string.
/// </summary>
// TODO: localize ValueFormatUtils.FormateDateTime
internal class LocalizedNeverConverter : MarkupExtension, IValueConverter
{
private static readonly LocalizedNeverConverter _instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not string valStr)
{
return "";
}
if (valStr == "Never")
{
return LocaleManager.Instance[LocaleKeys.Never];
}
return valStr;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _instance;
}
}
}

View File

@ -1,16 +0,0 @@
using System;
namespace Ryujinx.Ava.UI.Models
{
internal class StatusInitEventArgs : EventArgs
{
public string GpuBackend { get; }
public string GpuName { get; }
public StatusInitEventArgs(string gpuBackend, string gpuName)
{
GpuBackend = gpuBackend;
GpuName = gpuName;
}
}
}

View File

@ -11,7 +11,9 @@ namespace Ryujinx.Ava.UI.Models
public string FifoStatus { get; } public string FifoStatus { get; }
public string GameStatus { get; } public string GameStatus { get; }
public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus) public uint ShaderCount { get; }
public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, uint shaderCount)
{ {
VSyncEnabled = vSyncEnabled; VSyncEnabled = vSyncEnabled;
VolumeStatus = volumeStatus; VolumeStatus = volumeStatus;
@ -19,6 +21,7 @@ namespace Ryujinx.Ava.UI.Models
AspectRatio = aspectRatio; AspectRatio = aspectRatio;
GameStatus = gameStatus; GameStatus = gameStatus;
FifoStatus = fifoStatus; FifoStatus = fifoStatus;
ShaderCount = shaderCount;
} }
} }
} }

View File

@ -45,7 +45,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private PlayerIndex _playerId; private PlayerIndex _playerId;
private int _controller; private int _controller;
private readonly int _controllerNumber;
private string _controllerImage; private string _controllerImage;
private int _device; private int _device;
private object _configViewModel; private object _configViewModel;

View File

@ -8,6 +8,7 @@ using Avalonia.Threading;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Gommon;
using LibHac.Common; using LibHac.Common;
using Ryujinx.Ava.Common; using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
@ -64,7 +65,9 @@ namespace Ryujinx.Ava.UI.ViewModels
private string _gameStatusText; private string _gameStatusText;
private string _volumeStatusText; private string _volumeStatusText;
private string _gpuStatusText; private string _gpuStatusText;
private string _shaderCountText;
private bool _isAmiiboRequested; private bool _isAmiiboRequested;
private bool _showRightmostSeparator;
private bool _isGameRunning; private bool _isGameRunning;
private bool _isFullScreen; private bool _isFullScreen;
private int _progressMaximum; private int _progressMaximum;
@ -256,6 +259,17 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool ShowFirmwareStatus => !ShowLoadProgress; public bool ShowFirmwareStatus => !ShowLoadProgress;
public bool ShowRightmostSeparator
{
get => _showRightmostSeparator;
set
{
_showRightmostSeparator = value;
OnPropertyChanged();
}
}
public bool IsGameRunning public bool IsGameRunning
{ {
get => _isGameRunning; get => _isGameRunning;
@ -507,6 +521,16 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public string ShaderCountText
{
get => _shaderCountText;
set
{
_shaderCountText = value;
OnPropertyChanged();
}
}
public string BackendText public string BackendText
{ {
get => _backendText; get => _backendText;
@ -1188,7 +1212,6 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
RendererHostControl.WindowCreated += RendererHost_Created; RendererHostControl.WindowCreated += RendererHost_Created;
AppHost.StatusInitEvent += Init_StatusBar;
AppHost.StatusUpdatedEvent += Update_StatusBar; AppHost.StatusUpdatedEvent += Update_StatusBar;
AppHost.AppExit += AppHost_AppExit; AppHost.AppExit += AppHost_AppExit;
@ -1215,18 +1238,6 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
private void Init_StatusBar(object sender, StatusInitEventArgs args)
{
if (ShowMenuAndStatusBar && !ShowLoadProgress)
{
Dispatcher.UIThread.InvokeAsync(() =>
{
GpuNameText = args.GpuName;
BackendText = args.GpuBackend;
});
}
}
private void Update_StatusBar(object sender, StatusUpdatedEventArgs args) private void Update_StatusBar(object sender, StatusUpdatedEventArgs args)
{ {
if (ShowMenuAndStatusBar && !ShowLoadProgress) if (ShowMenuAndStatusBar && !ShowLoadProgress)
@ -1249,6 +1260,8 @@ namespace Ryujinx.Ava.UI.ViewModels
GameStatusText = args.GameStatus; GameStatusText = args.GameStatus;
VolumeStatusText = args.VolumeStatus; VolumeStatusText = args.VolumeStatus;
FifoStatusText = args.FifoStatus; FifoStatusText = args.FifoStatus;
ShaderCountText = args.ShaderCount > 0 ? $"Compiling shaders: {args.ShaderCount}" : string.Empty;
ShowRightmostSeparator = !ShaderCountText.IsNullOrEmpty();
ShowStatusSeparator = true; ShowStatusSeparator = true;
}); });

View File

@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Threading; using Avalonia.Threading;
using DynamicData; using DynamicData;
using Gommon;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
@ -313,11 +314,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public void DeleteAll() public void DeleteAll()
{ {
foreach (var mod in Mods) Mods.ForEach(Delete);
{
Delete(mod);
}
Mods.Clear(); Mods.Clear();
OnPropertyChanged(nameof(ModCount)); OnPropertyChanged(nameof(ModCount));
Sort(); Sort();

View File

@ -261,6 +261,19 @@
IsVisible="{Binding !ShowLoadProgress}" IsVisible="{Binding !ShowLoadProgress}"
Text="{Binding GpuNameText}" Text="{Binding GpuNameText}"
TextAlignment="Start" /> TextAlignment="Start" />
<Border
Width="2"
Height="12"
Margin="0"
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding ShowRightmostSeparator}" />
<TextBlock
Name="ShaderCount"
Margin="5,0,5,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding ShaderCountText}" />
</StackPanel> </StackPanel>
<StackPanel <StackPanel
Grid.Column="3" Grid.Column="3"

View File

@ -139,7 +139,7 @@ namespace Ryujinx.Ava.UI.Windows
var value = GetColorValue(color); var value = GetColorValue(color);
// If the color is rarely used on the image, // If the color is rarely used on the image,
// then chances are that theres a better candidate, even if the saturation value // then chances are that there's a better candidate, even if the saturation value
// is high. By multiplying the saturation value with a weight, we can lower // is high. By multiplying the saturation value with a weight, we can lower
// it if the color is almost never used (hit count is low). // it if the color is almost never used (hit count is low).
var satWeighted = quantSat; var satWeighted = quantSat;