summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2022-08-08 15:38:49 +0200
committerSimon Rettberg2022-08-08 15:38:49 +0200
commit923e8c9f0ece00973d6a2ebf70d382f0ebfaae26 (patch)
tree62840e43348069faed743883aeac33102d70ac11
parentPrint which screen has no EDID (and caused GUI to show on startup) (diff)
downloadbeamergui-923e8c9f0ece00973d6a2ebf70d382f0ebfaae26.tar.gz
beamergui-923e8c9f0ece00973d6a2ebf70d382f0ebfaae26.tar.xz
beamergui-923e8c9f0ece00973d6a2ebf70d382f0ebfaae26.zip
Add crap to add modes X11 ignored, cap to max pixel clock
-rw-r--r--src/xprivate.cpp79
-rw-r--r--src/xprivate.h5
2 files changed, 73 insertions, 11 deletions
diff --git a/src/xprivate.cpp b/src/xprivate.cpp
index 73b73ca..f040199 100644
--- a/src/xprivate.cpp
+++ b/src/xprivate.cpp
@@ -280,15 +280,23 @@ void XPrivate::addMissingEdidResolutions()
for (int i = 0; i < resptr->noutput; ++i) {
unsigned char prop[512];
unsigned long edidLen = 512;
+ int maxClock;
if (!getEdid(resptr->outputs[i], prop, &edidLen))
continue;
if (edidLen < 128)
continue;
+ for (unsigned int j = 128; j < edidLen - 127; j+= 128) {
+ maxClock = getMaxTmdsClockMhz(prop + j);
+ if (maxClock != 0)
+ break;
+ }
+ qDebug() << "Standard block DTD for output" << resptr->outputs[i] << "aka" << _outputMap[resptr->outputs[i]]->outputName
+ << "MaxClock" << maxClock << "MHz";
for (unsigned int j = 54; j < 125; j+= 18) {
- addMissingModesFromDtd(resptr, resptr->outputs[i], prop + j);
+ addMissingModesFromDtd(resptr, resptr->outputs[i], prop + j, maxClock);
}
for (unsigned int j = 128; j < edidLen - 127; j += 128) {
- addMissingModesFromExtBlock(resptr, resptr->outputs[i], prop + j);
+ addMissingModesFromExtBlock(resptr, resptr->outputs[i], prop + j, maxClock);
}
}
XRRFreeScreenResources(resptr);
@@ -358,9 +366,29 @@ bool XPrivate::readEdid(OutputInfo* output)
return true;
}
-void XPrivate::addMissingModesFromExtBlock(XRRScreenResources *res, RROutput outputId, unsigned char *data)
+int XPrivate::getMaxTmdsClockMhz(unsigned char *data)
+{
+ if (data[0] != 2) // Not type 2 (CTA extension block), skip
+ return 0;
+ if (data[1] < 1) // Need version 1+
+ return 0;
+ int nonDtdEnd = data[2];
+ int len;
+ for (int i = 4; i < nonDtdEnd; i += len) {
+ unsigned char *db = data + i;
+ len = (db[0] & 0x1f) + 1;
+ if ((db[0] & 0xe0) != 0x60) // Not vendor specific
+ continue;
+ if (db[3] != 0 || db[2] != 0x0c || db[1] != 0x03) // HDMI OUI? Non!
+ continue;
+ return db[7] * 5;
+ }
+ return 0;
+}
+
+void XPrivate::addMissingModesFromExtBlock(XRRScreenResources *res, RROutput outputId, unsigned char *data, unsigned int maxClockMhz)
{
- if (data[0] != 2) // Not type 2, skip
+ if (data[0] != 2) // Not type 2 (CTA extension block), skip
return;
if (data[2] == 0) // Empty block
return;
@@ -371,17 +399,17 @@ void XPrivate::addMissingModesFromExtBlock(XRRScreenResources *res, RROutput out
dtdOffset = 128;
}
- qDebug() << "addMissingModesFromExtBlock:" << outputId;
+ qDebug() << "addMissingModesFromExtBlock for output" << outputId;
for (int i = dtdOffset; i < 128 - 17; i += 18) {
- addMissingModesFromDtd(res, outputId, data + i);
+ addMissingModesFromDtd(res, outputId, data + i, maxClockMhz);
}
}
-void XPrivate::addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId, unsigned char *data)
+void XPrivate::addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId, unsigned char *data, unsigned int maxClockMhz)
{
if (data[0] == 0 && data[1] == 0)
return;
- int hactive, vactive, pixclk, hsyncoff, hsyncwidth, hblank, vsyncoff, vsyncwidth, vblank;
+ int hactive, vactive, pixclk, hsyncoff, hsyncwidth, hblank, vsyncoff, vsyncwidth, vblank, refresh;
hactive = data[2] + ((data[4] & 0xf0) << 4);
hblank = data[3] + ((data[4] & 0x0f) << 8);
vactive = data[5] + ((data[7] & 0xf0) << 4);
@@ -406,7 +434,8 @@ void XPrivate::addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId
m.vTotal = static_cast<unsigned int>(vactive + vblank);
m.id = 0;
m.name = buf;
- m.nameLength = static_cast<unsigned int>(snprintf(buf, sizeof(buf), "%dx%d_%d", hactive, vactive, static_cast<int>(m.dotClock / (m.hTotal * m.vTotal))));
+ refresh = static_cast<int>(m.dotClock / (m.hTotal * m.vTotal));
+ m.nameLength = static_cast<unsigned int>(snprintf(buf, sizeof(buf), "%dx%d_%d", hactive, vactive, refresh));
if (m.nameLength > sizeof(buf)) {
m.nameLength = sizeof(buf);
}
@@ -436,6 +465,34 @@ void XPrivate::addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId
if (data[17] & 0x80) {
m.modeFlags |= RR_Interlace;
}
+ // More special case B/S: So, X11 mysteriously ignores a couple of resolutions, sometimes.
+ // Curiously, this happens with a Philips TV, but not an LG TV. EDID dump looks very similar
+ // on both. More curiously, in Xorg.log, the first time the modelines for the Philips TV get dumped,
+ // the 4k resolution is missing, even though it's in the EDID dump from right before those lines.
+ // Then the xserver logs the modelines for the Philips TV a couple more times, and every time the 4k
+ // resolution is in the list. Just not the first time. However, the resolutions never get added to
+ // the TV.
+ if (m.dotClock > maxClockMhz * 1000000) {
+ bool found = false;
+ for (int mode = 0; mode < res->nmode; ++mode) {
+ if (res->modes[mode].width == m.width && res->modes[mode].height == m.height && res->modes[mode].dotClock <= maxClockMhz * 1000000) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ qDebug() << "Not creating/adding" << m.width << "x" << m.height <<
+ "because pixel clock > TMDS and resolution already exists with different clock";
+ return;
+ }
+ refresh = 30;
+ m.dotClock = refresh * m.hTotal * m.vTotal;
+ if (m.dotClock > maxClockMhz * 1000000) {
+ refresh = 24;
+ m.dotClock = refresh * m.hTotal * m.vTotal;
+ }
+ qDebug() << "Capping to" << refresh << "Hz, " << (m.dotClock / 1000000) << "MHz";
+ }
// See if we should add this mode
RRMode modeId = 0;
for (int mode = 0; mode < res->nmode; ++mode) {
@@ -445,9 +502,13 @@ void XPrivate::addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId
}
}
if (modeId == 0) {
+ qDebug() << "Creating" << m.name << "for output" << outputId << m.width << "x" << m.height << "@" << (m.dotClock / 1000000);
+ qDebug() << m.hSyncStart << m.hSyncEnd << m.hTotal;
+ qDebug() << m.vSyncStart << m.vSyncEnd << m.vTotal;
modeId = XRRCreateMode(_display, DefaultRootWindow(_display), &m);
}
if (modeId != 0) {
+ qDebug() << "Adding mode for output" << outputId << m.width << "x" << m.height << "@" << (m.dotClock / 1000000);
XRRAddOutputMode(_display, outputId, modeId);
}
}
diff --git a/src/xprivate.h b/src/xprivate.h
index bc8791e..c10832e 100644
--- a/src/xprivate.h
+++ b/src/xprivate.h
@@ -47,8 +47,9 @@ public:
void addMissingEdidResolutions();
bool getEdid(RROutput outputId, unsigned char *buffer, unsigned long *size);
bool readEdid(OutputInfo* output);
- void addMissingModesFromExtBlock(XRRScreenResources *res, RROutput outputId, unsigned char *data);
- void addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId, unsigned char *data);
+ int getMaxTmdsClockMhz(unsigned char *data);
+ void addMissingModesFromExtBlock(XRRScreenResources *res, RROutput outputId, unsigned char *data,unsigned int maxClockMhz);
+ void addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId, unsigned char *data, unsigned int maxClockMhz);
XRRModeInfo* getPreferredMode(const OutputInfo *oi, XRRModeInfo *fallback = nullptr) const;
QList<RRMode> getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const;
QList<RRMode> getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const;