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

Comparing ray/src/rt/pmap.c (file contents):
Revision 2.12 by greg, Mon Sep 26 20:19:30 2016 UTC vs.
Revision 2.14 by rschregle, Tue Mar 20 19:55:33 2018 UTC

# Line 2 | Line 2
2   static const char RCSid[] = "$Id$";
3   #endif
4  
5 +
6   /*
7     ======================================================================
8     Photon map main module
# Line 16 | Line 17 | static const char RCSid[] = "$Id$";
17   */
18  
19  
19
20   #include "pmap.h"
21   #include "pmapmat.h"
22   #include "pmapsrc.h"
# Line 26 | Line 26 | static const char RCSid[] = "$Id$";
26   #include "pmapdiag.h"
27   #include "otypes.h"
28   #include <time.h>
29 < #include <sys/stat.h>
30 < #include <sys/mman.h>
31 < #include <sys/wait.h>
29 > #if NIX
30 >   #include <sys/stat.h>
31 >   #include <sys/mman.h>
32 >   #include <sys/wait.h>
33 > #endif
34  
35  
34
36   void savePmaps (const PhotonMap **pmaps, int argc, char **argv)
37   {
38     unsigned t;
# Line 127 | Line 128 | void tracePhoton (RAY *ray)
128   /* Follow photon as it bounces around... */
129   {
130     long mod;
131 <   OBJREC* mat;
131 >   OBJREC *mat, *port = NULL;
132 >  
133 >   if (!ray -> parent) {
134 >      /* !!!  PHOTON PORT REJECTION SAMPLING HACK: get photon port for
135 >       * !!!  primary ray from ray -> ro, then reset the latter to NULL so
136 >       * !!!  as not to interfere with localhit() */
137 >      port = ray -> ro;
138 >      ray -> ro = NULL;
139 >   }
140  
141     if (ray -> rlvl > photonMaxBounce) {
142   #ifdef PMAP_RUNAWAY_WARN  
# Line 138 | Line 147 | void tracePhoton (RAY *ray)
147    
148     if (colorAvg(ray -> cext) > FTINY && !photonParticipate(ray))
149        return;
150 <      
150 >
151     if (localhit(ray, &thescene)) {
152        mod = ray -> ro -> omod;
153 <      
153 >
154 >      if (port && ray -> ro != port) {
155 >         /* !!! PHOTON PORT REJECTION SAMPLING HACK !!!
156 >          * Terminate photon if emitted from port without intersecting it;
157 >          * this can happen when the port's partitions extend beyond its
158 >          * actual geometry, e.g.  with polygons.  Since the total flux
159 >          * relayed by the port is based on the (in this case) larger
160 >          * partition area, it is overestimated; terminating these photons
161 >          * constitutes rejection sampling and thereby compensates any bias
162 >          * incurred by the overestimated flux.  */
163 > #ifdef PMAP_PORTREJECT_WARN
164 >         sprintf(errmsg, "photon outside port %s", ray -> ro -> oname);
165 >         error(WARNING, errmsg);
166 > #endif        
167 >         return;
168 >      }
169 >
170        if ((ray -> clipset && inset(ray -> clipset, mod)) || mod == OVOID) {
171           /* Transfer ray if modifier is VOID or clipped within antimatta */
172           RAY tray;
# Line 173 | Line 198 | static void preComputeGlobal (PhotonMap *pmap)
198  
199     repComplete = numPreComp = finalGather * pmap -> numPhotons;
200    
201 <   if (photonRepTime) {
202 <      sprintf(errmsg, "Precomputing irradiance for %ld global photons...\n",
201 >   if (verbose) {
202 >      sprintf(errmsg,
203 >              "\nPrecomputing irradiance for %ld global photons\n",
204                numPreComp);
205        eputs(errmsg);
206 + #if NIX      
207        fflush(stderr);
208 + #endif      
209     }
210    
211     /* Copy photon map for precomputed photons */
# Line 204 | Line 232 | static void preComputeGlobal (PhotonMap *pmap)
232    
233     for (i = 0; i < numPreComp; i++) {
234        /* Get random photon from stratified distribution in source heap to
235 <       * avoid duplicates and clutering */
235 >       * avoid duplicates and clustering */
236        pIdx = firstPhoton(pmap) +
237               (unsigned long)((i + pmapRandom(pmap -> randState)) /
238                               finalGather);
# Line 242 | Line 270 | static void preComputeGlobal (PhotonMap *pmap)
270     deletePhotons(pmap);
271     memcpy(pmap, &nuPmap, sizeof(PhotonMap));
272    
273 <   if (photonRepTime) {
274 <      eputs("Rebuilding precomputed photon map...\n");
273 >   if (verbose) {
274 >      eputs("\nRebuilding precomputed photon map\n");
275 > #if NIX      
276        fflush(stderr);
277 + #endif      
278     }
279  
280     /* Rebuild underlying data structure, destroying heap */  
# Line 263 | Line 293 | typedef struct {
293   void distribPhotons (PhotonMap **pmaps, unsigned numProc)
294   {
295     EmissionMap    emap;
296 <   char           errmsg2 [128], shmFname [255];
296 >   char           errmsg2 [128], shmFname [PMAP_TMPFNLEN];
297     unsigned       t, srcIdx, proc;
298     double         totalFlux = 0;
299     int            shmFile, stat, pid;
# Line 295 | Line 325 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
325           initPhotonHeap(pmaps [t]);
326           /* Per-subprocess target count */
327           pmaps [t] -> distribTarget /= numProc;
328 +        
329 +         if (!pmaps [t] -> distribTarget)
330 +            error(INTERNAL, "no photons to distribute in distribPhotons");
331        }
332  
333     initPhotonEmissionFuncs();
334     initPhotonScatterFuncs();
335    
336 <   /* Get photon ports if specified */
337 <   if (ambincl == 1)
305 <      getPhotonPorts();
336 >   /* Get photon ports from modifier list */
337 >   getPhotonPorts(photonPortList);
338  
339     /* Get photon sensor modifiers */
340     getPhotonSensors(photonSensorList);
341    
342 + #if NIX
343     /* Set up shared mem for photon counters (zeroed by ftruncate) */
344 < #if 0  
312 <   snprintf(shmFname, 255, PMAP_SHMFNAME, getpid());
313 <   shmFile = shm_open(shmFname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
314 < #else
315 <   strcpy(shmFname, PMAP_SHMFNAME);
344 >   strcpy(shmFname, PMAP_TMPFNAME);
345     shmFile = mkstemp(shmFname);
317 #endif      
346  
347 <   if (shmFile < 0)
348 <      error(SYSTEM, "failed opening shared memory file in distribPhotons");
347 >   if (shmFile < 0 || ftruncate(shmFile, sizeof(*photonCnt)) < 0)
348 >      error(SYSTEM, "failed shared mem init in distribPhotons");
349  
322   if (ftruncate(shmFile, sizeof(*photonCnt)) < 0)
323      error(SYSTEM, "failed setting shared memory size in distribPhotons");
324
350     photonCnt = mmap(NULL, sizeof(*photonCnt), PROT_READ | PROT_WRITE,
351                      MAP_SHARED, shmFile, 0);
352                      
353     if (photonCnt == MAP_FAILED)
354 <      error(SYSTEM, "failed mapping shared memory in distribPhotons");
354 >      error(SYSTEM, "failed mapping shared memory in distribPhotons");
355 > #else
356 >   /* Allocate photon counters statically on Windoze */
357 >   if (!(photonCnt = malloc(sizeof(PhotonCnt))))
358 >      error(SYSTEM, "failed trivial malloc in distribPhotons");
359 >   photonCnt -> numEmitted = photonCnt -> numComplete = 0;      
360 > #endif /* NIX */
361  
362 <   if (photonRepTime)
363 <      eputs("\n");
362 >   if (verbose) {
363 >      sprintf(errmsg, "\nIntegrating flux from %d sources", nsources);
364 >      
365 >      if (photonPorts) {
366 >         sprintf(errmsg2, " via %d ports", numPhotonPorts);
367 >         strcat(errmsg, errmsg2);
368 >      }
369 >      
370 >      strcat(errmsg, "\n");
371 >      eputs(errmsg);
372 >   }  
373    
374     /* ===================================================================
375      * FLUX INTEGRATION - Get total photon flux from light sources
# Line 343 | Line 383 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
383                                                     : NULL;
384           photonPartition [emap.src -> so -> otype] (&emap);
385          
386 <         if (photonRepTime) {
387 <            sprintf(errmsg, "Integrating flux from source %s ",
386 >         if (verbose) {
387 >            sprintf(errmsg, "\tIntegrating flux from source %s ",
388                      source [srcIdx].so -> oname);
389 <                    
389 >
390              if (emap.port) {
391                 sprintf(errmsg2, "via port %s ",
392                         photonPorts [portCnt].so -> oname);
393                 strcat(errmsg, errmsg2);
394              }
395 <            
396 <            sprintf(errmsg2, "(%lu partitions)...\n", emap.numPartitions);
395 >
396 >            sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions);
397              strcat(errmsg, errmsg2);
398              eputs(errmsg);
399 + #if NIX            
400              fflush(stderr);
401 + #endif            
402           }
403          
404           for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
# Line 371 | Line 413 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
413  
414     if (totalFlux < FTINY)
415        error(USER, "zero flux from light sources");
416 +      
417 +   /* Record start time for progress reports */
418 +   repStartTime = time(NULL);
419  
420 +   if (verbose) {
421 +      sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc);
422 +      eputs(errmsg);
423 +   }
424 +
425     /* MAIN LOOP */  
426     for (proc = 0; proc < numProc; proc++) {
427 + #if NIX          
428        if (!(pid = fork())) {
429 <         /* SUBPROCESS ENTERS HERE.
430 <            All opened and memory mapped files are inherited */
429 >         /* SUBPROCESS ENTERS HERE; open and mmapped files inherited */
430 > #else
431 >      if (1) {
432 >         /* No subprocess under Windoze */
433 > #endif
434 >         /* Local photon counters for this subprocess */
435           unsigned       passCnt = 0, prePassCnt = 0;
436           unsigned long  lastNumPhotons [NUM_PMAP_TYPES];
437           unsigned long  localNumEmitted = 0; /* Num photons emitted by this
# Line 384 | Line 439 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
439          
440           /* Seed RNGs from PID for decorellated photon distribution */
441           pmapSeed(randSeed + proc, partState);
442 <         pmapSeed(randSeed + proc, emitState);
443 <         pmapSeed(randSeed + proc, cntState);
444 <         pmapSeed(randSeed + proc, mediumState);
445 <         pmapSeed(randSeed + proc, scatterState);
446 <         pmapSeed(randSeed + proc, rouletteState);
442 >         pmapSeed(randSeed + (proc + 1) % numProc, emitState);
443 >         pmapSeed(randSeed + (proc + 2) % numProc, cntState);
444 >         pmapSeed(randSeed + (proc + 3) % numProc, mediumState);
445 >         pmapSeed(randSeed + (proc + 4) % numProc, scatterState);
446 >         pmapSeed(randSeed + (proc + 5) % numProc, rouletteState);
447                    
448           for (t = 0; t < NUM_PMAP_TYPES; t++)
449              lastNumPhotons [t] = 0;
# Line 409 | Line 464 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
464                  * iterations; make it clear to user which photon maps are
465                  * missing so (s)he can check geometry and materials */
466                 if (++prePassCnt > maxPreDistrib) {
467 <                  sprintf(errmsg,
413 <                          "proc %d, source %s: too many prepasses",
414 <                          proc, source [srcIdx].so -> oname);              
467 >                  sprintf(errmsg, "proc %d: too many prepasses", proc);
468  
469                    for (t = 0; t < NUM_PMAP_TYPES; t++)
470                       if (pmaps [t] && !pmaps [t] -> numPhotons) {
# Line 483 | Line 536 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
536                    break;
537              }
538  
539 <            /* Update shared completion counter for prog.report by parent */
539 >            /* Update shared completion counter for progreport by parent */
540              photonCnt -> numComplete += numEmit;                            
541  
542              /* PHOTON DISTRIBUTION LOOP */
# Line 496 | Line 549 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
549                                ? photonPorts + portCnt : NULL;
550                    photonPartition [emap.src -> so -> otype] (&emap);
551  
552 <                  if (photonRepTime && !proc) {
552 >                  if (verbose && !proc) {
553 >                     /* Output from subproc 0 only to avoid race condition
554 >                      * on console I/O */
555                       if (!passCnt)
556 <                        sprintf(errmsg, "PREPASS %d on source %s ",
556 >                        sprintf(errmsg, "\tPREPASS %d on source %s ",
557                                  prePassCnt, source [srcIdx].so -> oname);
558                       else
559 <                        sprintf(errmsg, "MAIN PASS on source %s ",
559 >                        sprintf(errmsg, "\tMAIN PASS on source %s ",
560                                  source [srcIdx].so -> oname);
561 <                            
561 >
562                       if (emap.port) {
563                          sprintf(errmsg2, "via port %s ",
564                                  photonPorts [portCnt].so -> oname);
565                          strcat(errmsg, errmsg2);
566                       }
567 <                    
567 >
568                       sprintf(errmsg2, "(%lu partitions)\n",
569                               emap.numPartitions);
570                       strcat(errmsg, errmsg2);
571                       eputs(errmsg);
572 + #if NIX                    
573                       fflush(stderr);
574 + #endif                    
575                    }
576                    
577                    for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
# Line 529 | Line 586 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
586                      
587                       /* Number of photons to emit from ziss partishunn --
588                        * proportional to flux; photon ray weight and scalar
589 <                      * flux are uniform (the latter only varying in RGB).
533 <                      * */
589 >                      * flux are uniform (latter only varying in RGB). */
590                       partNumEmit = numEmit * colorAvg(emap.partFlux) /
591                                     totalFlux;
592                       partEmitCnt = (unsigned long)partNumEmit;
# Line 551 | Line 607 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
607                          /* Emit photon based on PDF and trace through scene
608                           * until absorbed/leaked */
609                          emitPhoton(&emap, &photonRay);
610 + #if 1
611 +                        if (emap.port)
612 +                           /* !!!  PHOTON PORT REJECTION SAMPLING HACK: set
613 +                            * !!!  photon port as fake hit object for
614 +                            * !!!  primary ray to check for intersection in
615 +                            * !!!  tracePhoton() */
616 +                           photonRay.ro = emap.port -> so;
617 + #endif
618                          tracePhoton(&photonRay);
619                       }                                          
620 <                    
620 >
621                       /* Update shared global photon count for each pmap */
622                       for (t = 0; t < NUM_PMAP_TYPES; t++)
623                          if (pmaps [t]) {
# Line 561 | Line 625 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
625                                pmaps [t] -> numPhotons - lastNumPhotons [t];
626                             lastNumPhotons [t] = pmaps [t] -> numPhotons;
627                          }
628 + #if !NIX
629 +                     /* Synchronous progress report on Windoze */
630 +                     if (!proc && photonRepTime > 0 &&
631 +                           time(NULL) >= repLastTime + photonRepTime) {
632 +                        repEmitted = repProgress = photonCnt -> numEmitted;
633 +                        repComplete = photonCnt -> numComplete;                          
634 +                        pmapDistribReport();
635 +                     }
636 + #endif
637                    }
638                    
639                    portCnt++;
# Line 576 | Line 649 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
649                    break;
650                 }
651              
652 <            if (t >= NUM_PMAP_TYPES) {
652 >            if (t >= NUM_PMAP_TYPES)
653                 /* No empty photon maps found; now do pass 2 */
654                 passCnt++;
582 #if 0
583               if (photonRepTime)
584                  eputs("\n");
585 #endif
586            }
655           } while (passCnt < 2);
656          
657 <         /* Unmap shared photon counters */
658 < #if 0        
591 <         munmap(photonCnt, sizeof(*photonCnt));
592 <         close(shmFile);
593 < #endif
594 <        
595 <         /* Flush heap buffa for every pmap one final time; this is required
596 <          * to prevent data corruption! */
657 >         /* Flush heap buffa for every pmap one final time;
658 >          * avoids potential data corruption! */
659           for (t = 0; t < NUM_PMAP_TYPES; t++)
660              if (pmaps [t]) {
599 #if 0            
600               eputs("Final flush\n");
601 #endif              
661                 flushPhotonHeap(pmaps [t]);
662 <               fclose(pmaps [t] -> heap);
662 >               /* Heap file closed automatically on exit
663 >                  fclose(pmaps [t] -> heap); */
664   #ifdef DEBUG_PMAP              
665 <               sprintf(errmsg, "Proc %d: total %ld photons\n", getpid(),
665 >               sprintf(errmsg, "Proc %d: total %ld photons\n", proc,
666                         pmaps [t] -> numPhotons);
667                 eputs(errmsg);
668   #endif              
669              }
670 <
670 > #if NIX
671 >         /* Terminate subprocess */
672           exit(0);
673 + #endif
674        }
675        else if (pid < 0)
676           error(SYSTEM, "failed to fork subprocess in distribPhotons");        
677     }
678  
679 + #if NIX
680     /* PARENT PROCESS CONTINUES HERE */
618   /* Record start time and enable progress report signal handler */
619   repStartTime = time(NULL);
681   #ifdef SIGCONT
682 +   /* Enable progress report signal handler */
683     signal(SIGCONT, pmapDistribReport);
684 < #endif
685 <  
624 <   if (photonRepTime)
625 <      eputs("\n");
626 <  
627 <   /* Wait for subprocesses to complete while reporting progress */
684 > #endif  
685 >   /* Wait for subprocesses complete while reporting progress */
686     proc = numProc;
687     while (proc) {
688        while (waitpid(-1, &stat, WNOHANG) > 0) {
# Line 637 | Line 695 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
695        
696        /* Nod off for a bit and update progress  */
697        sleep(1);
698 <      /* Update progress report from shared subprocess counters */
698 >
699 >      /* Asynchronous progress report from shared subprocess counters */  
700        repEmitted = repProgress = photonCnt -> numEmitted;
701 <      repComplete = photonCnt -> numComplete;
701 >      repComplete = photonCnt -> numComplete;      
702  
703 +      repProgress = repComplete = 0;
704        for (t = 0; t < NUM_PMAP_TYPES; t++)
705           if ((pm = pmaps [t])) {
646 #if 0        
647            /* Get photon count from heapfile size for progress update */
648            fseek(pm -> heap, 0, SEEK_END);
649            pm -> numPhotons = ftell(pm -> heap) / sizeof(Photon); */
650 #else            
706              /* Get global photon count from shmem updated by subprocs */
707 <            pm -> numPhotons = photonCnt -> numPhotons [t];
708 < #endif            
707 >            repProgress += pm -> numPhotons = photonCnt -> numPhotons [t];
708 >            repComplete += pm -> distribTarget;
709           }
710 +      repComplete *= numProc;
711  
712        if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
713           pmapDistribReport();
# Line 659 | Line 715 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
715        else signal(SIGCONT, pmapDistribReport);
716   #endif
717     }
718 + #endif /* NIX */
719  
720     /* ===================================================================
721      * POST-DISTRIBUTION - Set photon flux and build data struct for photon
722      * storage, etc.
723      * =================================================================== */
724   #ifdef SIGCONT    
725 +   /* Reset signal handler */
726     signal(SIGCONT, SIG_DFL);
727   #endif
728     free(emap.samples);
729    
730 <   /* Set photon flux (repProgress is total num emitted) */
730 >   /* Set photon flux */
731     totalFlux /= photonCnt -> numEmitted;
732 <  
732 > #if NIX  
733     /* Photon counters no longer needed, unmap shared memory */
734     munmap(photonCnt, sizeof(*photonCnt));
735     close(shmFile);
678 #if 0  
679   shm_unlink(shmFname);
680 #else
736     unlink(shmFname);
737 + #else
738 +   free(photonCnt);  
739   #endif      
740 <  
740 >   if (verbose)
741 >      eputs("\n");
742 >      
743     for (t = 0; t < NUM_PMAP_TYPES; t++)
744        if (pmaps [t]) {
745 <         if (photonRepTime) {
746 <            sprintf(errmsg, "\nBuilding %s photon map...\n", pmapName [t]);
745 >         if (verbose) {
746 >            sprintf(errmsg, "Building %s photon map\n", pmapName [t]);
747              eputs(errmsg);
748 + #if NIX            
749              fflush(stderr);
750 + #endif            
751           }
752          
753           /* Build underlying data structure; heap is destroyed */
754           buildPhotonMap(pmaps [t], &totalFlux, NULL, numProc);
755        }
756 <
756 >      
757     /* Precompute photon irradiance if necessary */
758 <   if (preCompPmap)
758 >   if (preCompPmap) {
759 >      if (verbose)
760 >         eputs("\n");
761        preComputeGlobal(preCompPmap);
762 +   }      
763 +  
764 +   if (verbose)
765 +      eputs("\n");
766   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines