Move solution and projects to src

This commit is contained in:
TSR Berry 2023-04-08 01:22:00 +02:00 committed by Mary
parent cd124bda58
commit cee7121058
3466 changed files with 55 additions and 55 deletions

View file

@ -0,0 +1,35 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.SystemInterop
{
public partial class DisplaySleep
{
[Flags]
enum EXECUTION_STATE : uint
{
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
}
[LibraryImport("kernel32.dll", SetLastError = true)]
private static partial EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
static public void Prevent()
{
if (OperatingSystem.IsWindows())
{
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED);
}
}
static public void Restore()
{
if (OperatingSystem.IsWindows())
{
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
}
}
}
}

View file

@ -0,0 +1,96 @@
using Ryujinx.Common.Logging;
using System;
using System.Globalization;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.SystemInterop
{
public static partial class ForceDpiAware
{
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SetProcessDPIAware();
private const string X11LibraryName = "libX11.so.6";
[LibraryImport(X11LibraryName)]
private static partial IntPtr XOpenDisplay([MarshalAs(UnmanagedType.LPStr)] string display);
[LibraryImport(X11LibraryName)]
private static partial IntPtr XGetDefault(IntPtr display, [MarshalAs(UnmanagedType.LPStr)] string program, [MarshalAs(UnmanagedType.LPStr)] string option);
[LibraryImport(X11LibraryName)]
private static partial int XDisplayWidth(IntPtr display, int screenNumber);
[LibraryImport(X11LibraryName)]
private static partial int XDisplayWidthMM(IntPtr display, int screenNumber);
[LibraryImport(X11LibraryName)]
private static partial int XCloseDisplay(IntPtr display);
private static readonly double _standardDpiScale = 96.0;
private static readonly double _maxScaleFactor = 1.25;
/// <summary>
/// Marks the application as DPI-Aware when running on the Windows operating system.
/// </summary>
public static void Windows()
{
// Make process DPI aware for proper window sizing on high-res screens.
if (OperatingSystem.IsWindowsVersionAtLeast(6))
{
SetProcessDPIAware();
}
}
public static double GetActualScaleFactor()
{
double userDpiScale = 96.0;
try
{
if (OperatingSystem.IsWindows())
{
userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero);
}
else if (OperatingSystem.IsLinux())
{
string xdgSessionType = Environment.GetEnvironmentVariable("XDG_SESSION_TYPE")?.ToLower();
if (xdgSessionType == null || xdgSessionType == "x11")
{
IntPtr display = XOpenDisplay(null);
string dpiString = Marshal.PtrToStringAnsi(XGetDefault(display, "Xft", "dpi"));
if (dpiString == null || !double.TryParse(dpiString, NumberStyles.Any, CultureInfo.InvariantCulture, out userDpiScale))
{
userDpiScale = (double)XDisplayWidth(display, 0) * 25.4 / (double)XDisplayWidthMM(display, 0);
}
XCloseDisplay(display);
}
else if (xdgSessionType == "wayland")
{
// TODO
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: Wayland not yet supported");
}
else
{
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: Unrecognised XDG_SESSION_TYPE: {xdgSessionType}");
}
}
}
catch (Exception e)
{
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: {e.Message}");
}
return userDpiScale;
}
public static double GetWindowScaleFactor()
{
double userDpiScale = GetActualScaleFactor();
return Math.Min(userDpiScale / _standardDpiScale, _maxScaleFactor);
}
}
}

View file

@ -0,0 +1,76 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.SystemInterop
{
[SupportedOSPlatform("windows")]
public static partial class GdiPlusHelper
{
private const string LibraryName = "gdiplus.dll";
private static readonly IntPtr _initToken;
static GdiPlusHelper()
{
CheckStatus(GdiplusStartup(out _initToken, StartupInputEx.Default, out _));
}
private static void CheckStatus(int gdiStatus)
{
if (gdiStatus != 0)
{
throw new Exception($"GDI Status Error: {gdiStatus}");
}
}
private struct StartupInputEx
{
public int GdiplusVersion;
#pragma warning disable CS0649
public IntPtr DebugEventCallback;
public int SuppressBackgroundThread;
public int SuppressExternalCodecs;
public int StartupParameters;
#pragma warning restore CS0649
public static StartupInputEx Default => new StartupInputEx
{
// We assume Windows 8 and upper
GdiplusVersion = 2,
DebugEventCallback = IntPtr.Zero,
SuppressBackgroundThread = 0,
SuppressExternalCodecs = 0,
StartupParameters = 0,
};
}
private struct StartupOutput
{
public IntPtr NotificationHook;
public IntPtr NotificationUnhook;
}
[LibraryImport(LibraryName)]
private static partial int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output);
[LibraryImport(LibraryName)]
private static partial int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics);
[LibraryImport(LibraryName)]
private static partial int GdipDeleteGraphics(IntPtr graphics);
[LibraryImport(LibraryName)]
private static partial int GdipGetDpiX(IntPtr graphics, out float dpi);
public static float GetDpiX(IntPtr hwnd)
{
CheckStatus(GdipCreateFromHWND(hwnd, out IntPtr graphicsHandle));
CheckStatus(GdipGetDpiX(graphicsHandle, out float result));
CheckStatus(GdipDeleteGraphics(graphicsHandle));
return result;
}
}
}

View file

@ -0,0 +1,109 @@
using Microsoft.Win32.SafeHandles;
using Ryujinx.Common.Logging;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Common.SystemInterop
{
public partial class StdErrAdapter : IDisposable
{
private bool _disposable = false;
private Stream _pipeReader;
private Stream _pipeWriter;
private CancellationTokenSource _cancellationTokenSource;
private Task _worker;
public StdErrAdapter()
{
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
RegisterPosix();
}
}
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
private void RegisterPosix()
{
const int stdErrFileno = 2;
(int readFd, int writeFd) = MakePipe();
dup2(writeFd, stdErrFileno);
_pipeReader = CreateFileDescriptorStream(readFd);
_pipeWriter = CreateFileDescriptorStream(writeFd);
_cancellationTokenSource = new CancellationTokenSource();
_worker = Task.Run(async () => await EventWorkerAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
_disposable = true;
}
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
private async Task EventWorkerAsync(CancellationToken cancellationToken)
{
using TextReader reader = new StreamReader(_pipeReader, leaveOpen: true);
string line;
while (cancellationToken.IsCancellationRequested == false && (line = await reader.ReadLineAsync(cancellationToken)) != null)
{
Logger.Error?.PrintRawMsg(line);
}
}
private void Dispose(bool disposing)
{
if (_disposable)
{
_disposable = false;
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
_cancellationTokenSource.Cancel();
_worker.Wait(0);
_pipeReader?.Close();
_pipeWriter?.Close();
}
}
}
public void Dispose()
{
Dispose(true);
}
[LibraryImport("libc", SetLastError = true)]
private static partial int dup2(int fd, int fd2);
[LibraryImport("libc", SetLastError = true)]
private static partial int pipe(Span<int> pipefd);
private static (int, int) MakePipe()
{
Span<int> pipefd = stackalloc int[2];
if (pipe(pipefd) == 0)
{
return (pipefd[0], pipefd[1]);
}
else
{
throw new();
}
}
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
private static Stream CreateFileDescriptorStream(int fd)
{
return new FileStream(
new SafeFileHandle((IntPtr)fd, ownsHandle: true),
FileAccess.ReadWrite
);
}
}
}

View file

@ -0,0 +1,114 @@
using Ryujinx.Common.Logging;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.SystemInterop
{
/// <summary>
/// Handle Windows Multimedia timer resolution.
/// </summary>
[SupportedOSPlatform("windows")]
public partial class WindowsMultimediaTimerResolution : IDisposable
{
[StructLayout(LayoutKind.Sequential)]
public struct TimeCaps
{
public uint wPeriodMin;
public uint wPeriodMax;
};
[LibraryImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
private static partial uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
[LibraryImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
private static partial uint TimeBeginPeriod(uint uMilliseconds);
[LibraryImport("winmm.dll", EntryPoint = "timeEndPeriod")]
private static partial uint TimeEndPeriod(uint uMilliseconds);
private uint _targetResolutionInMilliseconds;
private bool _isActive;
/// <summary>
/// Create a new <see cref="WindowsMultimediaTimerResolution"/> and activate the given resolution.
/// </summary>
/// <param name="targetResolutionInMilliseconds"></param>
public WindowsMultimediaTimerResolution(uint targetResolutionInMilliseconds)
{
_targetResolutionInMilliseconds = targetResolutionInMilliseconds;
EnsureResolutionSupport();
Activate();
}
private void EnsureResolutionSupport()
{
TimeCaps timeCaps = default;
uint result = TimeGetDevCaps(ref timeCaps, (uint)Unsafe.SizeOf<TimeCaps>());
if (result != 0)
{
Logger.Notice.Print(LogClass.Application, $"timeGetDevCaps failed with result: {result}");
}
else
{
uint supportedTargetResolutionInMilliseconds = Math.Min(Math.Max(timeCaps.wPeriodMin, _targetResolutionInMilliseconds), timeCaps.wPeriodMax);
if (supportedTargetResolutionInMilliseconds != _targetResolutionInMilliseconds)
{
Logger.Notice.Print(LogClass.Application, $"Target resolution isn't supported by OS, using closest resolution: {supportedTargetResolutionInMilliseconds}ms");
_targetResolutionInMilliseconds = supportedTargetResolutionInMilliseconds;
}
}
}
private void Activate()
{
uint result = TimeBeginPeriod(_targetResolutionInMilliseconds);
if (result != 0)
{
Logger.Notice.Print(LogClass.Application, $"timeBeginPeriod failed with result: {result}");
}
else
{
_isActive = true;
}
}
private void Disable()
{
if (_isActive)
{
uint result = TimeEndPeriod(_targetResolutionInMilliseconds);
if (result != 0)
{
Logger.Notice.Print(LogClass.Application, $"timeEndPeriod failed with result: {result}");
}
else
{
_isActive = false;
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Disable();
}
}
}
}