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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rxpmain.cpp,v 2.3 2024/09/16 19:20:09 greg Exp $";
3 #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 quit(int code) /* quit program */
63 {
64 if (!code)
65 code = myRPmanager.Cleanup();
66
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 if (pct < 100.-FTINY && tnow - lastReportTime < ralrm)
499 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 }