* Copyright (c) 2006-2007 NVIDIA, Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
* nv-control-framelock.c - NV-CONTROL client that demonstrates how to
* interact with the frame lock capabilities on an X Server.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include "NVCtrl.h"
#include "NVCtrlLib.h"
* do_help()
*
* Prints some help on how to use this app.
*
*/
static void do_help(void)
{
printf("usage:\n");
printf("-q: query system frame lock information.\n");
printf("-e: enable frame lock on system.\n");
printf("-d: disable frame lock on system.\n");
printf("\n");
}
* do_query()
*
* Prints information for all frame lock (Quadro Sync) devices found on
* the given X server.
*
*/
static void do_query(Display *dpy)
{
Bool ret;
int num_framelocks;
int framelock;
int gpu, display;
int *gpu_data, *display_data;
char *gpu_name, *display_name;
int len;
int i, j;
int enabled;
int current_config;
int display_enabled;
const char *current_str;
ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK,
&num_framelocks);
if (!ret) {
printf("Failed to query number of frame lock devices!\n");
return;
}
printf("Found %d frame lock device(s) on server.\n", num_framelocks);
if ( !num_framelocks ) {
return;
}
for (framelock = 0; framelock < num_framelocks; framelock++) {
printf("\n");
printf("- Frame Lock Board %d :\n", framelock);
ret = XNVCTRLQueryTargetBinaryData
(dpy,
NV_CTRL_TARGET_TYPE_FRAMELOCK,
framelock,
0,
NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK,
(unsigned char **) &gpu_data,
&len);
if (!ret) {
printf(" - Failed to query list of GPUs!\n");
continue;
}
if ( !gpu_data[0] ) {
printf(" - No GPUs found!\n");
} else {
printf(" - Found %d GPU(s).\n", gpu_data[0]);
}
for (i = 1; i <= gpu_data[0]; i++) {
gpu = gpu_data[i];
ret = XNVCTRLQueryTargetStringAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_STRING_PRODUCT_NAME,
&gpu_name);
if (!ret) {
printf(" - Failed to query GPU %d product name.\n", gpu);
continue;
}
printf(" - GPU %d (%s) :\n", gpu, gpu_name);
XFree(gpu_name);
printf(" - Sync : ");
ret = XNVCTRLQueryTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_FRAMELOCK_SYNC,
&enabled);
if (!ret) {
printf("Failed to query sync state.\n");
} else {
printf("%sabled\n", enabled ? "En" : "Dis");
}
ret = XNVCTRLQueryTargetBinaryData
(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU,
(unsigned char **) &display_data,
&len);
if (!ret) {
printf(" - Failed to query connected displays.\n");
continue;
}
if (!display_data[0]) {
printf(" - No Connected Displays found.\n");
}
for (j = 1; j <= display_data[0]; j++) {
display = display_data[j];
ret = XNVCTRLQueryTargetAttribute
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_DISPLAY_ENABLED,
&display_enabled);
if (!ret) {
printf(" - Failed to query enabled displays.\n");
continue;
}
if (!display_enabled) {
continue;
}
ret = XNVCTRLQueryTargetAttribute
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG,
¤t_config);
if (!ret) {
current_config = -1;
}
if (current_config == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER) {
current_str = " - Server";
} else if (current_config ==
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT) {
current_str = " - Client";
} else if (current_config ==
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED) {
current_str = " - Disabled";
} else {
current_str = " - Unknown";
}
ret = XNVCTRLQueryTargetStringAttribute
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_STRING_DISPLAY_NAME_RANDR,
&display_name);
if (ret && display_name) {
printf(" - Display : %s%s\n", display_name, current_str);
XFree(display_name);
} else {
printf(" - Display : 0x%08x%s\n", display, current_str);
}
}
XFree(display_data);
}
XFree(gpu_data);
}
}
* do_enable()
*
* Enables frame lock on the X Server by setting the first capable/available
* display device as the frame lock server and setting all other display
* devices as clients.
*
* NOTE: It is up to the user to ensure that each display device is set with
* the same refresh rate (mode timings).
*
*/
static void do_enable(Display *dpy)
{
Bool ret;
int num_framelocks;
int framelock;
int gpu, display;
int *gpu_data, *display_data;
char *display_name;
int len;
int i, j;
int enabled;
int serverable;
int pick_server = 1;
int server_set = 0;
NVCTRLAttributeValidValuesRec values;
ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK,
&num_framelocks);
if (!ret) {
printf("Failed to query number of frame lock devices!\n");
return;
}
printf("Found %d frame lock device(s) on server.\n", num_framelocks);
if ( !num_framelocks ) {
return;
}
for (framelock = 0; framelock < num_framelocks; framelock++) {
printf("\n");
printf("- Frame Lock Board %d :\n", framelock);
ret = XNVCTRLQueryTargetBinaryData
(dpy,
NV_CTRL_TARGET_TYPE_FRAMELOCK,
framelock,
0,
NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK,
(unsigned char **) &gpu_data,
&len);
if (!ret) {
printf(" - Failed to query list of GPUs!\n");
continue;
}
if ( !gpu_data[0] ) {
printf(" - No GPUs found!\n");
} else {
printf(" - Found %d GPU(s).\n", gpu_data[0]);
}
for (i = 1; i <= gpu_data[0]; i++) {
gpu = gpu_data[i];
printf(" - Enabling Quadro Sync Device %d - GPU %d...\n",
framelock, gpu);
ret = XNVCTRLQueryTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_FRAMELOCK_SYNC,
&enabled);
if (!ret) {
printf(" - Failed to query Frame lock state.\n");
continue;
}
if (enabled != NV_CTRL_FRAMELOCK_SYNC_DISABLE) {
printf(" - Frame lock already enabled!\n");
continue;
}
ret = XNVCTRLQueryTargetBinaryData
(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU,
(unsigned char **) &display_data,
&len);
if (!ret) {
printf(" - Failed to query enabled displays.\n");
continue;
}
if (!display_data[0]) {
printf(" - No Connected Displays found!\n");
}
for (j = 1; j <= display_data[0]; j++) {
display = display_data[j];
ret = XNVCTRLQueryTargetAttribute
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_DISPLAY_ENABLED,
&enabled);
if (!ret) {
printf(" - Failed to query enabled displays.\n");
continue;
}
if (!enabled) {
continue;
}
ret = XNVCTRLQueryValidTargetAttributeValues
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG,
&values);
if (!ret) {
continue;
}
serverable = (values.u.bits.ints &
(1 << NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER));
ret = XNVCTRLQueryTargetStringAttribute
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_STRING_DISPLAY_NAME_RANDR,
&display_name);
if (ret && display_name) {
printf(" - Display %s", display_name);
XFree(display_name);
} else {
printf(" - Display 0x%08x", display);
}
if (pick_server && serverable) {
XNVCTRLSetTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_FRAMELOCK,
framelock,
0,
NV_CTRL_USE_HOUSE_SYNC,
NV_CTRL_USE_HOUSE_SYNC_FALSE);
XNVCTRLSetTargetAttribute
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG,
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER);
server_set = 1;
pick_server = 0;
printf(" - Set as Server\n");
} else {
XNVCTRLSetTargetAttribute
(dpy,
NV_CTRL_TARGET_TYPE_DISPLAY,
display,
0,
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG,
NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT);
printf(" - Set as Client\n");
}
}
XFree(display_data);
XNVCTRLSetTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_FRAMELOCK_SYNC,
NV_CTRL_FRAMELOCK_SYNC_ENABLE);
XFlush(dpy);
printf(" - Frame Lock Sync Enabled.\n");
* to guarantee accuracy of the universal frame count (as
* returned by the glXQueryFrameCountNV() function in the
* GLX_NV_swap_group extension).
*/
if (server_set) {
XNVCTRLSetTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_FRAMELOCK_TEST_SIGNAL,
NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE);
XNVCTRLSetTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_FRAMELOCK_TEST_SIGNAL,
NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE);
printf(" - Frame Lock Test Signal Toggled.\n");
server_set = 0;
}
}
XFree(gpu_data);
}
}
static void do_disable(Display *dpy)
{
Bool ret;
int num_framelocks;
int framelock;
int gpu;
int *data;
int len;
int i;
ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK,
&num_framelocks);
if (!ret) {
printf("Failed to query number of frame lock devices!\n");
return;
}
printf("Found %d frame lock device(s) on server.\n", num_framelocks);
if ( !num_framelocks ) {
return;
}
for (framelock = 0; framelock < num_framelocks; framelock++) {
printf("\n");
printf("- Frame Lock Board %d :\n", framelock);
ret = XNVCTRLQueryTargetBinaryData
(dpy,
NV_CTRL_TARGET_TYPE_FRAMELOCK,
framelock,
0,
NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK,
(unsigned char **) &data,
&len);
if (!ret) {
printf(" - Failed to query list of GPUs!\n");
continue;
}
if ( !data[0] ) {
printf(" - No GPUs found!\n");
} else {
printf(" - Found %d GPU(s).\n", data[0]);
}
for (i = 1; i <= data[0]; i++) {
gpu = data[i];
printf(" - Disabling Quadro Sync Device %d - GPU %d... ",
framelock, gpu);
XNVCTRLSetTargetAttribute(dpy,
NV_CTRL_TARGET_TYPE_GPU,
gpu,
0,
NV_CTRL_FRAMELOCK_SYNC,
NV_CTRL_FRAMELOCK_SYNC_DISABLE);
XFlush(dpy);
printf("Done.\n");
}
XFree(data);
}
}
int main(int argc, char *argv[])
{
Display *dpy;
Bool ret;
int major, minor;
* 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) {
printf("Cannot open display '%s'.\n", XDisplayName(NULL));
return 1;
}
ret = XNVCTRLQueryVersion(dpy, &major, &minor);
if (ret != True) {
printf("The NV-CONTROL X extension does not exist on '%s'.\n",
XDisplayName(NULL));
return 1;
}
printf("Using NV-CONTROL extension %d.%d on %s\n\n",
major, minor, XDisplayName(NULL));
if ((major < 1) || (major == 1 && minor < 9)) {
printf("The NV-CONTROL X extension is too old. Version 1.9 or above "
" is required for configuring Frame Lock via target types.\n");
return 1;
}
if (argc <= 1 || (strcmp(argv[1], "-q") == 0)) {
do_query(dpy);
} else if (strcmp(argv[1], "-e") == 0) {
do_enable(dpy);
} else if (strcmp(argv[1], "-d") == 0) {
do_disable(dpy);
} else {
do_help();
}
return 0;
}