Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
65778a6b78 | ||
|
f4e879a1e6 | ||
|
a1ddaa2736 | ||
|
008286b79f | ||
|
a0c77f8d11 |
@@ -21,6 +21,8 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
Name = $"Ryujinx {Program.Version}";
|
||||||
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -349,7 +349,10 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
|
|
||||||
|
if (_renderingThread.IsAlive)
|
||||||
|
{
|
||||||
_renderingThread.Join();
|
_renderingThread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
DisplaySleep.Restore();
|
DisplaySleep.Restore();
|
||||||
|
|
||||||
@@ -417,7 +420,6 @@ namespace Ryujinx.Ava
|
|||||||
public async Task<bool> LoadGuestApplication()
|
public async Task<bool> LoadGuestApplication()
|
||||||
{
|
{
|
||||||
InitializeSwitchInstance();
|
InitializeSwitchInstance();
|
||||||
|
|
||||||
MainWindow.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
|
|
||||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
@@ -428,17 +430,16 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
if (userError == UserError.NoFirmware)
|
if (userError == UserError.NoFirmware)
|
||||||
{
|
{
|
||||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"],
|
|
||||||
firmwareVersion.VersionString);
|
|
||||||
|
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"], message,
|
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
|
||||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
|
||||||
|
LocaleManager.Instance["InputDialogYes"],
|
||||||
|
LocaleManager.Instance["InputDialogNo"],
|
||||||
|
"");
|
||||||
|
|
||||||
if (result != UserResult.Yes)
|
if (result != UserResult.Yes)
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () => await
|
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -447,8 +448,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () => await
|
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -461,11 +461,9 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_parent.RefreshFirmwareStatus();
|
_parent.RefreshFirmwareStatus();
|
||||||
|
|
||||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString);
|
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
await ContentDialogHelper.CreateInfoDialog(
|
||||||
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
||||||
message,
|
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
|
||||||
LocaleManager.Instance["InputDialogOk"],
|
LocaleManager.Instance["InputDialogOk"],
|
||||||
"",
|
"",
|
||||||
LocaleManager.Instance["RyujinxInfo"]);
|
LocaleManager.Instance["RyujinxInfo"]);
|
||||||
@@ -473,9 +471,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () => await
|
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
|
||||||
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -514,7 +510,7 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
else if (File.Exists(ApplicationPath))
|
else if (File.Exists(ApplicationPath))
|
||||||
{
|
{
|
||||||
switch (System.IO.Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case ".xci":
|
case ".xci":
|
||||||
{
|
{
|
||||||
|
@@ -168,7 +168,7 @@ namespace Ryujinx.Ava.Ui.Applet
|
|||||||
|
|
||||||
object response = await msgDialog.Run();
|
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;
|
showDetails = true;
|
||||||
}
|
}
|
||||||
|
@@ -69,12 +69,12 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
|
|
||||||
public void MakeCurrent()
|
public void MakeCurrent()
|
||||||
{
|
{
|
||||||
Context.MakeCurrent(_window);
|
Context?.MakeCurrent(_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MakeCurrent(NativeWindowBase window)
|
public void MakeCurrent(NativeWindowBase window)
|
||||||
{
|
{
|
||||||
Context.MakeCurrent(window);
|
Context?.MakeCurrent(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SwapBuffers()
|
public void SwapBuffers()
|
||||||
|
@@ -251,9 +251,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
AppHost = new AppHost(RendererControl, InputManager, path, VirtualFileSystem, ContentManager, AccountManager, _userChannelPersistence, this);
|
AppHost = new AppHost(RendererControl, InputManager, path, VirtualFileSystem, ContentManager, AccountManager, _userChannelPersistence, this);
|
||||||
|
|
||||||
if (!AppHost.LoadGuestApplication().Result)
|
Dispatcher.UIThread.Post(async () =>
|
||||||
|
{
|
||||||
|
if (!await AppHost.LoadGuestApplication())
|
||||||
{
|
{
|
||||||
AppHost.DisposeContext();
|
AppHost.DisposeContext();
|
||||||
|
AppHost = null;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -264,11 +267,13 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
SwitchToGameControl(startFullscreen);
|
SwitchToGameControl(startFullscreen);
|
||||||
|
|
||||||
_currentEmulatedGamePath = path;
|
_currentEmulatedGamePath = path;
|
||||||
Thread gameThread = new Thread(InitializeGame)
|
|
||||||
|
Thread gameThread = new(InitializeGame)
|
||||||
{
|
{
|
||||||
Name = "GUI.WindowThread"
|
Name = "GUI.WindowThread"
|
||||||
};
|
};
|
||||||
gameThread.Start();
|
gameThread.Start();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeGame()
|
private void InitializeGame()
|
||||||
@@ -546,10 +551,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
{
|
{
|
||||||
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
||||||
{
|
{
|
||||||
DateTime lastPlayedDateTime = DateTime.Parse(appMetadata.LastPlayed);
|
if (DateTime.TryParse(appMetadata.LastPlayed, out DateTime lastPlayedDateTime))
|
||||||
|
{
|
||||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
|
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;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Common
|
namespace Ryujinx.Common
|
||||||
@@ -7,49 +8,15 @@ namespace Ryujinx.Common
|
|||||||
public static class BinaryReaderExtensions
|
public static class BinaryReaderExtensions
|
||||||
{
|
{
|
||||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||||
where T : struct
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
int size = Marshal.SizeOf<T>();
|
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||||
where T : struct
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
long size = Marshal.SizeOf<T>();
|
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.Write(data);
|
writer.Write(data);
|
||||||
}
|
}
|
||||||
|
@@ -180,6 +180,37 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
WriteImpl(va, data);
|
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>
|
/// <summary>
|
||||||
/// Writes data to CPU mapped memory.
|
/// Writes data to CPU mapped memory.
|
||||||
/// </summary>
|
/// </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/>
|
/// <inheritdoc/>
|
||||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||||
{
|
{
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
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>();
|
return MemoryMarshal.Cast<byte, T>(memory.GetSpan(position, Unsafe.SizeOf<T>()))[0];
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
|
|
||||||
memory.Read(position, data);
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>();
|
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
memory.Write(position, data);
|
memory.Write(position, data);
|
||||||
|
|
||||||
return (ulong)size;
|
return (ulong)data.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)
|
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)
|
||||||
|
@@ -422,7 +422,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
|
|
||||||
// Stop the GPU thread.
|
// Stop the GPU thread.
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
|
||||||
|
if (_gpuThread != null && _gpuThread.IsAlive)
|
||||||
|
{
|
||||||
_gpuThread.Join();
|
_gpuThread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
// Dispose the renderer.
|
// Dispose the renderer.
|
||||||
_baseRenderer.Dispose();
|
_baseRenderer.Dispose();
|
||||||
|
@@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class ConstantBufferUpdater
|
class ConstantBufferUpdater
|
||||||
{
|
{
|
||||||
|
private const int UniformDataCacheSize = 512;
|
||||||
|
|
||||||
private readonly GpuChannel _channel;
|
private readonly GpuChannel _channel;
|
||||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||||
|
|
||||||
@@ -16,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
private ulong _ubBeginCpuAddress = 0;
|
private ulong _ubBeginCpuAddress = 0;
|
||||||
private ulong _ubFollowUpAddress = 0;
|
private ulong _ubFollowUpAddress = 0;
|
||||||
private ulong _ubByteCount = 0;
|
private ulong _ubByteCount = 0;
|
||||||
|
private int _ubIndex = 0;
|
||||||
|
private int[] _ubData = new int[UniformDataCacheSize];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the constant buffer updater.
|
/// Creates a new instance of the constant buffer updater.
|
||||||
@@ -108,9 +112,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
if (_ubFollowUpAddress != 0)
|
if (_ubFollowUpAddress != 0)
|
||||||
{
|
{
|
||||||
var memoryManager = _channel.MemoryManager;
|
var memoryManager = _channel.MemoryManager;
|
||||||
|
|
||||||
|
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);
|
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||||
|
}
|
||||||
|
|
||||||
_ubFollowUpAddress = 0;
|
_ubFollowUpAddress = 0;
|
||||||
|
_ubIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||||
|
|
||||||
if (_ubFollowUpAddress != address)
|
if (_ubFollowUpAddress != address || _ubIndex == _ubData.Length)
|
||||||
{
|
{
|
||||||
FlushUboDirty();
|
FlushUboDirty();
|
||||||
|
|
||||||
@@ -132,8 +143,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
var byteData = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref argument, 1));
|
_ubData[_ubIndex++] = argument;
|
||||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
|
||||||
|
|
||||||
_ubFollowUpAddress = address + 4;
|
_ubFollowUpAddress = address + 4;
|
||||||
_ubByteCount += 4;
|
_ubByteCount += 4;
|
||||||
@@ -153,7 +163,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
ulong size = (ulong)data.Length * 4;
|
ulong size = (ulong)data.Length * 4;
|
||||||
|
|
||||||
if (_ubFollowUpAddress != address)
|
if (_ubFollowUpAddress != address || _ubIndex + data.Length > _ubData.Length)
|
||||||
{
|
{
|
||||||
FlushUboDirty();
|
FlushUboDirty();
|
||||||
|
|
||||||
@@ -161,8 +171,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
var byteData = MemoryMarshal.Cast<int, byte>(data);
|
data.CopyTo(_ubData.AsSpan(_ubIndex));
|
||||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
_ubIndex += data.Length;
|
||||||
|
|
||||||
_ubFollowUpAddress = address + size;
|
_ubFollowUpAddress = address + size;
|
||||||
_ubByteCount += size;
|
_ubByteCount += size;
|
||||||
|
@@ -242,6 +242,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
WriteImpl(range, data, _cpuMemory.WriteUntracked);
|
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);
|
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
private const int TextureCount = 3;
|
private const int TextureCount = 3;
|
||||||
private readonly OpenGLRenderer _renderer;
|
private readonly OpenGLRenderer _renderer;
|
||||||
|
|
||||||
|
private bool _initialized;
|
||||||
|
|
||||||
private int _width;
|
private int _width;
|
||||||
private int _height;
|
private int _height;
|
||||||
private int _copyFramebufferHandle;
|
private int _copyFramebufferHandle;
|
||||||
@@ -179,6 +181,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
public void InitializeBackgroundContext(IOpenGLContext baseContext)
|
public void InitializeBackgroundContext(IOpenGLContext baseContext)
|
||||||
{
|
{
|
||||||
BackgroundContext = new BackgroundContextWorker(baseContext);
|
BackgroundContext = new BackgroundContextWorker(baseContext);
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CaptureFrame(int x, int y, int width, int height, bool isBgra, bool flipX, bool flipY)
|
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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
if (!_initialized)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BackgroundContext.Dispose();
|
BackgroundContext.Dispose();
|
||||||
|
|
||||||
if (_copyFramebufferHandle != 0)
|
if (_copyFramebufferHandle != 0)
|
||||||
|
@@ -22,6 +22,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private Device _device;
|
private Device _device;
|
||||||
private WindowBase _window;
|
private WindowBase _window;
|
||||||
|
|
||||||
|
private bool _initialized;
|
||||||
|
|
||||||
internal FormatCapabilities FormatCapabilities { get; private set; }
|
internal FormatCapabilities FormatCapabilities { get; private set; }
|
||||||
internal HardwareCapabilities Capabilities;
|
internal HardwareCapabilities Capabilities;
|
||||||
|
|
||||||
@@ -266,6 +268,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
LoadFeatures(supportedExtensions, maxQueueCount, queueFamilyIndex);
|
LoadFeatures(supportedExtensions, maxQueueCount, queueFamilyIndex);
|
||||||
|
|
||||||
_window = new Window(this, _surface, _physicalDevice, _device);
|
_window = new Window(this, _surface, _physicalDevice, _device);
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferHandle CreateBuffer(int size)
|
public BufferHandle CreateBuffer(int size)
|
||||||
@@ -573,6 +577,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public unsafe void Dispose()
|
public unsafe void Dispose()
|
||||||
{
|
{
|
||||||
|
if (!_initialized)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CommandBufferPool.Dispose();
|
CommandBufferPool.Dispose();
|
||||||
BackgroundResources.Dispose();
|
BackgroundResources.Dispose();
|
||||||
_counters.Dispose();
|
_counters.Dispose();
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||||
@@ -9,6 +10,7 @@ using Ryujinx.Memory;
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -78,13 +80,13 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
var launchParams = _normalSession.Pop();
|
var launchParams = _normalSession.Pop();
|
||||||
var keyboardConfig = _normalSession.Pop();
|
var keyboardConfig = _normalSession.Pop();
|
||||||
|
|
||||||
_isBackground = keyboardConfig.Length == Marshal.SizeOf<SoftwareKeyboardInitialize>();
|
_isBackground = keyboardConfig.Length == Unsafe.SizeOf<SoftwareKeyboardInitialize>();
|
||||||
|
|
||||||
if (_isBackground)
|
if (_isBackground)
|
||||||
{
|
{
|
||||||
// Initialize the keyboard applet in background mode.
|
// Initialize the keyboard applet in background mode.
|
||||||
|
|
||||||
_keyboardBackgroundInitialize = ReadStruct<SoftwareKeyboardInitialize>(keyboardConfig);
|
_keyboardBackgroundInitialize = MemoryMarshal.Read<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||||
_backgroundState = InlineKeyboardState.Uninitialized;
|
_backgroundState = InlineKeyboardState.Uninitialized;
|
||||||
|
|
||||||
if (_device.UiHandler == null)
|
if (_device.UiHandler == null)
|
||||||
@@ -342,7 +344,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int wordsCount = reader.ReadInt32();
|
int wordsCount = reader.ReadInt32();
|
||||||
int wordSize = Marshal.SizeOf<SoftwareKeyboardUserWord>();
|
int wordSize = Unsafe.SizeOf<SoftwareKeyboardUserWord>();
|
||||||
remaining = stream.Length - stream.Position;
|
remaining = stream.Length - stream.Position;
|
||||||
|
|
||||||
if (wordsCount > MaxUserWords)
|
if (wordsCount > MaxUserWords)
|
||||||
@@ -359,8 +361,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
|
|
||||||
for (int word = 0; word < wordsCount; word++)
|
for (int word = 0; word < wordsCount; word++)
|
||||||
{
|
{
|
||||||
byte[] wordData = reader.ReadBytes(wordSize);
|
_keyboardBackgroundUserWords[word] = reader.ReadStruct<SoftwareKeyboardUserWord>();
|
||||||
_keyboardBackgroundUserWords[word] = ReadStruct<SoftwareKeyboardUserWord>(wordData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,27 +370,25 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
case InlineKeyboardRequest.SetCustomizeDic:
|
case InlineKeyboardRequest.SetCustomizeDic:
|
||||||
// Read the custom dic data.
|
// Read the custom dic data.
|
||||||
remaining = stream.Length - stream.Position;
|
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");
|
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var keyboardDicData = reader.ReadBytes((int)remaining);
|
_keyboardBackgroundDic = reader.ReadStruct<SoftwareKeyboardCustomizeDic>();
|
||||||
_keyboardBackgroundDic = ReadStruct<SoftwareKeyboardCustomizeDic>(keyboardDicData);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InlineKeyboardRequest.SetCustomizedDictionaries:
|
case InlineKeyboardRequest.SetCustomizedDictionaries:
|
||||||
// Read the custom dictionaries data.
|
// Read the custom dictionaries data.
|
||||||
remaining = stream.Length - stream.Position;
|
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");
|
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var keyboardDictData = reader.ReadBytes((int)remaining);
|
_keyboardBackgroundDictSet = reader.ReadStruct<SoftwareKeyboardDictSet>();
|
||||||
_keyboardBackgroundDictSet = ReadStruct<SoftwareKeyboardDictSet>(keyboardDictData);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InlineKeyboardRequest.Calc:
|
case InlineKeyboardRequest.Calc:
|
||||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure used by SetCustomizeDic request to software keyboard.
|
/// A structure used by SetCustomizeDic request to software keyboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
[StructLayout(LayoutKind.Sequential, Size = 0x70)]
|
||||||
struct SoftwareKeyboardCustomizeDic
|
struct SoftwareKeyboardCustomizeDic
|
||||||
{
|
{
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)]
|
// Unknown
|
||||||
public byte[] Unknown;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
{
|
{
|
||||||
@@ -21,8 +22,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Array of word entries in the buffer.
|
/// Array of word entries in the buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
public Array24<ulong> Entries;
|
||||||
public ulong[] Entries;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of used entries in the Entries field.
|
/// Number of used entries in the Entries field.
|
||||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure used by SetUserWordInfo request to the software keyboard.
|
/// A structure used by SetUserWordInfo request to the software keyboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
[StructLayout(LayoutKind.Sequential, Size = 0x64)]
|
||||||
struct SoftwareKeyboardUserWord
|
struct SoftwareKeyboardUserWord
|
||||||
{
|
{
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
|
// Unknown
|
||||||
public byte[] Unknown;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -479,7 +479,10 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
AudioRendererManager.Dispose();
|
AudioRendererManager.Dispose();
|
||||||
|
|
||||||
|
if (LibHacHorizonManager.ApplicationClient != null)
|
||||||
|
{
|
||||||
LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure();
|
LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure();
|
||||||
|
}
|
||||||
|
|
||||||
KernelContext.Dispose();
|
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.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)]
|
[StructLayout(LayoutKind.Sequential, Pack = 0x8)]
|
||||||
struct UserPresence
|
struct UserPresence
|
||||||
{
|
{
|
||||||
public UserId UserId;
|
public UserId UserId;
|
||||||
@@ -13,15 +16,20 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
|||||||
[MarshalAs(UnmanagedType.I1)]
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
public bool SamePresenceGroupApplication;
|
public bool SamePresenceGroupApplication;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)]
|
public Array3<byte> Unknown;
|
||||||
public char[] Unknown;
|
private AppKeyValueStorageHolder _appKeyValueStorage;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC0)]
|
public Span<byte> AppKeyValueStorage => MemoryMarshal.Cast<AppKeyValueStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size));
|
||||||
public char[] AppKeyValueStorage;
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)]
|
||||||
|
private struct AppKeyValueStorageHolder
|
||||||
|
{
|
||||||
|
public const int Size = 0xC0;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
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 position = context.Request.PtrBuff[0].Position;
|
||||||
ulong size = context.Request.PtrBuff[0].Size;
|
ulong size = context.Request.PtrBuff[0].Size;
|
||||||
|
|
||||||
byte[] bufferContent = new byte[size];
|
ReadOnlySpan<UserPresence> userPresenceInputArray = MemoryMarshal.Cast<byte, UserPresence>(context.Memory.GetSpan(position, (int)size));
|
||||||
|
|
||||||
context.Memory.Read(position, bufferContent);
|
|
||||||
|
|
||||||
if (uuid.IsNull)
|
if (uuid.IsNull)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
int elementCount = bufferContent.Length / Marshal.SizeOf<UserPresence>();
|
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() });
|
||||||
|
|
||||||
using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(bufferContent)))
|
|
||||||
{
|
|
||||||
UserPresence[] userPresenceInputArray = bufferReader.ReadStructArray<UserPresence>(elementCount);
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray });
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
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
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x10)]
|
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||||
struct NotificationInfo
|
struct NotificationInfo
|
||||||
{
|
{
|
||||||
public NotificationEventType Type;
|
public NotificationEventType Type;
|
||||||
|
private Array4<byte> _padding;
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)]
|
|
||||||
public char[] Padding;
|
|
||||||
|
|
||||||
public long NetworkUserIdPlaceholder;
|
public long NetworkUserIdPlaceholder;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
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++)
|
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());
|
context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
@@ -16,14 +17,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
||||||
public SteadyClockTimePoint SteadyClockTimePoint;
|
public SteadyClockTimePoint SteadyClockTimePoint;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
|
private LocationNameStorageHolder _locationName;
|
||||||
public char[] LocationName;
|
|
||||||
|
public Span<byte> LocationName => MemoryMarshal.Cast<LocationNameStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _locationName, LocationNameStorageHolder.Size));
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.I1)]
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
public bool IsAutomaticCorrectionEnabled;
|
public bool IsAutomaticCorrectionEnabled;
|
||||||
public byte Type;
|
public byte Type;
|
||||||
public ushort Unknown;
|
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)
|
public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
|
||||||
{
|
{
|
||||||
currentTime = 0;
|
currentTime = 0;
|
||||||
|
@@ -8,7 +8,9 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time
|
namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
{
|
{
|
||||||
@@ -281,7 +283,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
{
|
{
|
||||||
byte type = context.RequestData.ReadByte();
|
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;
|
context.RequestData.BaseStream.Position += 7;
|
||||||
|
|
||||||
@@ -372,12 +374,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] tzName = deviceLocationName.ToCharArray();
|
ReadOnlySpan<byte> tzName = Encoding.ASCII.GetBytes(deviceLocationName);
|
||||||
char[] locationName = new char[0x24];
|
|
||||||
|
|
||||||
Array.Copy(tzName, locationName, tzName.Length);
|
tzName.CopyTo(clockSnapshot.LocationName);
|
||||||
|
|
||||||
clockSnapshot.LocationName = locationName;
|
|
||||||
|
|
||||||
result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
|
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)
|
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];
|
byte[] temp = new byte[ipcDesc.Size];
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.Utilities;
|
|||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -890,14 +891,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
|||||||
|
|
||||||
long streamLength = reader.BaseStream.Length;
|
long streamLength = reader.BaseStream.Length;
|
||||||
|
|
||||||
if (streamLength < Marshal.SizeOf<TzifHeader>())
|
if (streamLength < Unsafe.SizeOf<TzifHeader>())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TzifHeader header = reader.ReadStruct<TzifHeader>();
|
TzifHeader header = reader.ReadStruct<TzifHeader>();
|
||||||
|
|
||||||
streamLength -= Marshal.SizeOf<TzifHeader>();
|
streamLength -= Unsafe.SizeOf<TzifHeader>();
|
||||||
|
|
||||||
int ttisGMTCount = Detzcode32(header.TtisGMTCount);
|
int ttisGMTCount = Detzcode32(header.TtisGMTCount);
|
||||||
int ttisSTDCount = Detzcode32(header.TtisSTDCount);
|
int ttisSTDCount = Detzcode32(header.TtisSTDCount);
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
@@ -8,9 +9,7 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
|||||||
public MessageType Type;
|
public MessageType Type;
|
||||||
public SubscriberType SubscriberType;
|
public SubscriberType SubscriberType;
|
||||||
public byte Slot;
|
public byte Slot;
|
||||||
|
public Array6<byte> MacAddress;
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
||||||
public byte[] MacAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
@@ -27,11 +26,8 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
|||||||
public uint DPadAnalog;
|
public uint DPadAnalog;
|
||||||
public ulong MainButtonsAnalog;
|
public ulong MainButtonsAnalog;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
public Array6<byte> Touch1;
|
||||||
public byte[] Touch1;
|
public Array6<byte> Touch2;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
||||||
public byte[] Touch2;
|
|
||||||
|
|
||||||
public ulong MotionTimestamp;
|
public ulong MotionTimestamp;
|
||||||
public float AccelerometerX;
|
public float AccelerometerX;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
@@ -14,8 +15,6 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
|||||||
{
|
{
|
||||||
public MessageType Type;
|
public MessageType Type;
|
||||||
public int PortsCount;
|
public int PortsCount;
|
||||||
|
public Array4<byte> PortIndices;
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
|
||||||
public byte[] PortIndices;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
@@ -11,8 +12,7 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
|||||||
public DeviceModelType ModelType;
|
public DeviceModelType ModelType;
|
||||||
public ConnectionType ConnectionType;
|
public ConnectionType ConnectionType;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
public Array6<byte> MacAddress;
|
||||||
public byte[] MacAddress;
|
|
||||||
public BatteryStatus BatteryStatus;
|
public BatteryStatus BatteryStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,6 +44,11 @@ namespace Ryujinx.Memory.Tests
|
|||||||
throw new NotImplementedException();
|
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)
|
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
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/>
|
/// <inheritdoc/>
|
||||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
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>
|
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||||
void Write(ulong va, ReadOnlySpan<byte> data);
|
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)
|
void Fill(ulong va, ulong size, byte value)
|
||||||
{
|
{
|
||||||
const int MaxChunkSize = 1 << 24;
|
const int MaxChunkSize = 1 << 24;
|
||||||
|
@@ -735,7 +735,6 @@ namespace Ryujinx.Ui
|
|||||||
|
|
||||||
_emulationContext.Dispose();
|
_emulationContext.Dispose();
|
||||||
SwitchToGameTable();
|
SwitchToGameTable();
|
||||||
RendererWidget.Dispose();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -747,7 +746,6 @@ namespace Ryujinx.Ui
|
|||||||
|
|
||||||
_emulationContext.Dispose();
|
_emulationContext.Dispose();
|
||||||
SwitchToGameTable();
|
SwitchToGameTable();
|
||||||
RendererWidget.Dispose();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -770,7 +768,6 @@ namespace Ryujinx.Ui
|
|||||||
|
|
||||||
_emulationContext.Dispose();
|
_emulationContext.Dispose();
|
||||||
SwitchToGameTable();
|
SwitchToGameTable();
|
||||||
RendererWidget.Dispose();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -519,11 +519,15 @@ namespace Ryujinx.Ui
|
|||||||
_gpuCancellationTokenSource.Cancel();
|
_gpuCancellationTokenSource.Cancel();
|
||||||
|
|
||||||
_isStopped = true;
|
_isStopped = true;
|
||||||
|
|
||||||
|
if (_isActive)
|
||||||
|
{
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
|
|
||||||
_exitEvent.WaitOne();
|
_exitEvent.WaitOne();
|
||||||
_exitEvent.Dispose();
|
_exitEvent.Dispose();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void NVStutterWorkaround()
|
private void NVStutterWorkaround()
|
||||||
{
|
{
|
||||||
|
@@ -72,7 +72,8 @@ namespace Ryujinx.Ui
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
Device.DisposeGpu();
|
Device?.DisposeGpu();
|
||||||
|
|
||||||
NpadManager.Dispose();
|
NpadManager.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user