Ralph Seguin (seguin++at++vr1.engin.umich.edu)
Mon, 21 Nov 1994 23:54:26 -0500
Ok. I have a question. We have a GL program that uses VLIB from
FakeSpace to drive a boom3C.
We are trying to drive a variety of different Onyx configurations
as well as boom configurations.
Onyx: 2 or more processors, 1 or 2 RE2 pipes
Boom2C, Boom3C, Boom3C Plus
The program was not very well developed originally, and we want
to get it going in MP mode. Unfortunately, I don't think that
there is an easy way of doing this. VLIB isn't structured to
allow us to do it easily, and GL has some factors that hurt
this as well.
We'd like to structure the code so that we have at least 1
process per pipe.
GL seems to have the rendering window as a state variable (ie,
I set the current window via a winset() and then all rendering
happens on that window). Ideally, there would be another
parameter to GL functions which is the window id to operate on.
What happens is that the program behaves in a non-deterministic
fashion. I think that the child process sets the rendering window
and starts rendering, and then the parent sets the render window to the
right eye and starts rendering. The problem is that the GL current
render window has been reassigned "underneath the child processes feet".
I imagine that it is too expensive to do a winset() before each
GL function call, and furthermore, is not guaranteed to work.
The problem is this:
VLIB has a vr_draw() function, which calls our drawing function
as a callback, once per eye. It loads the appropriate transformation
matrices (for each eye), before calling our rendering callback.
We're doing an sproc(). Do we have to do a heavyweight fork()
instead? Ie, if we do a fork(), we now have another copy of the
GL library, such that each process now has its state variable for
the current rendering window. My concern with doing a fork() is
that it will be more difficult to manage things without the
shared memory.
Thanks, Ralph
Here's a snippet of code:
// The shared memory arena, semaphores get built in here
static usptr_t *sharedArena=NULL;
// the PID of the parent process
static pid_t parentPid=0;
// Child PID, left eye renders with this PID (sproc())
static pid_t childPid=0; // Child forked yet?
// use a semaphore to cause child to block until the right time to render
static usema_t *child0Semaphore=NULL;
// The name of the shared memory arena
char arenaName[256];
// Used by child and parent
static boomrec *leftEyeBoomrecptr=NULL;
static int leftEyeColor=0;
// This is the child process which actually renders the
// left eye
void
PRendLeftEye(void *sdata)
{
register World *world=(World *)sdata;
pid_t myPid=getpid();
// Loop forever
while (1)
{
long savewin;
int rc;
// Wait until we're told to render by the parent process
// Hopefully, the semaphore routines will cause the
// child to block properly, instead of busywaiting.
rc=uspsema(child0Semaphore);
fprintf(stderr, "child(%d): down(%x) ==> %d\n", (int)myPid, child0Semaphore, rc);
if(world->graphicsData->boomMode == BOOM_STDRES_MONO ||
world->graphicsData->boomMode == BOOM_HIRES_MONO)
{
vr_color(world->graphicsData->boomrecptr, 127, 20, 255);
}
// Now do the rendering stuff
savewin=winget(); // Save and set the render window (pipe)
fprintf(stderr, "child(%d): sw=%d, p0=%d, p1=%d\n", myPid,
world->graphicsData->glWindowPipe0,
world->graphicsData->glWindowPipe1);
// winset(world->graphicsData->glWindowPipe0); // left pipe
pushmatrix(); // save current xformations
// Load the left eye xformation matrix
vr_load_eye_matrix(leftEyeBoomrecptr, LEFTEYE);
/* call the actual drawing function */
drawScene(leftEyeBoomrecptr, leftEyeColor,
world->graphicsData->boomScaleFactor);
popmatrix(); // Restore the xformation stuff
// winset(savewin); // Restore the prev window????
}
}
// Draw the scene on the left eye
// Really, just tell the child process (reader) to go ahead and do it
// Do this via a semaphore, wake up the child with a semaphore
int
DrawLeftEye(World *world, boomrec *boomrecptr, int color)
{
int rc;
leftEyeColor=color;
leftEyeBoomrecptr=boomrecptr;
if (! childPid)
{
// First time through, set up rendering for left eye
// on a child process.
// Get the PID for the parent (this) process
parentPid=getpid();
// Set the filename for the shared memory arena
sprintf(arenaName, "/usr/tmp/viewsvr.shm.%d", (int)parentPid);
fprintf(stderr, "parent(%d): SHM fn=\"%s\"\n", (int)parentPid, arenaName);
// Initialize shared memory arena
sharedArena=usinit(arenaName);
// Initialize the semaphore, make sure child blocks immediately
child0Semaphore=usnewsema(sharedArena, 0);
fprintf(stderr, "parent(%d): usnewsema(%x) ==> %x\n", (int)parentPid, sharedArena,
child0Semaphore);
// sproc() (fork) the left eye child
childPid=sproc(PRendLeftEye, PR_SADDR, (void *)world);
fprintf(stderr, "parent(%d): sproc() ==> %d\n", (int)parentPid, (int)childPid);
}
rc=usvsema(child0Semaphore); // unlock (increment) the semaphore
fprintf(stderr, "parent(%d): up(%x) ==> %d\n", (int)parentPid, child0Semaphore, rc);
return 1; // everything cool
}
// This is the callback function called by vr_draw() from VLIB
// It is called 1-4 times per eye (once/eye on 3C mode)
int
RenderWorld(boomrec *bp, EyeType eye, int color)
{
if (eye == LEFTEYE)
{
DrawLeftEye(world, bp, color);
}
else
{
DrawRightEye(world, bp, color);
}
return 1;
}
This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:50:40 PDT