diff options
author | Simon Rettberg | 2022-10-27 14:54:41 +0200 |
---|---|---|
committer | Simon Rettberg | 2022-10-27 14:54:41 +0200 |
commit | 9874a69997b03eec0c2825f59bae6fc3b6b4fd46 (patch) | |
tree | 51cd4edfe41dee9ac1bf2469be3241a8e436cdf4 | |
parent | Fix TMDS clock limiting if DTD info is missing (Default to 165MHz) (diff) | |
download | beamergui-9874a69997b03eec0c2825f59bae6fc3b6b4fd46.tar.gz beamergui-9874a69997b03eec0c2825f59bae6fc3b6b4fd46.tar.xz beamergui-9874a69997b03eec0c2825f59bae6fc3b6b4fd46.zip |
Remove projector resolution copy; use --scale-from instead
Instead of adding random resolutions to outputs that don't
report supporting them in the first place, if using
cloned output, scale the image to the screen's native resolution.
-rw-r--r-- | src/main.cpp | 1 | ||||
-rw-r--r-- | src/widget.cpp | 10 | ||||
-rw-r--r-- | src/xprivate.cpp | 58 | ||||
-rw-r--r-- | src/xprivate.h | 3 | ||||
-rw-r--r-- | src/xx.cpp | 66 | ||||
-rw-r--r-- | src/xx.h | 3 |
6 files changed, 30 insertions, 111 deletions
diff --git a/src/main.cpp b/src/main.cpp index 54bf745..c6990d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -66,7 +66,6 @@ int main(int argc, char *argv[]) } ScreenSetup::inst()->addMissingEdidResolutions(); - ScreenSetup::inst()->initModes(); if (CommandLine::center()) { ScreenSetup::inst()->setCenteredClone(); diff --git a/src/widget.cpp b/src/widget.cpp index c76bde7..491735a 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -91,7 +91,6 @@ Widget::Widget(QWidget *parent) : _ui->tabWidget->setCornerWidget(_ui->btnReload); connect(_ui->btnReload, &QPushButton::clicked, [=](bool) { _ui->btnReload->setStyleSheet(STYLE_RELOAD_BUTTON_NORMAL); - ScreenSetup::inst()->initModes(); initControls(); }); setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); @@ -141,7 +140,6 @@ Widget::Widget(QWidget *parent) : // Nothing seems to have changed. This might happen when another tool changes the screen config. Let's not interfere. } else if (currentCount > _lastScreenCount) { // Screen count increased - auto setup _lastScreenCount = currentCount; - ScreenSetup::inst()->initModes(); ScreenMode mode; auto ret = ScreenSetup::inst()->setDefaultMode(mode); if (!ret.ok() || !keepResolution()) { @@ -157,7 +155,6 @@ Widget::Widget(QWidget *parent) : } else { // GUI currently visible -- highlight refresh button if (currentCount > _lastScreenCount) { - ScreenSetup::inst()->initModes(); initControls(); } else { _ui->btnReload->setStyleSheet(STYLE_RELOAD_BUTTON_HOT); @@ -332,12 +329,15 @@ void Widget::initControls(bool jumpToTab) } auto resolutions = ScreenSetup::inst()->getVirtualResolutions(); auto screenMap = ScreenSetup::inst()->getScreenPositions(); - auto modes = ScreenSetup::inst()->getCommonModes(); + auto modes = ScreenSetup::inst()->getCommonModes(true); auto screenList = screenMap.values(); qSort(screenList.begin(), screenList.end(), dualHeadLess); // Clone + // Determine preferred resolution for cloning: If no screen is detected as projector, + // use the smallest prefered resolution across all screens + // Otherwise, use the prefered resolution of the first projector we encounter QSize preferredClone; - for (auto screen : screenList) { + for (const auto &screen : screenList) { if (!screen.preferredResolution.isEmpty()) { if (screen.isProjector // Projector always overrides || preferredClone.isEmpty() // Have no preferred yet diff --git a/src/xprivate.cpp b/src/xprivate.cpp index 3aea9b5..37ee5ef 100644 --- a/src/xprivate.cpp +++ b/src/xprivate.cpp @@ -518,30 +518,6 @@ void XPrivate::addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId } /** - * Copy first "num" modes from output to all other outputs if they - * dont have a suitable mode yet. - */ -void XPrivate::copyModesToAll(RROutput sourceId, int num) -{ - const XRROutputInfo *outputInfo = _outputMap[sourceId]->output; - for (int i = 0; i < num; ++i) { - if (!_modeMap.contains(outputInfo->modes[i])) { - qDebug() << "BUG: Mode" << outputInfo->modes[i] << "not found in copyModesToAll"; - continue; - } - const XRRModeInfo *mode = _modeMap[outputInfo->modes[i]]; - for (auto other : _outputMap.keys()) { - if (other == sourceId) - continue; - const XRROutputInfo *otherInfo = _outputMap[other]->output; - if (!getOutputModeForResolution(otherInfo, mode->width, mode->height).isEmpty()) - continue; - XRRAddOutputMode(_display, other, outputInfo->modes[i]); - } - } -} - -/** * Get all known modes matching the given resolution. * If multiple modes match the given resolution, the function will * put the preferred resolution first, then all others sorted by @@ -704,28 +680,6 @@ QList<QSize> XPrivate::getTotalSize(const QList<OutputInfo*> &projectors, const // Screen supports same resolution as projector modeS = _modeMap[list.first()]; qDebug() << "Screen supports same"; - } else { - // Screen does not support same resolution - // Usually that should not happen as we add the projector's mode(s) to the - // other outputs, but that doesn't work on nvidia cards, so try to use another - // suitable resolution there - int x = 0, y = 0; - if (modeP->width == 1280 && modeP->height == 800) { - x = 1280; - y = 720; - } else if (modeP->width == 1920 && modeP->height == 1200) { - x = 1920; - y = 1080; - } - if (x != 0) { - auto s = getOutputModeForResolution(screens.at(i)->output, x, y); - auto p = getOutputModeForResolution(projectors.at(i)->output, x, y); - if (!s.empty() && !p.empty()) { - modeP = _modeMap[p.first()]; - modeS = _modeMap[s.first()]; - qDebug() << "Falling back to" << modeP->width << "x" << modeP->height << " because of screen incompatibility"; - } - } } } if (modeS == nullptr) { @@ -749,21 +703,25 @@ QList<QSize> XPrivate::getTotalSize(const QList<OutputInfo*> &projectors, const return modes; } -XRRModeInfo* XPrivate::setOutputResolution(QStringList &args, OutputInfo *oi, int x, int y, const QSize &size) +XRRModeInfo* XPrivate::setOutputResolution(QStringList &args, OutputInfo *oi, int x, int y, const QSize &size, const QSize &scaleFrom) { QList<RRMode> modes = getOutputModeForResolution(oi->output, size); if (modes.isEmpty()) { qDebug() << "Cannot set" << oi->outputName << "to" << size << " since it's not supported"; - if (oi->output->nmode == 0) + auto *mp = getPreferredMode(oi); + if (mp == nullptr) return nullptr; - qDebug() << "falling back to its default mode"; - modes.append(oi->output->modes[0]); + modes.append(mp->id); + qDebug() << "falling back to its default mode" << mp->width << "x" << mp->height; } // modes list is known to be sorted by preferred resolution/rate, then sorted by highest to lowest rate // so we just pick the first one for now, as the GUI doesn't offer picking the rate XRRModeInfo *best = _modeMap[modes.first()]; args << "--output" << oi->outputName << "--mode" << best->name << "--rate" << QString::number(toVertRefresh(best), 'f', 2); args << "--pos" << QString::asprintf("%dx%d", x, y); + if (!scaleFrom.isEmpty() && scaleFrom != QSize(best->width, best->height)) { + args << "--scale-from" << QString::asprintf("%dx%d", scaleFrom.width(), scaleFrom.height()); + } if (x == 0 && y == 0 && !args.contains(QLatin1String("--primary"))) { args.append("--primary"); } diff --git a/src/xprivate.h b/src/xprivate.h index c10832e..6400ced 100644 --- a/src/xprivate.h +++ b/src/xprivate.h @@ -54,9 +54,8 @@ public: QList<RRMode> getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const; QList<RRMode> getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const; RRCrtc getFreeCrtc(const XRROutputInfo* output) const; - XRRModeInfo* setOutputResolution(QStringList &args, OutputInfo *oi, int x, int y, const QSize &size); + XRRModeInfo* setOutputResolution(QStringList &args, OutputInfo *oi, int x, int y, const QSize &size, const QSize &scaleFrom = {}); QList<QSize> getTotalSize(const QList<OutputInfo*> &projectors, const QList<OutputInfo*> &screens) const; - void copyModesToAll(RROutput id, int num); bool addResolutionToOutput(OutputInfo *oi, const QSize &res); Display* _display; @@ -250,52 +250,6 @@ QMap<QString, ScreenInfo> ScreenSetup::getScreenPositions() const return ret; } -/** - * Create common modes and add them to all outputs. - * Make sure every output has some variant of the most commonly - * used modes. - */ -void ScreenSetup::initModes() -{ - // First copy typical resolutions to all outputs -#define RES(x,y) (((y) << 16) | (x)) - QSet<quint32> wanted; - wanted << RES(1280, 720) << RES(1280, 800) << RES(1920, 1080); - for (XRRModeInfo *mode : a->_modeMap) { - if (toVertRefresh(mode) < 55 || toVertRefresh(mode) > 65) - continue; // Play it safe and consider only those for copying that are 60Hz - if (!wanted.remove(RES(mode->width, mode->height))) - continue; // Is not a wanted resolution - // Make sure all outputs got it - for (OutputInfo *info : a->_outputMap) { - if (!a->getOutputModeForResolution(info->output, mode->width, mode->height).isEmpty()) - continue; - XRRAddOutputMode(a->_display, info->id, mode->id); - qDebug() << "Adding mode" << mode->width << 'x' << mode->height << "to" << info->outputName; - } - } -#undef RES - // Create those that no output supported - for (auto res : wanted) { - unsigned int x = res & 0xffff; - unsigned int y = res >> 16; - qDebug() << "Creating missing wanted resolution of" << x << "x" << y; - createMode(x, y, 60, QString::asprintf("%ux%u", x, y)); - } - if (!wanted.isEmpty()) { // Modes were added, update for final loop below - updateScreenResources(); - } - // Finally copy all those the projector supports to other outputs - for (auto key : a->_outputMap.keys()) { - OutputInfo *oi = a->_outputMap[key]; - if (oi->outputType == Projector::Yes && oi->output->npreferred > 0) { // Only if has edid - qDebug() << "Copying" << oi->output->nmode << "modes to all from" << oi->outputName; - a->copyModesToAll(key, oi->output->nmode); - } - } - updateScreenResources(); -} - static QSize getTotalSizeHorz(const QList<QSize> &list) { QSize ret(0, 0); @@ -416,6 +370,8 @@ ConfigBackup ScreenSetup::setDefaultMode(ScreenMode &mode) mode = ScreenMode::Advanced; // Dunno lol return retval; } + // We now have a list of projectors and screens. + // Make them cloning pairs. for (;;) { QSize screenSize = getTotalSizeHorz(outputSizes); QStringList cmd; @@ -428,13 +384,13 @@ ConfigBackup ScreenSetup::setDefaultMode(ScreenMode &mode) const QSize &size = outputSizes.at(i); unsigned int w = 0; if (i < projectors.size()) { - auto *mode = a->setOutputResolution(cmd, projectors.at(i), offset, 0, size); + auto *mode = a->setOutputResolution(cmd, projectors.at(i), offset, 0, size, size); if (mode != nullptr && mode->width > w) { w = mode->width; } } if (i < screens.size()) { - auto *mode = a->setOutputResolution(cmd, screens.at(i), offset, 0, size); + auto *mode = a->setOutputResolution(cmd, screens.at(i), offset, 0, size, size); if (mode != nullptr && mode->width > w) { w = mode->width; } @@ -584,7 +540,7 @@ ConfigBackup ScreenSetup::setClone(const QSize &resolution) QStringList cmd; ConfigBackup retval = createCrtcBackup(); for (auto oi : a->_outputMap) { - a->setOutputResolution(cmd, oi, 0, 0, resolution); + a->setOutputResolution(cmd, oi, 0, 0, resolution, resolution); } retval._ok = runXrandr(cmd); return retval; @@ -658,10 +614,16 @@ static bool modeBiggerThan(const QSize &a, const QSize &b) return a.width() == b.width() && a.height() > b.height(); } -ResolutionVector ScreenSetup::getCommonModes() const +ResolutionVector ScreenSetup::getCommonModes(bool projectorsOnly) const { QHash<QPair<quint32, quint32>, QSet<RROutput>> matches; + int expectedNum = 0; + // For all outputs for (auto oi : a->_outputMap) { + if (projectorsOnly && oi->outputType == Projector::No) + continue; + expectedNum++; + // Validate all modes, add to match map's set for (int i = 0; i < oi->output->nmode; ++i) { if (!a->_modeMap.contains(oi->output->modes[i])) continue; @@ -672,7 +634,9 @@ ResolutionVector ScreenSetup::getCommonModes() const } ResolutionVector ret; for (auto it = matches.begin(); it != matches.end(); ++it) { - if (it.value().size() == a->_outputMap.size()) { + // If a resolution in the map contains all the outputs we expect, it + // means it's a common mode + if (it.value().size() == expectedNum) { ret.append(QSize(int(it.key().first), int(it.key().second))); } } @@ -68,7 +68,6 @@ class ScreenSetup : public QObject public: void addMissingEdidResolutions(); void updateScreenResources(); - void initModes(); ScreenMode getCurrentMode(); bool hasScreenWithoutEdid(); ConfigBackup setResolutionsFromString(const QString &resolutions, const QString &mapping); @@ -77,7 +76,7 @@ public: ConfigBackup setCenteredClone(); ConfigBackup setClone(const QSize &resolution); ConfigBackup setCustom(const QList<QPair<QSize, QList<QString>>> &list); - ResolutionVector getCommonModes() const; + ResolutionVector getCommonModes(bool projectorsOnly = false) const; int getOutputCount() const; int queryCurrentOutputCount() const; QMap<QString, ScreenInfo> getScreenPositions() const; |