ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/Development/ray/src/rt/RcontribSimulManager.cpp
(Generate patch)

Comparing ray/src/rt/RcontribSimulManager.cpp (file contents):
Revision 2.6 by greg, Wed Nov 6 18:28:52 2024 UTC vs.
Revision 2.24 by greg, Wed Nov 12 19:41:21 2025 UTC

# Line 24 | Line 24 | extern const char      HDRSTR[];
24   extern const char       BIGEND[];
25   extern const char       FMTSTR[];
26  
27 int     contrib = 0;                    // computing contributions?
28
29 int     xres = 0;                       // horizontal (scan) size
30 int     yres = 0;                       // vertical resolution
31
27   // new/exclusive, overwrite if exists, or recover data
28   int     RSDOflags[] = {RDSwrite|RDSexcl|RDSextend, RDSwrite|RDSextend,
29                                  RDSread|RDSwrite};
# Line 57 | Line 52 | struct RowAssignment {
52          uint32                  ac;             // accumulation count
53   };
54  
55 < // Our default data share function
61 < RdataShare *
62 < defDataShare(const char *name, RCOutputOp op, size_t siz)
63 < {
64 <        return new RdataShareMap(name, RSDOflags[op], siz);
65 < }
55 > static const char       ROW_DONE[] = "ROW FINISHED\n";
56  
57 < // Allocate rcontrib accumulator
58 < RcontribMod *
57 > // allocate rcontrib accumulator
58 > static RcontribMod *
59   NewRcMod(const char *prms, const char *binexpr, int ncbins)
60   {
61 <        if (ncbins <= 0) return NULL;
61 >        if (binexpr && !*binexpr) binexpr = NULL;
62          if (!prms) prms = "";
63 <        if (!binexpr & (ncbins > 1)) {
64 <                error(INTERNAL, "missing bin expression");
63 >        if ((ncbins > 1) & !binexpr) {
64 >                error(USER, "missing bin expression");
65                  return NULL;
66          }
67 <        if (ncbins == 1) {              // shouldn't have bin expression?
68 <                if (binexpr && strcmp(binexpr, "0"))
79 <                        error(WARNING, "ignoring non-zero expression for single bin");
80 <                prms = "";
81 <                binexpr = NULL;
82 <        }
67 >        if (ncbins < 1) ncbins = 1;
68 >        
69          RcontribMod *   mp = (RcontribMod *)ecalloc(1, sizeof(RcontribMod) +
70                                                  sizeof(DCOLORV)*(NCSAMP*ncbins-1) +
71                                                  strlen(prms)+1);
72  
73 <        mp->params = strcpy((char *)(mp->cbin + ncbins*NCSAMP), prms);
88 <        if (binexpr) {
73 >        if (binexpr) {                          // get/check bin expression
74                  mp->binv = eparse(const_cast<char *>(binexpr));
75 <                CHECK(mp->binv->type==NUM, WARNING, "constant bin expression");
75 >                if (mp->binv->type == NUM) {    // constant expression (0)?
76 >                        if ((int)evalue(mp->binv) != 0) {
77 >                                sprintf(errmsg, "illegal non-zero constant for bin (%s)",
78 >                                                binexpr);
79 >                                error(USER, errmsg);
80 >                        }
81 >                        if (ncbins > 1) {
82 >                                sprintf(errmsg, "bad bin count (%d should be 1)", ncbins);
83 >                                error(USER, errmsg);
84 >                        }
85 >                        epfree(mp->binv, true);
86 >                        mp->binv = NULL;
87 >                        prms = "";
88 >                        ncbins = 1;
89 >                }
90          }
91 +        mp->params = strcpy((char *)(mp->cbin + ncbins*NCSAMP), prms);
92          mp->nbins = ncbins;
93          return mp;
94   }
95  
96 < // Free an RcontribMod
96 > // Free an RcontribMod (public for RcontribSimulManager constructor)
97   void
98   FreeRcMod(void *p)
99   {
# Line 103 | Line 103 | FreeRcMod(void *p)
103          efree(p);
104   }
105  
106 + // Get format identifier
107 + const char *
108 + formstr(int f)
109 + {
110 +        switch (f) {
111 +        case 'a': return("ascii");
112 +        case 'f': return("float");
113 +        case 'd': return("double");
114 +        case 'c': return(NCSAMP==3 ? COLRFMT : SPECFMT);
115 +        }
116 +        return("unknown");
117 + }
118 +
119 + // Standard file data share function
120 + RdataShare *
121 + fileDataShare(const char *name, RCOutputOp op, size_t siz)
122 + {
123 +        if (op == RCOrecover && access(name, R_OK|W_OK) < 0) {
124 +                sprintf(errmsg, "cannot recover from '%s'", name);
125 +                error(SYSTEM, errmsg);
126 +                return NULL;
127 +        }
128 +        RdataShare *    rds = new RdataShareFile(name, RSDOflags[op],
129 +                                                 siz*(op != RCOforce));
130 +                                                
131 +        if (!rds || (op == RCOforce && rds->Resize(siz) < siz)) {
132 +                delete rds;
133 +                sprintf(errmsg, "cannot create %lu byte output file '%s'",
134 +                                        (unsigned long)siz, name);
135 +                error(SYSTEM, errmsg);
136 +                return NULL;
137 +        }
138 +        return rds;
139 + }
140 +
141 + // Memory-mapped data share function
142 + RdataShare *
143 + mapDataShare(const char *name, RCOutputOp op, size_t siz)
144 + {
145 +        if (op == RCOrecover && access(name, R_OK|W_OK) < 0) {
146 +                sprintf(errmsg, "cannot recover from '%s'", name);
147 +                error(SYSTEM, errmsg);
148 +                return NULL;
149 +        }
150 +        RdataShare *    rds = new RdataShareMap(name, RSDOflags[op],
151 +                                                 siz*(op != RCOforce));
152 +
153 +        if (!rds || (op == RCOforce && rds->Resize(siz) < siz)) {
154 +                delete rds;
155 +                sprintf(errmsg, "cannot create %lu byte output map '%s'",
156 +                                        (unsigned long)siz, name);
157 +                error(SYSTEM, errmsg);
158 +                return NULL;
159 +        }
160 +        return rds;
161 + }
162 +
163   // Set output format ('f', 'd', or 'c')
164   bool
165   RcontribSimulManager::SetDataFormat(int ty)
# Line 134 | Line 191 | RcontribSimulManager::SetDataFormat(int ty)
191   int
192   RcontribSimulManager::RctCall(RAY *r, void *cd)
193   {
194 <        if (!r->ro || r->ro->omod == OVOID)     // hit nothing?
195 <                return 0;
196 <                                                // shadow ray not on source?
194 >        int     i;
195 >
196 >        if (!r->ro || (i = r->ro->omod) == OVOID)
197 >                return 0;               // hit nothing
198 >
199          if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
200 <                return 0;
200 >                return 0;               // shadow ray not on source
201  
202 <        const char *            mname = objptr(r->ro->omod)->oname;
202 >        const char *            mname = objptr(i)->oname;
203          RcontribSimulManager *  rcp = (RcontribSimulManager *)cd;
204          RcontribMod *           mp = (RcontribMod *)lu_find(&rcp->modLUT,mname)->data;
205          if (!mp)
206                  return 0;               // not in our modifier list
207  
208 <        int                     bi = 0; // get bin index
208 >        if (rcp->HasFlag(RCcontrib)) {  // pre-emptive check for zero
209 >                for (i = NCSAMP; i--; )
210 >                        if (r->rcoef[i]*r->rcol[i] > FTINY)
211 >                                break;
212 >                if (i < 0)
213 >                        return 0;       // zero contribution
214 >        } else if (sintens(r->rcoef) <= FTINY)
215 >                return 0;               // zero coefficient
216 >
217 >        int     bi = 0;                 // get bin index
218          if (mp->binv) {
219                  worldfunc(RCCONTEXT, r);
220                  set_eparams(mp->params);
# Line 163 | Line 231 | RcontribSimulManager::RctCall(RAY *r, void *cd)
231          }
232          SCOLOR          contr;
233          raycontrib(contr, r, PRIMARY);          // compute coefficient
234 <        if (contrib)
234 >        if (rcp->HasFlag(RCcontrib))
235                  smultscolor(contr, r->rcol);    // -> value contribution
236 <        for (int i = 0; i < NCSAMP; i++)
236 >
237 >        for (i = 0; i < NCSAMP; i++)
238                  *dvp++ += contr[i];             // accumulate color/spectrum
239          return 1;
240   }
# Line 193 | Line 262 | bool
262   RcontribSimulManager::AddModifier(const char *modn, const char *outspec,
263                                  const char *prms, const char *binval, int bincnt)
264   {
265 <        if (!modn | !outspec | (bincnt <= 0) || !*modn | !*outspec) {
265 >        if (!modn | !outspec || !*modn | !*outspec) {
266                  error(WARNING, "ignoring bad call to AddModifier()");
267                  return false;
268          }
269 +        if (*outspec == '!') {
270 +                error(USER, "command output not supported by RcontribSimulManager");
271 +                return false;
272 +        }
273          if (!nChan) {                           // initial call?
274 +                if ((xres < 0) | (yres <= 0)) {
275 +                        error(USER, "xres, yres must be set before first modifier");
276 +                        return false;
277 +                }
278                  if (!SetDataFormat(dtyp))
279                          return false;
280                  nChan = NCSAMP;
281          } else if (nChan != NCSAMP) {
282 <                error(INTERNAL, "number of spectral channels must be fixed");
282 >                error(USER, "# spectral channels must be fixed in AddModifier()");
283                  return false;
284          }
285          if (Ready()) {
# Line 225 | Line 302 | RcontribSimulManager::AddModifier(const char *modn, co
302          const int       binndx = hasFormat(outspec, "diouxX");
303          int             bin0 = 0;
304          char            fnbuf[512];
305 <        if (!modndx | (modndx > binndx))
305 >        if (!modndx || (binndx > 0) & (modndx > binndx))
306                  sprintf(fnbuf, outspec, bin0, modn);
307          else
308                  sprintf(fnbuf, outspec, modn, bin0);
# Line 254 | Line 331 | RcontribSimulManager::AddModifier(const char *modn, co
331          mp->opl = op;                   // first (maybe only) output channel
332          if (modndx)                     // remember modifier if part of name
333                  op->omod = lp->key;
334 <        if (binndx > 0) {               // append output image/bin list
334 >        if (binndx) {                   // append output image/bin list
335                  op->rowBytes += dsiz;
336                  op->obin = bin0;
337                  for (bincnt = 1; bincnt < mp->nbins; bincnt++) {
338 <                        if (!modndx | (modndx > binndx))
338 >                        if (!modndx || (binndx > 0) &  (modndx > binndx))
339                                  sprintf(fnbuf, outspec, bin0+bincnt, modn);
340                          else
341                                  sprintf(fnbuf, outspec, modn, bin0+bincnt);
# Line 277 | Line 354 | RcontribSimulManager::AddModifier(const char *modn, co
354                          op->rowBytes += dsiz;
355                  }
356          } else                          // else send all results to this channel
357 <                op->rowBytes += bincnt*dsiz;
357 >                op->rowBytes += mp->nbins*dsiz;
358          return true;
359   }
360  
# Line 298 | Line 375 | RcontribSimulManager::AddModFile(const char *modfn, co
375          }
376          char            mod[MAXSTR];
377          while (fgetword(mod, sizeof(mod), fp))
378 <                if (!AddModifier(mod, outspec, prms, binval, bincnt))
378 >                if (!AddModifier(mod, outspec, prms, binval, bincnt)) {
379 >                        fclose(fp);
380                          return false;
381 +                }
382          fclose(fp);
383          return true;
384   }
# Line 308 | Line 387 | RcontribSimulManager::AddModFile(const char *modfn, co
387   static int
388   checkModExists(const LUENT *lp, void *p)
389   {
390 <        if (modifier(lp->key) != OVOID)
390 >        OBJECT  mod = modifier(lp->key);
391 >
392 >        if ((mod != OVOID) & (mod < nsceneobjs))
393                  return 1;
394  
395          sprintf(errmsg, "tracked modifier '%s' not found in main scene", lp->key);
# Line 321 | Line 402 | int
402   RcontribSimulManager::PrepOutput()
403   {
404          if (!outList || !RtraceSimulManager::Ready()) {
405 <                error(INTERNAL, "PrepOutput() called before octree & modifiers assigned");
405 >                error(INTERNAL, "PrepOutput() called before octree & modifiers set");
406                  return -1;
407          }
408          if (!cdsF) {
409 <                error(INTERNAL, "missing RdataShare constructor call (*cdsF)");
409 >                error(INTERNAL, "missing RdataShare constructor call (cdsF)");
410                  return -1;
411          }
412          if (lu_doall(&modLUT, checkModExists, NULL) < 0)
413                  return -1;
414  
415 +        outList->nRows = yres * (xres + !xres); // all outputs have same #rows
416          int     remWarnings = 20;
417          for (RcontribOutput *op = outList; op; op = op->next) {
418                  if (op->rData) {
419                          error(INTERNAL, "output channel already open in PrepOutput()");
420                          return -1;
421                  }
422 <                op->nRows = yres * (xres + !xres);
422 >                op->nRows = outList->nRows;
423                  op->rData = (*cdsF)(op->ofname, outOp,
424                                          GetHeadLen()+1024 + op->nRows*op->rowBytes);
425                  freeqstr(op->ofname); op->ofname = NULL;
# Line 346 | Line 428 | RcontribSimulManager::PrepOutput()
428                          if (rd < 0)
429                                  return -1;
430                          if (rd >= op->nRows) {
431 <                                if (remWarnings >= 0) {
432 <                                        sprintf(errmsg, "recovered output '%s' already done",
431 >                                if (remWarnings > 0) {
432 >                                        sprintf(errmsg, "recovered output '%s' is complete",
433                                                          op->GetName());
434 <                                        error(WARNING, remWarnings ? errmsg : "etc...");
353 <                                        remWarnings--;
434 >                                        error(WARNING, --remWarnings ? errmsg : "etc...");
435                                  }
436                                  rd = op->nRows;
437                          }
# Line 364 | Line 445 | RcontribSimulManager::PrepOutput()
445          }
446          rowsDone.NewBitMap(outList->nRows);     // create row completion map
447          rowsDone.ClearBits(0, rInPos, true);
448 <        return rInPos;
448 >        return nrDone = rInPos;
449   }
450  
451   // Create header in open write-only channel
# Line 392 | Line 473 | RcontribOutput::NewHeader(const RcontribSimulManager *
473          strcpy(hdr+begData, ROWZEROSTR);
474          rowCountPos = begData+LNROWSTR;
475          begData += sizeof(ROWZEROSTR)-1;
476 <        if (!xres | (rowBytes > esiz)) {
476 >        if (!rcp->xres | (rowBytes > esiz)) {
477                  sprintf(hdr+begData, "NCOLS=%d\n", int(rowBytes/esiz));
478                  begData += strlen(hdr+begData);
479          }
480          sprintf(hdr+begData, "%s%d\n", NCOMPSTR, NCSAMP);
481          begData += strlen(hdr+begData);
482          if (NCSAMP > 3) {
483 <                sprintf(hdr+begData, "%s %f %f %f %f\n", WLSPLTSTR,
483 >                sprintf(hdr+begData, "%s %g %g %g %g\n", WLSPLTSTR,
484                                  WLPART[0], WLPART[1], WLPART[2], WLPART[3]);
485                  begData += strlen(hdr+begData);
486          }
# Line 430 | Line 511 | RcontribOutput::NewHeader(const RcontribSimulManager *
511                          hdr[begData++] = ' ';
512          hdr[begData++] = '\n';          // EOL for data format
513          hdr[begData++] = '\n';          // end of nominal header
514 <        if ((xres > 0) & (rowBytes == esiz)) {  // tack on resolution string?
515 <                sprintf(hdr+begData, PIXSTDFMT, yres, xres);
514 >        if ((rcp->xres > 0) & (rowBytes == esiz)) {     // tack on resolution string?
515 >                sprintf(hdr+begData, PIXSTDFMT, rcp->yres, rcp->xres);
516                  begData += strlen(hdr+begData);
517          }
518          return rData->ReleaseMemory(hdr, RDSwrite);
# Line 484 | Line 565 | RcontribOutput::CheckHeader(const RcontribSimulManager
565                  return -1;
566          }
567                                                  // check #columns
568 <        if (((cp = findArgs(hdr, "NCOLS=", begData)) && atoi(cp)*esiz != rowBytes) ||
569 <                        !xres | (rowBytes > esiz)) {
570 <                sprintf(errmsg, "expected NCOLS=%d in '%s'",
490 <                                int(rowBytes/esiz), GetName());
568 >        if ((cp = findArgs(hdr, "NCOLS=", begData)) ? (atoi(cp)*esiz != rowBytes)
569 >                                                    : (!rcp->xres | (rowBytes > esiz))) {
570 >                sprintf(errmsg, "expected NCOLS=%d in '%s'", int(rowBytes/esiz), GetName());
571                  error(USER, errmsg);
572                  return -1;
573          }
# Line 500 | Line 580 | RcontribOutput::CheckHeader(const RcontribSimulManager
580          rowCountPos = cp - hdr;
581          int     rlast = atoi(cp);
582          begData++;                              // advance past closing EOL
583 <        if ((xres > 0) & (rowBytes == esiz)) {  // check/skip resolution string?
583 >        if ((rcp->xres > 0) & (rowBytes == esiz)) {     // check/skip resolution string?
584                  char    rbuf[64];
585 <                sprintf(rbuf, PIXSTDFMT, yres, xres);
585 >                sprintf(rbuf, PIXSTDFMT, rcp->yres, rcp->xres);
586                  int     rlen = strlen(rbuf);
587                  if (strncmp(rbuf, hdr+begData, rlen)) {
588                          sprintf(errmsg, "bad resolution string in '%s'", GetName());
# Line 529 | Line 609 | RcontribSimulManager::ResetRow(int r)
609                          return false;
610  
611          rowsDone.ClearBits(r, rInPos-r, false);
612 <        rInPos = r;
612 >        nrDone = rInPos = r;
613          return true;
614   }
615  
# Line 576 | Line 656 | putModContrib(const LUENT *lp, void *p)
656                  }
657                  } break;
658          default:
659 <                error(CONSISTENCY, "unsupported output type in sendModContrib()");
659 >                error(CONSISTENCY, "unsupported output type in putModContrib()");
660                  return -1;
661          }
662                                                  // clear for next tally
# Line 595 | Line 675 | RcontribSimulManager::ComputeRecord(const FVECT orig_d
675                  return 0;
676          }
677          if (nkids > 0) {                        // in parent process?
678 <                int     k = GetChild();         // updates output rows
679 <                if (k < 0) return -1;           // can't really happen
678 >                int     k = GetChild(false);    // updates output rows
679 >                if (k < 0) return -1;           // someone died?
680                  RowAssignment   rass;
681                  rass.row = kidRow[k] = rInPos++;
682                  rass.ac = accum;
# Line 641 | Line 721 | RcontribSimulManager::GetChild(bool forceWait)
721                  return -1;
722                                                  // take inventory
723          int     pn, n = 0;
724 <        fd_set  writeset, errset;
725 <        FD_ZERO(&writeset); FD_ZERO(&errset);
724 >        fd_set  readset, errset;
725 >        FD_ZERO(&readset); FD_ZERO(&errset);
726          for (pn = nkids; pn--; ) {
727                  if (kidRow[pn] < 0) {           // child already ready?
728                          if (forceWait) continue;
729                          return pn;              // good enough
730                  }
731 <                FD_SET(kid[pn].w, &writeset);   // will check on this one
732 <                FD_SET(kid[pn].w, &errset);
733 <                if (kid[pn].w >= n)
734 <                        n = kid[pn].w + 1;
731 >                FD_SET(kid[pn].r, &readset);    // will check on this one
732 >                FD_SET(kid[pn].r, &errset);
733 >                if (kid[pn].r >= n)
734 >                        n = kid[pn].r + 1;
735          }
736          if (!n)                                 // every child is idle?
737                  return -1;
738                                                  // wait on "busy" child(ren)
739 <        while ((n = select(n, NULL, &writeset, &errset, NULL)) <= 0)
739 >        while ((n = select(n, &readset, NULL, &errset, NULL)) <= 0)
740                  if (errno != EINTR) {
741                          error(SYSTEM, "select call failed in GetChild()");
742                          return -1;
743                  }
744 +        char    buf[sizeof(ROW_DONE)] = "X";
745          pn = -1;                                // get flags set by select
746          for (n = nkids; n--; )
747                  if (kidRow[n] >= 0 &&
748 <                                FD_ISSET(kid[n].w, &writeset) |
749 <                                FD_ISSET(kid[n].w, &errset)) {
748 >                                FD_ISSET(kid[n].r, &readset) |
749 >                                FD_ISSET(kid[n].r, &errset)) {
750 >                                                // check for error
751 >                        if (FD_ISSET(kid[n].r, &errset) ||
752 >                                        read(kid[n].r, buf, sizeof(ROW_DONE)) <= 0 ||
753 >                                        memcmp(buf, ROW_DONE, sizeof(ROW_DONE)))
754 >                                return -1;
755                                                  // update output row counts
756 <                        if (!FD_ISSET(kid[n].w, &errset))
757 <                                UpdateRowsDone(kidRow[n]);
672 <                        kidRow[n] = -1;         // flag it available
756 >                        UpdateRowsDone(kidRow[n]);
757 >                        kidRow[n] = -1;         // flag child available
758                          pn = n;
759                  }
760          return pn;
# Line 683 | Line 768 | RcontribSimulManager::UpdateRowsDone(int r)
768                  error(WARNING, "redundant call to UpdateRowsDone()");
769                  return false;
770          }
771 <        int     nDone = GetRowFinished();
772 <        if (nDone <= r)
771 >        GetRowFinished();
772 >        if (nrDone <= r)
773                  return true;                    // nothing to update, yet
774          for (RcontribOutput *op = outList; op; op = op->next)
775 <                if (!op->SetRowsDone(nDone))
775 >                if (!op->SetRowsDone(nrDone))
776                          return false;
777          return true;                            // up-to-date
778   }
# Line 707 | Line 792 | RcontribSimulManager::RunChild()
792                          error(CONSISTENCY, "bad accumulator count in child");
793                          exit(1);
794                  }
795 <                if (rass.ac > accum)
796 <                        vecList = (FVECT *)erealloc(vecList,
797 <                                                sizeof(FVECT)*2*rass.ac);
795 >                if (rass.ac > accum) {
796 >                        efree(vecList);
797 >                        vecList = (FVECT *)emalloc(sizeof(FVECT)*2*rass.ac);
798 >                }
799                  accum = rass.ac;
800                  rInPos = rass.row;
801  
# Line 719 | Line 805 | RcontribSimulManager::RunChild()
805  
806                  if (ComputeRecord(vecList) <= 0)
807                          exit(1);
808 +                                                // signal this row is done
809 +                if (write(1, ROW_DONE, sizeof(ROW_DONE)) != sizeof(ROW_DONE))
810 +                        exit(1);
811          }
812          if (nr) {
813                  error(SYSTEM, "read error in child process");
# Line 744 | Line 833 | RcontribSimulManager::StartKids(int n2go)
833          fflush(stdout);                         // shouldn't use, anyway
834          while (nkids < n2go) {
835                  kid[nkids] = sp_inactive;
747                kid[nkids].w = dup(1);
748                kid[nkids].flags |= PF_FILT_OUT;
836                  int     rv = open_process(&kid[nkids], NULL);
837                  if (!rv) {                      // in child process?
838 <                        while (nkids-- > 0)
838 >                        while (nkids-- > 0) {
839 >                                close(kid[nkids].r);
840                                  close(kid[nkids].w);
841 +                        }
842                          free(kid); free(kidRow);
843                          kid = NULL; kidRow = NULL;
844                          RunChild();             // should never return

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)