ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcomb.c
(Generate patch)

Comparing ray/src/util/rcomb.c (file contents):
Revision 2.2 by greg, Mon Dec 18 23:04:05 2023 UTC vs.
Revision 2.16 by greg, Thu May 23 15:48:44 2024 UTC

# Line 5 | Line 5 | static const char RCSid[] = "$Id$";
5   * General component matrix combiner, operating on a row at a time.
6   */
7  
8 #include <errno.h>
8   #include <math.h>
9   #include "platform.h"
10 + #include "rtprocess.h"
11   #include "rtio.h"
12 #include "resolu.h"
12   #include "rmatrix.h"
13   #include "calcomp.h"
15 #include "paths.h"
14  
15   #ifndef M_PI
16   #define M_PI    3.14159265358979323846
# Line 55 | Line 53 | int            cur_row;                        /* current input/output row */
53   int             cur_col;                        /* current input/output column */
54   int             cur_chan;                       /* if we're looping channels */
55  
56 + SUBPROC         *cproc = NULL;                  /* child process array */
57 + int             nchildren = 0;                  /* # of child processes */
58 + int             inchild = -1;                   /* our child ID (-1: parent) */
59 +
60   static int      checksymbolic(ROPMAT *rop);
61  
62   static int
# Line 186 | Line 188 | checksymbolic(ROPMAT *rop)
188   {
189          const int       nc = rop->imx.ncomp;
190          const int       dt = rop->imx.dtype;
191 +        double          cf = 1;
192          int             i, j;
193                                          /* check suffix => reference file */
194          if (strchr(rop->preop.csym, '.') > rop->preop.csym)
# Line 206 | Line 209 | checksymbolic(ROPMAT *rop)
209                  int     comp = 0;
210                  switch (rop->preop.csym[j]) {
211                  case 'B':
212 +                case 'b':
213                          ++comp;
214                          /* fall through */
215                  case 'G':
216 +                case 'g':
217                          ++comp;
218                          /* fall through */
219                  case 'R':
220 +                case 'r':
221 +                        if (rop->preop.csym[j] <= 'Z')
222 +                                cf = 1./WHTEFFICACY;
223                          if (dt == DTxyze) {
224                                  for (i = 3; i--; )
225 <                                        rop->preop.cmat[j*nc+i] = 1./WHTEFFICACY *
218 <                                                        xyz2rgbmat[comp][i];
225 >                                        rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
226                          } else if (nc == 3)
227                                  rop->preop.cmat[j*nc+comp] = 1.;
228                          else
229                                  rgbrow(rop, j, comp);
230                          break;
231                  case 'Z':
232 +                case 'z':
233                          ++comp;
234                          /* fall through */
235                  case 'Y':
236 +                case 'y':
237                          ++comp;
238                          /* fall through */
239                  case 'X':
240 +                case 'x':
241 +                        if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
242 +                                cf = WHTEFFICACY;
243                          if (dt == DTxyze) {
244                                  rop->preop.cmat[j*nc+comp] = 1.;
245                          } else if (nc == 3) {
# Line 239 | Line 251 | checksymbolic(ROPMAT *rop)
251                          else
252                                  xyzrow(rop, j, comp);
253  
254 <                        for (i = nc*(dt != DTxyze); i--; )
255 <                                rop->preop.cmat[j*nc+i] *= WHTEFFICACY;
254 >                        for (i = nc*(cf != 1); i--; )
255 >                                rop->preop.cmat[j*nc+i] *= cf;
256                          break;
257                  case 'S':               /* scotopic (il)luminance */
258 +                        cf = WHTSCOTOPIC;
259 +                        /* fall through */
260 +                case 's':
261                          sensrow(rop, j, scolor2scotopic);
262 <                        for (i = nc; i--; )
263 <                                rop->preop.cmat[j*nc+i] *= WHTSCOTOPIC;
262 >                        for (i = nc*(cf != 1); i--; )
263 >                                rop->preop.cmat[j*nc+i] *= cf;
264                          break;
265                  case 'M':               /* melanopic (il)luminance */
266 +                        cf = WHTMELANOPIC;
267 +                        /* fall through */
268 +                case 'm':
269                          sensrow(rop, j, scolor2melanopic);
270 <                        for (i = nc; i--; )
271 <                                rop->preop.cmat[j*nc+i] *= WHTMELANOPIC;
270 >                        for (i = nc*(cf != 1); i--; )
271 >                                rop->preop.cmat[j*nc+i] *= cf;
272                          break;
273                  case 'A':               /* average component */
274 +                case 'a':
275                          for (i = nc; i--; )
276                                  rop->preop.cmat[j*nc+i] = 1./(double)nc;
277                          break;
# Line 267 | Line 286 | checksymbolic(ROPMAT *rop)
286          memcpy(rop->rmp->wlpart, WLPART, sizeof(rop->rmp->wlpart));
287          rop->rmp->ncomp = rop->preop.clen / nc;
288                                          /* decide on output type */
289 <        if (!strcmp(rop->preop.csym, "XYZ")) {
289 >        if (!strcasecmp(rop->preop.csym, "XYZ")) {
290                  if (dt <= DTspec)
291                          rop->rmp->dtype = DTxyze;
292 <        } else if (!strcmp(rop->preop.csym, "RGB")) {
292 >        } else if (!strcasecmp(rop->preop.csym, "RGB")) {
293                  if (dt <= DTspec)
294                          rop->rmp->dtype = DTrgbe;
295          } else if (rop->rmp->dtype == DTspec)
# Line 374 | Line 393 | apply_op(RMATRIX *dst, const RMATRIX *src, const RUNAR
393                          return(0);
394                  rmx_free(res);
395          } else if (dst != src)
396 <                memcpy(dst->mtx, src->mtx,
378 <                                sizeof(double)*dst->ncomp*dst->ncols*dst->nrows);
396 >                memcpy(dst->mtx, src->mtx, rmx_array_size(dst));
397          if (ro->nsf == dst->ncomp)
398                  rmx_scale(dst, ro->sca);
399          return(1);
# Line 523 | Line 541 | output_headinfo(FILE *fp)
541   }
542  
543   static int
544 < combine_input(ROPMAT *res, FILE *fout)
544 > spawned_children(int np)
545   {
546 <        int     set_r, set_c;
547 <        RMATRIX *tmp = NULL;
548 <        int     co_set;
549 <        int     i;
550 <                                        /* allocate input row buffers */
546 >        long    inpwidth = 0;
547 >        int     i, rv;
548 >
549 > #if defined(_WIN32) || defined(_WIN64)
550 >        if (np > 1) {
551 >                fputs("Warning: only one process under Windows\n", stderr);
552 >                np = 1;
553 >        } else
554 > #endif
555 >        if ((in_nrows > 0) & (np > in_nrows))
556 >                np = in_nrows;
557 >                                /* we'll be doing a row at a time */
558          for (i = 0; i < nmats; i++) {
559 <                mop[i].imx.nrows = 1;   /* we'll be doing a row at a time */
559 >                mop[i].imx.nrows = 1;
560                  if (!rmx_prepare(&mop[i].imx))
561                          goto memerror;
562 +                inpwidth += rmx_array_size(&mop[i].imx);
563                  if (mop[i].rmp != &mop[i].imx) {
564                          mop[i].rmp->nrows = 1;
565                          if (!rmx_prepare(mop[i].rmp))
566                                  goto memerror;
567 +                        inpwidth += rmx_array_size(mop[i].rmp);
568                  }
569          }
570 <                                        /* prep output row buffers */
571 <        if (mcat || res->preop.clen > 0) {
572 <                if (!split_input(res))  /* need separate buffer */
570 >                                /* prep output row buffer */
571 >        if (mcat || mop[nmats].preop.clen > 0) {
572 >                if (!split_input(&mop[nmats]))  /* need separate buffer */
573                          return(0);
574 <                if (res->preop.clen > 0)
575 <                        res->rmp->ncomp = res->preop.clen / res->imx.ncomp;
576 <                res->rmp->nrows = 1;
577 <                if (!mcat | !mcat_last && !rmx_prepare(res->rmp))
574 >                if (mop[nmats].preop.clen > 0)
575 >                        mop[nmats].rmp->ncomp = mop[nmats].preop.clen /
576 >                                                mop[nmats].imx.ncomp;
577 >                mop[nmats].rmp->nrows = 1;
578 >                if (!mcat | !mcat_last && !rmx_prepare(mop[nmats].rmp))
579                          goto memerror;
580          }
581 +        mop[nmats].imx.nrows = 1;
582 +        if (!rmx_prepare(&mop[nmats].imx))
583 +                goto memerror;
584 +        if (np <= 1) {          /* single process return point */
585 + #ifdef getc_unlocked
586 +                for (i = 0; i < nmats; i++)
587 +                        flockfile(mop[i].infp);
588 +                flockfile(stdout);
589 + #endif
590 +                return(0);
591 +        }
592 +        fflush(stdout);         /* flush header & spawn children */
593 +        cproc = (SUBPROC *)malloc(sizeof(SUBPROC)*np);
594 +        if (!cproc)
595 +                goto memerror;
596 +        nchildren = np;
597 +        for (i = 0; i < np; i++) {
598 +                cproc[i].flags = PF_FILT_OUT;
599 +                cproc[i].w = dup(1);
600 +                cproc[i].r = 0;
601 +                cproc[i].pid = -1;
602 +                rv = open_process(&cproc[i], NULL);
603 +                if (rv <= 0) break;
604 +                if (!i && 2*rv >= inpwidth) {
605 +                        fputs("Problem too small for multi-processing\n",
606 +                                        stderr);
607 +                        exit(1);
608 +                }
609 +        }
610 +        if (rv > 0)
611 +                return(1);      /* parent return value */
612 +        if (rv < 0) {
613 +                perror("fork");
614 +                exit(1);
615 +        }
616 +        inchild = i;            /* our child index */
617 +        while (i-- > 0)         /* don't share siblings' pipes */
618 +                close(cproc[i].w);
619 +        fpurge(stdin);          /* discard previous matrix input */
620 + #ifdef getc_unlocked
621 +        flockfile(stdin);
622 + #endif
623 +        for (i = 0; i < nmats; i++) {
624 +                if (mop[i].infp != stdin)
625 +                        fclose(mop[i].infp);    /* ! pclose() */
626 +                mop[i].infp = stdin;
627 +                mop[i].imx.dtype = DTdouble;
628 +        }
629 +        return(0);              /* child return */
630 + memerror:
631 +        fputs("Out of memory in spawned_children()\n", stderr);
632 +        exit(1);
633 + }
634 +
635 + static int
636 + parent_loop()
637 + {
638 +        FILE    **outfp = (FILE **)malloc(nchildren*sizeof(FILE *));
639 +        int     i;
640 +
641 +        if (!outfp) goto memerror;
642 +        for (i = 0; i < nchildren; i++) {
643 +                outfp[i] = fdopen(cproc[i].w, "w");
644 +                if (!outfp[i]) goto memerror;
645 + #ifdef getc_unlocked
646 +                flockfile(outfp[i]);
647 + #endif
648 +        }
649 + #ifdef getc_unlocked
650 +        for (i = 0; i < nmats; i++)
651 +                flockfile(mop[i].infp);
652 + #endif
653 +        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
654 +            FILE        *ofp = outfp[cur_row % nchildren];
655 +            for (i = 0; i < nmats; i++)
656 +                if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
657 +                        if (cur_row > in_nrows) /* unknown #input rows? */
658 +                                break;
659 +                        fprintf(stderr, "%s: read error at row %d\n",
660 +                                        mop[i].inspec, cur_row);
661 +                        return(0);
662 +                }
663 +            if (i < nmats)
664 +                break;
665 +            for (i = 0; i < nmats; i++)
666 +                if (!rmx_write_data(mop[i].imx.mtx, mop[i].imx.ncomp,
667 +                                        mop[i].imx.ncols, DTdouble, ofp))
668 +                        return(0);
669 +            if (fflush(ofp) == EOF)
670 +                return(0);
671 +        }
672 +        for (i = 0; i < nchildren; i++) {
673 +                sleep(2);                       /* try to maintain order */
674 +                fclose(outfp[i]);
675 +        }
676 +        free(outfp);
677 +        i = close_processes(cproc, nchildren);
678 +        free(cproc); cproc = NULL;
679 +        if (i < 0) {
680 +                fputs("Warning: missing child in parent_loop()\n", stderr);
681 +                return(1);
682 +        }
683 +        if (i > 0) {
684 +                fprintf(stderr, "Child exited with status %d\n", i);
685 +                return(0);
686 +        }
687 +        return(1);
688 + memerror:
689 +        fputs("Out of memory in parent_loop()\n", stderr);
690 +        exit(1);
691 + }
692 +
693 + static int
694 + combine_input()
695 + {
696 +        const int       row0 = (inchild >= 0)*inchild;
697 +        const int       rstep = nchildren + !nchildren;
698 +        ROPMAT          *res = &mop[nmats];
699 +        int             set_r, set_c;
700 +        RMATRIX         *tmp = NULL;
701 +        int             co_set;
702 +        int             i;
703 +
704          if (mcat && mcat_last &&
705                          !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp)))
706                  goto memerror;
556        res->imx.nrows = 1;
557        if (!rmx_prepare(&res->imx))
558                goto memerror;
707                                          /* figure out what the user set */
708          co_set = fundefined("co");
709          if (!co_set)
# Line 570 | Line 718 | combine_input(ROPMAT *res, FILE *fout)
718                  set_c = varlookup("c") != NULL && !vardefined("c");
719          } else                          /* save a little time */
720                  set_r = set_c = 0;
721 +
722                                          /* read/process row-by-row */
723 <        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
723 >        for (cur_row = row0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row += rstep) {
724              RMATRIX     *mres = NULL;
725 <            for (i = 0; i < nmats; i++) {
725 >            for (i = 0; i < nmats; i++)
726                  if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
727 <                        if (in_nrows <= 0)      /* normal end? */
728 <                                goto loop_exit;
727 >                        if (cur_row > in_nrows) /* unknown #input rows? */
728 >                                break;
729                          fprintf(stderr, "%s: read error at row %d\n",
730                                          mop[i].inspec, cur_row);
731                          return(0);
732                  }
733 +            if (i < nmats)
734 +                break;
735 +            for (i = 0; i < nmats; i++)
736                  if (!apply_op(mop[i].rmp, &mop[i].imx, &mop[i].preop))
737                          return(0);
586            }
738              if (set_r) varset("r", '=', cur_row);
739              for (cur_col = 0; cur_col < in_ncols; cur_col++) {
740                  if (set_c) varset("c", '=', cur_col);
# Line 620 | Line 771 | combine_input(ROPMAT *res, FILE *fout)
771                          return(0);
772              }
773              rmx_free(mres); mres = NULL;
774 +            if (inchild >= 0) {         /* children share stdout */
775 +                i = getc(stdin);        /* signals it's our turn */
776 +                if (i != EOF) ungetc(i, stdin);
777 +            }
778              if (!rmx_write_data(res->rmp->mtx, res->rmp->ncomp,
779 <                                res->rmp->ncols, res->rmp->dtype, fout))
779 >                                res->rmp->ncols, res->rmp->dtype, stdout))
780                  return(0);
781 +            if (inchild >= 0 && fflush(stdout) == EOF)
782 +                return(0);
783          }
784 < loop_exit:
628 < #if 0           /* we're about to exit, so who cares? */
629 <        rmx_free(tmp);                  /* clean up */
630 <        rmx_reset(res->rmp);
631 <        rmx_reset(&res->imx);
632 <        for (i = 0; i < nmats; i++) {
633 <                rmx_reset(mop[i].rmp);
634 <                rmx_reset(&mop[i].imx);
635 <                if (mop[i].inspec[0] == '!')
636 <                        pclose(mop[i].infp);
637 <                else if (mop[i].inspec != stdin_name)
638 <                        fclose(mop[i].infp);
639 <                mop[i].infp = NULL;
640 <        }
641 < #endif
642 <        return(fflush(fout) != EOF);
784 >        return(inchild >= 0 || fflush(stdout) != EOF);
785   memerror:
786          fputs("Out of buffer space in combine_input()\n", stderr);
787          return(0);
# Line 663 | Line 805 | resize_inparr(int n2alloc)
805   {
806          int     i;
807  
808 <        for (i = nmats; i > n2alloc; i--) {
808 >        if (n2alloc == nall)
809 >                return;
810 >        for (i = nall; i > n2alloc; i--) {
811                  rmx_reset(&mop[i].imx);
812                  if (mop[i].rmp != &mop[i].imx)
813                          rmx_free(mop[i].rmp);
# Line 673 | Line 817 | resize_inparr(int n2alloc)
817                  fputs("Out of memory in resize_inparr()\n", stderr);
818                  exit(1);
819          }
820 <        if (n2alloc > nmats)
821 <                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
820 >        if (n2alloc > nall)
821 >                memset(mop+nall, 0, (n2alloc-nall)*sizeof(ROPMAT));
822          nall = n2alloc;
823   }
824  
# Line 687 | Line 831 | main(int argc, char *argv[])
831          const char      *defCsym = NULL;
832          int             echoheader = 1;
833          int             stdin_used = 0;
834 +        int             nproc = 1;
835          const char      *mcat_spec = NULL;
836          int             n2comp = 0;
837          uby8            comp_ndx[128];
# Line 714 | Line 859 | main(int argc, char *argv[])
859                          case 'h':
860                                  echoheader = !echoheader;
861                                  break;
862 +                        case 'n':
863 +                                nproc = atoi(argv[++i]);
864 +                                if (nproc <= 0)
865 +                                        goto userr;
866 +                                break;
867                          case 'e':
868                                  if (!n) goto userr;
869                                  comp_ndx[n2comp++] = i++;
# Line 762 | Line 912 | main(int argc, char *argv[])
912                                  if (n && !isflt(argv[i+1])) {
913                                          mop[nmats].preop.csym = argv[++i];
914                                          mop[nmats].preop.clen = 0;
915 +                                        mcat_last = 0;
916                                          break;
917                                  }
918                                  if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
# Line 851 | Line 1002 | main(int argc, char *argv[])
1002                  fprintf(stderr, "%s: unsupported output format\n", argv[0]);
1003                  return(1);
1004          }
1005 +        doptimize(1);                   /* optimize definitions */
1006 +        if (spawned_children(nproc))    /* running in parent process? */
1007 +                return(parent_loop() ? 0 : 1);
1008                                          /* process & write rows */
1009 <        return(combine_input(&mop[nmats], stdout) ? 0 : 1);
1009 >        return(combine_input() ? 0 : 1);
1010   stdin_error:
1011          fprintf(stderr, "%s: %s used for more than one input\n",
1012                          argv[0], stdin_name);
1013          return(1);
1014   userr:
1015          fprintf(stderr,
1016 <        "Usage: %s [-h][-f{adfc}][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1016 >        "Usage: %s [-h][-f{adfc}][-n nproc][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1017                          argv[0]);
1018          return(1);
1019   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines