QByteArray UINVControl::GetNVEDID(Display *XDisplay, int Screen) { if (!NVControlAvailable(XDisplay)) return QByteArray(); QMutexLocker locker(gNVCtrlLock); QByteArray result; if (!XNVCTRLIsNvScreen(XDisplay, Screen)) { LOG(VB_GENERAL, LOG_ERR, QString("NV-CONTROL is not available on screen %1 of display '%2'") .arg(Screen).arg(XDisplayName(NULL))); return result; } int displays = 0; Bool ok = XNVCTRLQueryAttribute(XDisplay, Screen, 0, NV_CTRL_CONNECTED_DISPLAYS, &displays); if (ok != True) { LOG(VB_GENERAL, LOG_ERR, "Failed to retrieve display list"); return result; } int displaycount = ListDisplays(displays); if (displaycount != 1) { LOG(VB_GENERAL, LOG_WARNING, "There is more than one physical display attached to this screen. Ignoring EDID"); return result; } int edid = NV_CTRL_EDID_AVAILABLE_FALSE; ok = XNVCTRLQueryAttribute(XDisplay, Screen, displays, NV_CTRL_EDID_AVAILABLE, &edid); if (ok != True) { LOG(VB_GENERAL, LOG_INFO, "Failed to check EDID_AVAILABLE attribute"); return result; } if (edid != NV_CTRL_EDID_AVAILABLE_TRUE) { LOG(VB_GENERAL, LOG_INFO, "EDID not available"); return result; } unsigned char* data = NULL; int datalength = 0; ok = XNVCTRLQueryBinaryData(XDisplay, Screen, displays, NV_CTRL_BINARY_DATA_EDID, &data, &datalength); if (ok != True) { LOG(VB_GENERAL, LOG_INFO, QString("EDID not available on screen %1 of display '%2'") .arg(Screen).arg(XDisplayName(NULL))); return result; } result = QByteArray((const char*)data, datalength); delete data; return result; }
float nvidia_gpu_temperature(Display *dpy, int screen) { int core; int ret = XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_GPU_CORE_TEMPERATURE, &core); if(ret) { return core; } return 0.0; }
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; }
// this function does some checks int nvidia_gpu_init(Display * dpy, int screen) { int event_base, error_base; int ret = XNVCTRLQueryExtension(dpy, &event_base, &error_base); if (ret != True) { fprintf(stderr, "The NV-CONTROL X extension does not exist on '%s'.\n", XDisplayName(NULL)); return 0; } if(!XNVCTRLIsNvScreen(dpy, screen)) { fprintf(stderr, "Screen %d does not support the NV-Control extension\n", screen); return 0; } int max; ret = XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_GPU_CORE_THRESHOLD, &max); if(ret) { nvidia_gpu_max_temperature = max; } return 1; }
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]; }
int main(int argc, char *argv[]) { Display *dpy; Bool ret; int screen, retval, setval = -1; int display_devices, mask; NVCTRLAttributeValidValuesRec valid_values; /* * If there is a commandline argument, interpret it as the value * to use to set DVC. */ if (argc == 2) { setval = atoi(argv[1]); } /* * Open a display connection, and make sure the NV-CONTROL X * extension is present on the screen we want to use. */ dpy = XOpenDisplay(NULL); if (!dpy) { fprintf(stderr, "Cannot open display '%s'.\n", XDisplayName(NULL)); return 1; } screen = GetNvXScreen(dpy); /* * Get the bitmask of enabled display devices */ ret = XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_ENABLED_DISPLAYS, &display_devices); if (!ret) { fprintf(stderr, "Unable to determine enabled display devices for " "screen %d of '%s'\n", screen, XDisplayName(NULL)); return 1; } /* * loop over each enabled display device */ for (mask = 1; mask < (1<<24); mask <<= 1) { if (!(mask & display_devices)) continue; /* * Query the valid values for NV_CTRL_DIGITAL_VIBRANCE */ ret = XNVCTRLQueryValidAttributeValues(dpy, screen, mask, NV_CTRL_DIGITAL_VIBRANCE, &valid_values); if (!ret) { fprintf(stderr, "Unable to query the valid values for " "NV_CTRL_DIGITAL_VIBRANCE on display device %s of " "screen %d of '%s'.\n", display_device_name(mask), screen, XDisplayName(NULL)); return 1; } /* we assume that NV_CTRL_DIGITAL_VIBRANCE is a range type */ if (valid_values.type != ATTRIBUTE_TYPE_RANGE) { fprintf(stderr, "NV_CTRL_DIGITAL_VIBRANCE is not of " "type RANGE.\n"); return 1; } /* print the range of valid values */ printf("Valid values for NV_CTRL_DIGITAL_VIBRANCE: " "(%" PRId64 " - %" PRId64 ").\n", valid_values.u.range.min, valid_values.u.range.max); /* * if a value was specified on the commandline, set it; * otherwise, query the current value */ if (setval != -1) { XNVCTRLSetAttribute(dpy, screen, mask, NV_CTRL_DIGITAL_VIBRANCE, setval); XFlush(dpy); printf("Set NV_CTRL_DIGITAL_VIBRANCE to %d on display device " "%s of screen %d of '%s'.\n", setval, display_device_name(mask), screen, XDisplayName(NULL)); } else { ret = XNVCTRLQueryAttribute(dpy, screen, mask, NV_CTRL_DIGITAL_VIBRANCE, &retval); printf("The current value of NV_CTRL_DIGITAL_VIBRANCE " "is %d on display device %s of screen %d of '%s'.\n", retval, display_device_name(mask), screen, XDisplayName(NULL)); } } return 0; }
int main(int argc, char *argv[]) { Display *dpy; Bool ret; int screen, display_devices, mask, major, minor; char *str; int nDisplayDevice; /* * Open a display connection, and make sure the NV-CONTROL X * extension is present on the screen we want to use. */ dpy = XOpenDisplay(NULL); if (!dpy) { fprintf(stderr, "Cannot open display '%s'.\n\n", XDisplayName(NULL)); return 1; } screen = GetNvXScreen(dpy); ret = XNVCTRLQueryVersion(dpy, &major, &minor); if (ret != True) { fprintf(stderr, "The NV-CONTROL X extension does not exist on '%s'.\n\n", XDisplayName(NULL)); return 1; } /* * 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) { fprintf(stderr, "Failed to query the enabled Display Devices.\n\n"); return 1; } int pci_bus; int pci_device; int pci_func; ret = XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GPU, 0 /* Just query first GPU */, 0, NV_CTRL_PCI_BUS, &pci_bus); ret = XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GPU, 0 /* Just query first GPU */, 0, NV_CTRL_PCI_DEVICE, &pci_device); ret = XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GPU, 0 /* Just query first GPU */, 0, NV_CTRL_PCI_FUNCTION, &pci_func); dbset("system.hardware.nvidia.busid=%i:%i:%i", pci_bus, pci_device, pci_func); nDisplayDevice = 0; for (mask = 1; mask < (1 << 24); mask <<= 1) { if (display_devices & mask) { XNVCTRLQueryStringAttribute(dpy, screen, mask, NV_CTRL_STRING_DISPLAY_DEVICE_NAME, &str); dbset("system.x11.display.%i.device=%s" , nDisplayDevice, display_device_name(mask)); dbset("system.x11.display.%i.mode.0=nvidia-auto-select", nDisplayDevice); dbset("system.x11.display.%i.default=nvidia-auto-select", nDisplayDevice); printf("%i:%s:0x%08x:%s\n", nDisplayDevice, display_device_name(mask), mask, str); nDisplayDevice++; } } if (nDisplayDevice > 1) { // more than one screen found dbset("system.x11.dualhead.enabled=1"); } else { dbset("system.x11.dualhead.enabled=0"); } char *dummy; for (; nDisplayDevice <= 3; nDisplayDevice++) { if (asprintf(&dummy, "system.x11.display.%i", nDisplayDevice) >= 0) { dbremove(dummy); free(dummy); } } return 0; }
void UINVControl::InitialiseMetaModes(Display *XDisplay, int Screen) { if (!NVControlAvailable(XDisplay)) return; QMutexLocker locker(gNVCtrlLock); gMetaModeMap.clear(); if (!XNVCTRLIsNvScreen(XDisplay, Screen)) { LOG(VB_GENERAL, LOG_ERR, QString("NV-CONTROL is not available on screen %1 of display '%2'") .arg(Screen).arg(XDisplayName(NULL))); return; } int displays = 0; Bool ok = XNVCTRLQueryAttribute(XDisplay, Screen, 0, NV_CTRL_CONNECTED_DISPLAYS, &displays); if (ok != True) { LOG(VB_GENERAL, LOG_ERR, "Failed to retrieve display list"); return; } int displaycount = ListDisplays(displays); if (displaycount != 1) { LOG(VB_GENERAL, LOG_WARNING, "There is more than one physical display attached to this screen. Ignoring metamodes"); return; } // retrieve a list of refresh rates by mode name QMap<QString,double> rates; QStringList interlacedrates; unsigned char* modelines = NULL; int modelinelength = 0; if (XNVCTRLQueryBinaryData(XDisplay, Screen, displays, NV_CTRL_BINARY_DATA_MODELINES, &modelines, &modelinelength)) { QByteArray data((const char*)modelines, modelinelength); QList<QByteArray> lines = data.split('\0'); foreach (QByteArray line, lines) { QString modeline = QString::fromLatin1(line.data()).simplified(); LOG(VB_GUI, LOG_DEBUG, QString("Modeline: %1").arg(modeline)); QStringList parts = modeline.split("::", QString::SkipEmptyParts); if (parts.size() < 1) continue; modeline = parts.last(); parts = modeline.split(" ", QString::SkipEmptyParts); if (parts.size() < 10) continue; QString name = parts[0].replace("\"", ""); double rate = parts[5].toInt() * parts[9].toInt(); double clock = parts[1].toDouble(); if (rate > 0.0 && clock > 0.0f) { rate = (clock * 1000000) / rate; bool interlaced = false; if (modeline.contains("interlace", Qt::CaseInsensitive)) { rate *= 2.0f; interlaced = true; } if (rate > 20.0f && rate < 121.0f) { rates.insert(name, rate); if (interlaced) interlacedrates.append(name); } } }
int main(int argc, char *argv[]) { Display *dpy; Bool ret; int screen, display_devices[2]; char* environment = getenv("XDG_CONFIG_HOME"); char* configuration; if (environment == NULL) { // no XDG_CONFIG_HOME set, default is $HOME/.config/ environment = getenv("HOME"); configuration = (char*)calloc(sizeof(char), strlen(environment) + strlen(CONFIG_FILE) + strlen("/.config/") + 1); strcpy(configuration, environment); strcat(configuration, "/.config/"); } else { configuration = (char*)calloc(sizeof(char), strlen(environment) + strlen(CONFIG_FILE) + 1); } strcat(configuration, CONFIG_FILE); printf("Using callback file %s\n", configuration); ret = setup(&dpy, &screen); if (!ret) { return 1; } ret = XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_PROBE_DISPLAYS, &display_devices[0]); if (!ret) { fprintf(stderr, "Failed to query the enabled Display Devices.\n\n"); return 1; } while (True) { usleep(2 * 1000 * 1000); /* * first, probe for new display devices; while * NV_CTRL_CONNECTED_DISPLAYS reports what the NVIDIA X driver * believes is currently connected to the GPU, * NV_CTRL_PROBE_DISPLAYS forces the driver to redetect what * is connected. */ ret = XNVCTRLQueryAttribute(dpy, screen, 0, NV_CTRL_PROBE_DISPLAYS, &display_devices[0]); if (display_devices[0] != display_devices[1]) { display_devices[1] = display_devices[0]; char** strs = identifier(dpy, display_devices[0], screen); strs[0] = configuration; // First argument is the executable, by convention if (fork() == 0) { // Child execv(configuration, strs); fprintf(stderr, "An error occured executing the daemon callback file\n"); return 0; } int i = 1; while(strs[i] != NULL) { #ifdef DEBUG printf("%d: \"%s\"\n", i, strs[i]); #endif free(strs[i++]); } } } return 0; }
/* ================ Sys_GetVideoRam returns in megabytes open your own display connection for the query and close it using the one shared with GLimp_Init is not stable ================ */ int Sys_GetVideoRam( void ) { #ifdef USE_SDL return 128; #else static int run_once = 0; int major, minor, value; Display *l_dpy; int l_scrnum; if ( run_once ) { return run_once; } if ( sys_videoRam.GetInteger() ) { run_once = sys_videoRam.GetInteger(); return sys_videoRam.GetInteger(); } // try a few strategies to guess the amount of video ram common->Printf( "guessing video ram ( use +set sys_videoRam to force ) ..\n" ); if ( !GLimp_OpenDisplay( ) ) { run_once = 64; return run_once; } l_dpy = dpy; l_scrnum = scrnum; // go for nvidia ext first if ( XNVCTRLQueryVersion( l_dpy, &major, &minor ) ) { common->Printf( "found XNVCtrl extension %d.%d\n", major, minor ); if ( XNVCTRLIsNvScreen( l_dpy, l_scrnum ) ) { if ( XNVCTRLQueryAttribute( l_dpy, l_scrnum, 0, NV_CTRL_VIDEO_RAM, &value ) ) { run_once = value / 1024; return run_once; } else { common->Printf( "XNVCtrlQueryAttribute NV_CTRL_VIDEO_RAM failed\n" ); } } else { common->Printf( "default screen %d is not controlled by NVIDIA driver\n", l_scrnum ); } } // try ATI /proc read ( for the lack of a better option ) int fd; if ( ( fd = open( "/proc/dri/0/umm", O_RDONLY ) ) != -1 ) { int len; char umm_buf[ 1024 ]; char *line; if ( ( len = read( fd, umm_buf, 1024 ) ) != -1 ) { // should be way enough to get the full file // grab "free LFB = " line and "free Inv = " lines umm_buf[ len-1 ] = '\0'; line = umm_buf; line = strtok( umm_buf, "\n" ); int total = 0; while ( line ) { if ( strlen( line ) >= 13 && strstr( line, "max LFB =" ) == line ) { total += atoi( line + 12 ); } else if ( strlen( line ) >= 13 && strstr( line, "max Inv =" ) == line ) { total += atoi( line + 12 ); } line = strtok( NULL, "\n" ); } if ( total ) { run_once = total / 1048576; // round to the lower 16Mb run_once &= ~15; return run_once; } } else { common->Printf( "read /proc/dri/0/umm failed: %s\n", strerror( errno ) ); } } common->Printf( "guess failed, return default low-end VRAM setting ( 64MB VRAM )\n" ); run_once = 64; return run_once; #endif }