| /*************************************************************************/ |
| /* */ |
| /* Copyright (c) 1994 Stanford University */ |
| /* */ |
| /* All rights reserved. */ |
| /* */ |
| /* Permission is given to use, copy, and modify this software for any */ |
| /* non-commercial purpose as long as this copyright notice is not */ |
| /* removed. All other uses, including redistribution in whole or in */ |
| /* part, are forbidden without prior written permission. */ |
| /* */ |
| /* This software is provided with absolutely no warranty and no */ |
| /* support. */ |
| /* */ |
| /*************************************************************************/ |
| |
| |
| /* |
| * NAME |
| * prt - parallel ray tracer |
| * |
| * SYNOPSIS |
| * prt [options] envfile |
| * |
| * -h Print this usage message. |
| * -a<n> Enable antialiasing with n subpixels (default = 1). |
| * -m<n> Request n megabytes of global memory (default = 32). |
| * -p<n> Run on n processors (default = 1). |
| * |
| * DESCRIPTION |
| * |
| * RETURNS |
| * PRT returns an exit code of 0 to the OS for successful operation; it |
| * returns a non-zero exit code (usually 1) if any type of error occurs. |
| * |
| * EXAMPLES |
| * To ray trace cube.env on 1 processor and default global memory size: |
| * |
| * prt cube.env |
| * |
| * To ray trace car.env on 4 processors and 72MB of global memory: |
| * |
| * prt -p4 -m72 car.env |
| * |
| * FILES |
| * |
| * SEE ALSO |
| * |
| * DIAGNOSTICS |
| * All error messages take the form: |
| * |
| * prt: Text of the error message. |
| * |
| * All possible error messages are listed below, including the potential |
| * cause of the error, and the corrective action, if any. |
| * |
| * FATAL ERRORS |
| * Invalid option '%c'. |
| * The command line included an option which was not |
| * recognized. Check your command line syntax, remove |
| * the offending option, and try again. |
| * |
| * Cannot open file "filename". |
| * The specified file could not be found, or some other |
| * OS error prevented it from being opened. Check your |
| * typing and try again. |
| * |
| * Cannot allocate local memory. |
| * malloc() failed for some reason. |
| * |
| * Cannot allocate global memory. |
| * G_MALLOC() failed for some reason. |
| * |
| * Valid range for #processors is [1, %ld]. |
| * Do not exceed the ranges shown by the message. |
| * |
| */ |
| |
| #define MAIN /* indicate to rt.H that we need main_env for this file*/ |
| #define VERSION "1.00" |
| |
| |
| #include <stdio.h> |
| #include <math.h> |
| #include "rt.h" |
| |
| |
| CHAR *ProgName = "RAYTRACE"; /* The program name. */ |
| INT nprocs = 1; /* The number of processors to use. */ |
| INT MaxGlobMem = 32; /* Maximum global memory needed (MB).*/ |
| INT NumSubRays = 1; /* Number of subpixel samples to calc*/ |
| INT dostats = 0; |
| |
| |
| /* |
| * NAME |
| * Usage - print proper usage message |
| * |
| * SYNOPSIS |
| * VOID Usage() |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| |
| VOID Usage() |
| { |
| fprintf(stdout, "%s - parallel ray tracer\n", ProgName); |
| fprintf(stdout, "Version %s\n\n", VERSION); |
| |
| fprintf(stdout, "Usage:\t%s [options] envfile\n\n", ProgName); |
| |
| fprintf(stdout, "\t-h\tPrint this usage message.\n"); |
| fprintf(stdout, "\t-a<n>\tEnable antialiasing with n subpixels (default = 1).\n\tWhen using with SPLASH suite for evaluation, use default (no antialiasing)\n"); |
| fprintf(stdout, "\t-m<n>\tRequest n megabytes of global memory (default = 32).\n"); |
| fprintf(stdout, "\t-p<n>\tRun on n processors (default = 1).\n"); |
| fprintf(stdout, "\t-s\tMeasure and print per-process timing information.\n"); |
| fprintf(stdout, "\n"); |
| } |
| |
| |
| |
| /* |
| * NAME |
| * PrintStatistics - print out various ray tracer statistics |
| * |
| * SYNOPSIS |
| * VOID PrintStatistics() |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| |
| VOID PrintStatistics() |
| { |
| /* |
| printf("\n****** Ray trace Stats ******\n"); |
| |
| printf("\tResolution:\t\t%ld by %ld\n", Display.xres+1, Display.yres+1); |
| printf("\tNumber Lights:\t\t%ld\n", nlights); |
| printf("\tAnti level:\t\t%ld\n", Display.maxAAsubdiv); |
| printf("\tTotal Rays:\t\t%ld\n", Stats.total_rays); |
| printf("\tPrimary Rays:\t\t%ld\n", Stats.prim_rays); |
| printf("\tShadow Rays:\t\t%ld\n", Stats.shad_rays); |
| printf("\tShadow Rays Hit:\t%ld\n", Stats.shad_rays_hit); |
| printf("\tShadow Rays Not Hit:\t%ld\n", Stats.shad_rays_not_hit); |
| printf("\tShadow Coherence Rays:\t%ld\n", Stats.shad_coherence_rays); |
| printf("\tReflective Rays:\t%ld\n", Stats.refl_rays); |
| printf("\tTransmissiveRays:\t%ld\n", Stats.trans_rays); |
| printf("\tAnti-Aliasing Rays:\t%ld\n", Stats.aa_rays); |
| printf("\tBackground Pixels:\t%ld\n", Stats.coverage); |
| printf("\tMax Tree depth reached:\t%ld\n", Stats.max_tree_depth); |
| printf("\tMax # prims tested for a ray:\t%ld\n", Stats.max_objs_ray); |
| printf("\tMax Rays shot for a pixel:\t%ld\n", Stats.max_rays_pixel); |
| printf("\tMax # prims tested for a pixel:\t%ld\n", Stats.max_objs_pixel); |
| printf("\n"); |
| */ |
| |
| if (TraversalType == TT_HUG) |
| { |
| /* prn_ds_stats(); |
| prn_tv_stats(); */ |
| ma_print(); |
| } |
| } |
| |
| |
| |
| /* |
| * NAME |
| * StartRayTrace - starting point for all ray tracing proceses |
| * |
| * SYNOPSIS |
| * VOID StartRayTrace() |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| |
| VOID StartRayTrace() |
| { |
| INT pid; /* Our internal process id number. */ |
| UINT begin; |
| UINT end; |
| UINT lapsed; |
| |
| |
| LOCK(gm->pidlock) |
| pid = gm->pid++; |
| UNLOCK(gm->pidlock) |
| |
| if ((pid == 0) || (dostats)) |
| CLOCK(begin); |
| |
| /* POSSIBLE ENHANCEMENT: Here's where one might lock processes down |
| to processors if need be */ |
| |
| InitWorkPool(pid); |
| InitRayTreeStack(Display.maxlevel, pid); |
| |
| /* |
| * Wait for all processes to be created, initialize their work |
| * pools, and arrive at this point; then proceed. This BARRIER |
| * is absolutely required. Read comments in PutJob before |
| * moving this barrier. |
| */ |
| |
| BARRIER(gm->start, gm->nprocs) |
| |
| /* POSSIBLE ENHANCEMENT: Here's where one would RESET STATISTICS |
| and TIMING if one wanted to measure only the parallel part */ |
| |
| RayTrace(pid); |
| |
| |
| if ((pid == 0) || (dostats)) { |
| CLOCK(end); |
| gm->partime[pid] = (end - begin) & 0x7FFFFFFF; |
| if (pid == 0) gm->par_start_time = begin; |
| } |
| } |
| |
| |
| |
| /* |
| * NAME |
| * main - mainline for the program |
| * |
| * SYNOPSIS |
| * INT main(argc, argv) |
| * INT argc; |
| * CHAR *argv[]; |
| * |
| * DESCRIPTION |
| * Main parses command line arguments, opens/closes the files involved, |
| * performs initializations, reads in the model database, partitions it |
| * as needed, and calls StartTraceRay() to do the work. |
| * |
| * RETURNS |
| * 0 if successful. |
| * 1 for any type of failure. |
| */ |
| |
| int main(argc, argv) |
| int argc; |
| CHAR *argv[]; |
| { |
| INT i; |
| UINT begin; |
| UINT end; |
| UINT lapsed; |
| U16 tmp; |
| CHAR *pch; |
| MATRIX vtrans, Vinv; /* View transformation and inverse. */ |
| |
| |
| /* |
| * First, process command line arguments. |
| */ |
| |
| while (argc-- > 1 && (*++argv)[0] == '-') |
| for (pch = argv[0] + 1; *pch != '\0'; pch++) |
| switch (*pch) |
| { |
| case '?': |
| case 'h': |
| case 'H': |
| Usage(); |
| exit(1); |
| |
| case 'a': |
| case 'A': |
| AntiAlias = TRUE; |
| if (*++pch) |
| NumSubRays = atoi(pch); |
| |
| *pch = '\0'; |
| pch--; |
| break; |
| |
| case 'm': |
| if (*++pch) |
| MaxGlobMem = atoi(pch); |
| |
| *pch = '\0'; |
| pch--; |
| break; |
| |
| case 'p': |
| if (*++pch) |
| nprocs = atoi(pch); |
| |
| *pch = '\0'; |
| pch--; |
| break; |
| |
| case 's': |
| case 'S': |
| dostats = TRUE; |
| break; |
| |
| default: |
| fprintf(stderr, "%s: Invalid option \'%c\'.\n", ProgName, *pch); |
| exit(1); |
| } |
| |
| |
| /* |
| * If no more command line arguments, the environment file name |
| * is missing. Print a usage message and terminate. |
| */ |
| |
| if (!argc) |
| { |
| Usage(); |
| exit(1); |
| } |
| |
| |
| /* |
| * Make sure nprocs is within valid range. |
| */ |
| |
| if (nprocs < 1 || nprocs > MAX_PROCS) |
| { |
| fprintf(stderr, "%s: Valid range for #processors is [1, %ld].\n", ProgName, MAX_PROCS); |
| exit(1); |
| } |
| |
| |
| /* |
| * Print command line parameters. |
| */ |
| |
| printf("\n"); |
| printf("Number of processors: \t%ld\n", nprocs); |
| printf("Global shared memory size:\t%ld MB\n", MaxGlobMem); |
| printf("Samples per pixel: \t%ld\n", NumSubRays); |
| printf("\n"); |
| |
| |
| /* |
| * Initialize the shared memory environment and request the total |
| * amount of amount of shared memory we might need. This |
| * includes memory for the database, grid, and framebuffer. |
| */ |
| |
| MaxGlobMem <<= 20; /* Convert MB to bytes. */ |
| MAIN_INITENV(,MaxGlobMem + 512*1024) |
| gm = (GMEM *)G_MALLOC(sizeof(GMEM)); |
| |
| |
| /* |
| * Perform shared environment initializations. |
| */ |
| |
| gm->nprocs = nprocs; |
| gm->pid = 0; |
| gm->rid = 1; |
| |
| BARINIT(gm->start) |
| LOCKINIT(gm->pidlock) |
| LOCKINIT(gm->ridlock) |
| LOCKINIT(gm->memlock) |
| ALOCKINIT(gm->wplock, nprocs) |
| |
| /* POSSIBLE ENHANCEMENT: Here is where one might distribute the |
| raystruct data structure across physically distributed memories as |
| desired. */ |
| |
| if (!GlobalHeapInit(MaxGlobMem)) |
| { |
| fprintf(stderr, "%s: Cannot initialize global heap.\n", ProgName); |
| exit(1); |
| } |
| |
| |
| /* |
| * Initialize HUG parameters, read environment and geometry files. |
| */ |
| |
| Huniform_defaults(); |
| ReadEnvFile(*argv); |
| ReadGeoFile(GeoFileName); |
| OpenFrameBuffer(); |
| |
| |
| /* |
| * Compute view transform and its inverse. |
| */ |
| |
| CreateViewMatrix(); |
| MatrixCopy(vtrans, View.vtrans); |
| MatrixInverse(Vinv, vtrans); |
| MatrixCopy(View.vtransInv, Vinv); |
| |
| |
| /* |
| * Print out what we have so far. |
| */ |
| |
| printf("Number of primitive objects: \t%ld\n", prim_obj_cnt); |
| printf("Number of primitive elements:\t%ld\n", prim_elem_cnt); |
| |
| /* |
| * Preprocess database into hierarchical uniform grid. |
| */ |
| |
| if (TraversalType == TT_HUG) |
| BuildHierarchy_Uniform(); |
| |
| |
| |
| /* |
| * Now create slave processes. |
| */ |
| |
| CLOCK(begin) |
| //for (i = 0; i < gm->nprocs - 1; i++) |
| CREATE(StartRayTrace, gm->nprocs) |
| |
| //StartRayTrace(); |
| |
| WAIT_FOR_END(gm->nprocs) |
| CLOCK(end) |
| |
| |
| |
| /* |
| * We are finished. Clean up, print statistics and run time. |
| */ |
| |
| CloseFrameBuffer(PicFileName); |
| PrintStatistics(); |
| |
| lapsed = (end - begin) & 0x7FFFFFFF; |
| |
| |
| |
| printf("TIMING STATISTICS MEASURED BY MAIN PROCESS:\n"); |
| printf(" Overall start time %20lu\n", begin); |
| printf(" Overall end time %20lu\n", end); |
| printf(" Total time with initialization %20lu\n", lapsed); |
| printf(" Total time without initialization %20lu\n", end - gm->par_start_time); |
| |
| if (dostats) { |
| unsigned totalproctime, maxproctime, minproctime; |
| |
| printf("\n\n\nPER-PROCESS STATISTICS:\n"); |
| |
| printf("%20s%20s\n","Proc","Time"); |
| printf("%20s%20s\n\n","","Tracing Rays"); |
| for (i = 0; i < gm->nprocs; i++) |
| printf("%20d%20d\n",i,gm->partime[i]); |
| |
| totalproctime = gm->partime[0]; |
| minproctime = gm->partime[0]; |
| maxproctime = gm->partime[0]; |
| |
| for (i = 1; i < gm->nprocs; i++) { |
| totalproctime += gm->partime[i]; |
| if (gm->partime[i] > maxproctime) |
| maxproctime = gm->partime[i]; |
| if (gm->partime[i] < minproctime) |
| minproctime = gm->partime[i]; |
| } |
| printf("\n\n%20s%20d\n","Max = ",maxproctime); |
| printf("%20s%20d\n","Min = ",minproctime); |
| printf("%20s%20d\n","Avg = ",(int) (((double) totalproctime) / ((double) (1.0 * gm->nprocs)))); |
| } |
| |
| MAIN_END |
| } |
| |