summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2022-10-27 14:54:41 +0200
committerSimon Rettberg2022-10-27 14:54:41 +0200
commit9874a69997b03eec0c2825f59bae6fc3b6b4fd46 (patch)
tree51cd4edfe41dee9ac1bf2469be3241a8e436cdf4
parentFix TMDS clock limiting if DTD info is missing (Default to 165MHz) (diff)
downloadbeamergui-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.cpp1
-rw-r--r--src/widget.cpp10
-rw-r--r--src/xprivate.cpp58
-rw-r--r--src/xprivate.h3
-rw-r--r--src/xx.cpp66
-rw-r--r--src/xx.h3
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;
diff --git a/src/xx.cpp b/src/xx.cpp
index 85f843f..6080316 100644
--- a/src/xx.cpp
+++ b/src/xx.cpp
@@ -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)));
}
}
diff --git a/src/xx.h b/src/xx.h
index 43cb043..702568c 100644
--- a/src/xx.h
+++ b/src/xx.h
@@ -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;