ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxpmain.cpp
Revision: 2.7
Committed: Thu Jan 2 20:19:48 2025 UTC (3 months, 4 weeks ago) by greg
Branch: MAIN
Changes since 2.6: +2 -5 lines
Log Message:
perf(rxpiece,rxcontrib): Don't bother to free data structs on exit

File Contents

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