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;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.