(none)
Lance M. Optican - LMO
lmo at lsr-vax.UUCP
Tue Nov 27 03:26:32 AEST 1990
Subject: Parallel Programming
To all:
I am learning to use the parallel
library on my 4D/140. As an exercise, I took
Paul Haeberli's amusing chaos program "smoke"
and modified it to run in parallel and display
in 3-D (and stereo, if you have it!). There is
also some code to give timing info for testing
efficiency of parallelism. I have also included
my animation version of SGI's stereo perspective
call.
I hope some of you find this of interest.
The m_fork(), etc. calls on the Iris work
wonderfully, and are easy to use. I highly
recommend the minimal effort it takes to go
through the Iris manual on parallel programming.
Another useful reference is:
"Guide to Parallel Programming on Sequent
Computer Systems", 2nd edition, A. Osterhaug, Ed.,
Prentice-Hall, 1989.
To run, just cut this note apart, and
type "make". Then "smoke" with no parameters
to see the help message.
Thanks to Paul Haeberli for posting his
original program.
Good Luck!
----------------------------------------------+--------------------------
Lance M. Optican | uunet.uu.net!lsr-vax!lmo
Laboratory of Sensorimotor Research | lsr-vax!lmo at uunet.uu.net
National Eye Institute, NIH, Bethesda, MD | (301) 496-3549
----------------------------------------------+--------------------------
---------------------------------------------
Makefile
---------------------------------------------
#
#
smoke: smoke.o stereo.o
cc -O -o smoke smoke.o stereo.o -lmpc -lgl_s -lm
smoke.o: smoke.c
cc -align16 -c -O smoke.c
stereo.o: stereo.c
cc -align16 -c -O stereo.c
---------------------------------------------
smoke.c
---------------------------------------------
/*
* smoke -
* Render a 3D Chaotic attractor on your IRIS.
* create an image of a 3-D chaotic attractor.
* From a paper by Clifford Pickover called "A Note on
* Rendering 3-D Strange Attractors" from Computers
* and Graphics Vol 12, No 2. pp. 263-267, 1988.
*
* Paul Haeberli - 1990
* paul haeberli
* paul at sgi.com
* 415-962-3665
*
* 7nov90 LM Optican Modified to run in parallel, 3-D
* and stereo! Use 3-producer and
* 1-consumer model of parallelism.
*
*/
#include <stdio.h>
#include <math.h>
#include <task.h>
#include <gl/gl.h>
#include <device.h>
#include "stereo.h"
/* timing info ... */
long start=0; /* second of start */
long stop =0; /* second of stop */
/* timing info ... */
int num_proc = 3;
/*
* make global for sharing
*/
float xxmin, xxmax;
float yymin, yymax;
float zzmin, zzmax;
float xinc, yinc, zinc;
float neighborhood;
int pstop = 0;
int iter;
int istereo = 0;
float a, b, c, d, e;
float *xi, *yi, *zi;
short val;
#define Y_WIDTH 4.0 /* width of y-field in user units */
Angle fovy = 700;
Coord nearclip = 0.25, farclip = 12.0; /* clipping planes */
Coord cx_dist = 0, cy_dist = 0, cz_dist = 4; /* camera distances */
float eye_sep = 0.15;
Object O_view = 0, O_look = 0, O_clr = 0;
Angle xangle = 0, yangle = 0, zangle = 0; /* rotation angles */
typedef struct list {
Coord x, y, z;
unsigned char r, g, b;
} LIST;
#define SIZE 512
#define LSIZE 2500
LIST buf[LSIZE] = { 0 }; /* x,y,z & r, g, b values */
int lfree = LSIZE;
#define STEP 250
main(argc, argv)
int argc;
char **argv;
{
int i;
parse_com(argc, argv); /* parse the command line */
xxmax = 2.0;
xxmin = -2.0;
yymax = 2.0;
yymin = -2.0;
zzmax = 2.0;
zzmin = -2.0;
xinc = SIZE/(xxmax-xxmin);
yinc = SIZE/(yymax-yymin);
zinc = SIZE/(zzmax-zzmin);
a = 2.24;
b = 0.43;
c = -0.65;
d = -2.43;
e = 1.00;
set_graph();
/*
* allocate processors
*/
i = cpus_online() - 1;
if (i < 1) i = 1;
if (num_proc > i) num_proc = i;
m_set_procs(num_proc+1); /* +1 for graphics consumer */
if (m_get_numprocs() != (num_proc + 1)) {
fprintf(stderr, "too few processors !\n");
exit(1);
}
iter = 3 * 1000 * LSIZE / num_proc;
xi = (float *) malloc(num_proc * sizeof(*xi));
yi = (float *) malloc(num_proc * sizeof(*yi));
zi = (float *) malloc(num_proc * sizeof(*zi));
for (i = 0; i < num_proc; i++) { /* start in different places */
xi[i] = yi[i] = zi[i] = i * xxmax / 1e2;
}
xangle = yangle = zangle = 0;
start = time ( (long *) 0 ); /* set up for current second */
do_pix();
stop = time ( (long *) 0 ); /* set up for current second */
m_kill_procs(); /* get rid of parallel procs */
ringbell();
printf("smoke done!!!\n");
printf("Elapsed Time with %d %s = %d sec\n", num_proc, (num_proc == 1 ? "cpu" : "cpus"),(stop - start));
while(1) {
pstop = 0;
do_draw();
if(qread(&val) == REDRAW) drawit();
}
}
set_graph()
{
char namebuf[100];
sprintf(namebuf, "smoke: %d CPUs\n", num_proc);
if (istereo) {
neighborhood = 2 * (xxmax - xxmin) / (WX_MAX - WX_MIN);
prefposition(WX_MIN, WX_MAX, WY_MIN, WY_MAX);
}
else {
neighborhood = 2 * (xxmax - xxmin) / SIZE;
prefposition(10, 10+SIZE, 10, 10+SIZE);
}
neighborhood *= neighborhood;
foreground(); /* required for parallel */
winopen(namebuf);
RGBmode();
doublebuffer();
gconfig();
cpack(0x000000);
clear();
swapbuffers();
clear();
makeobj(O_view);
perspective(fovy, 1.0, nearclip, farclip);
closeobj();
makeobj(O_look);
lookat(cx_dist, cy_dist, cz_dist, 0.0, 0.0, 0.0, 0);
closeobj();
if (istereo) {
stereop_set(fovy, 1.0, nearclip, farclip,
cz_dist, eye_sep / 2, O_look);
}
else {
viewport(10, 10+SIZE, 10, 10+SIZE);
callobj(O_view);
}
}
/* PARSE_COM
* parse command line
*/
parse_com(argc, argv)
register int argc;
register char **argv;
{
register char * str;
/* are there any parameters? */
if (argc < 2) {
fprintf(stderr, "Usage: smoke [flags]\n");
fprintf(stderr, "Flags:\n");
fprintf(stderr, "\t-P n: Use n processors\n");
fprintf(stderr, "\t-s: stereo\n");
return;
}
/* process parameters */
for (argv++; *argv > 0; argv++) {
str = *argv;
/*
* do flags
*/
if (*str == '-') {
while(*++str) switch(*str) {
case 'P': /* processor number */
sscanf(*(++argv), "%d", &num_proc);
break;
case 's': /* stereo */
istereo = 1;
break;
default:
fprintf(stdout, "BAD FLAG: %c\n",*str);
exit(2);
break;
} /* end while switch */
}
else {
}
}
}
do_draw()
{
int i;
for (i = 0; i < 1000; i++) {
xangle += 2;
yangle += 5;
zangle += 9;
if (xangle >= 3600) xangle -= 3600;
if (yangle >= 3600) yangle -= 3600;
if (zangle >= 3600) zangle -= 3600;
draw_eyes();
if (pstop == num_proc) return(0);
}
return(1);
}
draw_eyes()
{
int eye;
if (istereo) {
for(eye = 0; eye < 2; eye++) {
pushmatrix();
stereop_do(eye);
rotate(xangle, 'x');
rotate(yangle, 'y');
rotate(zangle, 'z');
draw_all();
popmatrix();
}
}
else {
pushmatrix();
perspective(fovy, 1.0, nearclip, farclip);
lookat(cx_dist, cy_dist, cz_dist, 0.0, 0.0, 0.0, 0);
rotate(xangle, 'x');
rotate(yangle, 'y');
rotate(zangle, 'z');
draw_all();
popmatrix();
}
swapbuffers();
}
drawit()
{
reshapeviewport();
draw_eyes();
}
draw_all()
{
int i, j;
register LIST *p;
cpack(0x000000);
clear();
for (i = 0, p = buf; i < LSIZE; i++, p++) {
RGBcolor((short) p->r, (short) p->g, (short) p->b);
pnt(p->x, p->y, p->z);
}
}
LIST *
get_index(x, y, z)
float x, y, z;
{
LIST *p;
static int indx = 0;
p = &buf[indx];
p->x = x;
p->y = y;
p->z = z;
p->r = p->g = p->b = 150;
if (++indx == LSIZE) indx = 0;
return(p);
}
LIST *
near(x, y, z)
float x, y, z;
{
register LIST *p, *m;
register int i, im;
float d, dm, dx, dy, dz;
dm = 3 * 10 * 10;
m = NULL;
if (lfree) {
for (i = im = 0, p = buf; i < LSIZE; i++, p++) {
if (p->r || p->g || p->b) {
dx = p->x - x;
dx *= dx;
if (dx > neighborhood) continue;
dy = p->y - y;
dy *= dy;
if (dy > neighborhood) continue;
dz = p->z - z;
dz *= dz;
if (dz > neighborhood) continue;
d = dx + dy + dz;
if (d < dm) {
dm = d;
m = p;
im = i;
}
}
else break; /* have hit a new list element */
}
if (i == LSIZE) return(NULL);
if (m == NULL) {
--lfree;
p->x = x;
p->y = y;
p->z = z;
return(p);
}
}
else { /* use only existing points */
for (i = im = 0, p = buf; i < LSIZE; i++, p++) {
dx = p->x - x;
dx *= dx;
dy = p->y - y;
dy *= dy;
dz = p->z - z;
dz *= dz;
d = dx + dy + dz;
if (d < dm) {
dm = d;
m = p;
im = i;
}
}
}
return(m);
}
para_pix()
{
register int i, j, me;
static int first[3] = {1, 1, 1};
static float x[3], y[3], z[3];
float xx, yy, zz;
register LIST *p;
me = m_get_myid();
if (me == num_proc) {
while(do_draw()); /* start the consumer */
return;
}
for(; (i = m_next()) < iter; ) {
if (first[me] == 1) {
first[me] = 0;
x[me] = xi[me];
y[me] = yi[me];
z[me] = zi[me];
}
xx = sin(a*y[me])-z[me]*cos(b*x[me]);
yy = z[me]*sin(c*x[me])-cos(d*y[me]);
zz = e*sin(x[me]);
x[me] = xx;
y[me] = yy;
z[me] = zz;
if (xx < xxmin || xxmax < xx ||
yy < yymin || yymax < yy ||
zz < zzmin || zzmax < zz) continue;
m_lock();
p = get_index(xx, yy, zz);
m_unlock();
switch(me) {
case 0:
p->r = 255;
break;
case 1:
p->g = 255;
break;
case 2:
p->b = 255;
break;
}
}
pstop++;
}
do_pix()
{
/*
* PARALLEL THREADS
*/
m_fork(para_pix);
/*
* SINGLE THREAD
*/
}
---------------------------------------------
stereo.h
---------------------------------------------
/*
* STEREO.H
* Header for carrying out stereo perspective
* transformations in SGI GL immediate mode
*/
#ifndef STEREO_H
#define STEREO_H
/*
* window sizes
*/
#define WX_MIN 0
#define WX_MAX 1279
#define WY_MIN 0
#define WY_MAX 1023
#define WX_SIZE (WX_MAX - WX_MIN + 1)
#define WY_SIZE (WY_MAX - WY_MIN + 1)
/*
* RV_ are the y-coords of the right-view's viewport
* LV_ are the y-coords of the left-view's viewport
*/
#define STEREO_VBLANK 41
#define RV_BOTTOM WY_MIN
#define RV_TOP (RV_BOTTOM + (WY_SIZE - STEREO_VBLANK)/2)
#define LV_BOTTOM (RV_TOP + STEREO_VBLANK)
#define LV_TOP WY_MAX
#define YMAXSTEREO RV_TOP
#define YOFFSET LV_BOTTOM
extern void stereopersp(Angle, float, float, float, float, float);
extern void sterop_set(Angle, float, float, float, float, float, Object);
extern void stereop_do(int);
#endif STEREO_H
---------------------------------------------
stereo.c
---------------------------------------------
#include <gl/gl.h>
#include "stereo.h"
#include "math.h"
extern void translate(float, float, float);
extern void window(float, float, float,float, float, float);
static float st_left[2], st_right[2], st_bottom, st_top, st_near,
st_far, st_eye[2];
Object O_view_left = 0;
Object O_view_right = 0;
/*
* calculate transformations and do them. This is
* the original function from "Iris Universe", but is
* very slow. This can be replaced by calls to
* sterop_set() and stereop_do() for speeding up loops.
*/
void
stereopersp(fovy, aspect, near, far, conv, eye_sep)
Angle fovy;
float aspect, near, far, conv, eye_sep;
{
float left, right, top, bottom;
float gltan;
gltan = tan(fovy/2.0/10.0*M_PI/180.0);
top = gltan * near;
bottom = -top;
gltan = tan(fovy*aspect/2.0/10.0*M_PI/180.0);
left = -gltan*near - eye_sep*near/conv;
right = gltan*near - eye_sep*near/conv;
window(left, right, bottom, top, near, far);
translate(-eye_sep, 0.0, 0.0);
}
/*
* function to set up transformations as objects
* to be called in a fast display loop. This is
* like the perspective call for non-3D. Note that
* "conv" is the distance to the point at which the
* eyes converge.
*/
void
stereop_set(fovy, aspect, near, far, conv, eye_sep, O_look)
Angle fovy;
float aspect, near, far, conv, eye_sep;
Object O_look; /* must be set to object for lookat() */
{
float gltan;
gltan = tan(fovy/2.0/10.0*M_PI/180.0);
st_top = gltan * near;
st_bottom = -st_top;
gltan = tan(fovy*aspect/2.0/10.0*M_PI/180.0);
/*
* right eye
*/
st_left[1] = near * (-gltan - eye_sep/conv);
st_right[1] = near * (gltan - eye_sep/conv);
/*
* left eye
*/
st_left[0] = near * (-gltan + eye_sep/conv);
st_right[0] = near * (gltan + eye_sep/conv);
st_eye[0] = -eye_sep;
st_eye[1] = eye_sep;
st_near = near;
st_far = far;
/*
* set up display objects for speed
*/
if (O_view_left == 0) O_view_left = genobj();
makeobj(O_view_left);
viewport(WX_MIN, WX_MAX, LV_BOTTOM, LV_TOP);
window(st_left[0], st_right[0], st_bottom, st_top,
st_near, st_far);
translate(-st_eye[0], 0.0, 0.0);
callobj(O_look);
closeobj();
if (O_view_right == 0) O_view_right = genobj();
makeobj(O_view_right);
viewport(WX_MIN, WX_MAX, RV_BOTTOM, RV_TOP);
window(st_left[1], st_right[1], st_bottom, st_top,
st_near, st_far);
translate(-st_eye[1], 0.0, 0.0);
callobj(O_look);
closeobj();
}
/*
* sets up stereo window for:
* rt_eye = 0 left eye
* = 1 right eye
*/
void
stereop_do(rt_eye)
int rt_eye;
{
if (rt_eye) callobj(O_view_right);
else callobj(O_view_left);
}
More information about the Comp.sys.sgi
mailing list