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.1 by greg, Tue Dec 12 16:31:45 2023 UTC vs.
Revision 2.34 by greg, Tue Aug 5 16:40:10 2025 UTC

# Line 3 | Line 3 | static const char RCSid[] = "$Id$";
3   #endif
4   /*
5   * General component matrix combiner, operating on a row at a time.
6 + *
7 + * Multi-processing mode under Unix creates children that each work
8 + * on one input row at a time, fed by the original process.  Final conversion
9 + * and output to stdout is sorted by last child while its siblings send it
10 + * their record calculations.
11   */
12  
8 #include <errno.h>
13   #include <math.h>
14   #include "platform.h"
15 + #include "rtprocess.h"
16   #include "rtio.h"
12 #include "resolu.h"
17   #include "rmatrix.h"
18   #include "calcomp.h"
15 #include "paths.h"
19  
20   #ifndef M_PI
21   #define M_PI    3.14159265358979323846
22   #endif
23  
21 #define MAXCOMP         MAXCSAMP        /* #components we support */
22
24   /* Unary matrix operation(s) */
25   typedef struct {
26          double          cmat[MAXCOMP*MAXCOMP];  /* component transformation */
# Line 45 | Line 46 | int            nmats = 0;                      /* number of actual inputs */
46   RMATRIX         *mcat = NULL;                   /* final concatenation */
47   int             mcat_last = 0;                  /* goes after trailing ops? */
48  
49 < int             in_nrows;                       /* input row count */
50 < #define in_ncols        (mop[0].rmp->ncols)     /* input column count */
49 > int             in_nrows;                       /* number of input rows (or 0) */
50 > #define in_ncols        (mop[0].rmp->ncols)     /* number of input columns */
51   #define in_ncomp        (mop[0].rmp->ncomp)     /* input #components */
52  
53   extern int      nowarn;                         /* turn off warnings? */
# Line 55 | Line 56 | int            cur_row;                        /* current input/output row */
56   int             cur_col;                        /* current input/output column */
57   int             cur_chan;                       /* if we're looping channels */
58  
59 < static int      checksymbolic(ROPMAT *rop);
59 > SUBPROC         *cproc = NULL;                  /* child process array */
60 > int             nchildren = 0;                  /* # of child processes */
61 > int             inchild = -1;                   /* our child ID (-1: parent) */
62  
63 < static int
63 > extern int      checksymbolic(ROPMAT *rop);
64 >
65 > /* Split input matrices to allow for certain operations */
66 > int
67   split_input(ROPMAT *rop)
68   {
69          if (rop->rmp == &rop->imx && !(rop->rmp = rmx_copy(&rop->imx))) {
# Line 69 | Line 75 | split_input(ROPMAT *rop)
75   }
76  
77   /* Check/set transform based on a reference input file */
78 < static int
78 > int
79   checkreffile(ROPMAT *rop)
80   {
81          static const char       *curRF = NULL;
# Line 132 | Line 138 | checkreffile(ROPMAT *rop)
138   }
139  
140   /* Compute conversion row from spectrum to one channel of RGB */
141 < static void
141 > void
142   rgbrow(ROPMAT *rop, int r, int p)
143   {
144          const int       nc = rop->imx.ncomp;
# Line 149 | Line 155 | rgbrow(ROPMAT *rop, int r, int p)
155   }
156  
157   /* Compute conversion row from spectrum to one channel of XYZ */
158 < static void
158 > void
159   xyzrow(ROPMAT *rop, int r, int p)
160   {
161          const int       nc = rop->imx.ncomp;
# Line 166 | Line 172 | xyzrow(ROPMAT *rop, int r, int p)
172   }
173  
174   /* Use the spectral sensitivity function to compute matrix coefficients */
175 < static void
176 < sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, int ncs, const float wlpt[4]))
175 > void
176 > sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
177   {
178          const int       nc = rop->imx.ncomp;
179          int             i;
# Line 181 | Line 187 | sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, in
187   }
188  
189   /* Check/set symbolic transform */
190 < static int
190 > int
191   checksymbolic(ROPMAT *rop)
192   {
193          const int       nc = rop->imx.ncomp;
194          const int       dt = rop->imx.dtype;
195 +        double          cf = 1;
196          int             i, j;
197                                          /* check suffix => reference file */
198 <        if (strchr(rop->preop.csym, '.') > rop->preop.csym)
198 >        if (strchr(rop->preop.csym, '.') != NULL)
199                  return(checkreffile(rop));
200  
201          if (nc < 3) {
# Line 206 | Line 213 | checksymbolic(ROPMAT *rop)
213                  int     comp = 0;
214                  switch (rop->preop.csym[j]) {
215                  case 'B':
216 +                case 'b':
217                          ++comp;
218                          /* fall through */
219                  case 'G':
220 +                case 'g':
221                          ++comp;
222                          /* fall through */
223                  case 'R':
224 +                case 'r':
225 +                        if (rop->preop.csym[j] <= 'Z')
226 +                                cf = 1./WHTEFFICACY;
227                          if (dt == DTxyze) {
228                                  for (i = 3; i--; )
229 <                                        rop->preop.cmat[j*nc+i] = 1./WHTEFFICACY *
218 <                                                        xyz2rgbmat[comp][i];
229 >                                        rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
230                          } else if (nc == 3)
231                                  rop->preop.cmat[j*nc+comp] = 1.;
232                          else
233                                  rgbrow(rop, j, comp);
234                          break;
235                  case 'Z':
236 +                case 'z':
237                          ++comp;
238                          /* fall through */
239                  case 'Y':
240 +                case 'y':
241                          ++comp;
242                          /* fall through */
243                  case 'X':
244 +                case 'x':
245 +                        if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
246 +                                cf = WHTEFFICACY;
247                          if (dt == DTxyze) {
248                                  rop->preop.cmat[j*nc+comp] = 1.;
249                          } else if (nc == 3) {
# Line 239 | Line 255 | checksymbolic(ROPMAT *rop)
255                          else
256                                  xyzrow(rop, j, comp);
257  
258 <                        for (i = nc*(dt != DTxyze); i--; )
259 <                                rop->preop.cmat[j*nc+i] *= WHTEFFICACY;
258 >                        for (i = nc*(cf != 1); i--; )
259 >                                rop->preop.cmat[j*nc+i] *= cf;
260                          break;
261                  case 'S':               /* scotopic (il)luminance */
262 +                        cf = WHTSCOTOPIC;
263 +                        /* fall through */
264 +                case 's':
265                          sensrow(rop, j, scolor2scotopic);
266 <                        for (i = nc; i--; )
267 <                                rop->preop.cmat[j*nc+i] *= WHTSCOTOPIC;
266 >                        for (i = nc*(cf != 1); i--; )
267 >                                rop->preop.cmat[j*nc+i] *= cf;
268                          break;
269                  case 'M':               /* melanopic (il)luminance */
270 +                        cf = WHTMELANOPIC;
271 +                        /* fall through */
272 +                case 'm':
273                          sensrow(rop, j, scolor2melanopic);
274 <                        for (i = nc; i--; )
275 <                                rop->preop.cmat[j*nc+i] *= WHTMELANOPIC;
274 >                        for (i = nc*(cf != 1); i--; )
275 >                                rop->preop.cmat[j*nc+i] *= cf;
276                          break;
277                  case 'A':               /* average component */
278 +                case 'a':
279                          for (i = nc; i--; )
280                                  rop->preop.cmat[j*nc+i] = 1./(double)nc;
281                          break;
# Line 267 | Line 290 | checksymbolic(ROPMAT *rop)
290          memcpy(rop->rmp->wlpart, WLPART, sizeof(rop->rmp->wlpart));
291          rop->rmp->ncomp = rop->preop.clen / nc;
292                                          /* decide on output type */
293 <        if (!strcmp(rop->preop.csym, "XYZ")) {
293 >        if (!strcasecmp(rop->preop.csym, "XYZ")) {
294                  if (dt <= DTspec)
295                          rop->rmp->dtype = DTxyze;
296 <        } else if (!strcmp(rop->preop.csym, "RGB")) {
296 >        } else if (!strcasecmp(rop->preop.csym, "RGB")) {
297                  if (dt <= DTspec)
298                          rop->rmp->dtype = DTrgbe;
299          } else if (rop->rmp->dtype == DTspec)
# Line 278 | Line 301 | checksymbolic(ROPMAT *rop)
301          return(1);
302   }
303  
304 < static int
304 > /* Set up color transform for matrix */
305 > int
306   get_component_xfm(ROPMAT *rop)
307   {
308          int     i, j;
# Line 361 | Line 385 | get_component_xfm(ROPMAT *rop)
385          return(1);
386   }
387  
388 < static int
388 > /* Apply the given color transform and/or scaling operation */
389 > int
390   apply_op(RMATRIX *dst, const RMATRIX *src, const RUNARYOP *ro)
391   {
392          if (ro->clen > 0) {
# Line 374 | Line 399 | apply_op(RMATRIX *dst, const RMATRIX *src, const RUNAR
399                          return(0);
400                  rmx_free(res);
401          } else if (dst != src)
402 <                memcpy(dst->mtx, src->mtx,
378 <                                sizeof(double)*dst->ncomp*dst->ncols*dst->nrows);
402 >                memcpy(dst->mtx, src->mtx, rmx_array_size(dst));
403          if (ro->nsf == dst->ncomp)
404                  rmx_scale(dst, ro->sca);
405          return(1);
406   }
407  
408 < static int
408 > /* Open the associated input file and load/check header */
409 > int
410   open_input(ROPMAT *rop)
411   {
412          int     outtype;
# Line 403 | Line 428 | open_input(ROPMAT *rop)
428   }
429  
430   /* Return nominal wavelength associated with input component (return nm) */
431 < static double
431 > double
432   l_wavelength(char *nam)
433   {
434          double  comp = argument(1);
# Line 427 | Line 452 | l_wavelength(char *nam)
452   }
453  
454   /* Return ith input with optional channel selector */
455 < static double
455 > double
456   l_chanin(char *nam)
457   {
458          double  inp = argument(1);
# Line 452 | Line 477 | l_chanin(char *nam)
477          return(mop[mi].rmp->mtx[cur_col*in_ncomp + chan]);
478   }
479  
480 < static int
480 > /* Set up our operations and check consistency */
481 > int
482   initialize(RMATRIX *imp)
483   {
484          int     i;
# Line 465 | Line 491 | initialize(RMATRIX *imp)
491                  restype = mop[i].rmp->dtype;
492                  if (!imp->dtype || (restype = rmx_newtype(restype, imp->dtype)) > 0)
493                          imp->dtype = restype;
494 <                else
494 >                else if (!nowarn)
495                          fprintf(stderr, "%s: warning - data type mismatch\n",
496                                          mop[i].inspec);
497                  if (!i) {
472                        imp->nrows = in_nrows = mop[0].rmp->nrows;
498                          imp->ncols = mop[0].rmp->ncols;
499                          imp->ncomp = mop[0].rmp->ncomp;
500                          memcpy(imp->wlpart, mop[0].rmp->wlpart, sizeof(imp->wlpart));
501 <                } else if ((mop[i].rmp->nrows != imp->nrows) |
502 <                                (mop[i].rmp->ncols != imp->ncols) |
503 <                                (mop[i].rmp->ncomp != imp->ncomp)) {
501 >                } else if ((mop[i].rmp->ncols != imp->ncols) |
502 >                                (mop[i].rmp->ncomp != imp->ncomp) |
503 >                                ((in_nrows > 0) & (mop[i].rmp->nrows > 0) &
504 >                                        (mop[i].rmp->nrows != in_nrows))) {
505                          fprintf(stderr, "%s: mismatch in size or #components\n",
506                                          mop[i].inspec);
507                          return(0);
508                  }                       /* XXX should check wlpart? */
509 +                if (in_nrows <= 0)
510 +                        in_nrows = imp->nrows = mop[i].rmp->nrows;
511          }                               /* set up .cal environment */
512          esupport |= E_VARIABLE|E_FUNCTION|E_RCONST;
513          esupport &= ~(E_OUTCHAN|E_INCHAN);
# Line 497 | Line 525 | initialize(RMATRIX *imp)
525          return(1);
526   }
527  
528 < static void
528 > /* Copy input header information to output header, indented */
529 > void
530   output_headinfo(FILE *fp)
531   {
532          int     i;
# Line 520 | Line 549 | output_headinfo(FILE *fp)
549          }
550   }
551  
552 < static int
553 < combine_input(ROPMAT *res, FILE *fout)
552 > /* Spawn the indicated number of children and return 1 in parent */
553 > int
554 > spawned_children(int np)
555   {
556 <        int     set_r, set_c;
557 <        RMATRIX *tmp = NULL;
558 <        int     co_set;
559 <        int     i;
560 <                                        /* allocate input row buffers */
556 >        int     i, rv;
557 >
558 > #if defined(_WIN32) || defined(_WIN64)
559 >        if (np > 1) {
560 >                if (!nowarn)
561 >                        fputs("Warning: only one process under Windows\n", stderr);
562 >                np = 1;
563 >        } else
564 > #endif
565 >        if ((in_nrows > 0) & (np*4 > in_nrows))
566 >                np = in_nrows/4;
567 >                                /* we'll be doing a row at a time */
568          for (i = 0; i < nmats; i++) {
569 <                mop[i].imx.nrows = 1;   /* we'll be doing a row at a time */
569 >                mop[i].imx.nrows = 1;
570                  if (!rmx_prepare(&mop[i].imx))
571                          goto memerror;
572                  if (mop[i].rmp != &mop[i].imx) {
# Line 538 | Line 575 | combine_input(ROPMAT *res, FILE *fout)
575                                  goto memerror;
576                  }
577          }
578 <                                        /* prep output row buffers */
579 <        if (mcat || res->preop.clen > 0) {
580 <                if (!split_input(res))  /* need separate buffer */
544 <                        return(0);
545 <                if (res->preop.clen > 0)
546 <                        res->rmp->ncomp = res->preop.clen / res->imx.ncomp;
547 <                res->rmp->nrows = 1;
548 <                if (!mcat | !mcat_last && !rmx_prepare(res->rmp))
578 >                                /* prep output row buffer(s) */
579 >        if (mop[nmats].preop.clen > 0) {
580 >                if (!split_input(&mop[nmats]))  /* need separate buffer */
581                          goto memerror;
582 +                mop[nmats].rmp->ncomp = mop[nmats].preop.clen /
583 +                                        mop[nmats].imx.ncomp;
584          }
585 <        if (mcat && mcat_last &&
586 <                        !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp)))
585 >        mop[nmats].imx.nrows = 1;
586 >        if (!rmx_prepare(&mop[nmats].imx))
587                  goto memerror;
588 <        res->imx.nrows = 1;
589 <        if (!rmx_prepare(&res->imx))
588 >        if (mop[nmats].rmp != &mop[nmats].imx) {
589 >                mop[nmats].rmp->nrows = 1;
590 >                if (!rmx_prepare(mop[nmats].rmp))
591 >                        goto memerror;
592 >        }
593 >        if (np <= 1) {          /* single process return */
594 > #ifdef getc_unlocked
595 >                for (i = 0; i < nmats; i++)
596 >                        flockfile(mop[i].infp);
597 >                flockfile(stdout);
598 > #endif
599 >                return(0);
600 >        }
601 >        fflush(stdout);         /* flush header & spawn children */
602 >        nchildren = np + 1;     /* extra child to sequence output */
603 >        cproc = (SUBPROC *)malloc(sizeof(SUBPROC)*nchildren);
604 >        if (!cproc)
605                  goto memerror;
606 +        for (i = nchildren; i--; ) cproc[i] = sp_inactive;
607 +        cproc[nchildren-1].flags |= PF_FILT_OUT;
608 +                                /* start each child from parent */
609 +        for (i = 0; i < nchildren; i++)
610 +                if ((rv = open_process(&cproc[i], NULL)) <= 0)
611 +                        break;  /* child breaks here */
612 +        if (rv < 0) {
613 +                perror("fork"); /* WTH? */
614 +                close_processes(cproc, i);
615 +                exit(1);
616 +        }
617 +        if (i != nchildren-1) { /* last child is sole reader */
618 +                int     j = i;
619 +                while (j-- > 0) {
620 +                        close(cproc[j].r);
621 +                        cproc[j].r = -1;
622 +                }
623 +        }
624 +        if (rv > 0)
625 +                return(1);      /* parent return value */
626 +
627 +        inchild = i;            /* else set our child index */
628 +        while (i-- > 0)         /* only parent writes siblings */
629 +                close(cproc[i].w);
630 +
631 +        i = nmats;              /* close matrix streams (carefully) */
632 +        while (i-- > 0) {
633 +                if (mop[i].infp != stdin) {
634 +                        close(fileno(mop[i].infp));     /* avoid lseek() */
635 +                        fclose(mop[i].infp);            /* ! pclose() */
636 +                }
637 +                mop[i].infp = NULL;
638 +        }
639 +        fpurge(stdin);          /* discard previously buffered input */
640 +
641 +        if (inchild == nchildren-1)
642 +                return(-1);     /* output process return value */
643 +
644 +        i = nmats;              /* get matrix rows from parent */
645 +        while (i-- > 0) {
646 +                mop[i].infp = stdin;
647 +                mop[i].imx.dtype = DTrmx_native;
648 +                mop[i].imx.pflags &= ~RMF_SWAPIN;
649 +        }
650 + #ifdef getc_unlocked
651 +        flockfile(stdin);
652 + #endif
653 +        mop[nmats].rmp->dtype = DTrmx_native;
654 +        return(0);              /* worker child return value */
655 + memerror:
656 +        fputs("Out of memory in spawned_children()\n", stderr);
657 +        exit(1);
658 + }
659 +
660 + /* Run parental feeder loop */
661 + int
662 + parent_loop(void)
663 + {
664 +        int     i;
665 +
666 +        rmx_reset(&mop[nmats].imx);             /* not touching output side */
667 +        if (mop[nmats].rmp != &mop[nmats].imx) {
668 +                rmx_free(mop[nmats].rmp);
669 +                mop[nmats].rmp = &mop[nmats].imx;
670 +        }
671 + #ifdef getc_unlocked
672 +        for (i = 0; i < nmats; i++)             /* we handle matrix inputs */
673 +                flockfile(mop[i].infp);
674 + #endif
675 +                                                /* load & send rows to kids */
676 +        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
677 +            int         wfd = cproc[cur_row % (nchildren-1)].w;
678 +            for (i = 0; i < nmats; i++)
679 +                if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
680 +                        if (cur_row > in_nrows) /* unknown #input rows? */
681 +                                break;
682 +                        fprintf(stderr, "%s: load error at row %d\n",
683 +                                        mop[i].inspec, cur_row);
684 +                        return(0);
685 +                }
686 +            if (i < nmats)
687 +                break;
688 +            for (i = 0; i < nmats; i++)
689 +                if (writebuf(wfd, mop[i].imx.mtx, rmx_array_size(&mop[i].imx))
690 +                                        != rmx_array_size(&mop[i].imx)) {
691 +                        fprintf(stderr, "%s: write error at row %d\n",
692 +                                        mop[i].inspec, cur_row);
693 +                        return(0);
694 +                }
695 +        }
696 +        i = close_processes(cproc, nchildren);  /* collect family */
697 +        free(cproc); cproc = NULL; nchildren = 0;
698 +        if (i < 0) {
699 +                if (!nowarn)
700 +                        fputs("Warning: lost child process\n", stderr);
701 +                return(1);
702 +        }
703 +        if (i > 0) {
704 +                fprintf(stderr, "Child exited with status %d\n", i);
705 +                return(0);
706 +        }
707 +        return(1);                              /* return success! */
708 + }
709 +
710 + /* Main operation loop, may be run in each child */
711 + int
712 + combine_input(void)
713 + {
714 +        const int       row0 = (inchild >= 0)*inchild;
715 +        const int       rstep = nchildren ? nchildren-1 : 1;
716 +        ROPMAT          *res = &mop[nmats];
717 +        int             set_r, set_c;
718 +        RMATRIX         *tmp = NULL;
719 +        int             co_set;
720 +        int             i;
721 +
722 +        if (mcat_last && !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp))) {
723 +                fputs("Out of buffer space in combine_input()\n", stderr);
724 +                return(0);
725 +        }
726                                          /* figure out what the user set */
727          co_set = fundefined("co");
728          if (!co_set)
# Line 569 | Line 738 | combine_input(ROPMAT *res, FILE *fout)
738          } else                          /* save a little time */
739                  set_r = set_c = 0;
740                                          /* read/process row-by-row */
741 <        for (cur_row = 0; cur_row < in_nrows; cur_row++) {
741 >        for (cur_row = row0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row += rstep) {
742              RMATRIX     *mres = NULL;
743 <            for (i = 0; i < nmats; i++) {
743 >            for (i = 0; i < nmats; i++)
744                  if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
745 <                        fprintf(stderr, "%s: read error at row %d\n",
745 >                        if (cur_row > in_nrows) /* unknown #input rows? */
746 >                                break;
747 >                        fprintf(stderr, "%s: load error at row %d\n",
748                                          mop[i].inspec, cur_row);
749                          return(0);
750                  }
751 +            if (i < nmats)
752 +                break;
753 +            for (i = 0; i < nmats; i++)
754                  if (!apply_op(mop[i].rmp, &mop[i].imx, &mop[i].preop))
755                          return(0);
582            }
756              if (set_r) varset("r", '=', cur_row);
757              for (cur_col = 0; cur_col < in_ncols; cur_col++) {
758                  if (set_c) varset("c", '=', cur_col);
# Line 617 | Line 790 | combine_input(ROPMAT *res, FILE *fout)
790              }
791              rmx_free(mres); mres = NULL;
792              if (!rmx_write_data(res->rmp->mtx, res->rmp->ncomp,
793 <                                res->rmp->ncols, res->rmp->dtype, fout))
793 >                                res->rmp->ncols, res->rmp->dtype, stdout) ||
794 >                                 (inchild >= 0 && fflush(stdout) == EOF)) {
795 >                fprintf(stderr, "Conversion/write error at row %d\n",
796 >                                cur_row);
797                  return(0);
798 +            }
799          }
800 < #if 0           /* we're about to exit, so who cares? */
801 <        rmx_free(tmp);                  /* clean up */
802 <        rmx_reset(res->rmp);
803 <        rmx_reset(&res->imx);
804 <        for (i = 0; i < nmats; i++) {
805 <                rmx_reset(mop[i].rmp);
800 >        return(inchild >= 0 || fflush(stdout) != EOF);
801 > multerror:
802 >        fputs("Unexpected matrix multiply error\n", stderr);
803 >        return(0);
804 > }
805 >
806 > /* Run output process loop when #processes > 1 */
807 > int
808 > output_loop(void)
809 > {
810 >        const size_t    row_size = rmx_array_size(mop[nmats].rmp);
811 >        int             cur_child = 0;
812 >        int             i = nmats;
813 >
814 >        while (i-- > 0) {                               /* free input buffers */
815                  rmx_reset(&mop[i].imx);
816 <                if (mop[i].inspec[0] == '!')
817 <                        pclose(mop[i].infp);
818 <                else if (mop[i].inspec != stdin_name)
819 <                        fclose(mop[i].infp);
634 <                mop[i].infp = NULL;
816 >                if (mop[i].rmp != &mop[i].imx) {
817 >                        rmx_free(mop[i].rmp);
818 >                        mop[i].rmp = &mop[i].imx;
819 >                }
820          }
821 +        if (mop[nmats].rmp != &mop[nmats].imx)          /* output is split? */
822 +                rmx_reset(&mop[nmats].imx);
823 + #ifdef getc_unlocked
824 +        flockfile(stdout);                              /* we own this, now */
825   #endif
826 <        return(fflush(fout) != EOF);
827 < memerror:
828 <        fputs("Out of buffer space in combine_input()\n", stderr);
829 <        return(0);
830 < multerror:
831 <        fputs("Unexpected matrix multiply error in combine_input()\n", stderr);
832 <        return(0);
826 >        for ( ; ; ) {                                   /* loop until no more */
827 >                ssize_t         rv;
828 >                rv = readbuf(cproc[cur_child].r, mop[nmats].rmp->mtx, row_size);
829 >                if (!rv)                                /* out of rows? */
830 >                        break;
831 >                if (rv != row_size) {
832 >                        fputs("Read error\n", stderr);
833 >                        return(0);
834 >                }                                       /* do final conversion */
835 >                if (!rmx_write_data(mop[nmats].rmp->mtx, mop[nmats].rmp->ncomp,
836 >                                mop[nmats].rmp->ncols, mop[nmats].rmp->dtype, stdout)) {
837 >                        fputs("Conversion/write error\n", stderr);
838 >                        return(0);
839 >                }
840 >                cur_child++;
841 >                cur_child *= (cur_child < inchild);     /* loop over workers */
842 >        }
843 >        return(fflush(stdout) != EOF);
844   }
845  
846 < static int
846 > /* Check/convert floating-point arguments following this */
847 > int
848   get_factors(double da[], int n, char *av[])
849   {
850          int     ac;
# Line 653 | Line 854 | get_factors(double da[], int n, char *av[])
854          return(ac);
855   }
856  
857 < static void
857 > /* Resize/reallocate the input array as requested */
858 > void
859   resize_inparr(int n2alloc)
860   {
861          int     i;
862  
863 <        for (i = nmats; i > n2alloc; i--) {
863 >        if (n2alloc == nall)
864 >                return;
865 >        for (i = nall; i-- > n2alloc; ) {
866                  rmx_reset(&mop[i].imx);
867                  if (mop[i].rmp != &mop[i].imx)
868                          rmx_free(mop[i].rmp);
# Line 668 | Line 872 | resize_inparr(int n2alloc)
872                  fputs("Out of memory in resize_inparr()\n", stderr);
873                  exit(1);
874          }
875 <        if (n2alloc > nmats)
876 <                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
875 >        if (n2alloc > nall)
876 >                memset(mop+nall, 0, (n2alloc-nall)*sizeof(ROPMAT));
877          nall = n2alloc;
878   }
879  
# Line 682 | Line 886 | main(int argc, char *argv[])
886          const char      *defCsym = NULL;
887          int             echoheader = 1;
888          int             stdin_used = 0;
889 +        int             nproc = 1;
890          const char      *mcat_spec = NULL;
891 +        int             transpose_mcat = 0;
892          int             n2comp = 0;
893          uby8            comp_ndx[128];
894          int             i;
# Line 709 | Line 915 | main(int argc, char *argv[])
915                          case 'h':
916                                  echoheader = !echoheader;
917                                  break;
918 +                        case 'n':
919 +                                nproc = atoi(argv[++i]);
920 +                                if (nproc <= 0)
921 +                                        goto userr;
922 +                                break;
923                          case 'e':
924                                  if (!n) goto userr;
925                                  comp_ndx[n2comp++] = i++;
# Line 747 | Line 958 | main(int argc, char *argv[])
958                                  }
959                                  break;
960                          case 'C':
961 +                                mcat_last = 0;
962                                  if (!n || isflt(argv[i+1]))
963                                          goto userr;
964                                  defCsym = mop[nmats].preop.csym = argv[++i];
965                                  mop[nmats].preop.clen = 0;
754                                mcat_last = 0;
966                                  break;
967                          case 'c':
968 +                                mcat_last = 0;
969                                  if (n && !isflt(argv[i+1])) {
970                                          mop[nmats].preop.csym = argv[++i];
971                                          mop[nmats].preop.clen = 0;
# Line 769 | Line 981 | main(int argc, char *argv[])
981                                          goto userr;
982                                  }
983                                  mop[nmats].preop.csym = NULL;
772                                mcat_last = 0;
984                                  break;
985                          case 'm':
986                                  if (!n) goto userr;
987 +                                mcat_last = 1;
988 +                                transpose_mcat = (argv[i][2] == 't');
989                                  if (argv[++i][0] == '-' && !argv[i][1]) {
990                                          if (stdin_used++) goto stdin_error;
991                                          mcat_spec = stdin_name;
992                                  } else
993                                          mcat_spec = argv[i];
781                                mcat_last = 1;
994                                  break;
995                          default:
996                                  fprintf(stderr, "%s: unknown option '%s'\n",
# Line 792 | Line 1004 | main(int argc, char *argv[])
1004          }
1005          resize_inparr(nmats+1);         /* extra matrix at end for result */
1006          mop[nmats].inspec = "trailing_ops";
1007 <                                        /* load final concatenation matrix */
1008 <        if (mcat_spec && !(mcat = rmx_load(mcat_spec, RMPnone))) {
1009 <                fprintf(stderr, "%s: error loading concatenation matrix: %s\n",
1010 <                                argv[0], mcat_spec);
1011 <                return(1);
1007 >
1008 >        if (mcat_spec) {                /* load final concatenation matrix? */
1009 >                mcat = rmx_load(mcat_spec);
1010 >                if (!mcat) {
1011 >                        fprintf(stderr, "%s: error loading concatenation matrix: %s\n",
1012 >                                        argv[0], mcat_spec);
1013 >                        return(1);
1014 >                }
1015 >                if (transpose_mcat && !rmx_transpose(mcat)) {
1016 >                        fprintf(stderr, "%s: error transposing concatenation matrix: %s\n",
1017 >                                        argv[0], mcat_spec);
1018 >                        return(1);
1019 >                }
1020          }
1021                                          /* get/check inputs, set constants */
1022          if (!initialize(&mop[nmats].imx))
# Line 836 | Line 1056 | main(int argc, char *argv[])
1056                          return(1);
1057                  mop[nmats].rmp->ncols = mcat->ncols;
1058          }
1059 + #if DTrmx_native==DTfloat
1060 +        if (outfmt == DTdouble)
1061 +                fprintf(stderr, "%s: warning - writing float result as double\n", argv[0]);
1062 + #endif
1063          newheader("RADIANCE", stdout);  /* write output header */
1064          if (echoheader)
1065                  output_headinfo(stdout);
# Line 846 | Line 1070 | main(int argc, char *argv[])
1070                  fprintf(stderr, "%s: unsupported output format\n", argv[0]);
1071                  return(1);
1072          }
1073 <                                        /* process & write rows */
1074 <        return(combine_input(&mop[nmats], stdout) ? 0 : 1);
1073 >        doptimize(1);                   /* optimize definitions */
1074 >        i = spawned_children(nproc);    /* create multiple processes if requested */
1075 >        if (i > 0)                      /* running in parent process? */
1076 >                return(parent_loop() ? 0 : 1);
1077 >        if (i < 0)                      /* running in output process? */
1078 >                return(output_loop() ? 0 : 1);
1079 >                                        /* else we are a worker process */
1080 >        return(combine_input() ? 0 : 1);
1081   stdin_error:
1082          fprintf(stderr, "%s: %s used for more than one input\n",
1083                          argv[0], stdin_name);
1084          return(1);
1085   userr:
1086          fprintf(stderr,
1087 <        "Usage: %s [-h][-f{adfc}][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1087 >        "Usage: %s [-h][-f{adfc}][-n nproc][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1088                          argv[0]);
1089          return(1);
1090   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines