Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
548bfd60a2 | ||
|
65778a6b78 | ||
|
f4e879a1e6 | ||
|
a1ddaa2736 | ||
|
008286b79f | ||
|
a0c77f8d11 |
@@ -21,6 +21,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
Name = $"Ryujinx {Program.Version}";
|
||||
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
|
@@ -60,7 +60,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
private const float VolumeDelta = 0.05f;
|
||||
|
||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||
|
||||
private readonly long _ticksPerFrame;
|
||||
private readonly Stopwatch _chrono;
|
||||
@@ -349,7 +349,10 @@ namespace Ryujinx.Ava
|
||||
|
||||
_isActive = false;
|
||||
|
||||
_renderingThread.Join();
|
||||
if (_renderingThread.IsAlive)
|
||||
{
|
||||
_renderingThread.Join();
|
||||
}
|
||||
|
||||
DisplaySleep.Restore();
|
||||
|
||||
@@ -378,7 +381,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
_gpuCancellationTokenSource.Cancel();
|
||||
_gpuCancellationTokenSource.Dispose();
|
||||
|
||||
|
||||
_chrono.Stop();
|
||||
}
|
||||
|
||||
@@ -393,7 +396,7 @@ namespace Ryujinx.Ava
|
||||
Renderer?.MakeCurrent();
|
||||
|
||||
Device.DisposeGpu();
|
||||
|
||||
|
||||
Renderer?.MakeCurrent(null);
|
||||
}
|
||||
|
||||
@@ -417,7 +420,6 @@ namespace Ryujinx.Ava
|
||||
public async Task<bool> LoadGuestApplication()
|
||||
{
|
||||
InitializeSwitchInstance();
|
||||
|
||||
MainWindow.UpdateGraphicsConfig();
|
||||
|
||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
@@ -428,17 +430,16 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
if (userError == UserError.NoFirmware)
|
||||
{
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"],
|
||||
firmwareVersion.VersionString);
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"], message,
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
"");
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@@ -447,8 +448,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@@ -461,11 +461,9 @@ namespace Ryujinx.Ava
|
||||
|
||||
_parent.RefreshFirmwareStatus();
|
||||
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString);
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
||||
message,
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
@@ -473,9 +471,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@@ -514,7 +510,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else if (File.Exists(ApplicationPath))
|
||||
{
|
||||
switch (System.IO.Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
{
|
||||
@@ -602,7 +598,7 @@ namespace Ryujinx.Ava
|
||||
if (Renderer.IsVulkan)
|
||||
{
|
||||
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
||||
|
||||
|
||||
renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
||||
}
|
||||
else
|
||||
|
@@ -57,14 +57,14 @@ namespace Ryujinx.Ava.Ui.Applet
|
||||
|
||||
bool opened = false;
|
||||
|
||||
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
||||
title,
|
||||
message,
|
||||
"",
|
||||
LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
|
||||
"",
|
||||
LocaleManager.Instance["SettingsButtonClose"],
|
||||
(int)Symbol.Important,
|
||||
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
||||
title,
|
||||
message,
|
||||
"",
|
||||
LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
|
||||
"",
|
||||
LocaleManager.Instance["SettingsButtonClose"],
|
||||
(int)Symbol.Important,
|
||||
deferEvent,
|
||||
async (window) =>
|
||||
{
|
||||
@@ -168,7 +168,7 @@ namespace Ryujinx.Ava.Ui.Applet
|
||||
|
||||
object response = await msgDialog.Run();
|
||||
|
||||
if (response != null && buttons.Length > 1 && (int)response != buttons.Length - 1)
|
||||
if (response != null && buttons != null && buttons.Length > 1 && (int)response != buttons.Length - 1)
|
||||
{
|
||||
showDetails = true;
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
var flags = OpenGLContextFlags.Compat;
|
||||
if (_graphicsDebugLevel != GraphicsDebugLevel.None)
|
||||
{
|
||||
@@ -69,12 +69,12 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
|
||||
public void MakeCurrent()
|
||||
{
|
||||
Context.MakeCurrent(_window);
|
||||
Context?.MakeCurrent(_window);
|
||||
}
|
||||
|
||||
public void MakeCurrent(NativeWindowBase window)
|
||||
{
|
||||
Context.MakeCurrent(window);
|
||||
Context?.MakeCurrent(window);
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
|
@@ -251,24 +251,29 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
AppHost = new AppHost(RendererControl, InputManager, path, VirtualFileSystem, ContentManager, AccountManager, _userChannelPersistence, this);
|
||||
|
||||
if (!AppHost.LoadGuestApplication().Result)
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
AppHost.DisposeContext();
|
||||
if (!await AppHost.LoadGuestApplication())
|
||||
{
|
||||
AppHost.DisposeContext();
|
||||
AppHost = null;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||
|
||||
SwitchToGameControl(startFullscreen);
|
||||
SwitchToGameControl(startFullscreen);
|
||||
|
||||
_currentEmulatedGamePath = path;
|
||||
Thread gameThread = new Thread(InitializeGame)
|
||||
{
|
||||
Name = "GUI.WindowThread"
|
||||
};
|
||||
gameThread.Start();
|
||||
_currentEmulatedGamePath = path;
|
||||
|
||||
Thread gameThread = new(InitializeGame)
|
||||
{
|
||||
Name = "GUI.WindowThread"
|
||||
};
|
||||
gameThread.Start();
|
||||
});
|
||||
}
|
||||
|
||||
private void InitializeGame()
|
||||
@@ -546,10 +551,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
||||
{
|
||||
DateTime lastPlayedDateTime = DateTime.Parse(appMetadata.LastPlayed);
|
||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
|
||||
if (DateTime.TryParse(appMetadata.LastPlayed, out DateTime lastPlayedDateTime))
|
||||
{
|
||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
|
||||
|
||||
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
|
||||
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
@@ -7,49 +8,15 @@ namespace Ryujinx.Common
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||
where T : struct
|
||||
where T : unmanaged
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = reader.ReadBytes(size);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static T[] ReadStructArray<T>(this BinaryReader reader, int count)
|
||||
where T : struct
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
T[] result = new T[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
byte[] data = reader.ReadBytes(size);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
result[i] = Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||
where T : struct
|
||||
where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
||||
}
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
writer.Write(data);
|
||||
}
|
||||
|
@@ -180,6 +180,37 @@ namespace Ryujinx.Cpu.Jit
|
||||
WriteImpl(va, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
if (data.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SignalMemoryTracking(va, (ulong)data.Length, false);
|
||||
|
||||
if (IsContiguousAndMapped(va, data.Length))
|
||||
{
|
||||
var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length);
|
||||
|
||||
bool changed = !data.SequenceEqual(target);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
data.CopyTo(target);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteImpl(va, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to CPU mapped memory.
|
||||
/// </summary>
|
||||
|
@@ -307,6 +307,34 @@ namespace Ryujinx.Cpu.Jit
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
SignalMemoryTracking(va, (ulong)data.Length, false);
|
||||
|
||||
Span<byte> target = _addressSpaceMirror.GetSpan(va, data.Length);
|
||||
bool changed = !data.SequenceEqual(target);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
data.CopyTo(target);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
catch (InvalidMemoryRegionException)
|
||||
{
|
||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -23,34 +24,18 @@ namespace Ryujinx.Cpu
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : struct
|
||||
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
memory.Read(position, data);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
return MemoryMarshal.Cast<byte, T>(memory.GetSpan(position, Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
||||
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : struct
|
||||
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
||||
}
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
memory.Write(position, data);
|
||||
|
||||
return (ulong)size;
|
||||
return (ulong)data.Length;
|
||||
}
|
||||
|
||||
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)
|
||||
|
@@ -422,7 +422,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
|
||||
// Stop the GPU thread.
|
||||
_disposed = true;
|
||||
_gpuThread.Join();
|
||||
|
||||
if (_gpuThread != null && _gpuThread.IsAlive)
|
||||
{
|
||||
_gpuThread.Join();
|
||||
}
|
||||
|
||||
// Dispose the renderer.
|
||||
_baseRenderer.Dispose();
|
||||
@@ -435,4 +439,4 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
Sync.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
class ConstantBufferUpdater
|
||||
{
|
||||
private const int UniformDataCacheSize = 512;
|
||||
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
|
||||
@@ -16,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
private ulong _ubBeginCpuAddress = 0;
|
||||
private ulong _ubFollowUpAddress = 0;
|
||||
private ulong _ubByteCount = 0;
|
||||
private int _ubIndex = 0;
|
||||
private int[] _ubData = new int[UniformDataCacheSize];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the constant buffer updater.
|
||||
@@ -108,9 +112,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
if (_ubFollowUpAddress != 0)
|
||||
{
|
||||
var memoryManager = _channel.MemoryManager;
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
|
||||
Span<byte> data = MemoryMarshal.Cast<int, byte>(_ubData.AsSpan(0, (int)(_ubByteCount / 4)));
|
||||
|
||||
if (memoryManager.Physical.WriteWithRedundancyCheck(_ubBeginCpuAddress, data))
|
||||
{
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
}
|
||||
|
||||
_ubFollowUpAddress = 0;
|
||||
_ubIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
if (_ubFollowUpAddress != address || _ubIndex == _ubData.Length)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
@@ -132,8 +143,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref argument, 1));
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
_ubData[_ubIndex++] = argument;
|
||||
|
||||
_ubFollowUpAddress = address + 4;
|
||||
_ubByteCount += 4;
|
||||
@@ -153,7 +163,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
ulong size = (ulong)data.Length * 4;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
if (_ubFollowUpAddress != address || _ubIndex + data.Length > _ubData.Length)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
@@ -161,8 +171,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(data);
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
data.CopyTo(_ubData.AsSpan(_ubIndex));
|
||||
_ubIndex += data.Length;
|
||||
|
||||
_ubFollowUpAddress = address + size;
|
||||
_ubByteCount += size;
|
||||
|
@@ -242,6 +242,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
WriteImpl(range, data, _cpuMemory.WriteUntracked);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the application process, returning false if the data was not changed.
|
||||
/// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
|
||||
/// </summary>
|
||||
/// <remarks>The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.</remarks>
|
||||
/// <param name="address">Address to write into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <returns>True if the data was changed, false otherwise</returns>
|
||||
public bool WriteWithRedundancyCheck(ulong address, ReadOnlySpan<byte> data)
|
||||
{
|
||||
return _cpuMemory.WriteWithRedundancyCheck(address, data);
|
||||
}
|
||||
|
||||
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
|
||||
|
||||
/// <summary>
|
||||
|
@@ -54,4 +54,4 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
private const int TextureCount = 3;
|
||||
private readonly OpenGLRenderer _renderer;
|
||||
|
||||
private bool _initialized;
|
||||
|
||||
private int _width;
|
||||
private int _height;
|
||||
private int _copyFramebufferHandle;
|
||||
@@ -179,6 +181,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
public void InitializeBackgroundContext(IOpenGLContext baseContext)
|
||||
{
|
||||
BackgroundContext = new BackgroundContextWorker(baseContext);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public void CaptureFrame(int x, int y, int width, int height, bool isBgra, bool flipX, bool flipY)
|
||||
@@ -193,6 +196,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BackgroundContext.Dispose();
|
||||
|
||||
if (_copyFramebufferHandle != 0)
|
||||
@@ -203,4 +211,4 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,6 +22,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private Device _device;
|
||||
private WindowBase _window;
|
||||
|
||||
private bool _initialized;
|
||||
|
||||
internal FormatCapabilities FormatCapabilities { get; private set; }
|
||||
internal HardwareCapabilities Capabilities;
|
||||
|
||||
@@ -266,6 +268,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
LoadFeatures(supportedExtensions, maxQueueCount, queueFamilyIndex);
|
||||
|
||||
_window = new Window(this, _surface, _physicalDevice, _device);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public BufferHandle CreateBuffer(int size)
|
||||
@@ -573,6 +577,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CommandBufferPool.Dispose();
|
||||
BackgroundResources.Dispose();
|
||||
_counters.Dispose();
|
||||
@@ -613,4 +622,4 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Api.DestroyInstance(_instance, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||
@@ -9,6 +10,7 @@ using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -78,13 +80,13 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
var launchParams = _normalSession.Pop();
|
||||
var keyboardConfig = _normalSession.Pop();
|
||||
|
||||
_isBackground = keyboardConfig.Length == Marshal.SizeOf<SoftwareKeyboardInitialize>();
|
||||
_isBackground = keyboardConfig.Length == Unsafe.SizeOf<SoftwareKeyboardInitialize>();
|
||||
|
||||
if (_isBackground)
|
||||
{
|
||||
// Initialize the keyboard applet in background mode.
|
||||
|
||||
_keyboardBackgroundInitialize = ReadStruct<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||
_keyboardBackgroundInitialize = MemoryMarshal.Read<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||
_backgroundState = InlineKeyboardState.Uninitialized;
|
||||
|
||||
if (_device.UiHandler == null)
|
||||
@@ -342,7 +344,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
else
|
||||
{
|
||||
int wordsCount = reader.ReadInt32();
|
||||
int wordSize = Marshal.SizeOf<SoftwareKeyboardUserWord>();
|
||||
int wordSize = Unsafe.SizeOf<SoftwareKeyboardUserWord>();
|
||||
remaining = stream.Length - stream.Position;
|
||||
|
||||
if (wordsCount > MaxUserWords)
|
||||
@@ -359,8 +361,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
|
||||
for (int word = 0; word < wordsCount; word++)
|
||||
{
|
||||
byte[] wordData = reader.ReadBytes(wordSize);
|
||||
_keyboardBackgroundUserWords[word] = ReadStruct<SoftwareKeyboardUserWord>(wordData);
|
||||
_keyboardBackgroundUserWords[word] = reader.ReadStruct<SoftwareKeyboardUserWord>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,27 +370,25 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
case InlineKeyboardRequest.SetCustomizeDic:
|
||||
// Read the custom dic data.
|
||||
remaining = stream.Length - stream.Position;
|
||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardCustomizeDic>())
|
||||
if (remaining != Unsafe.SizeOf<SoftwareKeyboardCustomizeDic>())
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyboardDicData = reader.ReadBytes((int)remaining);
|
||||
_keyboardBackgroundDic = ReadStruct<SoftwareKeyboardCustomizeDic>(keyboardDicData);
|
||||
_keyboardBackgroundDic = reader.ReadStruct<SoftwareKeyboardCustomizeDic>();
|
||||
}
|
||||
break;
|
||||
case InlineKeyboardRequest.SetCustomizedDictionaries:
|
||||
// Read the custom dictionaries data.
|
||||
remaining = stream.Length - stream.Position;
|
||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardDictSet>())
|
||||
if (remaining != Unsafe.SizeOf<SoftwareKeyboardDictSet>())
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyboardDictData = reader.ReadBytes((int)remaining);
|
||||
_keyboardBackgroundDictSet = ReadStruct<SoftwareKeyboardDictSet>(keyboardDictData);
|
||||
_keyboardBackgroundDictSet = reader.ReadStruct<SoftwareKeyboardDictSet>();
|
||||
}
|
||||
break;
|
||||
case InlineKeyboardRequest.Calc:
|
||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// A structure used by SetCustomizeDic request to software keyboard.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x70)]
|
||||
struct SoftwareKeyboardCustomizeDic
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)]
|
||||
public byte[] Unknown;
|
||||
// Unknown
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
@@ -21,8 +22,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// Array of word entries in the buffer.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
||||
public ulong[] Entries;
|
||||
public Array24<ulong> Entries;
|
||||
|
||||
/// <summary>
|
||||
/// Number of used entries in the Entries field.
|
||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// A structure used by SetUserWordInfo request to the software keyboard.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x64)]
|
||||
struct SoftwareKeyboardUserWord
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
|
||||
public byte[] Unknown;
|
||||
// Unknown
|
||||
}
|
||||
}
|
||||
|
@@ -479,7 +479,10 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
AudioRendererManager.Dispose();
|
||||
|
||||
LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure();
|
||||
if (LibHacHorizonManager.ApplicationClient != null)
|
||||
{
|
||||
LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure();
|
||||
}
|
||||
|
||||
KernelContext.Dispose();
|
||||
}
|
||||
|
@@ -1,9 +1,12 @@
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8)]
|
||||
struct UserPresence
|
||||
{
|
||||
public UserId UserId;
|
||||
@@ -13,15 +16,20 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool SamePresenceGroupApplication;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)]
|
||||
public char[] Unknown;
|
||||
public Array3<byte> Unknown;
|
||||
private AppKeyValueStorageHolder _appKeyValueStorage;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC0)]
|
||||
public char[] AppKeyValueStorage;
|
||||
public Span<byte> AppKeyValueStorage => MemoryMarshal.Cast<AppKeyValueStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size));
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)]
|
||||
private struct AppKeyValueStorageHolder
|
||||
{
|
||||
public const int Size = 0xC0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {AppKeyValueStorage} }}";
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {Encoding.ASCII.GetString(AppKeyValueStorage)} }}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -236,23 +236,14 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||
ulong position = context.Request.PtrBuff[0].Position;
|
||||
ulong size = context.Request.PtrBuff[0].Size;
|
||||
|
||||
byte[] bufferContent = new byte[size];
|
||||
|
||||
context.Memory.Read(position, bufferContent);
|
||||
ReadOnlySpan<UserPresence> userPresenceInputArray = MemoryMarshal.Cast<byte, UserPresence>(context.Memory.GetSpan(position, (int)size));
|
||||
|
||||
if (uuid.IsNull)
|
||||
{
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
int elementCount = bufferContent.Length / Marshal.SizeOf<UserPresence>();
|
||||
|
||||
using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(bufferContent)))
|
||||
{
|
||||
UserPresence[] userPresenceInputArray = bufferReader.ReadStructArray<UserPresence>(elementCount);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray });
|
||||
}
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@@ -1,15 +1,13 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x10)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
struct NotificationInfo
|
||||
{
|
||||
public NotificationEventType Type;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)]
|
||||
public char[] Padding;
|
||||
|
||||
private Array4<byte> _padding;
|
||||
public long NetworkUserIdPlaceholder;
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
@@ -75,7 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
|
||||
for (int i = 0; i < filteredApplicationPlayStatistics.Count(); i++)
|
||||
{
|
||||
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Marshal.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
||||
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Unsafe.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
||||
}
|
||||
|
||||
context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
@@ -16,14 +17,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
||||
public SteadyClockTimePoint SteadyClockTimePoint;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
|
||||
public char[] LocationName;
|
||||
private LocationNameStorageHolder _locationName;
|
||||
|
||||
public Span<byte> LocationName => MemoryMarshal.Cast<LocationNameStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _locationName, LocationNameStorageHolder.Size));
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsAutomaticCorrectionEnabled;
|
||||
public byte Type;
|
||||
public ushort Unknown;
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = Size)]
|
||||
private struct LocationNameStorageHolder
|
||||
{
|
||||
public const int Size = 0x24;
|
||||
}
|
||||
|
||||
public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
|
||||
{
|
||||
currentTime = 0;
|
||||
|
@@ -8,7 +8,9 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
@@ -281,7 +283,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
byte type = context.RequestData.ReadByte();
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ClockSnapshot>());
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Unsafe.SizeOf<ClockSnapshot>());
|
||||
|
||||
context.RequestData.BaseStream.Position += 7;
|
||||
|
||||
@@ -372,12 +374,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
return result;
|
||||
}
|
||||
|
||||
char[] tzName = deviceLocationName.ToCharArray();
|
||||
char[] locationName = new char[0x24];
|
||||
ReadOnlySpan<byte> tzName = Encoding.ASCII.GetBytes(deviceLocationName);
|
||||
|
||||
Array.Copy(tzName, locationName, tzName.Length);
|
||||
|
||||
clockSnapshot.LocationName = locationName;
|
||||
tzName.CopyTo(clockSnapshot.LocationName);
|
||||
|
||||
result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
|
||||
|
||||
@@ -414,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
|
||||
private ClockSnapshot ReadClockSnapshotFromBuffer(ServiceCtx context, IpcPtrBuffDesc ipcDesc)
|
||||
{
|
||||
Debug.Assert(ipcDesc.Size == (ulong)Marshal.SizeOf<ClockSnapshot>());
|
||||
Debug.Assert(ipcDesc.Size == (ulong)Unsafe.SizeOf<ClockSnapshot>());
|
||||
|
||||
byte[] temp = new byte[ipcDesc.Size];
|
||||
|
||||
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -890,14 +891,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||
|
||||
long streamLength = reader.BaseStream.Length;
|
||||
|
||||
if (streamLength < Marshal.SizeOf<TzifHeader>())
|
||||
if (streamLength < Unsafe.SizeOf<TzifHeader>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TzifHeader header = reader.ReadStruct<TzifHeader>();
|
||||
|
||||
streamLength -= Marshal.SizeOf<TzifHeader>();
|
||||
streamLength -= Unsafe.SizeOf<TzifHeader>();
|
||||
|
||||
int ttisGMTCount = Detzcode32(header.TtisGMTCount);
|
||||
int ttisSTDCount = Detzcode32(header.TtisSTDCount);
|
||||
|
@@ -40,20 +40,16 @@ namespace Ryujinx.Headless.SDL2.Vulkan
|
||||
return (IntPtr)surfaceHandle;
|
||||
}
|
||||
|
||||
// TODO: Fix this in SDL2-CS.
|
||||
[DllImport("SDL2", EntryPoint = "SDL_Vulkan_GetInstanceExtensions", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern SDL_bool SDL_Vulkan_GetInstanceExtensions_Workaround(IntPtr window, out uint count, IntPtr names);
|
||||
|
||||
public unsafe string[] GetRequiredInstanceExtensions()
|
||||
{
|
||||
if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out uint extensionsCount, IntPtr.Zero) == SDL_bool.SDL_TRUE)
|
||||
if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out uint extensionsCount, IntPtr.Zero) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
IntPtr[] rawExtensions = new IntPtr[(int)extensionsCount];
|
||||
string[] extensions = new string[(int)extensionsCount];
|
||||
|
||||
fixed (IntPtr* rawExtensionsPtr = rawExtensions)
|
||||
{
|
||||
if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out extensionsCount, (IntPtr)rawExtensionsPtr) == SDL_bool.SDL_TRUE)
|
||||
if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out extensionsCount, (IntPtr)rawExtensionsPtr) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
for (int i = 0; i < extensions.Length; i++)
|
||||
{
|
||||
|
@@ -1,16 +1,15 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ControllerDataRequest
|
||||
{
|
||||
public MessageType Type;
|
||||
public MessageType Type;
|
||||
public SubscriberType SubscriberType;
|
||||
public byte Slot;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] MacAddress;
|
||||
public byte Slot;
|
||||
public Array6<byte> MacAddress;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
@@ -27,11 +26,8 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
public uint DPadAnalog;
|
||||
public ulong MainButtonsAnalog;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] Touch1;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] Touch2;
|
||||
public Array6<byte> Touch1;
|
||||
public Array6<byte> Touch2;
|
||||
|
||||
public ulong MotionTimestamp;
|
||||
public float AccelerometerX;
|
||||
|
@@ -1,21 +1,20 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ControllerInfoResponse
|
||||
{
|
||||
public SharedResponse Shared;
|
||||
private byte _zero;
|
||||
public SharedResponse Shared;
|
||||
private byte _zero;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ControllerInfoRequest
|
||||
{
|
||||
public MessageType Type;
|
||||
public int PortsCount;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[] PortIndices;
|
||||
public int PortsCount;
|
||||
public Array4<byte> PortIndices;
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
@@ -11,8 +12,7 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
public DeviceModelType ModelType;
|
||||
public ConnectionType ConnectionType;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] MacAddress;
|
||||
public Array6<byte> MacAddress;
|
||||
public BatteryStatus BatteryStatus;
|
||||
}
|
||||
|
||||
|
@@ -44,6 +44,11 @@ namespace Ryujinx.Memory.Tests
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
@@ -136,6 +136,14 @@ namespace Ryujinx.Memory
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
Write(va, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
|
@@ -58,6 +58,17 @@ namespace Ryujinx.Memory
|
||||
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
void Write(ulong va, ReadOnlySpan<byte> data);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the application process, returning false if the data was not changed.
|
||||
/// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
|
||||
/// </summary>
|
||||
/// <remarks>The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.</remarks>
|
||||
/// <param name="va">Virtual address to write the data into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
/// <returns>True if the data was changed, false otherwise</returns>
|
||||
bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data);
|
||||
|
||||
void Fill(ulong va, ulong size, byte value)
|
||||
{
|
||||
const int MaxChunkSize = 1 << 24;
|
||||
|
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" Version="2.0.22-build20" />
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -43,6 +43,8 @@ namespace Ryujinx.SDL2.Common
|
||||
|
||||
private SDL2Driver() {}
|
||||
|
||||
private const string SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS = "SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS";
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -60,6 +62,11 @@ namespace Ryujinx.SDL2.Common
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
|
||||
|
||||
|
||||
// NOTE: As of SDL2 2.24.0, joycons are combined by default but the motion source only come from one of them.
|
||||
// We disable this behavior for now.
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
|
||||
|
||||
if (SDL_Init(SdlInitFlags) != 0)
|
||||
{
|
||||
string errorMessage = $"SDL2 initlaization failed with error \"{SDL_GetError()}\"";
|
||||
|
@@ -735,7 +735,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
_emulationContext.Dispose();
|
||||
SwitchToGameTable();
|
||||
RendererWidget.Dispose();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -747,7 +746,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
_emulationContext.Dispose();
|
||||
SwitchToGameTable();
|
||||
RendererWidget.Dispose();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -770,7 +768,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
_emulationContext.Dispose();
|
||||
SwitchToGameTable();
|
||||
RendererWidget.Dispose();
|
||||
|
||||
return;
|
||||
}
|
||||
|
@@ -519,10 +519,14 @@ namespace Ryujinx.Ui
|
||||
_gpuCancellationTokenSource.Cancel();
|
||||
|
||||
_isStopped = true;
|
||||
_isActive = false;
|
||||
|
||||
if (_isActive)
|
||||
{
|
||||
_isActive = false;
|
||||
|
||||
_exitEvent.WaitOne();
|
||||
_exitEvent.Dispose();
|
||||
_exitEvent.WaitOne();
|
||||
_exitEvent.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void NVStutterWorkaround()
|
||||
|
@@ -72,7 +72,8 @@ namespace Ryujinx.Ui
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Device.DisposeGpu();
|
||||
Device?.DisposeGpu();
|
||||
|
||||
NpadManager.Dispose();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user