bool DisplayResX::SwitchToVideoMode(int width, int height, double desired_rate) { double rate; DisplayResScreen desired_screen(width, height, 0, 0, -1.0, desired_rate); int idx = DisplayResScreen::FindBestMatch(m_videoModesUnsorted, desired_screen, rate); if (idx >= 0) { short finalrate; MythXDisplay *display = NULL; XRRScreenConfiguration *cfg = GetScreenConfig(display); if (!cfg) return false; Rotation rot; XRRConfigCurrentConfiguration(cfg, &rot); // Search real xrandr rate for desired_rate finalrate = (short) rate; for (uint i = 0; i < m_videoModes.size(); i++) { if ((m_videoModes[i].Width() == width) && (m_videoModes[i].Height() == height)) { if (m_videoModes[i].Custom()) { finalrate = m_videoModes[i].realRates[rate]; LOG(VB_PLAYBACK, LOG_INFO, QString("Dynamic TwinView rate found, set %1Hz as " "XRandR %2") .arg(rate) .arg(finalrate)); } break; } } Window root = display->GetRoot(); Status status = XRRSetScreenConfigAndRate(display->GetDisplay(), cfg, root, idx, rot, finalrate, CurrentTime); XRRFreeScreenConfigInfo(cfg); delete display; if (RRSetConfigSuccess != status) LOG(VB_GENERAL, LOG_ERR, "XRRSetScreenConfigAndRate() call failed."); return RRSetConfigSuccess == status; } LOG(VB_GENERAL, LOG_ERR, "Desired Resolution and FrameRate not found."); return false; }
void save_port_attributes(int port) { if (!open_xv_ports.count(port)) return; open_xv_ports[port].attribs.clear(); int attrib_count = 0; MythXDisplay *disp = open_xv_ports[port].disp; MythXLocker lock(disp); XvAttribute *attributes = XvQueryPortAttributes(disp->GetDisplay(), port, &attrib_count); if (!attributes || !attrib_count) return; for (int i = 0; i < attrib_count; i++) { if (!(attributes[i].flags & XvGettable)) continue; int current; if (xv_get_attrib(disp, port, attributes[i].name, current)) open_xv_ports[port].attribs[QString(attributes[i].name)] = current; } }
int CheckNVOpenGLSyncToVBlank(void) { MythXDisplay *d = OpenMythXDisplay(); if (!d) return -1; Display *dpy = d->GetDisplay(); int screen = d->GetScreen(); if (!XNVCTRLIsNvScreen(dpy, screen)) { delete d; return -1; } int major, minor; if (!XNVCTRLQueryVersion(dpy, &major, &minor)) return -1; int sync = NV_CTRL_SYNC_TO_VBLANK_OFF; if (!XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_SYNC_TO_VBLANK, &sync)) { delete d; return -1; } if (!sync) { LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenGL Sync to VBlank is disabled."); LOG(VB_GENERAL, LOG_WARNING, LOC + "For best results enable this in NVidia settings or try running:"); LOG(VB_GENERAL, LOG_WARNING, LOC + "nvidia-settings -a \"SyncToVBlank=1\""); } if (!sync && getenv("__GL_SYNC_TO_VBLANK")) { LOG(VB_GENERAL, LOG_INFO, LOC + "OpenGL Sync to VBlank enabled via __GL_SYNC_TO_VBLANK."); sync = 1; } else if (!sync) { LOG(VB_GENERAL, LOG_WARNING, LOC + "Alternatively try setting the '__GL_SYNC_TO_VBLANK' environment variable."); } return sync; }
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 GetNvidiaRates(t_screenrate& screenmap) { #ifdef USING_XRANDR MythXDisplay *d = OpenMythXDisplay(); if (!d) { return -1; } Display *dpy; bool ret; int screen, display_devices, mask, major, minor, len, j; char *str, *start; int nDisplayDevice; char *pMetaModes, *pModeLines[8], *tmp, *modeString; char *modeLine, *modeName; int MetaModeLen, ModeLineLen[8]; int thisMask; int id; int twinview = 0; map<int, map<int,bool> > maprate; memset(pModeLines, 0, sizeof(pModeLines)); memset(ModeLineLen, 0, sizeof(ModeLineLen)); /* * Open a display connection, and make sure the NV-CONTROL X * extension is present on the screen we want to use. */ dpy = d->GetDisplay(); screen = d->GetScreen(); if (!XNVCTRLIsNvScreen(dpy, screen)) { LOG(VB_PLAYBACK, LOG_INFO, QString("The NV-CONTROL X extension is not available on screen %1 " "of '%2'.") .arg(screen) .arg(XDisplayName(NULL))); delete d; return -1; } ret = XNVCTRLQueryVersion(dpy, &major, &minor); if (ret != True) { LOG(VB_PLAYBACK, LOG_INFO, QString("The NV-CONTROL X extension does not exist on '%1'.") .arg(XDisplayName(NULL))); delete d; return -1; } ret = XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_DYNAMIC_TWINVIEW, &twinview); if (!ret) { LOG(VB_PLAYBACK, LOG_ERR, "Failed to query if Dynamic Twinview is enabled"); XCloseDisplay(dpy); return -1; } if (!twinview) { LOG(VB_PLAYBACK, LOG_ERR, "Dynamic Twinview not enabled, ignoring"); delete d; return 0; } /* * query the connected display devices on this X screen and print * basic information about each X screen */ ret = XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_CONNECTED_DISPLAYS, &display_devices); if (!ret) { LOG(VB_PLAYBACK, LOG_ERR, "Failed to query the enabled Display Devices."); delete d; return -1; } /* first, we query the MetaModes on this X screen */ ret = XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a NV_CTRL_BINARY_DATA_METAMODES, (unsigned char **)&pMetaModes, &MetaModeLen); if (!ret) { LOG(VB_PLAYBACK, LOG_ERR, "Failed to query the metamode on selected display device."); delete d; return -1; } /* * then, we query the ModeLines for each display device on * this X screen; we'll need these later */ nDisplayDevice = 0; for (mask = 1; mask < (1 << 24); mask <<= 1) { if (!(display_devices & mask)) continue; ret = XNVCTRLQueryBinaryData(dpy, screen, mask, NV_CTRL_BINARY_DATA_MODELINES, (unsigned char **)&str, &len); if (!ret) { LOG(VB_PLAYBACK, LOG_ERR, "Unknown error. Failed to query the enabled Display Devices."); // Free Memory currently allocated for (j=0; j < nDisplayDevice; ++j) { free(pModeLines[j]); } delete d; return -1; } pModeLines[nDisplayDevice] = str; ModeLineLen[nDisplayDevice] = len; nDisplayDevice++; } /* now, parse each MetaMode */ str = start = pMetaModes; for (j = 0; j < MetaModeLen - 1; ++j) { /* * if we found the end of a line, treat the string from * start to str[j] as a MetaMode */ if ((str[j] == '\0') && (str[j+1] != '\0')) { id = extract_id_string(start); /* * the MetaMode may be preceded with "token=value" * pairs, separated by the main MetaMode with "::"; if * "::" exists in the string, skip past it */ tmp = strstr(start, "::"); if (tmp) { tmp += 2; } else { tmp = start; } /* split the MetaMode string by comma */ char *strtok_state = NULL; for (modeString = strtok_r(tmp, ",", &strtok_state); modeString; modeString = strtok_r(NULL, ",", &strtok_state)) { /* * retrieve the modeName and display device mask * for this segment of the Metamode */ parse_mode_string(modeString, &modeName, &thisMask); /* lookup the modeline that matches */ nDisplayDevice = 0; if (thisMask) { for (mask = 1; mask < (1 << 24); mask <<= 1) { if (!(display_devices & mask)) continue; if (thisMask & mask) break; nDisplayDevice++; } } modeLine = find_modeline(modeName, pModeLines[nDisplayDevice], ModeLineLen[nDisplayDevice]); if (modeLine && !modeline_is_interlaced(modeLine)) { int w, h, vfl, hfl, i, irate; double dcl, r; char *buf[256]; uint64_t key, key2; // skip name tmp = strchr(modeLine, '"'); tmp = strchr(tmp+1, '"') +1 ; while (*tmp == ' ') tmp++; i = 0; for (modeString = strtok_r(tmp, " ", &strtok_state); modeString; modeString = strtok_r(NULL, " ", &strtok_state)) { buf[i++] = modeString; } w = strtol(buf[1], NULL, 10); h = strtol(buf[5], NULL, 10); vfl = strtol(buf[8], NULL, 10); hfl = strtol(buf[4], NULL, 10); h = strtol(buf[5], NULL, 10); istringstream istr(buf[0]); istr.imbue(locale("C")); istr >> dcl; r = (dcl * 1000000.0) / (vfl * hfl); irate = (int) round(r * 1000.0); key = DisplayResScreen::CalcKey(w, h, (double) id); key2 = DisplayResScreen::CalcKey(w, h, 0.0); // We need to eliminate duplicates, giving priority to the first entries found if (maprate.find(key2) == maprate.end()) { // First time we see this resolution, create a map for it maprate[key2] = map<int, bool>(); } if ((maprate[key2].find(irate) == maprate[key2].end()) && (screenmap.find(key) == screenmap.end())) { screenmap[key] = r; maprate[key2][irate] = true; } } free(modeName); } /* move to the next MetaMode */ start = &str[j+1]; }