Re: [Chromium-dev] Re: Nvidia 3000G Support
Brian Paul <[email protected]>
| Newsgroups | gmane.comp.graphics.chromium.user,gmane.comp.graphics.chromium.devel |
|---|---|
| Message-ID | <[email protected]> |
Chartrand Katharine N. wrote: > I am running nvidia 3000gs with the 6591 driver and linux 2.4.26 and I > am not sure I have a swaplock or framelock problem. Unless you explicitly set the proper Render SPU options for framelock, you're not using that facility. And since I was never able to get the framelock feature to work here, I'm not sure the Render SPU code is up to snuff. > Everything > seems to be in sync unless I have a very large data set in a particular > application (not running over chromium). With this application, an image > on our multipanel display will be six inches out of alignment between > panels as we translate it quickly. That sounds like ordinary network/Chromium latency. The tilesort SPU sends geometry in round-robin order to the servers so there is some latency in the updates from one server to the next. > My hunch, however, was that the > problem was with > the application, not the cards because we see the same behavior with our > wildcats cards. Probably Chromium, not the application. > This 6591 driver was given to us by nvidia to stop a combination of > problems: stereo flickering and chromium apps crashing, and it seems to > have fixed them both. I don't believe it is a released driver, but I will > ask our nvidia contact if I can distribute it. My questions are: > > 1. can I have a copy of your test program so I can see if I have this > framelock problem (and don't know it!) with this 6591 driver. Attached. I've sent it to so many people I figured everyone had it by now. :) > 2. what are the exact symptoms of this type of framelock, swaplock > problem. For example, would stereo work at all with this framelock problem > you describe. Would you just get a flicker in the stereo? Stereo would probably "work" but the left/right synchronization among all the screens wouldn't occur. It would confuse your eyes and maybe give you a headache after a while. -Brian
swaplock.c
(text/plain, 8.7 KB)
/*
* Test the NVIDIA Quadro FX 3000G swap-lock feature.
* Brian Paul
* 9 April 2004
*
* Usage:
* Run an instance of this program on two or more systems with 3000G cards.
* For each instance, specify a different frame time (interval).
* For example:
* in shell#1: ./swaplock -f 300
* in shell#2: ./swaplock -f 1000
*
* The first instance will issue glXSwapBuffers every 300 ms and the second
* instance will issue glXSwapBuffers every 1000 ms.
* If frame lock is working, the glXSwapBuffer calls should be synchronized
* so both windows will animate at the same rate.
*/
#define GLX_GLXEXT_PROTOTYPES
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
typedef Bool (*glXJoinSwapGroupNVFunc_t)(Display *dpy, GLXDrawable drawable, GLuint group);
typedef Bool (*glXBindSwapBarrierNVFunc_t)(Display *dpy, GLuint group, GLuint barrier);
typedef Bool (*glXQuerySwapGroupNVFunc_t)(Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
typedef Bool (*glXQueryMaxSwapGroupsNVFunc_t)(Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
typedef Bool (*glXQueryFrameCountNVFunc_t)(Display *dpy, int screen, GLuint *count);
typedef Bool (*glXResetFrameCountNVFunc_t)(Display *dpy, int screen);
static glXJoinSwapGroupNVFunc_t glXJoinSwapGroupNV_func = NULL;
static glXBindSwapBarrierNVFunc_t glXBindSwapBarrierNV_func = NULL;
static glXQuerySwapGroupNVFunc_t glXQuerySwapGroupNV_func = NULL;
static glXQueryMaxSwapGroupsNVFunc_t glXQueryMaxSwapGroupsNV_func = NULL;
static glXQueryFrameCountNVFunc_t glXQueryFrameCountNV_func = NULL;
static glXResetFrameCountNVFunc_t glXResetFrameCountNV_func = NULL;
static GLfloat Angle = 0.0;
static void
draw(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(Angle, 0.0, 0.0, 1.0);
glBegin(GL_POLYGON);
glVertex2f(-2, -5);
glVertex2f( 2, -5);
glVertex2f( 0, 5);
glEnd();
glPopMatrix();
}
/* new window size or exposure */
static void
reshape(int width, int height)
{
GLfloat h = (GLfloat) height / (GLfloat) width;
glViewport(0, 0, (GLint) width, (GLint) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -40.0);
}
static void
init(Display *dpy)
{
int scr = DefaultScreen(dpy);
const char *ext;
ext = glXQueryExtensionsString(dpy, scr);
if (!strstr(ext, "GLX_NV_swap_group")) {
printf("Error: This program requires GLX_NV_swap_group!\n");
exit(1);
}
glXJoinSwapGroupNV_func = (glXJoinSwapGroupNVFunc_t) glXGetProcAddressARB((const GLubyte *) "glXJoinSwapGroupNV");
glXBindSwapBarrierNV_func = (glXBindSwapBarrierNVFunc_t) glXGetProcAddressARB((const GLubyte *) "glXBindSwapBarrierNV");
glXQuerySwapGroupNV_func = (glXQuerySwapGroupNVFunc_t) glXGetProcAddressARB((const GLubyte *) "glXQuerySwapGroupNV");
glXQueryMaxSwapGroupsNV_func = (glXQueryMaxSwapGroupsNVFunc_t) glXGetProcAddressARB((const GLubyte *) "glXQueryMaxSwapGroupsNV");
glXQueryFrameCountNV_func = (glXQueryFrameCountNVFunc_t) glXGetProcAddressARB((const GLubyte *) "glXQueryFrameCountNV");
glXResetFrameCountNV_func = (glXResetFrameCountNVFunc_t) glXGetProcAddressARB((const GLubyte *) "glXResetFrameCountNV");
glEnable(GL_DEPTH_TEST);
}
/*
* Create an RGB, double-buffered window.
* Return the window and context handles.
*/
static void
make_window( Display *dpy, const char *name,
int x, int y, int width, int height,
Window *winRet, GLXContext *ctxRet)
{
int attrib[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DOUBLEBUFFER,
GLX_DEPTH_SIZE, 1,
None };
int scrnum;
XSetWindowAttributes attr;
unsigned long mask;
Window root;
Window win;
GLXContext ctx;
XVisualInfo *visinfo;
scrnum = DefaultScreen( dpy );
root = RootWindow( dpy, scrnum );
visinfo = glXChooseVisual( dpy, scrnum, attrib );
if (!visinfo) {
printf("Error: couldn't get an RGB, Double-buffered visual\n");
exit(1);
}
/* window attributes */
attr.background_pixel = 0;
attr.border_pixel = 0;
attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
win = XCreateWindow( dpy, root, 0, 0, width, height,
0, visinfo->depth, InputOutput,
visinfo->visual, mask, &attr );
/* set hints and properties */
{
XSizeHints sizehints;
sizehints.x = x;
sizehints.y = y;
sizehints.width = width;
sizehints.height = height;
sizehints.flags = USSize | USPosition;
XSetNormalHints(dpy, win, &sizehints);
XSetStandardProperties(dpy, win, name, name,
None, (char **)NULL, 0, &sizehints);
}
ctx = glXCreateContext( dpy, visinfo, NULL, True );
if (!ctx) {
printf("Error: glXCreateContext failed\n");
exit(1);
}
XFree(visinfo);
*winRet = win;
*ctxRet = ctx;
}
static void
event_loop(Display *dpy, Window win, int frameTime)
{
while (1) {
while (XPending(dpy) > 0) {
XEvent event;
XNextEvent(dpy, &event);
switch (event.type) {
case Expose:
/* we'll redraw below */
break;
case ConfigureNotify:
reshape(event.xconfigure.width, event.xconfigure.height);
break;
case KeyPress:
{
char buffer[10];
int r, code;
code = XLookupKeysym(&event.xkey, 0);
r = XLookupString(&event.xkey, buffer, sizeof(buffer),
NULL, NULL);
if (buffer[0] == 27) {
/* escape */
return;
}
}
}
}
draw();
if (0)
{
/* insert a random delay */
int ms = (rand() % 5) * 100 + 500; /* 500 to 1000 ms */
usleep(ms * 1000);
}
else {
usleep(frameTime * 1000);
}
glXSwapBuffers(dpy, win);
if (0)
{
unsigned int c;
glXQueryFrameCountNV_func(dpy, DefaultScreen(dpy), &c);
printf("Frame Count: %d\n", c);
}
/* next frame */
Angle += 5.0;
}
}
int
main(int argc, char *argv[])
{
Display *dpy;
Window win;
GLXContext ctx;
char *dpyName = ":0";
GLboolean printInfo = GL_FALSE;
int i;
struct timeval tv;
int group = 1;
int barrier = 1;
int frameTime = 500;
gettimeofday(&tv, NULL);
srand(tv.tv_usec);
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-display") == 0) {
dpyName = argv[i+1];
i++;
}
else if (strcmp(argv[i], "-info") == 0) {
printInfo = GL_TRUE;
}
else if (strcmp(argv[i], "-g") == 0) {
group = atoi(argv[i+1]);
i++;
}
else if (strcmp(argv[i], "-b") == 0) {
barrier = atoi(argv[i+1]);
i++;
}
else if (strcmp(argv[i], "-f") == 0) {
frameTime = atoi(argv[i+1]);
i++;
}
}
printf("Using swap group %d, barrier %d\n", group, barrier);
printf("Frame time = %d ms\n", frameTime);
dpy = XOpenDisplay(dpyName);
if (!dpy) {
printf("Error: couldn't open display %s\n", dpyName);
return -1;
}
make_window(dpy, "NV swap lock test", 0, 0, 800, 800, &win, &ctx);
XMapWindow(dpy, win);
glXMakeCurrent(dpy, win, ctx);
if (printInfo) {
printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
}
init(dpy);
/* swap lock setup */
{
unsigned int maxGroups, maxBarriers, b;
int scr = DefaultScreen(dpy);
b = glXQueryMaxSwapGroupsNV_func(dpy, scr, &maxGroups, &maxBarriers);
if (!b) {
printf("Error: glXQueryMaxSwapGroupsNV failed!\n");
}
else {
printf("glXQueryMaxSwapGroupsNV: maxGroups=%d maxBarriers=%d\n",
maxGroups, maxBarriers);
}
b = glXJoinSwapGroupNV_func(dpy, win, group);
if (!b) {
printf("Error: glXJoinSwapGroupNV(group=%d) failed!\n", group);
}
else {
printf("glXJoinSwapGroupNV worked!\n");
}
b = glXBindSwapBarrierNV_func(dpy, group, barrier);
if (!b) {
printf("Error: glBindSwapBarrierNV(group=%d, barrier=%d) failed!\n",
group, barrier);
}
else {
printf("glXBindSwapBarrierNV worked!\n");
}
}
event_loop(dpy, win, frameTime);
glXDestroyContext(dpy, ctx);
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
return 0;
}