diff options
author | Alexander Golubev <fatzer2@gmail.com> | 2023-12-24 11:09:32 +0300 |
---|---|---|
committer | Alexander Golubev <fatzer2@gmail.com> | 2023-12-24 12:57:08 +0300 |
commit | d32b076ae65478e6ce78ac3cc1db6957cf1ebb25 (patch) | |
tree | e9567d4bc475e6ffe85c89cb4433ed794250962f | |
parent | ac6c53f3fa24444a902adaf7f904b320ef327ec5 (diff) | |
download | tdelibs-d32b076ae65478e6ce78ac3cc1db6957cf1ebb25.tar.gz tdelibs-d32b076ae65478e6ce78ac3cc1db6957cf1ebb25.zip |
tderandr: workaround for tde/75fix/tde-75
Some videocards' drivers (most notably propryetary nvidia) report
incorrect screen refresh rate via XRRRates(). Use
XRRGetScreenResources() + some math borrowed from xrandr instead.
Bug: https://mirror.git.trinitydesktop.org/gitea/TDE/tde/issues/75
Signed-off-by: Alexander Golubev <fatzer2@gmail.com>
-rw-r--r-- | tderandr/randr.cpp | 155 | ||||
-rw-r--r-- | tderandr/randr.h | 2 |
2 files changed, 121 insertions, 36 deletions
diff --git a/tderandr/randr.cpp b/tderandr/randr.cpp index 6a3d0381e..e050852df 100644 --- a/tderandr/randr.cpp +++ b/tderandr/randr.cpp @@ -40,6 +40,10 @@ #undef INT32 #include <X11/extensions/Xrandr.h> +static int refreshRateForModeInfo (const XRRModeInfo *mode_info); +static int refreshRateIndexToXRR(int screen, int size, int index); +static int refreshRateXRRToIndex(int screen, int size, int hz); + HotPlugRule::HotPlugRule() { // @@ -169,7 +173,8 @@ KDE_EXPORT void RandRScreen::loadSettings() } if (d->config) { - m_currentRefreshRate = m_proposedRefreshRate = refreshRateHzToIndex(m_currentSize, XRRConfigCurrentRate(d->config)); + m_currentRefreshRate = m_proposedRefreshRate = + refreshRateXRRToIndex(m_screen, m_currentSize, XRRConfigCurrentRate(d->config)); } else { m_currentRefreshRate = m_proposedRefreshRate = 0; @@ -185,8 +190,12 @@ KDE_EXPORT void RandRScreen::setOriginal() KDE_EXPORT bool RandRScreen::applyProposed() { - //kdDebug() << k_funcinfo << " size " << (SizeID)proposedSize() << ", rotation " << proposedRotation() << ", refresh " << refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) << endl; - +#if 0 + kdDebug() << k_funcinfo << " size " << (SizeID)proposedSize() << + ", rotation " << proposedRotation() << + ", refresh " << refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) + << " (" << refreshRateIndexToXRR(m_screen, proposedSize(), proposedRefreshRate()) << ")" << endl; +#endif Status status; if (!d->config) { @@ -198,10 +207,11 @@ KDE_EXPORT bool RandRScreen::applyProposed() if (proposedRefreshRate() < 0) status = XRRSetScreenConfig(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), CurrentTime); else { - if( refreshRateIndexToHz(proposedSize(), proposedRefreshRate()) <= 0 ) { + int hz = refreshRateIndexToXRR(m_screen, proposedSize(), proposedRefreshRate()); + if( hz <= 0 ) { m_proposedRefreshRate = 0; } - status = XRRSetScreenConfigAndRate(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), refreshRateIndexToHz(proposedSize(), proposedRefreshRate()), CurrentTime); + status = XRRSetScreenConfigAndRate(tqt_xdisplay(), d->config, DefaultRootWindow(tqt_xdisplay()), (SizeID)proposedSize(), (Rotation)proposedRotation(), hz, CurrentTime); } } else { @@ -487,26 +497,22 @@ KDE_EXPORT int RandRScreen::currentMMHeight() const return m_pixelSizes[m_currentSize].height(); } -KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const +KDE_EXPORT TQValueVector<int> RandRScreen::refreshRatesValues(int size) const { - int nrates; - TQStringList ret; + ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay()); + int numSizes = screeninfo->res->nmode; + TQValueVector<int> ret; - if (d->config) { - short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates); - - for (int i = 0; i < nrates; i++) - ret << refreshRateDirectDescription(rates[i]); + if (size > numSizes-1) { // out of range + return ret; } - else { - // Great, now we have to go after the information manually. Ughh. - ScreenInfo *screeninfo = internal_read_screen_info(tqt_xdisplay()); - int numSizes = screeninfo->res->nmode; - for (int i = 0; i < numSizes; i++) { - int refresh_rate = ((screeninfo->res->modes[i].dotClock*1.0)/((screeninfo->res->modes[i].hTotal)*(screeninfo->res->modes[i].vTotal)*1.0)); - TQString newRate = refreshRateDirectDescription(refresh_rate); - if (!ret.contains(newRate)) { - ret.append(newRate); + + char * currentModeName = screeninfo->res->modes[size].name; + for (int i = 0; i < numSizes; i++) { + if (strcmp(currentModeName, screeninfo->res->modes[i].name) == 0) { + int rate = refreshRateForModeInfo(&screeninfo->res->modes[i]); + if (rate!=0) { + ret.append(rate); } } } @@ -514,6 +520,17 @@ KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const return ret; } +KDE_EXPORT TQStringList RandRScreen::refreshRates(int size) const +{ + TQStringList ret; + + for (int rate: refreshRatesValues(size)) { + ret.append(refreshRateDirectDescription(rate)); + } + + return ret; +} + KDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(int rate) const { return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(rate); @@ -521,7 +538,7 @@ KDE_EXPORT TQString RandRScreen::refreshRateDirectDescription(int rate) const KDE_EXPORT TQString RandRScreen::refreshRateIndirectDescription(int size, int index) const { - return i18n("Refresh rate in Hertz (Hz)", "%1 Hz").arg(refreshRateIndexToHz(size, index)); + return refreshRateDirectDescription(refreshRateIndexToHz(size, index)); } KDE_EXPORT TQString RandRScreen::refreshRateDescription(int size, int index) const @@ -556,30 +573,28 @@ KDE_EXPORT int RandRScreen::proposedRefreshRate() const KDE_EXPORT int RandRScreen::refreshRateHzToIndex(int size, int hz) const { - int nrates; - short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates); - - for (int i = 0; i < nrates; i++) - if (hz == rates[i]) + TQValueVector<int> rates = refreshRatesValues(size); + for (size_t i=0; i<rates.size(); i++) { + if ( (int) (rates[i] + 0.5) == hz) { return i; + } + } - if (nrates != 0) + if (rates.size() != 0) // Wrong input Hz! Q_ASSERT(false); return -1; } -KDE_EXPORT int RandRScreen::refreshRateIndexToHz(int size, int index) const -{ - int nrates; - short* rates = XRRRates(tqt_xdisplay(), m_screen, (SizeID)size, &nrates); +KDE_EXPORT int RandRScreen::refreshRateIndexToHz(int size, int index) const { + TQValueVector<int> rates = refreshRatesValues(size); - if (nrates == 0 || index < 0) + if (rates.size() == 0 || index < 0) return 0; - // Wrong input Hz! - if(index >= nrates) + // Wrong input index! + if(index >= (ssize_t)rates.size()) return 0; return rates[index]; @@ -880,4 +895,72 @@ KDE_EXPORT int RandRScreen::pixelCount( int index ) const return sz.width() * sz.height(); } +// Calculates refresh rate for modeinfo +// snatch from xrandr-1.5 +static int refreshRateForModeInfo(const XRRModeInfo *mode_info) +{ + double rate; + double vTotal = mode_info->vTotal; + + if (mode_info->modeFlags & RR_DoubleScan) { + /* doublescan doubles the number of lines */ + vTotal *= 2; + } + + if (mode_info->modeFlags & RR_Interlace) { + /* interlace splits the frame into two fields */ + /* the field rate is what is typically reported by monitors */ + vTotal /= 2; + } + + if (mode_info->hTotal && vTotal) + rate = ((double) mode_info->dotClock / + ((double) mode_info->hTotal * (double) vTotal)); + else + rate = 0; + return (int) (rate+0.5); +} + +// On some video drivers (e.g. proprietary nvidia) XRandR returns incorrect +// readings for refresh rate[1], when read via XRRRates(), so for display +// purposes we will use data from XRRGetScreenResources() and some fancy +// calculations (see internal_read_screen_info() and refreshRateForModeInfo()). +// Unfortunately, other XRandR functions (like XRRConfigCurrentRate() and +// XRRSetScreenConfigAndRate()) expect the data reported by XRRRates(). So, +// in order to be able to correctly set a refresh rate we have to request +// it via XRRRates() anyway. +// +// [1]: see https://mirror.git.trinitydesktop.org/gitea/TDE/tde/issues/75 + +static int refreshRateXRRToIndex(int screen, int size, int hz) +{ + int nrates; + short* rates = XRRRates(tqt_xdisplay(), screen, (SizeID)size, &nrates); + + for (int i = 0; i < nrates; i++) + if (hz == rates[i]) + return i; + + if (nrates != 0) + // Wrong input Hz! + Q_ASSERT(false); + + return -1; +} + +static int refreshRateIndexToXRR(int screen, int size, int index) +{ + int nrates; + short* rates = XRRRates(tqt_xdisplay(), screen, (SizeID)size, &nrates); + + if (nrates == 0 || index < 0) + return 0; + + // Wrong input Hz! + if(index >= nrates) + return 0; + + return rates[index]; +} + #include "randr.moc" diff --git a/tderandr/randr.h b/tderandr/randr.h index 36e87badd..36cdd0088 100644 --- a/tderandr/randr.h +++ b/tderandr/randr.h @@ -21,6 +21,7 @@ #include <tqobject.h> #include <tqstringlist.h> +#include <tqvaluevector.h> #include <tqptrlist.h> #include <tdecmodule.h> @@ -152,6 +153,7 @@ public: /** * Refresh rate functions. */ + TQValueVector<int> refreshRatesValues(int size) const; TQStringList refreshRates(int size) const; TQString refreshRateDirectDescription(int rate) const; |