macOS: Fix blurry rendering on Retina displays by setting correct backing scale factor
This commit is contained in:
@@ -42,6 +42,9 @@ namespace Ryujinx.Common.Helper
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool bool_objc_msgSend(nint receiver, Selector selector, nint param);
|
||||
|
||||
[LibraryImport(ObjCRuntime, EntryPoint = "objc_msgSend")]
|
||||
private static partial double double_objc_msgSend(nint receiver, Selector selector);
|
||||
|
||||
public readonly struct Object
|
||||
{
|
||||
public readonly nint ObjPtr;
|
||||
@@ -105,6 +108,11 @@ namespace Ryujinx.Common.Helper
|
||||
{
|
||||
return bool_objc_msgSend(ObjPtr, selector, obj.ObjPtr);
|
||||
}
|
||||
|
||||
public double GetDoubleFromMessage(Selector selector)
|
||||
{
|
||||
return double_objc_msgSend(ObjPtr, selector);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct Selector
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Ryujinx.Common.Helper;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
@@ -53,6 +55,10 @@ namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
userDpiScale = GdiPlusHelper.GetDpiX(nint.Zero);
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
userDpiScale = GetMacOSDpiScale();
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
string xdgSessionType = Environment.GetEnvironmentVariable("XDG_SESSION_TYPE")?.ToLower();
|
||||
@@ -93,5 +99,27 @@ namespace Ryujinx.Common.SystemInterop
|
||||
|
||||
return Math.Min(userDpiScale / StandardDpiScale, MaxScaleFactor);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
private static double GetMacOSDpiScale()
|
||||
{
|
||||
try
|
||||
{
|
||||
ObjectiveC.Object screenClass = new("NSScreen");
|
||||
ObjectiveC.Object mainScreen = screenClass.GetFromMessage("mainScreen");
|
||||
if (mainScreen.ObjPtr != nint.Zero)
|
||||
{
|
||||
double backingScale = mainScreen.GetDoubleFromMessage("backingScaleFactor");
|
||||
// Convert backing scale factor (e.g., 2.0) to equivalent DPI (e.g., 192).
|
||||
return StandardDpiScale * backingScale;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI on macOS: {e.Message}");
|
||||
}
|
||||
|
||||
return StandardDpiScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,9 +243,18 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
// Make its renderer our metal layer.
|
||||
child.SendMessage("setWantsLayer:", 1);
|
||||
child.SendMessage("setLayer:", metalLayer);
|
||||
metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor);
|
||||
|
||||
// Ensure the scale factor is up to date.
|
||||
// Query the actual backing scale factor from the screen.
|
||||
// This ensures the CAMetalLayer drawable is created at the correct
|
||||
// pixel resolution for Retina displays, preventing blurry rendering.
|
||||
double backingScaleFactor = GetBackingScaleFactor();
|
||||
metalLayer.SendMessage("setContentsScale:", backingScaleFactor);
|
||||
|
||||
// Update DesktopScaleFactor immediately so the rest of the app
|
||||
// (including the bounds callback) uses the correct value.
|
||||
Program.DesktopScaleFactor = backingScaleFactor;
|
||||
|
||||
// Ensure the scale factor is up to date on bounds changes.
|
||||
_updateBoundsCallback = rect =>
|
||||
{
|
||||
metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor);
|
||||
@@ -258,6 +267,26 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
return new PlatformHandle(nsView, "NSView");
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
private static double GetBackingScaleFactor()
|
||||
{
|
||||
try
|
||||
{
|
||||
ObjectiveC.Object screenClass = new("NSScreen");
|
||||
ObjectiveC.Object mainScreen = screenClass.GetFromMessage("mainScreen");
|
||||
if (mainScreen.ObjPtr != nint.Zero)
|
||||
{
|
||||
return mainScreen.GetDoubleFromMessage("backingScaleFactor");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fallback to default scale if ObjC call fails.
|
||||
}
|
||||
|
||||
return 2.0;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("Linux")]
|
||||
void DestroyLinux()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user