ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxpmain.cpp
Revision: 2.4
Committed: Wed Nov 6 18:28:52 2024 UTC (5 months, 3 weeks ago) by greg
Branch: MAIN
Changes since 2.3: +3 -7 lines
Log Message:
perf(rxtrace,rxpict,rxpiece,rxcontrib): Improved exit strategy in children

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.4 static const char RCSid[] = "$Id: rxpmain.cpp,v 2.3 2024/09/16 19:20:09 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * rxpmain.cpp - main for rxpict batch rendering program
6     */
7    
8     #include "copyright.h"
9    
10     #include <time.h>
11     #include <signal.h>
12    
13     #include "rtprocess.h" /* getpid() */
14     #include "platform.h"
15     #include "RpictSimulManager.h"
16    
17     extern char *progname; /* argv[0] */
18     const char *sigerr[NSIG]; /* signal error messages */
19     char *errfile = NULL; /* error output file */
20    
21     VIEW ourview = STDVIEW; /* view parameters */
22     int hresolu = 512; /* horizontal resolution */
23     int vresolu = 512; /* vertical resolution */
24     double pixaspect = 1.0; /* pixel aspect ratio */
25     int hres, vres; /* current image resolution for srcdraw.c */
26    
27     int psample = 4; /* pixel sample size */
28     double maxdiff = .05; /* max. difference for interpolation */
29     double dstrpix = 0.67; /* square pixel distribution */
30    
31     double mblur = 0.; /* motion blur parameter */
32    
33     double dblur = 0.; /* depth-of-field blur parameter */
34    
35     int nproc = 1; /* number of processes to run */
36    
37     int ralrm = 0; /* seconds between reports */
38    
39     double pctdone = 0.0; /* percentage done */
40     time_t tlastrept = 0L; /* time at last report */
41     time_t tstart; /* starting time */
42    
43     RenderDataType dtype = RDTrgbe; // output data flags
44    
45     RpictSimulManager myRPmanager; // global simulation manager
46    
47     static void onsig(int signo);
48     static void sigdie(int signo, const char *msg);
49     static void printdefaults(void);
50    
51     /* rxpict additional features */
52     #define RXPICT_FEATURES "Recovery\nIrradianceCalc\nViewTypes=v,l,a,h,s,c\n" \
53     "ParticipatingMedia=Mist\n" \
54     "HessianAmbientCache\nAmbientAveraging\nAmbientValueSharing\n" \
55     "PixelJitter\nPixelSampling\nPixelMotion\nPixelDepthOfField\n" \
56     "SmallSourceDrawing\nViewSequence\nProgressReporting\n" \
57     "AdaptiveShadowTesting\nOutputs=v,l\n" \
58     "OutputCS=RGB,XYZ,prims,spec\n"
59    
60    
61     void
62 greg 2.3 quit(int code) /* quit program */
63 greg 2.1 {
64 greg 2.4 if (!code)
65     code = myRPmanager.Cleanup();
66 greg 2.1
67     exit(code);
68     }
69    
70    
71     int
72     main(int argc, char *argv[])
73     {
74     #define check(ol,al) if (argv[i][ol] || \
75     badarg(argc-i-1,argv+i+1,al)) \
76     goto badopt
77     #define check_bool(olen,var) switch (argv[i][olen]) { \
78     case '\0': var = !var; break; \
79     case 'y': case 'Y': case 't': case 'T': \
80     case '+': case '1': var = 1; break; \
81     case 'n': case 'N': case 'f': case 'F': \
82     case '-': case '0': var = 0; break; \
83     default: goto badopt; }
84     RGBPRIMS our_prims; /* private output color primitives */
85     int seqstart = 0;
86     char *recover = NULL;
87     char *outfile = NULL;
88     char *zfile = NULL;
89     int outfmt = 'c';
90     int rval;
91     int i;
92     /* record start time */
93     tstart = time(NULL);
94     /* global program name */
95     progname = argv[0];
96     /* feature check only? */
97     strcat(RFeatureList, RXPICT_FEATURES);
98     if (argc > 1 && !strcmp(argv[1], "-features"))
99     return feature_status(argc-2, argv+2);
100     /* option city */
101     for (i = 1; i < argc; i++) {
102     /* expand arguments */
103     while ((rval = expandarg(&argc, &argv, i)) > 0)
104     ;
105     if (rval < 0) {
106     sprintf(errmsg, "cannot expand '%s'", argv[i]);
107     error(SYSTEM, errmsg);
108     }
109     if (argv[i] == NULL || argv[i][0] != '-')
110     break; /* break from options */
111     if (!strcmp(argv[i], "-version")) {
112     puts(VersionID);
113     quit(0);
114     }
115     if (!strcmp(argv[i], "-defaults") ||
116     !strcmp(argv[i], "-help")) {
117     printdefaults();
118     quit(0);
119     }
120     rval = getrenderopt(argc-i, argv+i);
121     if (rval >= 0) {
122     i += rval;
123     continue;
124     }
125     rval = getviewopt(&ourview, argc-i, argv+i);
126     if (rval >= 0) {
127     i += rval;
128     continue;
129     }
130     /* rxpict options */
131     switch (argv[i][1]) {
132     case 'v': /* view file */
133     if (argv[i][2] != 'f')
134     goto badopt;
135     check(3,"s");
136     rval = viewfile(argv[++i], &ourview, NULL);
137     if (rval < 0) {
138     sprintf(errmsg,
139     "cannot open view file \"%s\"",
140     argv[i]);
141     error(SYSTEM, errmsg);
142     } else if (rval == 0) {
143     sprintf(errmsg,
144     "bad view file \"%s\"",
145     argv[i]);
146     error(USER, errmsg);
147     }
148     break;
149     case 'n': /* number of processes */
150     check(2,"i");
151     nproc = atoi(argv[++i]);
152     if (nproc < 0 && (nproc += RadSimulManager::GetNCores()) <= 0)
153     nproc = 1;
154     break;
155     case 'f': /* output format */
156     if ((argv[i][2] != 'c') & (argv[i][2] != 'f')
157     || argv[i][3])
158     goto badopt;
159     outfmt = argv[i][2];
160     break;
161     case 'p': /* pixel */
162     switch (argv[i][2]) {
163     case 's': /* sample */
164     check(3,"i");
165     psample = atoi(argv[++i]);
166     if (psample < 1) psample = 1;
167     break;
168     case 't': /* threshold */
169     check(3,"f");
170     maxdiff = atof(argv[++i]);
171     break;
172     case 'j': /* jitter */
173     check(3,"f");
174     dstrpix = atof(argv[++i]);
175     break;
176     case 'a': /* aspect */
177     check(3,"f");
178     pixaspect = atof(argv[++i]);
179     break;
180     case 'm': /* motion */
181     check(3,"f");
182     mblur = atof(argv[++i]);
183     mblur *= (mblur > 0);
184     break;
185     case 'd': /* aperture */
186     check(3,"f");
187     dblur = atof(argv[++i]);
188     dblur *= (dblur > 0);
189     break;
190     case 'R': /* standard RGB output */
191     if (strcmp(argv[i]+2, "RGB"))
192     goto badopt;
193     myRPmanager.prims = stdprims;
194     dtype = RDTnewCT(dtype, RDTrgbe);
195     break;
196     case 'X': /* XYZ output */
197     if (strcmp(argv[i]+2, "XYZ"))
198     goto badopt;
199     myRPmanager.prims = xyzprims;
200     dtype = RDTnewCT(dtype, RDTxyze);
201     break;
202     case 'c': /* chromaticities */
203     check(3,"ffffffff");
204     rval = 0;
205     for (int j = 0; j < 8; j++) {
206     our_prims[0][j] = atof(argv[++i]);
207     rval |= fabs(our_prims[0][j]-stdprims[0][j]) > .001;
208     }
209     if (rval) {
210     if (!colorprimsOK(our_prims))
211     error(USER, "illegal primary chromaticities");
212     myRPmanager.prims = our_prims;
213     } else
214     myRPmanager.prims = stdprims;
215     dtype = RDTnewCT(dtype, RDTrgbe);
216     break;
217     default:
218     goto badopt;
219     }
220     break;
221     case 'd': /* reference depth */
222     if (argv[i][2] || !myRPmanager.SetReferenceDepth(argv[++i]))
223     goto badopt;
224     dtype = RDTnewDT(dtype, RDTdshort);
225     break;
226     case 'x': /* x resolution */
227     check(2,"i");
228     hresolu = atoi(argv[++i]);
229     break;
230     case 'y': /* y resolution */
231     check(2,"i");
232     vresolu = atoi(argv[++i]);
233     break;
234     case 'S': /* start index */
235     check(2,"i");
236     seqstart = atoi(argv[++i]);
237     seqstart *= (seqstart > 0);
238     break;
239     case 'o': /* output file */
240     check(2,"s");
241     outfile = argv[++i];
242     break;
243     case 'z': /* z file */
244     check(2,"s");
245     zfile = argv[++i];
246     break;
247     case 'r': /* recover file */
248     if (argv[i][2] == 'o') { /* +output */
249     check(3,"s");
250     outfile = argv[i+1];
251     } else
252     check(2,"s");
253     recover = argv[++i];
254     break;
255     #if MAXCSAMP>3
256     case 'c': /* output spectral results */
257     if (argv[i][2] != 'o')
258     goto badopt;
259     rval = (myRPmanager.prims == NULL);
260     check_bool(3,rval);
261     if (rval)
262     myRPmanager.prims = NULL;
263     else if (myRPmanager.prims == NULL)
264     myRPmanager.prims = stdprims;
265     dtype = RDTnewCT(dtype, rval ? RDTscolr : RDTrgbe);
266     break;
267     #endif
268     case 't': /* timer */
269     check(2,"i");
270     ralrm = atoi(argv[++i]);
271     break;
272     case 'w': /* warnings */
273     rval = erract[WARNING].pf != NULL;
274     check_bool(2,rval);
275     if (rval) erract[WARNING].pf = wputs;
276     else erract[WARNING].pf = NULL;
277     break;
278     case 'e': /* error file */
279     check(2,"s");
280     errfile = argv[++i];
281     break;
282     default:
283     goto badopt;
284     }
285     }
286     if (maxdiff <= FTINY) /* check for useless sampling */
287     psample = 1;
288     if (zfile == NULL) /* set up depth output */
289     dtype = RDTnewDT(dtype, RDTnone);
290     else if (!RDTdepthT(dtype))
291     dtype = RDTnewDT(dtype, RDTdfloat);
292     /* check pixel output type */
293     if ((myRPmanager.prims == NULL) & (NCSAMP == 3)) {
294     myRPmanager.prims = stdprims;
295     dtype = RDTnewCT(dtype, RDTrgbe);
296     }
297     if (outfmt == 'f')
298     switch (RDTcolorT(dtype)) {
299     case RDTrgbe:
300     dtype = RDTnewCT(dtype, RDTrgb);
301     break;
302     case RDTxyze:
303     dtype = RDTnewCT(dtype, RDTxyz);
304     break;
305     case RDTscolr:
306     dtype = RDTnewCT(dtype, RDTscolor);
307     break;
308     case RDTrgb:
309     case RDTxyz:
310     case RDTscolor:
311     break;
312     default:
313     error(INTERNAL, "botched color output type");
314     }
315     /* set up signal handling */
316     sigdie(SIGINT, "Interrupt");
317     #ifdef SIGHUP
318     sigdie(SIGHUP, "Hangup");
319     #endif
320     sigdie(SIGTERM, "Terminate");
321     #ifdef SIGPIPE
322     sigdie(SIGPIPE, "Broken pipe");
323     #endif
324     #ifdef SIGALRM
325     sigdie(SIGALRM, "Alarm clock");
326     #endif
327     #ifdef SIGXCPU
328     sigdie(SIGXCPU, "CPU limit exceeded");
329     sigdie(SIGXFSZ, "File size exceeded");
330     #endif
331     /* open error file */
332     if (errfile != NULL) {
333     if (freopen(errfile, "a", stderr) == NULL)
334     quit(2);
335     fprintf(stderr, "**************\n*** PID %5d: ",
336     getpid());
337     printargs(argc, argv, stderr);
338     putc('\n', stderr);
339     fflush(stderr);
340     }
341     #ifdef NICE
342     nice(NICE); /* lower priority */
343     #endif
344     if (i < argc-1)
345     goto badopt;
346     // load octree
347     if (!myRPmanager.LoadOctree(argv[i]))
348     error(USER, "missing octree argument");
349     // add new header info
350     myRPmanager.AddHeader(i, argv);
351     {
352     char buf[128] = "SOFTWARE= ";
353     strcpy(buf+10, VersionID);
354     myRPmanager.AddHeader(buf);
355     }
356     // start our engines
357     nproc = myRPmanager.SetThreadCount(nproc);
358     // batch render picture(s)
359     rpict(seqstart, outfile, zfile, recover);
360    
361     quit(0); // clean up and exit
362    
363     badopt:
364     sprintf(errmsg, "command line error at '%s'", argv[i]);
365     error(USER, errmsg);
366     return 1; /* pro forma return */
367    
368     #undef check
369     #undef check_bool
370     }
371    
372    
373     void
374     wputs( /* warning output function */
375     const char *s
376     )
377     {
378     int lasterrno = errno;
379     eputs(s);
380     errno = lasterrno;
381     }
382    
383    
384     void
385     eputs( /* put string to stderr */
386     const char *s
387     )
388     {
389     static int midline = 0;
390    
391     if (!*s)
392     return;
393     if (!midline++) {
394     fputs(progname, stderr);
395     fputs(": ", stderr);
396     }
397     fputs(s, stderr);
398     if (s[strlen(s)-1] == '\n') {
399     fflush(stderr);
400     midline = 0;
401     }
402     }
403    
404    
405     static void
406     onsig( /* fatal signal */
407     int signo
408     )
409     {
410     static int gotsig = 0;
411    
412     if (gotsig++) /* two signals and we're gone! */
413     _exit(signo);
414    
415     #ifdef SIGALRM /* XXX how critical is this? */
416     alarm(30); /* allow 30 seconds to clean up */
417     signal(SIGALRM, SIG_DFL); /* make certain we do die */
418     #endif
419     eputs("signal - ");
420     eputs(sigerr[signo]);
421     eputs("\n");
422     quit(3);
423     }
424    
425    
426     static void
427     sigdie( /* set fatal signal */
428     int signo,
429     const char *msg
430     )
431     {
432     if (signal(signo, onsig) == SIG_IGN)
433     signal(signo, SIG_IGN);
434     sigerr[signo] = msg;
435     }
436    
437    
438     static void
439     printdefaults(void) /* print default values to stdout */
440     {
441     printf("-n %-2d\t\t\t\t# number of rendering processes\n", nproc);
442     printf("-vt%c\t\t\t\t# view type %s\n", ourview.type,
443     ourview.type==VT_PER ? "perspective" :
444     ourview.type==VT_PAR ? "parallel" :
445     ourview.type==VT_HEM ? "hemispherical" :
446     ourview.type==VT_ANG ? "angular" :
447     ourview.type==VT_CYL ? "cylindrical" :
448     ourview.type==VT_PLS ? "planisphere" :
449     "unknown");
450     printf("-vp %f %f %f\t# view point\n",
451     ourview.vp[0], ourview.vp[1], ourview.vp[2]);
452     printf("-vd %f %f %f\t# view direction\n",
453     ourview.vdir[0], ourview.vdir[1], ourview.vdir[2]);
454     printf("-vu %f %f %f\t# view up\n",
455     ourview.vup[0], ourview.vup[1], ourview.vup[2]);
456     printf("-vh %f\t\t\t# view horizontal size\n", ourview.horiz);
457     printf("-vv %f\t\t\t# view vertical size\n", ourview.vert);
458     printf("-vo %f\t\t\t# view fore clipping plane\n", ourview.vfore);
459     printf("-va %f\t\t\t# view aft clipping plane\n", ourview.vaft);
460     printf("-vs %f\t\t\t# view shift\n", ourview.hoff);
461     printf("-vl %f\t\t\t# view lift\n", ourview.voff);
462     printf("-x %-9d\t\t\t# x resolution\n", hresolu);
463     printf("-y %-9d\t\t\t# y resolution\n", vresolu);
464     if (myRPmanager.prims == stdprims)
465     printf("-pRGB\t\t\t\t# standard RGB color output\n");
466     else if (myRPmanager.prims == xyzprims)
467     printf("-pXYZ\t\t\t\t# CIE XYZ color output\n");
468     else if (myRPmanager.prims != NULL)
469     printf("-pc %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\t# output color primaries and white point\n",
470     myRPmanager.prims[RED][0], myRPmanager.prims[RED][1],
471     myRPmanager.prims[GRN][0], myRPmanager.prims[GRN][1],
472     myRPmanager.prims[BLU][0], myRPmanager.prims[BLU][1],
473     myRPmanager.prims[WHT][0], myRPmanager.prims[WHT][1]);
474     if (NCSAMP > 3)
475     printf(myRPmanager.prims != NULL ? "-co-\t\t\t\t# output tristimulus colors\n" :
476     "-co+\t\t\t\t# output spectral values\n");
477     printf("-pa %f\t\t\t# pixel aspect ratio\n", pixaspect);
478     printf("-pj %f\t\t\t# pixel jitter\n", dstrpix);
479     printf("-pm %f\t\t\t# pixel motion\n", mblur);
480     printf("-pd %f\t\t\t# pixel depth-of-field\n", dblur);
481     printf("-ps %-9d\t\t\t# pixel sample\n", psample);
482     printf("-pt %f\t\t\t# pixel threshold\n", maxdiff);
483     printf("-t %-9d\t\t\t# time between reports\n", ralrm);
484     printf(erract[WARNING].pf != NULL ?
485     "-w+\t\t\t\t# warning messages on\n" :
486     "-w-\t\t\t\t# warning messages off\n");
487     print_rdefaults();
488     }
489    
490    
491     // my progress report call-back
492     static void
493     progReporter(double pct)
494     {
495     static time_t lastReportTime = 0;
496     time_t tnow = time(NULL);
497    
498 greg 2.2 if (pct < 100.-FTINY && tnow - lastReportTime < ralrm)
499 greg 2.1 return; // too soon, my Precious...
500    
501     sprintf(errmsg, "%7.3f%% done after %7.3f hours\n", pct, (tnow-tstart)/3600.);
502     eputs(errmsg);
503     // reset timer at 100%
504     lastReportTime = tnow * (pct < 100.-FTINY);
505     }
506    
507    
508     // Principal function for rpict execution (prototype in ray.h for some reason)
509     void
510     rpict(int seq, char *pout, char *zout, char *prvr)
511     /*
512     * If seq is greater than zero, then we will render a sequence of
513     * images based on view parameter strings read from the standard input.
514     * If pout is NULL, then all images will be sent to the standard ouput.
515     * If seq is greater than zero and prvr is an integer, then it is the
516     * frame number at which rendering should begin. Preceeding view parameter
517     * strings will be skipped in the input.
518     * Note that pout and zout should contain %d format specifications for
519     * sequenced file naming.
520     */
521     {
522     char fbuf[256], dbuf[256];
523    
524     if (!zout ^ !RDTdepthT(dtype))
525     error(INTERNAL, "output depth type requires spec and vice versa");
526    
527     if (prvr && isint(prvr)) { // sequence recovery?
528     if (!seq)
529     error(USER, "sequence recovery requires starting frame");
530     if (!pout)
531     error(USER, "need output spec for sequence recovery");
532     int rno = atoi(prvr);
533     if (rno < seq)
534     error(USER, "recovery frame before starting frame");
535     while (seq <= rno) {
536     if (!fgets(fbuf, sizeof(fbuf), stdin))
537     error(USER, "recovery frame past end of sequence");
538     seq += (isview(fbuf) && sscanview(&ourview, fbuf) > 0);
539     }
540     sprintf(prvr=fbuf, pout, rno);
541     }
542     if (ralrm > 0)
543     myRPmanager.prCB = progReporter;
544     else
545     myRPmanager.prCB = NULL;
546     if (prvr) { // recovering partial render?
547     if ((seq > 0) & (prvr != fbuf))
548     error(USER, "recover spec must be number in sequence");
549     if (zout) sprintf(dbuf, zout, seq);
550     if (ralrm > 0) {
551     sprintf(errmsg, "resuming partial rendering '%s'\n", prvr);
552     eputs(errmsg);
553     }
554     dtype = myRPmanager.ResumeFrame(prvr, zout ? dbuf : zout);
555     if (!dtype)
556     error(USER, "ResumeFrame() failed");
557     if (!seq)
558     return; // all done if we're running a sequence
559     }
560     do {
561     if (prvr) // have view from sequence recovery?
562     prvr = NULL;
563     else if (seq) { // else read next view in sequence
564     while (fgets(fbuf, sizeof(fbuf), stdin))
565     if (isview(fbuf) && sscanview(&ourview, fbuf) > 0)
566     break;
567     if (feof(stdin))
568     return; // reached end of view input
569     }
570     // get (indexed) output file name(s)
571     if (pout) sprintf(fbuf, pout, seq);
572     if (zout) sprintf(dbuf, zout, seq);
573    
574     if (ralrm > 0) { // start report if requested
575     if (myRPmanager.NThreads() > 1)
576     sprintf(errmsg, "%2d processes ", myRPmanager.NThreads());
577     else
578     sprintf(errmsg, "PID %6d ", getpid());
579     eputs(errmsg);
580     if (seq) {
581     sprintf(errmsg, "rendering frame %5d ", seq);
582     eputs(errmsg);
583     } else
584     eputs("rendering picture ");
585     if (pout) {
586     sprintf(errmsg, "to '%s'\n", fbuf);
587     eputs(errmsg);
588     } else
589     eputs("to stdout\n");
590     if (zout) {
591     sprintf(errmsg, "\twith %s depth map in '%s'\n",
592     RDTdepthT(dtype)==RDTdshort ?
593     "encoded 16-bit" : "raw float",
594     dbuf);
595     eputs(errmsg);
596     }
597     }
598     // set up view and size
599     int xydim[2] = {hresolu, vresolu};
600     if (!myRPmanager.NewFrame(ourview, xydim, &pixaspect))
601     error(USER, "NewFrame() failed");
602    
603     myRPmanager.frameNo = seq;
604    
605     errno = 0; // render frame, skipping if it exists
606     if (!myRPmanager.RenderFrame(pout ? fbuf : pout, dtype,
607     zout ? dbuf : zout)
608     && !seq | (errno != EEXIST))
609     error(USER, "RenderFrame() failed");
610     } while (seq++); // all done if we're running a sequence
611     }