From 923e8c9f0ece00973d6a2ebf70d382f0ebfaae26 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 8 Aug 2022 15:38:49 +0200 Subject: Add crap to add modes X11 ignored, cap to max pixel clock --- src/xprivate.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++++++------- src/xprivate.h | 5 ++-- 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(vactive + vblank); m.id = 0; m.name = buf; - m.nameLength = static_cast(snprintf(buf, sizeof(buf), "%dx%d_%d", hactive, vactive, static_cast(m.dotClock / (m.hTotal * m.vTotal)))); + refresh = static_cast(m.dotClock / (m.hTotal * m.vTotal)); + m.nameLength = static_cast(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 getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const; QList getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const; -- cgit v1.2.3-55-g7522