Add FPS values for all attached displays and support custom FPS values

Fixes #926
This commit is contained in:
Cameron Gutman 2023-02-03 00:45:27 -06:00
parent 80659160d3
commit 90e25e60d6
3 changed files with 70 additions and 41 deletions

View file

@ -70,7 +70,7 @@ SystemProperties::SystemProperties()
// and cache the results to speed up future queries on this data.
querySdlVideoInfo();
Q_ASSERT(maximumStreamingFrameRate >= 60);
Q_ASSERT(!monitorRefreshRates.isEmpty());
Q_ASSERT(!monitorNativeResolutions.isEmpty());
}
@ -80,6 +80,12 @@ QRect SystemProperties::getNativeResolution(int displayIndex)
return monitorNativeResolutions.value(displayIndex);
}
int SystemProperties::getRefreshRate(int displayIndex)
{
// Returns 0 if out of bounds
return monitorRefreshRates.value(displayIndex);
}
class QuerySdlVideoThread : public QThread
{
public:
@ -188,9 +194,6 @@ void SystemProperties::refreshDisplaysInternal()
monitorNativeResolutions.clear();
// Never let the maximum drop below 60 FPS
maximumStreamingFrameRate = 60;
SDL_DisplayMode bestMode;
for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
SDL_DisplayMode desktopMode;
@ -218,7 +221,17 @@ void SystemProperties::refreshDisplaysInternal()
}
}
maximumStreamingFrameRate = qMax(maximumStreamingFrameRate, bestMode.refresh_rate);
// Try to normalize values around our our standard refresh rates.
// Some displays/OSes report values that are slightly off.
if (bestMode.refresh_rate >= 58 && bestMode.refresh_rate <= 62) {
monitorRefreshRates.append(60);
}
else if (bestMode.refresh_rate >= 28 && bestMode.refresh_rate <= 32) {
monitorRefreshRates.append(30);
}
else {
monitorRefreshRates.append(bestMode.refresh_rate);
}
}
}

View file

@ -23,13 +23,13 @@ public:
Q_PROPERTY(bool hasBrowser MEMBER hasBrowser CONSTANT)
Q_PROPERTY(bool hasDiscordIntegration MEMBER hasDiscordIntegration CONSTANT)
Q_PROPERTY(QString unmappedGamepads MEMBER unmappedGamepads NOTIFY unmappedGamepadsChanged)
Q_PROPERTY(int maximumStreamingFrameRate MEMBER maximumStreamingFrameRate CONSTANT)
Q_PROPERTY(QSize maximumResolution MEMBER maximumResolution CONSTANT)
Q_PROPERTY(QString versionString MEMBER versionString CONSTANT)
Q_PROPERTY(bool supportsHdr MEMBER supportsHdr CONSTANT)
Q_INVOKABLE void refreshDisplays();
Q_INVOKABLE QRect getNativeResolution(int displayIndex);
Q_INVOKABLE int getRefreshRate(int displayIndex);
signals:
void unmappedGamepadsChanged();
@ -49,9 +49,9 @@ private:
bool hasBrowser;
bool hasDiscordIntegration;
QString unmappedGamepads;
int maximumStreamingFrameRate;
QSize maximumResolution;
QList<QRect> monitorNativeResolutions;
QList<int> monitorRefreshRates;
QString versionString;
bool supportsHdr;
};

View file

@ -388,48 +388,58 @@ Flickable {
}
AutoResizingComboBox {
function addRefreshRateOrdered(fpsListModel, refreshRate, description) {
var indexToAdd = 0
for (var j = 0; j < fpsListModel.count; j++) {
var existing_fps = parseInt(fpsListModel.get(j).video_fps);
if (refreshRate === existing_fps) {
// Duplicate entry, skip
indexToAdd = -1
break
}
else if (refreshRate > existing_fps) {
// Candidate entrypoint after this entry
indexToAdd = j + 1
}
}
// Insert this display's resolution if it's not a duplicate
if (indexToAdd >= 0) {
fpsListModel.insert(indexToAdd,
{
"text": description,
"video_fps": ""+refreshRate
})
}
return indexToAdd
}
function createModel() {
var fpsListModel = Qt.createQmlObject('import QtQuick 2.0; ListModel {}', parent, '')
var max_fps = SystemProperties.maximumStreamingFrameRate
// Default entries
fpsListModel.append({"text": qsTr("%1 FPS").arg("30"), "video_fps": "30"})
fpsListModel.append({"text": qsTr("%1 FPS").arg("60"), "video_fps": "60"})
// Add unsupported FPS values that come before the display max FPS
if (StreamingPreferences.unsupportedFps) {
if (max_fps > 90) {
fpsListModel.append({"text": qsTr("%1 FPS (Unsupported)").arg("90"), "video_fps": "90"})
}
if (max_fps > 120) {
fpsListModel.append({"text": qsTr("%1 FPS (Unsupported)").arg("120"), "video_fps": "120"})
// Add native refresh rate for all attached displays
var done = false
for (var displayIndex = 0; !done; displayIndex++) {
var refreshRate = SystemProperties.getRefreshRate(displayIndex);
if (refreshRate === 0) {
// Exceeded max count of displays
done = true
break
}
addRefreshRateOrdered(fpsListModel, refreshRate, qsTr("%1 FPS").arg(refreshRate))
}
// Use 64 as the cutoff for adding a separate option to
// handle wonky displays that report just over 60 Hz.
if (max_fps > 64) {
// Mark any FPS value greater than 120 as unsupported
if (StreamingPreferences.unsupportedFps && max_fps > 120) {
fpsListModel.append({"text": qsTr("%1 FPS (Unsupported)").arg(max_fps), "video_fps": ""+max_fps})
}
else if (max_fps > 120) {
fpsListModel.append({"text": qsTr("%1 FPS").arg("120"), "video_fps": "120"})
}
else {
fpsListModel.append({"text": qsTr("%1 FPS").arg(max_fps), "video_fps": ""+max_fps})
}
}
// Add unsupported FPS values that come after the display max FPS
// Add unsupported FPS values
if (StreamingPreferences.unsupportedFps) {
if (max_fps < 90) {
fpsListModel.append({"text":qsTr("%1 FPS (Unsupported)").arg("90"), "video_fps": "90"})
}
if (max_fps < 120) {
fpsListModel.append({"text":qsTr("%1 FPS (Unsupported)").arg("120"), "video_fps": "120"})
}
addRefreshRateOrdered(fpsListModel, 90, qsTr("%1 FPS (Unsupported)").arg(90))
addRefreshRateOrdered(fpsListModel, 120, qsTr("%1 FPS (Unsupported)").arg(120))
}
return fpsListModel
@ -439,16 +449,22 @@ Flickable {
model = createModel()
var saved_fps = StreamingPreferences.fps
currentIndex = 0
currentIndex = -1
for (var i = 0; i < model.count; i++) {
var el_fps = parseInt(model.get(i).video_fps);
// Pick the highest value lesser or equal to the saved FPS
if (saved_fps >= el_fps) {
// Look for a matching frame rate
if (saved_fps === el_fps) {
currentIndex = i
break
}
}
// If we didn't find one, add a custom frame rate for the current value
if (currentIndex === -1) {
currentIndex = addRefreshRateOrdered(model, saved_fps, qsTr("%1 FPS (Custom)").arg(saved_fps))
}
// Persist the selected value
activated(currentIndex)
}