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.15 by rschregle, Thu Jun 7 19:26:04 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 68 | Line 69 | static int photonParticipate (RAY *ray)
69        colorNorm(ray -> rcol);
70        VCOPY(ray -> rorg, ray -> rop);
71        
72 + #if 0
73        if (albedo > FTINY && ray -> rlvl > 0)
74 + #else
75 +      /* Store volume photons unconditionally in mist to also account for
76 +         direct inscattering from sources */
77 +      if (albedo > FTINY)
78 + #endif
79           /* Add to volume photon map */
80           newPhoton(volumePmap, ray);
81          
# Line 127 | Line 134 | void tracePhoton (RAY *ray)
134   /* Follow photon as it bounces around... */
135   {
136     long mod;
137 <   OBJREC* mat;
137 >   OBJREC *mat, *port = NULL;
138 >  
139 >   if (!ray -> parent) {
140 >      /* !!!  PHOTON PORT REJECTION SAMPLING HACK: get photon port for
141 >       * !!!  primary ray from ray -> ro, then reset the latter to NULL so
142 >       * !!!  as not to interfere with localhit() */
143 >      port = ray -> ro;
144 >      ray -> ro = NULL;
145 >   }
146  
147     if (ray -> rlvl > photonMaxBounce) {
148   #ifdef PMAP_RUNAWAY_WARN  
# Line 138 | Line 153 | void tracePhoton (RAY *ray)
153    
154     if (colorAvg(ray -> cext) > FTINY && !photonParticipate(ray))
155        return;
156 <      
156 >
157     if (localhit(ray, &thescene)) {
158        mod = ray -> ro -> omod;
159 <      
159 >
160 >      if (port && ray -> ro != port) {
161 >         /* !!! PHOTON PORT REJECTION SAMPLING HACK !!!
162 >          * Terminate photon if emitted from port without intersecting it;
163 >          * this can happen when the port's partitions extend beyond its
164 >          * actual geometry, e.g.  with polygons.  Since the total flux
165 >          * relayed by the port is based on the (in this case) larger
166 >          * partition area, it is overestimated; terminating these photons
167 >          * constitutes rejection sampling and thereby compensates any bias
168 >          * incurred by the overestimated flux.  */
169 > #ifdef PMAP_PORTREJECT_WARN
170 >         sprintf(errmsg, "photon outside port %s", ray -> ro -> oname);
171 >         error(WARNING, errmsg);
172 > #endif        
173 >         return;
174 >      }
175 >
176        if ((ray -> clipset && inset(ray -> clipset, mod)) || mod == OVOID) {
177           /* Transfer ray if modifier is VOID or clipped within antimatta */
178           RAY tray;
# Line 173 | Line 204 | static void preComputeGlobal (PhotonMap *pmap)
204  
205     repComplete = numPreComp = finalGather * pmap -> numPhotons;
206    
207 <   if (photonRepTime) {
208 <      sprintf(errmsg, "Precomputing irradiance for %ld global photons...\n",
207 >   if (verbose) {
208 >      sprintf(errmsg,
209 >              "\nPrecomputing irradiance for %ld global photons\n",
210                numPreComp);
211        eputs(errmsg);
212 + #if NIX      
213        fflush(stderr);
214 + #endif      
215     }
216    
217     /* Copy photon map for precomputed photons */
# Line 204 | Line 238 | static void preComputeGlobal (PhotonMap *pmap)
238    
239     for (i = 0; i < numPreComp; i++) {
240        /* Get random photon from stratified distribution in source heap to
241 <       * avoid duplicates and clutering */
241 >       * avoid duplicates and clustering */
242        pIdx = firstPhoton(pmap) +
243               (unsigned long)((i + pmapRandom(pmap -> randState)) /
244                               finalGather);
# Line 242 | Line 276 | static void preComputeGlobal (PhotonMap *pmap)
276     deletePhotons(pmap);
277     memcpy(pmap, &nuPmap, sizeof(PhotonMap));
278    
279 <   if (photonRepTime) {
280 <      eputs("Rebuilding precomputed photon map...\n");
279 >   if (verbose) {
280 >      eputs("\nRebuilding precomputed photon map\n");
281 > #if NIX      
282        fflush(stderr);
283 + #endif      
284     }
285  
286     /* Rebuild underlying data structure, destroying heap */  
# Line 263 | Line 299 | typedef struct {
299   void distribPhotons (PhotonMap **pmaps, unsigned numProc)
300   {
301     EmissionMap    emap;
302 <   char           errmsg2 [128], shmFname [255];
302 >   char           errmsg2 [128], shmFname [PMAP_TMPFNLEN];
303     unsigned       t, srcIdx, proc;
304     double         totalFlux = 0;
305     int            shmFile, stat, pid;
# Line 295 | Line 331 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
331           initPhotonHeap(pmaps [t]);
332           /* Per-subprocess target count */
333           pmaps [t] -> distribTarget /= numProc;
334 +        
335 +         if (!pmaps [t] -> distribTarget)
336 +            error(INTERNAL, "no photons to distribute in distribPhotons");
337        }
338  
339     initPhotonEmissionFuncs();
340     initPhotonScatterFuncs();
341    
342 <   /* Get photon ports if specified */
343 <   if (ambincl == 1)
305 <      getPhotonPorts();
342 >   /* Get photon ports from modifier list */
343 >   getPhotonPorts(photonPortList);
344  
345     /* Get photon sensor modifiers */
346     getPhotonSensors(photonSensorList);
347    
348 + #if NIX
349     /* Set up shared mem for photon counters (zeroed by ftruncate) */
350 < #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);
350 >   strcpy(shmFname, PMAP_TMPFNAME);
351     shmFile = mkstemp(shmFname);
317 #endif      
352  
353 <   if (shmFile < 0)
354 <      error(SYSTEM, "failed opening shared memory file in distribPhotons");
353 >   if (shmFile < 0 || ftruncate(shmFile, sizeof(*photonCnt)) < 0)
354 >      error(SYSTEM, "failed shared mem init in distribPhotons");
355  
322   if (ftruncate(shmFile, sizeof(*photonCnt)) < 0)
323      error(SYSTEM, "failed setting shared memory size in distribPhotons");
324
356     photonCnt = mmap(NULL, sizeof(*photonCnt), PROT_READ | PROT_WRITE,
357                      MAP_SHARED, shmFile, 0);
358                      
359     if (photonCnt == MAP_FAILED)
360 <      error(SYSTEM, "failed mapping shared memory in distribPhotons");
360 >      error(SYSTEM, "failed mapping shared memory in distribPhotons");
361 > #else
362 >   /* Allocate photon counters statically on Windoze */
363 >   if (!(photonCnt = malloc(sizeof(PhotonCnt))))
364 >      error(SYSTEM, "failed trivial malloc in distribPhotons");
365 >   photonCnt -> numEmitted = photonCnt -> numComplete = 0;      
366 > #endif /* NIX */
367  
368 <   if (photonRepTime)
369 <      eputs("\n");
368 >   if (verbose) {
369 >      sprintf(errmsg, "\nIntegrating flux from %d sources", nsources);
370 >      
371 >      if (photonPorts) {
372 >         sprintf(errmsg2, " via %d ports", numPhotonPorts);
373 >         strcat(errmsg, errmsg2);
374 >      }
375 >      
376 >      strcat(errmsg, "\n");
377 >      eputs(errmsg);
378 >   }  
379    
380     /* ===================================================================
381      * FLUX INTEGRATION - Get total photon flux from light sources
# Line 343 | Line 389 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
389                                                     : NULL;
390           photonPartition [emap.src -> so -> otype] (&emap);
391          
392 <         if (photonRepTime) {
393 <            sprintf(errmsg, "Integrating flux from source %s ",
392 >         if (verbose) {
393 >            sprintf(errmsg, "\tIntegrating flux from source %s ",
394                      source [srcIdx].so -> oname);
395 <                    
395 >
396              if (emap.port) {
397                 sprintf(errmsg2, "via port %s ",
398                         photonPorts [portCnt].so -> oname);
399                 strcat(errmsg, errmsg2);
400              }
401 <            
402 <            sprintf(errmsg2, "(%lu partitions)...\n", emap.numPartitions);
401 >
402 >            sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions);
403              strcat(errmsg, errmsg2);
404              eputs(errmsg);
405 + #if NIX            
406              fflush(stderr);
407 + #endif            
408           }
409          
410           for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
# Line 371 | Line 419 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
419  
420     if (totalFlux < FTINY)
421        error(USER, "zero flux from light sources");
422 +      
423 +   /* Record start time for progress reports */
424 +   repStartTime = time(NULL);
425  
426 +   if (verbose) {
427 +      sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc);
428 +      eputs(errmsg);
429 +   }
430 +
431     /* MAIN LOOP */  
432     for (proc = 0; proc < numProc; proc++) {
433 + #if NIX          
434        if (!(pid = fork())) {
435 <         /* SUBPROCESS ENTERS HERE.
436 <            All opened and memory mapped files are inherited */
435 >         /* SUBPROCESS ENTERS HERE; open and mmapped files inherited */
436 > #else
437 >      if (1) {
438 >         /* No subprocess under Windoze */
439 > #endif
440 >         /* Local photon counters for this subprocess */
441           unsigned       passCnt = 0, prePassCnt = 0;
442           unsigned long  lastNumPhotons [NUM_PMAP_TYPES];
443           unsigned long  localNumEmitted = 0; /* Num photons emitted by this
# Line 384 | Line 445 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
445          
446           /* Seed RNGs from PID for decorellated photon distribution */
447           pmapSeed(randSeed + proc, partState);
448 <         pmapSeed(randSeed + proc, emitState);
449 <         pmapSeed(randSeed + proc, cntState);
450 <         pmapSeed(randSeed + proc, mediumState);
451 <         pmapSeed(randSeed + proc, scatterState);
452 <         pmapSeed(randSeed + proc, rouletteState);
453 <                  
448 >         pmapSeed(randSeed + (proc + 1) % numProc, emitState);
449 >         pmapSeed(randSeed + (proc + 2) % numProc, cntState);
450 >         pmapSeed(randSeed + (proc + 3) % numProc, mediumState);
451 >         pmapSeed(randSeed + (proc + 4) % numProc, scatterState);
452 >         pmapSeed(randSeed + (proc + 5) % numProc, rouletteState);
453 >              
454 > #ifdef DEBUG_PMAP          
455 >         /* Output child process PID after random delay to prevent corrupted
456 >          * console output due to race condition */
457 >         usleep(1e6 * pmapRandom(rouletteState));
458 >         fprintf(stderr, "Proc %d: PID = %d "
459 >                 "(waiting 10 sec to attach debugger...)\n",
460 >                 proc, getpid());
461 >         /* Allow time for debugger to attach to child process */
462 >         sleep(10);
463 > #endif            
464 >
465           for (t = 0; t < NUM_PMAP_TYPES; t++)
466              lastNumPhotons [t] = 0;
467              
# Line 409 | Line 481 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
481                  * iterations; make it clear to user which photon maps are
482                  * missing so (s)he can check geometry and materials */
483                 if (++prePassCnt > maxPreDistrib) {
484 <                  sprintf(errmsg,
413 <                          "proc %d, source %s: too many prepasses",
414 <                          proc, source [srcIdx].so -> oname);              
484 >                  sprintf(errmsg, "proc %d: too many prepasses", proc);
485  
486                    for (t = 0; t < NUM_PMAP_TYPES; t++)
487                       if (pmaps [t] && !pmaps [t] -> numPhotons) {
# Line 483 | Line 553 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
553                    break;
554              }
555  
556 <            /* Update shared completion counter for prog.report by parent */
556 >            /* Update shared completion counter for progreport by parent */
557              photonCnt -> numComplete += numEmit;                            
558  
559              /* PHOTON DISTRIBUTION LOOP */
# Line 496 | Line 566 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
566                                ? photonPorts + portCnt : NULL;
567                    photonPartition [emap.src -> so -> otype] (&emap);
568  
569 <                  if (photonRepTime && !proc) {
569 >                  if (verbose && !proc) {
570 >                     /* Output from subproc 0 only to avoid race condition
571 >                      * on console I/O */
572                       if (!passCnt)
573 <                        sprintf(errmsg, "PREPASS %d on source %s ",
573 >                        sprintf(errmsg, "\tPREPASS %d on source %s ",
574                                  prePassCnt, source [srcIdx].so -> oname);
575                       else
576 <                        sprintf(errmsg, "MAIN PASS on source %s ",
576 >                        sprintf(errmsg, "\tMAIN PASS on source %s ",
577                                  source [srcIdx].so -> oname);
578 <                            
578 >
579                       if (emap.port) {
580                          sprintf(errmsg2, "via port %s ",
581                                  photonPorts [portCnt].so -> oname);
582                          strcat(errmsg, errmsg2);
583                       }
584 <                    
584 >
585                       sprintf(errmsg2, "(%lu partitions)\n",
586                               emap.numPartitions);
587                       strcat(errmsg, errmsg2);
588                       eputs(errmsg);
589 + #if NIX                    
590                       fflush(stderr);
591 + #endif                    
592                    }
593                    
594                    for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
# Line 529 | Line 603 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
603                      
604                       /* Number of photons to emit from ziss partishunn --
605                        * proportional to flux; photon ray weight and scalar
606 <                      * flux are uniform (the latter only varying in RGB).
533 <                      * */
606 >                      * flux are uniform (latter only varying in RGB). */
607                       partNumEmit = numEmit * colorAvg(emap.partFlux) /
608                                     totalFlux;
609                       partEmitCnt = (unsigned long)partNumEmit;
# Line 551 | Line 624 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
624                          /* Emit photon based on PDF and trace through scene
625                           * until absorbed/leaked */
626                          emitPhoton(&emap, &photonRay);
627 + #if 1
628 +                        if (emap.port)
629 +                           /* !!!  PHOTON PORT REJECTION SAMPLING HACK: set
630 +                            * !!!  photon port as fake hit object for
631 +                            * !!!  primary ray to check for intersection in
632 +                            * !!!  tracePhoton() */
633 +                           photonRay.ro = emap.port -> so;
634 + #endif
635                          tracePhoton(&photonRay);
636                       }                                          
637 <                    
637 >
638                       /* Update shared global photon count for each pmap */
639                       for (t = 0; t < NUM_PMAP_TYPES; t++)
640                          if (pmaps [t]) {
# Line 561 | Line 642 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
642                                pmaps [t] -> numPhotons - lastNumPhotons [t];
643                             lastNumPhotons [t] = pmaps [t] -> numPhotons;
644                          }
645 + #if !NIX
646 +                     /* Synchronous progress report on Windoze */
647 +                     if (!proc && photonRepTime > 0 &&
648 +                           time(NULL) >= repLastTime + photonRepTime) {
649 +                        repEmitted = repProgress = photonCnt -> numEmitted;
650 +                        repComplete = photonCnt -> numComplete;                          
651 +                        pmapDistribReport();
652 +                     }
653 + #endif
654                    }
655                    
656                    portCnt++;
# Line 576 | Line 666 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
666                    break;
667                 }
668              
669 <            if (t >= NUM_PMAP_TYPES) {
669 >            if (t >= NUM_PMAP_TYPES)
670                 /* No empty photon maps found; now do pass 2 */
671                 passCnt++;
582 #if 0
583               if (photonRepTime)
584                  eputs("\n");
585 #endif
586            }
672           } while (passCnt < 2);
673          
674 <         /* Unmap shared photon counters */
675 < #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! */
674 >         /* Flush heap buffa for every pmap one final time;
675 >          * avoids potential data corruption! */
676           for (t = 0; t < NUM_PMAP_TYPES; t++)
677              if (pmaps [t]) {
599 #if 0            
600               eputs("Final flush\n");
601 #endif              
678                 flushPhotonHeap(pmaps [t]);
679 <               fclose(pmaps [t] -> heap);
679 >               /* Heap file closed automatically on exit
680 >                  fclose(pmaps [t] -> heap); */
681   #ifdef DEBUG_PMAP              
682 <               sprintf(errmsg, "Proc %d: total %ld photons\n", getpid(),
682 >               sprintf(errmsg, "Proc %d: total %ld photons\n", proc,
683                         pmaps [t] -> numPhotons);
684                 eputs(errmsg);
685   #endif              
686              }
687 <
687 > #if NIX
688 >         /* Terminate subprocess */
689           exit(0);
690 + #endif
691        }
692        else if (pid < 0)
693           error(SYSTEM, "failed to fork subprocess in distribPhotons");        
694     }
695  
696 + #if NIX
697     /* PARENT PROCESS CONTINUES HERE */
618   /* Record start time and enable progress report signal handler */
619   repStartTime = time(NULL);
698   #ifdef SIGCONT
699 +   /* Enable progress report signal handler */
700     signal(SIGCONT, pmapDistribReport);
701 < #endif
702 <  
624 <   if (photonRepTime)
625 <      eputs("\n");
626 <  
627 <   /* Wait for subprocesses to complete while reporting progress */
701 > #endif  
702 >   /* Wait for subprocesses complete while reporting progress */
703     proc = numProc;
704     while (proc) {
705        while (waitpid(-1, &stat, WNOHANG) > 0) {
# Line 637 | Line 712 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
712        
713        /* Nod off for a bit and update progress  */
714        sleep(1);
715 <      /* Update progress report from shared subprocess counters */
715 >
716 >      /* Asynchronous progress report from shared subprocess counters */  
717        repEmitted = repProgress = photonCnt -> numEmitted;
718 <      repComplete = photonCnt -> numComplete;
718 >      repComplete = photonCnt -> numComplete;      
719  
720 +      repProgress = repComplete = 0;
721        for (t = 0; t < NUM_PMAP_TYPES; t++)
722           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            
723              /* Get global photon count from shmem updated by subprocs */
724 <            pm -> numPhotons = photonCnt -> numPhotons [t];
725 < #endif            
724 >            repProgress += pm -> numPhotons = photonCnt -> numPhotons [t];
725 >            repComplete += pm -> distribTarget;
726           }
727 +      repComplete *= numProc;
728  
729        if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
730           pmapDistribReport();
# Line 659 | Line 732 | void distribPhotons (PhotonMap **pmaps, unsigned numPr
732        else signal(SIGCONT, pmapDistribReport);
733   #endif
734     }
735 + #endif /* NIX */
736  
737     /* ===================================================================
738      * POST-DISTRIBUTION - Set photon flux and build data struct for photon
739      * storage, etc.
740      * =================================================================== */
741   #ifdef SIGCONT    
742 +   /* Reset signal handler */
743     signal(SIGCONT, SIG_DFL);
744   #endif
745     free(emap.samples);
746    
747 <   /* Set photon flux (repProgress is total num emitted) */
747 >   /* Set photon flux */
748     totalFlux /= photonCnt -> numEmitted;
749 <  
749 > #if NIX  
750     /* Photon counters no longer needed, unmap shared memory */
751     munmap(photonCnt, sizeof(*photonCnt));
752     close(shmFile);
678 #if 0  
679   shm_unlink(shmFname);
680 #else
753     unlink(shmFname);
754 + #else
755 +   free(photonCnt);  
756   #endif      
757 <  
757 >   if (verbose)
758 >      eputs("\n");
759 >      
760     for (t = 0; t < NUM_PMAP_TYPES; t++)
761        if (pmaps [t]) {
762 <         if (photonRepTime) {
763 <            sprintf(errmsg, "\nBuilding %s photon map...\n", pmapName [t]);
762 >         if (verbose) {
763 >            sprintf(errmsg, "Building %s photon map\n", pmapName [t]);
764              eputs(errmsg);
765 + #if NIX            
766              fflush(stderr);
767 + #endif            
768           }
769          
770           /* Build underlying data structure; heap is destroyed */
771           buildPhotonMap(pmaps [t], &totalFlux, NULL, numProc);
772        }
773 <
773 >      
774     /* Precompute photon irradiance if necessary */
775 <   if (preCompPmap)
775 >   if (preCompPmap) {
776 >      if (verbose)
777 >         eputs("\n");
778        preComputeGlobal(preCompPmap);
779 +   }      
780 +  
781 +   if (verbose)
782 +      eputs("\n");
783   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines