/* * Open a display connection, and make sure the NV-CONTROL X * extension is present on the screen we want to use. */ static Bool setup(Display** dpy, int* screen) { int major, minor; Bool ret; *dpy = XOpenDisplay(NULL); if (!(*dpy)) { fprintf(stderr, "Cannot open display '%s'.\n\n", XDisplayName(NULL)); return False; } *screen = GetNvXScreen(*dpy); if (*screen == -1) { return False; } 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 False; } return True; }
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, major, minor, len, i, j; char *str, *start, *str0, *str1; int *enabledDpyIds; /* * 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; } printf("\nUsing NV-CONTROL extension %d.%d on %s\n\n", major, minor, XDisplayName(NULL)); /* * query the enabled display devices on this X screen and print basic * information about each X screen. */ ret = XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN, (unsigned char **) &enabledDpyIds, &len); if (!ret || (len < sizeof(enabledDpyIds[0]))) { fprintf(stderr, "Failed to query the enabled Display Devices.\n\n"); return 1; } printf("Enabled Display Devices:\n"); for (i = 0; i < enabledDpyIds[0]; i++) { int dpyId = enabledDpyIds[i+1]; print_display_id_and_name(dpy, dpyId, " "); } printf("\n"); /* * perform the requested action, based on the specified * commandline option */ if (argc <= 1) goto printHelp; /* * for each enabled display device on this X screen, query the list of * modelines in the mode pool using NV_CTRL_BINARY_DATA_MODELINES, then * print the results. */ if (strcmp(argv[1], "--print-modelines") == 0) { for (i = 0; i < enabledDpyIds[0]; i++) { int dpyId = enabledDpyIds[i+1]; ret = XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_BINARY_DATA_MODELINES, (void *) &str, &len); if (!ret) { fprintf(stderr, "Failed to query ModeLines.\n\n"); return 1; } /* * the returned data is in the form: * * "ModeLine 1\0ModeLine 2\0ModeLine 3\0Last ModeLine\0\0" * * so walk from one "\0" to the next to print each ModeLine. */ printf("Modelines for DPY-%d:\n", dpyId); start = str; for (j = 0; j < len; j++) { if (str[j] == '\0') { printf(" %s\n", start); start = &str[j+1]; } } XFree(str); } } /* * for each enabled display device on this X screen, query the current * modeline using NV_CTRL_STRING_CURRENT_MODELINE. */ else if (strcmp(argv[1], "--print-current-modeline") == 0) { for (i = 0; i < enabledDpyIds[0]; i++) { int dpyId = enabledDpyIds[i+1]; ret = XNVCTRLQueryTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_STRING_CURRENT_MODELINE, &str); if (!ret) { fprintf(stderr, "Failed to query current ModeLine.\n\n"); return 1; } printf("Current Modeline for DPY-%d:\n", dpyId); printf(" %s\n\n", str); XFree(str); } } /* * add the specified modeline to the mode pool for the specified * display device, using NV_CTRL_STRING_ADD_MODELINE */ else if ((strcmp(argv[1], "--add-modeline") == 0) && argv[2] && argv[3]) { int dpyId = strtol(argv[2], NULL, 0); ret = XNVCTRLSetTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_STRING_ADD_MODELINE, argv[3]); if (!ret) { fprintf(stderr, "Failed to add the modeline \"%s\" to DPY-%d's " "mode pool.\n\n", argv[3], dpyId); return 1; } printf("Added modeline \"%s\" to DPY-%d's mode pool.\n\n", argv[3], dpyId); } /* * delete the specified modeline from the mode pool for the * specified display device, using NV_CTRL_STRING_DELETE_MODELINE */ else if ((strcmp(argv[1], "--delete-modeline") == 0) && argv[2] && argv[3]) { int dpyId = strtol(argv[2], NULL, 0); ret = XNVCTRLSetTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_STRING_DELETE_MODELINE, argv[3]); if (!ret) { fprintf(stderr, "Failed to delete the mode \"%s\" from DPY-%d's " "mode pool.\n\n", argv[3], dpyId); return 1; } printf("Deleted modeline \"%s\" from DPY-%d's mode pool.\n\n", argv[3], dpyId); } /* * generate a GTF modeline using NV_CTRL_STRING_OPERATION_GTF_MODELINE */ else if ((strcmp(argv[1], "--generate-gtf-modeline") == 0) && argv[2] && argv[3] && argv[4]) { char pGtfString[128]; char *pOut; snprintf(pGtfString, 128, "width=%s, height=%s, refreshrate=%s", argv[2], argv[3], argv[4]); ret = XNVCTRLStringOperation(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, NV_CTRL_STRING_OPERATION_GTF_MODELINE, pGtfString, &pOut); if (!ret) { fprintf(stderr, "Failed to generate GTF ModeLine from " "\"%s\".\n\n", pGtfString); return 1; } printf("GTF ModeLine from \"%s\": %s\n\n", pGtfString, pOut); } /* * generate a CVT modeline using NV_CTRL_STRING_OPERATION_CVT_MODELINE */ else if ((strcmp(argv[1], "--generate-cvt-modeline") == 0) && argv[2] && argv[3] && argv[4] && argv[5]) { char pCvtString[128]; char *pOut; snprintf(pCvtString, 128, "width=%s, height=%s, refreshrate=%s, " "reduced-blanking=%s", argv[2], argv[3], argv[4], argv[5]); ret = XNVCTRLStringOperation(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, NV_CTRL_STRING_OPERATION_CVT_MODELINE, pCvtString, &pOut); if (!ret) { fprintf(stderr, "Failed to generate CVT ModeLine from " "\"%s\".\n\n", pCvtString); return 1; } printf("CVT ModeLine from \"%s\": %s\n\n", pCvtString, pOut); } /* * query the MetaModes for the X screen, using * NV_CTRL_BINARY_DATA_METAMODES. */ else if (strcmp(argv[1], "--print-metamodes") == 0) { /* get list of metamodes */ ret = XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a NV_CTRL_BINARY_DATA_METAMODES, (void *) &str, &len); if (!ret) { fprintf(stderr, "Failed to query MetaModes.\n\n"); return 1; } /* * the returned data is in the form: * * "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0" * * so walk from one "\0" to the next to print each MetaMode. */ printf("MetaModes:\n"); start = str; for (j = 0; j < len; j++) { if (str[j] == '\0') { printf(" %s\n", start); start = &str[j+1]; } } XFree(str); } /* * query the MetaModes for the X screen, using * NV_CTRL_BINARY_DATA_METAMODES_VERSION_2. */ else if (strcmp(argv[1], "--print-metamodes-version2") == 0) { /* get list of metamodes */ ret = XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a NV_CTRL_BINARY_DATA_METAMODES_VERSION_2, (void *) &str, &len); if (!ret) { fprintf(stderr, "Failed to query MetaModes.\n\n"); return 1; } /* * the returned data is in the form: * * "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0" * * so walk from one "\0" to the next to print each MetaMode. */ printf("MetaModes:\n"); start = str; for (j = 0; j < len; j++) { if (str[j] == '\0') { printf(" %s\n", start); start = &str[j+1]; } } XFree(str); } /* * query the currently in use MetaMode. Note that an alternative * way to accomplish this is to use XRandR to query the current * mode's refresh rate, and then match the refresh rate to the id * reported in the returned NV_CTRL_BINARY_DATA_METAMODES data. */ else if (strcmp(argv[1], "--print-current-metamode") == 0) { ret = XNVCTRLQueryStringAttribute(dpy, screen, 0, NV_CTRL_STRING_CURRENT_METAMODE, &str); if (!ret) { fprintf(stderr, "Failed to query the current MetaMode.\n\n"); return 1; } printf("current metamode: \"%s\"\n\n", str); XFree(str); } /* * query the currently in use MetaMode. Note that an alternative * way to accomplish this is to use XRandR to query the current * mode's refresh rate, and then match the refresh rate to the id * reported in the returned NV_CTRL_BINARY_DATA_METAMODES_VERSION_2 data. */ else if (strcmp(argv[1], "--print-current-metamode-version2") == 0) { ret = XNVCTRLQueryStringAttribute(dpy, screen, 0, NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2, &str); if (!ret) { fprintf(stderr, "Failed to query the current MetaMode.\n\n"); return 1; } printf("current metamode: \"%s\"\n\n", str); XFree(str); } /* * add the given MetaMode to X screen's list of MetaModes, using * NV_CTRL_STRING_OPERATION_ADD_METAMODE; example MetaMode string: * * "nvidia-auto-select, nvidia-auto-select" * * The output string will contain "id=#" which indicates the * unique identifier for this MetaMode. You can then use XRandR * to switch to this mode by matching the identifier with the * refresh rate reported via XRandR. * * For example: * * $ ./nv-control-dpy --add-metamode \ * "nvidia-auto-select, nvidia-auto-select" * * Using NV-CONTROL extension 1.12 on :0 * Enabled Display Devices: * DPY-0 : EIZO F931 * DPY-1 : ViewSonic P815-4 * * Added MetaMode "nvidia-auto-select, nvidia-auto-select"; * pOut: "id=52" * * $ xrandr -q * SZ: Pixels Physical Refresh * 0 3200 x 1200 ( 821mm x 302mm ) 51 52 * *1 1600 x 600 ( 821mm x 302mm ) *50 * Current rotation - normal * Current reflection - none * Rotations possible - normal * Reflections possible - none * * $ xrandr -s 0 -r 52 */ else if ((strcmp(argv[1], "--add-metamode") == 0) && (argv[2])) { char *pOut; ret = XNVCTRLStringOperation(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, NV_CTRL_STRING_OPERATION_ADD_METAMODE, argv[2], &pOut); if (!ret) { fprintf(stderr, "Failed to add the MetaMode \"%s\".\n\n", argv[2]); return 1; } printf("Added MetaMode \"%s\"; pOut: \"%s\"\n\n", argv[2], pOut); XFree(pOut); } /* * delete the given MetaMode from the X screen's list of * MetaModes, using NV_CTRL_STRING_DELETE_METAMODE */ else if ((strcmp(argv[1], "--delete-metamode") == 0) && (argv[1])) { ret = XNVCTRLSetStringAttribute(dpy, screen, 0, NV_CTRL_STRING_DELETE_METAMODE, argv[2]); if (!ret) { fprintf(stderr, "Failed to delete the MetaMode.\n\n"); return 1; } printf("Deleted MetaMode \"%s\".\n\n", argv[2]); } /* * query the valid frequency ranges for each display device, using * NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES and * NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES */ else if (strcmp(argv[1], "--get-valid-freq-ranges") == 0) { for (i = 0; i < enabledDpyIds[0]; i++) { int dpyId = enabledDpyIds[i+1]; ret = XNVCTRLQueryTargetStringAttribute (dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES, &str0); if (!ret) { fprintf(stderr, "Failed to query HorizSync for DPY-%d.\n\n", dpyId); return 1; } ret = XNVCTRLQueryTargetStringAttribute (dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES, &str1); if (!ret) { fprintf(stderr, "Failed to query VertRefresh for DPY-%d.\n\n", dpyId); XFree(str0); return 1; } printf("frequency information for DPY-%d:\n", dpyId); printf(" HorizSync : \"%s\"\n", str0); printf(" VertRefresh : \"%s\"\n\n", str1); XFree(str0); XFree(str1); } } /* * attempt to build the modepool for each display device; this * will fail for any display device that already has a modepool */ else if (strcmp(argv[1], "--build-modepool") == 0) { for (i = 0; i < enabledDpyIds[0]; i++) { int dpyId = enabledDpyIds[i+1]; ret = XNVCTRLStringOperation (dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL, argv[2], &str0); if (!ret) { fprintf(stderr, "Failed to build modepool for DPY-%d (it most " "likely already has a modepool).\n\n", dpyId); } else { printf("Built modepool for DPY-%d.\n\n", dpyId); } } } /* * query the assigned display devices on this X screen; these are the * display devices that are available to the X screen for use by MetaModes. */ else if (strcmp(argv[1], "--get-assigned-dpys") == 0) { int *pData = NULL; int len; ret = XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN, (unsigned char **) &pData, &len); if (!ret || (len < sizeof(pData[0]))) { fprintf(stderr, "failed to query the assigned display " "devices.\n\n"); return 1; } printf("Assigned display devices:\n"); for (i = 0; i < pData[0]; i++) { int dpyId = pData[i+1]; printf(" DPY-%d\n", dpyId); } printf("\n"); XFree(pData); } /* * query information about the GPUs in the system */ else if (strcmp(argv[1], "--query-gpus") == 0) { int num_gpus, num_screens, i; int *pData; printf("GPU Information:\n"); /* Get the number of gpus in the system */ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, &num_gpus); if (!ret) { fprintf(stderr, "Failed to query number of gpus.\n\n"); return 1; } printf(" number of GPUs: %d\n", num_gpus); /* List the X screen number of all X screens driven by each gpu */ for (i = 0; i < num_gpus; i++) { ret = XNVCTRLQueryTargetBinaryData (dpy, NV_CTRL_TARGET_TYPE_GPU, i, // target_id 0, NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU, (unsigned char **) &pData, &len); if (!ret || (len < sizeof(pData[0]))) { fprintf(stderr, "Failed to query list of X Screens\n"); return 1; } printf(" number of X screens using GPU %d: %d\n", i, pData[0]); /* List X Screen number of all X Screens driven by this GPU. */ printf(" Indices of X screens using GPU %d: ", i); for (j = 1; j <= pData[0]; j++) { printf(" %d", pData[j]); } printf("\n"); XFree(pData); } /* Get the number of X Screens in the system * * NOTE: If Xinerama is enabled, ScreenCount(dpy) will return 1, * where as querying the screen count information from * NV-CONTROL will return the number of underlying X Screens. */ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, &num_screens); if (!ret) { fprintf(stderr, "Failed to query number of X Screens\n\n"); return 1; } printf("\n"); printf(" number of X screens (ScreenCount): %d\n", ScreenCount(dpy)); printf(" number of X screens (NV-CONTROL): %d\n\n", num_screens); for (i = 0; i < num_screens; i++) { ret = XNVCTRLQueryTargetBinaryData (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, i, // target_id 0, NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN, (unsigned char **) &pData, &len); if (!ret || (len < sizeof(pData[0]))) { fprintf(stderr, "Failed to query list of gpus\n\n"); return 1; } printf(" number of GPUs used by X screen %d: %d\n", i, pData[0]); /* List gpu number of all gpus driven by this X screen */ printf(" Indices of GPUs used by X screen %d: ", i); for (j = 1; j <= pData[0]; j++) { printf(" %d", pData[j]); } printf("\n"); XFree(pData); } printf("\n"); } /* * probe for any newly connected display devices */ else if (strcmp(argv[1], "--probe-dpys") == 0) { int num_gpus, i; printf("Display Device Probed Information:\n\n"); /* Get the number of gpus in the system */ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, &num_gpus); if (!ret) { fprintf(stderr, "Failed to query number of gpus\n\n"); return 1; } printf(" number of GPUs: %d\n", num_gpus); /* Probe and list the Display devices */ for (i = 0; i < num_gpus; i++) { int deprecated; int *pData; /* Get the gpu name */ ret = XNVCTRLQueryTargetStringAttribute (dpy, NV_CTRL_TARGET_TYPE_GPU, i, 0, NV_CTRL_STRING_PRODUCT_NAME, &str); if (!ret) { fprintf(stderr, "Failed to query gpu name\n\n"); return 1; } /* Probe the GPU for new/old display devices */ ret = XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GPU, i, 0, NV_CTRL_PROBE_DISPLAYS, &deprecated); if (!ret) { fprintf(stderr, "Failed to probe the enabled Display " "Devices on GPU-%d (%s).\n\n", i, str); return 1; } printf(" display devices on GPU-%d (%s):\n", i, str); XFree(str); /* Report results */ ret = XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_GPU, i, 0, NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU, (unsigned char **) &pData, &len); if (!ret || (len < sizeof(pData[0]))) { fprintf(stderr, "Failed to query the connected Display Devices.\n\n"); return 1; } for (j = 0; j < pData[0]; j++) { int dpyId = pData[j+1]; print_display_id_and_name(dpy, dpyId, " "); } printf("\n"); } printf("\n"); } /* * query the nvidiaXineramaInfoOrder */ else if (strcmp(argv[1], "--query-nvidia-xinerama-info-order") == 0) { ret = XNVCTRLQueryTargetStringAttribute (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, NV_CTRL_STRING_NVIDIA_XINERAMA_INFO_ORDER, &str); if (!ret) { fprintf(stderr, "Failed to query nvidiaXineramaInfoOrder.\n\n"); return 1; } printf("nvidiaXineramaInfoOrder: %s\n\n", str); } /* * assign the nvidiaXineramaInfoOrder */ else if ((strcmp(argv[1], "--assign-nvidia-xinerama-info-order")== 0) && argv[2]) { ret = XNVCTRLSetStringAttribute (dpy, screen, 0, NV_CTRL_STRING_NVIDIA_XINERAMA_INFO_ORDER, argv[2]); if (!ret) { fprintf(stderr, "Failed to assign " "nvidiaXineramaInfoOrder = \"%s\".\n\n", argv[2]); return 1; } printf("assigned nvidiaXineramaInfoOrder: \"%s\"\n\n", argv[2]); } /* * use NV_CTRL_MAX_SCREEN_WIDTH and NV_CTRL_MAX_SCREEN_HEIGHT to * query the maximum screen dimensions on each GPU in the system */ else if (strcmp(argv[1], "--max-screen-size") == 0) { int num_gpus, i, width, height; /* Get the number of gpus in the system */ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, &num_gpus); if (!ret) { fprintf(stderr, "Failed to query number of gpus.\n\n"); return 1; } for (i = 0; i < num_gpus; i++) { ret = XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GPU, i, 0, NV_CTRL_MAX_SCREEN_WIDTH, &width); if (!ret) { fprintf(stderr, "Failed to query the maximum screen " "width on GPU-%d\n\n", i); return 1; } ret = XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_GPU, i, 0, NV_CTRL_MAX_SCREEN_HEIGHT, &height); if (!ret) { fprintf(stderr, "Failed to query the maximum screen " "height on GPU-%d.\n\n", i); return 1; } printf("GPU-%d: maximum X screen size: %d x %d.\n\n", i, width, height); } } /* * demonstrate how to use NV-CONTROL to query what modelines are * used by the MetaModes of the X screen: we first query all the * MetaModes, parse out the display device names and mode names, * and then lookup the modelines associated with those mode names * on those display devices * * this could be implemented much more efficiently, but * demonstrates the general idea */ else if (strcmp(argv[1], "--print-used-modelines") == 0) { char *pMetaModes, *pModeLines[8], *tmp, *modeString; char *modeLine, *modeName, *noWhiteSpace; int MetaModeLen, ModeLineLen[8], ModeLineDpyId[8]; int dpyId; /* first, we query the MetaModes on this X screen */ XNVCTRLQueryBinaryData(dpy, screen, 0, NV_CTRL_BINARY_DATA_METAMODES_VERSION_2, (void *) &pMetaModes, &MetaModeLen); /* * then, we query the ModeLines for each display device on * this X screen; we'll need these later */ for (i = 0; i < enabledDpyIds[0]; i++) { dpyId = enabledDpyIds[i+1]; XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_DISPLAY, dpyId, 0, NV_CTRL_BINARY_DATA_MODELINES, (void *) &str, &len); pModeLines[i] = str; ModeLineLen[i] = len; ModeLineDpyId[i] = dpyId; } /* 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')) { printf("MetaMode: %s\n", start); /* * remove any white space from the string to make * parsing easier */ noWhiteSpace = remove_whitespace(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(noWhiteSpace, "::"); if (tmp) { tmp += 2; } else { tmp = noWhiteSpace; } /* Parse each mode from the metamode */ for (modeString = mode_strtok(tmp); modeString; modeString = mode_strtok(NULL)) { /* * retrieve the modeName and display device id * for this segment of the Metamode */ if (!parse_mode_string(modeString, &modeName, &dpyId)) { fprintf(stderr, " Failed to parse mode string '%s'." "\n\n", modeString); continue; } /* lookup the modeline that matches */ for (i = 0; i < enabledDpyIds[0]; i++) { if (ModeLineDpyId[i] == dpyId) { break; } } if ( i >= enabledDpyIds[0] ) { fprintf(stderr, " Failed to find modelines for " "DPY-%d.\n\n", dpyId); continue; } modeLine = find_modeline(modeName, pModeLines[i], ModeLineLen[i]); printf(" DPY-%d: %s\n", dpyId, modeLine); } printf("\n"); free(noWhiteSpace); /* move to the next MetaMode */ start = &str[j+1]; } } } /* Display all names each display device goes by */ else if (strcmp(argv[1], "--print-display-names") == 0) { int *pData; int len, i; printf("Display Device Information:\n"); ret = XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_GPU, 0, 0, NV_CTRL_BINARY_DATA_DISPLAY_TARGETS, (unsigned char **) &pData, &len); if (!ret || (len < sizeof(pData[0]))) { fprintf(stderr, "Failed to query number of display devices.\n\n"); return 1; } printf(" number of display devices: %d\n", pData[0]); for (i = 1; i <= pData[0]; i++) { printf("\n Display Device: %d\n", pData[i]); print_display_name(dpy, pData[i], NV_CTRL_STRING_DISPLAY_NAME_TYPE_BASENAME, "Type Basename"); print_display_name(dpy, pData[i], NV_CTRL_STRING_DISPLAY_NAME_TYPE_ID, "Type ID"); print_display_name(dpy, pData[i], NV_CTRL_STRING_DISPLAY_NAME_DP_GUID, "DP GUID"); print_display_name(dpy, pData[i], NV_CTRL_STRING_DISPLAY_NAME_EDID_HASH, "EDID HASH"); print_display_name(dpy, pData[i], NV_CTRL_STRING_DISPLAY_NAME_TARGET_INDEX, "Target Index"); print_display_name(dpy, pData[i], NV_CTRL_STRING_DISPLAY_NAME_RANDR, "RANDR"); } } /* * print help information */ else { printHelp: printf("\nnv-control-dpy [options]:\n\n"); printf(" ModeLine options:\n\n"); printf(" --print-modelines: print the modelines in the mode pool " "for each Display Device.\n\n"); printf(" --print-current-modeline: print the current modeline " "for each Display Device.\n\n"); printf(" --add-modeline [dpy id] [modeline]: " "add new modeline.\n\n"); printf(" --delete-modeline [dpy id] [modename]: " "delete modeline with modename.\n\n"); printf(" --generate-gtf-modeline [width] [height] [refreshrate]:" " use the GTF formula" " to generate a modeline for the specified parameters.\n\n"); printf(" --generate-cvt-modeline [width] [height] [refreshrate]" " [reduced-blanking]: use the CVT formula" " to generate a modeline for the specified parameters.\n\n"); printf(" MetaMode options:\n\n"); printf(" --print-metamodes: print the current MetaModes for the " "X screen\n\n"); printf(" --print-metamodes-version2: print the current MetaModes for " "the X screen with extended information\n\n"); printf(" --add-metamode [metamode]: add the specified " "MetaMode to the X screen's list of MetaModes.\n\n"); printf(" --delete-metamode [metamode]: delete the specified MetaMode " "from the X screen's list of MetaModes.\n\n"); printf(" --print-current-metamode: print the current MetaMode.\n\n"); printf(" --print-current-metamode-version2: print the current " "MetaMode with extended information.\n\n"); printf(" Misc options:\n\n"); printf(" --get-valid-freq-ranges: query the valid frequency " "information for each display device.\n\n"); printf(" --build-modepool: build a modepool for any display device " "that does not already have one.\n\n"); printf(" --get-assigned-dpys: query the assigned display device for " "this X screen\n\n"); printf(" --query-gpus: print GPU information and relationship to " "X screens.\n\n"); printf(" --probe-dpys: probe GPUs for new display devices\n\n"); printf(" --query-nvidia-xinerama-info-order: query the " "nvidiaXineramaInfoOrder.\n\n"); printf(" --assign-nvidia-xinerama-info-order [order]: assign the " "nvidiaXineramaInfoOrder.\n\n"); printf(" --max-screen-size: query the maximum screen size " "on all GPUs in the system\n\n"); printf(" --print-used-modelines: print the modeline for each display " "device for each MetaMode on the X screen.\n\n"); printf(" --print-display-names: print all the names associated with " "each display device on the server\n\n"); } 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; }