mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-02 15:55:39 +00:00
Detect native panel resolution on Retina displays. Fixes #59
This commit is contained in:
parent
af6e99cbac
commit
dae21f2638
@ -56,37 +56,51 @@ ScrollView {
|
|||||||
// ignore setting the index at first, and actually set it when the component is loaded
|
// ignore setting the index at first, and actually set it when the component is loaded
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// Add native resolutions for all attached displays
|
// Add native resolutions for all attached displays
|
||||||
for (var displayIndex = 0;; displayIndex++) {
|
var done = false
|
||||||
var screenRect = prefs.getDisplayResolution(displayIndex)
|
for (var displayIndex = 0; !done; displayIndex++) {
|
||||||
if (screenRect.width === 0) {
|
for (var displayResIndex = 0; displayResIndex < 2; displayResIndex++) {
|
||||||
// Exceeded max count of displays
|
var screenRect;
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
var indexToAdd = 0
|
// Some platforms have different desktop resolutions
|
||||||
for (var j = 0; j < resolutionComboBox.count; j++) {
|
// and native resolutions (like macOS with Retina displays)
|
||||||
var existing_width = parseInt(resolutionListModel.get(j).video_width);
|
if (displayResIndex == 0) {
|
||||||
var existing_height = parseInt(resolutionListModel.get(j).video_height);
|
screenRect = prefs.getDesktopResolution(displayIndex)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
screenRect = prefs.getNativeResolution(displayIndex)
|
||||||
|
}
|
||||||
|
|
||||||
if (screenRect.width === existing_width && screenRect.height === existing_height) {
|
if (screenRect.width === 0) {
|
||||||
// Duplicate entry, skip
|
// Exceeded max count of displays
|
||||||
indexToAdd = -1
|
done = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
else if (screenRect.width * screenRect.height > existing_width * existing_height) {
|
|
||||||
// Candidate entrypoint after this entry
|
|
||||||
indexToAdd = j + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert this display's resolution if it's not a duplicate
|
var indexToAdd = 0
|
||||||
if (indexToAdd >= 0) {
|
for (var j = 0; j < resolutionComboBox.count; j++) {
|
||||||
resolutionListModel.insert(indexToAdd,
|
var existing_width = parseInt(resolutionListModel.get(j).video_width);
|
||||||
{
|
var existing_height = parseInt(resolutionListModel.get(j).video_height);
|
||||||
"text": "Native ("+screenRect.width+"x"+screenRect.height+")",
|
|
||||||
"video_width": ""+screenRect.width,
|
if (screenRect.width === existing_width && screenRect.height === existing_height) {
|
||||||
"video_height": ""+screenRect.height
|
// Duplicate entry, skip
|
||||||
})
|
indexToAdd = -1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
else if (screenRect.width * screenRect.height > existing_width * existing_height) {
|
||||||
|
// Candidate entrypoint after this entry
|
||||||
|
indexToAdd = j + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert this display's resolution if it's not a duplicate
|
||||||
|
if (indexToAdd >= 0) {
|
||||||
|
resolutionListModel.insert(indexToAdd,
|
||||||
|
{
|
||||||
|
"text": "Native ("+screenRect.width+"x"+screenRect.height+")",
|
||||||
|
"video_width": ""+screenRect.width,
|
||||||
|
"video_height": ""+screenRect.height
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "streamingpreferences.h"
|
#include "streamingpreferences.h"
|
||||||
#include "streaming/session.hpp"
|
#include "streaming/session.hpp"
|
||||||
|
#include "streaming/streamutils.h"
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
@ -94,7 +95,7 @@ int StreamingPreferences::getMaximumStreamingFrameRate()
|
|||||||
SDL_DisplayMode mode, bestMode, desktopMode;
|
SDL_DisplayMode mode, bestMode, desktopMode;
|
||||||
for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
|
for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
|
||||||
// Get the native desktop resolution
|
// Get the native desktop resolution
|
||||||
if (SDL_GetDesktopDisplayMode(displayIndex, &desktopMode) == 0) {
|
if (StreamUtils::getRealDesktopMode(displayIndex, &desktopMode)) {
|
||||||
|
|
||||||
// Start at desktop mode and work our way up
|
// Start at desktop mode and work our way up
|
||||||
bestMode = desktopMode;
|
bestMode = desktopMode;
|
||||||
@ -119,7 +120,7 @@ int StreamingPreferences::getMaximumStreamingFrameRate()
|
|||||||
return maxFrameRate;
|
return maxFrameRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect StreamingPreferences::getDisplayResolution(int displayIndex)
|
QRect StreamingPreferences::getDesktopResolution(int displayIndex)
|
||||||
{
|
{
|
||||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
@ -134,7 +135,7 @@ QRect StreamingPreferences::getDisplayResolution(int displayIndex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_DisplayMode mode;
|
SDL_DisplayMode mode;
|
||||||
int err = SDL_GetCurrentDisplayMode(displayIndex, &mode);
|
int err = SDL_GetDesktopDisplayMode(displayIndex, &mode);
|
||||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
@ -142,12 +143,38 @@ QRect StreamingPreferences::getDisplayResolution(int displayIndex)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SDL_GetCurrentDisplayMode() failed: %s",
|
"SDL_GetDesktopDisplayMode() failed: %s",
|
||||||
SDL_GetError());
|
SDL_GetError());
|
||||||
return QRect();
|
return QRect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRect StreamingPreferences::getNativeResolution(int displayIndex)
|
||||||
|
{
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayIndex >= SDL_GetNumVideoDisplays()) {
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
bool success = StreamUtils::getRealDesktopMode(displayIndex, &mode);
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
return QRect(0, 0, mode.w, mode.h);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
|
int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
|
||||||
{
|
{
|
||||||
// This table prefers 16:10 resolutions because they are
|
// This table prefers 16:10 resolutions because they are
|
||||||
|
@ -21,7 +21,9 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE static int getMaximumStreamingFrameRate();
|
Q_INVOKABLE static int getMaximumStreamingFrameRate();
|
||||||
|
|
||||||
Q_INVOKABLE QRect getDisplayResolution(int displayIndex);
|
Q_INVOKABLE QRect getDesktopResolution(int displayIndex);
|
||||||
|
|
||||||
|
Q_INVOKABLE QRect getNativeResolution(int displayIndex);
|
||||||
|
|
||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ public:
|
|||||||
WM_FULLSCREEN_DESKTOP,
|
WM_FULLSCREEN_DESKTOP,
|
||||||
WM_WINDOWED
|
WM_WINDOWED
|
||||||
};
|
};
|
||||||
Q_ENUM(WindowMode);
|
Q_ENUM(WindowMode)
|
||||||
|
|
||||||
Q_PROPERTY(int width MEMBER width NOTIFY displayModeChanged)
|
Q_PROPERTY(int width MEMBER width NOTIFY displayModeChanged)
|
||||||
Q_PROPERTY(int height MEMBER height NOTIFY displayModeChanged)
|
Q_PROPERTY(int height MEMBER height NOTIFY displayModeChanged)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "session.hpp"
|
#include "session.hpp"
|
||||||
#include "settings/streamingpreferences.h"
|
#include "settings/streamingpreferences.h"
|
||||||
|
#include "streaming/streamutils.h"
|
||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
@ -544,7 +545,7 @@ void Session::getWindowDimensions(bool fullScreen,
|
|||||||
else if (fullScreen) {
|
else if (fullScreen) {
|
||||||
for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) {
|
for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) {
|
||||||
SDL_DisplayMode mode;
|
SDL_DisplayMode mode;
|
||||||
if (SDL_GetDesktopDisplayMode(i, &mode) == 0 &&
|
if (StreamUtils::getRealDesktopMode(i, &mode) &&
|
||||||
m_ActiveVideoWidth == mode.w &&
|
m_ActiveVideoWidth == mode.w &&
|
||||||
m_ActiveVideoHeight == mode.h) {
|
m_ActiveVideoHeight == mode.h) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
@ -603,7 +604,7 @@ void Session::updateOptimalWindowDisplayMode()
|
|||||||
int displayIndex = SDL_GetWindowDisplayIndex(m_Window);
|
int displayIndex = SDL_GetWindowDisplayIndex(m_Window);
|
||||||
|
|
||||||
// Get the native desktop resolution
|
// Get the native desktop resolution
|
||||||
if (SDL_GetDesktopDisplayMode(displayIndex, &desktopMode) == 0) {
|
if (StreamUtils::getRealDesktopMode(displayIndex, &desktopMode)) {
|
||||||
// Start with the native desktop resolution and try to find
|
// Start with the native desktop resolution and try to find
|
||||||
// the highest refresh rate that our stream FPS evenly divides.
|
// the highest refresh rate that our stream FPS evenly divides.
|
||||||
bestMode = desktopMode;
|
bestMode = desktopMode;
|
||||||
@ -757,7 +758,7 @@ void Session::exec()
|
|||||||
y,
|
y,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
0);
|
SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
if (!m_Window) {
|
if (!m_Window) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"SDL_CreateWindow() failed: %s",
|
"SDL_CreateWindow() failed: %s",
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
#include "streamutils.h"
|
#include "streamutils.h"
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
|
||||||
|
#ifdef Q_OS_DARWIN
|
||||||
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
void StreamUtils::scaleSourceToDestinationSurface(SDL_Rect* src, SDL_Rect* dst)
|
void StreamUtils::scaleSourceToDestinationSurface(SDL_Rect* src, SDL_Rect* dst)
|
||||||
{
|
{
|
||||||
int dstH = dst->w * src->h / src->w;
|
int dstH = dst->w * src->h / src->w;
|
||||||
@ -18,3 +24,58 @@ void StreamUtils::scaleSourceToDestinationSurface(SDL_Rect* src, SDL_Rect* dst)
|
|||||||
SDL_assert(dst->h * src->w / src->h <= dst->w);
|
SDL_assert(dst->h * src->w / src->h <= dst->w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StreamUtils::getRealDesktopMode(int displayIndex, SDL_DisplayMode* mode)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_DARWIN
|
||||||
|
#define MAX_DISPLAYS 16
|
||||||
|
CGDirectDisplayID displayIds[MAX_DISPLAYS];
|
||||||
|
uint32_t displayCount = 0;
|
||||||
|
CGGetActiveDisplayList(MAX_DISPLAYS, displayIds, &displayCount);
|
||||||
|
if (displayIndex >= displayCount) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Too many displays: %d vs %d",
|
||||||
|
displayIndex, displayCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_zerop(mode);
|
||||||
|
|
||||||
|
// Retina displays have non-native resolutions both below and above (!) their
|
||||||
|
// native resolution, so it's impossible for us to figure out what's actually
|
||||||
|
// native on macOS using the SDL API alone. We'll talk to CoreGraphics to
|
||||||
|
// find the correct resolution and match it in our SDL list.
|
||||||
|
CFArrayRef modeList = CGDisplayCopyAllDisplayModes(displayIds[displayIndex], nullptr);
|
||||||
|
CFIndex count = CFArrayGetCount(modeList);
|
||||||
|
for (CFIndex i = 0; i < count; i++) {
|
||||||
|
auto cgMode = (CGDisplayModeRef)(CFArrayGetValueAtIndex(modeList, i));
|
||||||
|
if ((CGDisplayModeGetIOFlags(cgMode) & kDisplayModeNativeFlag) != 0) {
|
||||||
|
mode->w = static_cast<int>(CGDisplayModeGetWidth(cgMode));
|
||||||
|
mode->h = static_cast<int>(CGDisplayModeGetHeight(cgMode));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(modeList);
|
||||||
|
|
||||||
|
// Now find the SDL mode that matches the CG native mode
|
||||||
|
for (int i = 0; i < SDL_GetNumDisplayModes(displayIndex); i++) {
|
||||||
|
SDL_DisplayMode thisMode;
|
||||||
|
if (SDL_GetDisplayMode(displayIndex, i, &thisMode) == 0) {
|
||||||
|
if (thisMode.w == mode->w && thisMode.h == mode->h &&
|
||||||
|
thisMode.refresh_rate >= mode->refresh_rate) {
|
||||||
|
*mode = thisMode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (SDL_GetDesktopDisplayMode(displayIndex, mode) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_GetDesktopDisplayMode() failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -7,4 +7,7 @@ class StreamUtils
|
|||||||
public:
|
public:
|
||||||
static
|
static
|
||||||
void scaleSourceToDestinationSurface(SDL_Rect* src, SDL_Rect* dst);
|
void scaleSourceToDestinationSurface(SDL_Rect* src, SDL_Rect* dst);
|
||||||
|
|
||||||
|
static
|
||||||
|
bool getRealDesktopMode(int displayIndex, SDL_DisplayMode* mode);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "pacer.h"
|
#include "pacer.h"
|
||||||
|
#include "streaming/streamutils.h"
|
||||||
|
|
||||||
#include "nullthreadedvsyncsource.h"
|
#include "nullthreadedvsyncsource.h"
|
||||||
|
|
||||||
@ -143,10 +144,7 @@ bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enableVsync)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Use the current display mode for windowed and borderless
|
// Use the current display mode for windowed and borderless
|
||||||
if (SDL_GetCurrentDisplayMode(displayIndex, &mode) != 0) {
|
if (!StreamUtils::getRealDesktopMode(displayIndex, &mode)) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"SDL_GetCurrentDisplayMode() failed: %s",
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user