const DisplayResVector& DisplayResX::GetVideoModes(void) const { if (!m_videoModes.empty()) return m_videoModes; MythXDisplay *display = NULL; XRRScreenConfiguration *cfg = GetScreenConfig(display); if (!cfg) return m_videoModes; int num_sizes, num_rates; XRRScreenSize *sizes = NULL; sizes = XRRConfigSizes(cfg, &num_sizes); for (int i = 0; i < num_sizes; ++i) { short *rates = NULL; rates = XRRRates(display->GetDisplay(), display->GetScreen(), i, &num_rates); DisplayResScreen scr(sizes[i].width, sizes[i].height, sizes[i].mwidth, sizes[i].mheight, rates, num_rates); m_videoModes.push_back(scr); } t_screenrate screenmap; int nvidiarate = GetNvidiaRates(screenmap); if (nvidiarate > 0) { // Update existing DisplayResScreen vector, and update it with // new frequencies for (uint i = 0; i < m_videoModes.size(); i++) { DisplayResScreen scr = m_videoModes[i]; int w = scr.Width(); int h = scr.Height(); int mw = scr.Width_mm(); int mh = scr.Height_mm(); std::vector<double> newrates; std::map<double, short> realRates; const std::vector<double>& rates = scr.RefreshRates(); bool found = false; for (std::vector<double>::const_iterator it = rates.begin(); it != rates.end(); ++it) { uint64_t key = DisplayResScreen::CalcKey(w, h, *it); if (screenmap.find(key) != screenmap.end()) { // Rate is defined in NV-CONTROL extension, use it newrates.push_back(screenmap[key]); realRates[screenmap[key]] = (int) round(*it); found = true; #if 0 LOG(VB_PLAYBACK, LOG_INFO, QString("CustomRate Found, set %1x%2@%3 as %4Hz") .arg(w) .arg(h) .arg(*it) .arg(screenmap[key])); #endif } } if (found) { m_videoModes.erase(m_videoModes.begin() + i); std::sort(newrates.begin(), newrates.end()); m_videoModes.insert(m_videoModes.begin() + i, DisplayResScreen(w, h, mw, mh, newrates, realRates)); } } } m_videoModesUnsorted = m_videoModes; std::sort(m_videoModes.begin(), m_videoModes.end()); XRRFreeScreenConfigInfo(cfg); delete display; return m_videoModes; }
int DisplayResScreen::FindBestMatch(const DisplayResVector& dsr, const DisplayResScreen& d, double& target_rate) { double videorate = d.RefreshRate(); bool rate2x = false; bool end = false; // We will give priority to refresh rates that are twice what is looked for if ((videorate > 24.5) && (videorate < 30.5)) { rate2x = true; videorate *= 2.0; } // Amend vector with custom list for (uint i=0; i<dsr.size(); ++i) { if (dsr[i].Width()==d.Width() && dsr[i].Height()==d.Height()) { const std::vector<double>& rates = dsr[i].RefreshRates(); if (rates.size() && videorate != 0) { while (!end) { for (double precision = 0.001; precision < 1.0; precision *= 10.0) { for (uint j=0; j < rates.size(); ++j) { // Multiple of target_rate will do if (compare_rates(videorate,rates[j], precision) || (fabs(videorate - fmod(rates[j],videorate)) <= precision) || (fmod(rates[j],videorate) <= precision)) { target_rate = rates[j]; return i; } } } // Can't find exact frame rate, so try rounding to the // nearest integer, so 23.97Hz will work with 24Hz etc for (double precision = 0.01; precision < 2.0; precision *= 10.0) { double rounded = round(videorate); for (uint j=0; j < rates.size(); ++j) { // Multiple of target_rate will do if (compare_rates(rounded,rates[j], precision) || (fabs(rounded - fmod(rates[j],rounded)) <= precision) || (fmod(rates[j],rounded) <= precision)) { target_rate = rates[j]; return i; } } } if (rate2x) { videorate /= 2.0; rate2x = false; } else end = true; } target_rate = rates[rates.size() - 1]; } return i; } } return -1; }