Page MenuHomec4science

pmapcontrib.c
No OneTemporary

File Metadata

Created
Mon, Sep 23, 11:43

pmapcontrib.c

#ifndef lint
static const char RCSid[] = "$Id: pmapcontrib.c,v 2.19 2018/11/08 00:54:07 greg Exp $";
#endif
/*
=========================================================================
Photon map for light source contributions
Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
(c) Lucerne University of Applied Sciences and Arts,
supported by the Swiss National Science Foundation
(SNSF #147053, "Daylight Redirecting Components",
SNSF #179067, "Light Fields for Spatio-Temporal Glare Assessment")
=========================================================================
$Id: pmapcontrib.c,v 2.19 2018/11/08 00:54:07 greg Exp $
*/
#include "pmapcontrib.h"
#include "pmapmat.h"
#include "pmapsrc.h"
#include "pmaprand.h"
#include "pmapio.h"
#include "pmapdiag.h"
#include "rcontrib.h"
#include "otypes.h"
#include "otspecial.h"
#if NIX
#include <sys/mman.h>
#include <sys/wait.h>
#endif
static int photonBin (const PhotonMap *pmap, const Photon* p, const RAY *ray)
/* Map contribution photon to its bin according its ray */
{
unsigned i;
PhotonSearchQueueNode *sqn;
float r2, invArea;
RREAL rayCoeff [3];
Photon *photon;
static char warnPos = 1, warnDir = 1;
/* Check we have a source contribution LUT */
if (pmap -> srcContribs) {
const PhotonContribOrigin *org = &pmap -> contribOrgs [photon -> org];
const SRCREC *src = &source [org -> srcIdx];
OBJREC *srcMod = findmaterial(src -> so);
MODCONT *srcContrib = (MODCONT*)lu_find(
pmap -> srcContribs, srcMod -> oname
) -> data;
double srcBinReal;
int srcBin;
RAY srcRay;
if (!srcContrib)
/* We're not interested in this source (modifier not in LUT) */
return -1;
if (srcContrib -> binv -> type != NUM) {
/* Set up a shadow ray to evaluate binning function */
rayorigin(&srcRay, SHADOW, NULL, NULL);
srcRay.rsrc = org -> srcIdx;
#ifdef PMAP_PRIMARYPOS
VCOPY(srcRay.rorg, primary -> pos);
#else
/* No primary hitpoints; set dummy ray origin and warn once */
srcRay.rorg [0] = srcRay.rorg [1] = srcRay.rorg [2] = 0;
if (warnPos) {
error(WARNING,
"no photon primary hitpoints for bin evaluation; "
"using dummy (0,0,0)! Recompile with -DPMAP_CBDM.");
warnPos = 0;
}
#endif
#ifdef PMAP_PRIMARYDIR
decodedir(srcRay.rdir, primary -> dir);
#else
/* No primary incident direction; set dummy and warn once */
if (warnDir) {
error(WARNING,
"no photon primary directions for bin evaluation; "
"using dummy (0,0,0)! Recompile with -DPMAP_CBDM.");
warnDir = 0;
}
srcRay.rdir [0] = srcRay.rdir [1] = srcRay.rdir [2] = 0;
#endif
if (!(sp->sflags & SDISTANT
? sourcehit(&srcRay)
: (*ofun[sp -> so -> otype].funp)(sp -> so, &srcRay)))
continue; /* XXX shouldn't happen! */
worldfunc(RCCONTEXT, &srcRay);
set_eparams((char *)srcContrib -> params);
}
if ((srcBinReal = evalue(srcContrib -> binv)) < -.5)
continue; /* silently ignore negative bins */
if ((srcBin = srcBinReal + .5) >= srcContrib -> nbins) {
error(WARNING, "bad bin number (ignored)");
continue;
}
if (!contrib) {
/* Ray coefficient mode; normalise by light source radiance
* after applying distrib pattern */
int j;
raytexture(ray, srcMod -> omod);
setcolor(ray -> rcol, srcMod -> oargs.farg [0],
srcMod -> oargs.farg [1], srcMod -> oargs.farg [2]);
multcolor(ray -> rcol, ray -> pcol);
for (j = 0; j < 3; j++)
flux [j] = ray -> rcol [j] ? flux [j] / ray -> rcol [j] : 0;
}
multcolor(flux, rayCoeff);
addcolor(srcContrib -> cbin [srcBin], flux);
}
return;
}
static PhotonOrigin newPhotonOrigin (
PhotonMap *pmap, const RAY *orgRay, FILE *orgHeap
)
/* Add origin ray for emitted photon and save light source index, and
* binned direction fot contrib photons. The current origin is stored in
* pmap -> lastContribOrg. If the previous origin spawned photons (i.e.
* has srcIdx >= 0), it's appended to orgHeap. If orgRay == NULL, the
* current origin is still flushed, but no new origin is set.
* Returns updated origin counter pmap -> numContribOrg. */
{
if (!pmap || !orgHeap)
return 0;
/* Check if last origin ray has spawned photons (srcIdx >= 0, see
* newPhoton()), in which case we save it to the origin heap file
* before clobbering it. (Note this is short-term storage, so we doan'
* need da portable I/O stuff here). */
if (pmap -> lastContribOrg.srcIdx >= 0) {
if (!fwrite(
&pmap -> lastContribOrg, sizeof(PhotonContribOrigin), 1, orgHeap
))
error(
SYSTEM,
"failed writing contrib photon origin in newPhotonOrigin"
);
pmap -> numContribOrg++;
if (!pmap -> numContribOrg || pmap -> numContribOrg > PMAP_MAXORIGIN)
/* numContribOrg overflowed (wrapped around) or exceeded max */
error(INTERNAL, "contrib photon origin overflow in newPhotonOrigin");
}
/* Mark unused with negative source index until path spawns a photon
* (see newPhoton()) */
pmap -> lastContribOrg.srcIdx = -1;
if (orgRay) {
/* TODO: Map incident dir to bin here! */
/* Reverse incident direction to point to light source */
dvec [0] = -orgRay -> rdir [0];
dvec [1] = -orgRay -> rdir [1];
dvec [2] = -orgRay -> rdir [2];
pmap -> lastContribOrg.srcBin = (dvec);
#endif
#ifdef PMAP_PRIMARYPOS
VCOPY(pmap -> lastPrimary.pos, primRay -> rop);
#endif
}
return pmap -> numContribOrg;
}
static PhotonOrigin buildOrigins (
PhotonMap *pmap, FILE **orgHeap, char **orgyHeapFname,
PhotonOrigin *orgOfs, unsigned numHeaps
)
/* Consolidate per-subprocess photon origin heaps into the origin array
* pmap -> contribOrg. Returns offset for origin index linearisation in
* pmap -> numContribOrg. The heap files in orgHeap are closed on return. */
{
PhotonOrigin heapLen;
unsigned heap;
if (!pmap || !orgHeap || !orgOfs || !numHeaps)
return 0;
pmap -> numContribOrg = 0;
for (heap = 0; heap < numHeaps; heap++) {
orgOfs [heap] = pmap -> numContribOrg;
if (fseek(orgHeap [heap], 0, SEEK_END) < 0)
error(SYSTEM, "failed contrib photon origin seek in buildOrigins");
pmap -> numContribOrg +=
heapLen = ftell(orgHeap [heap]) / sizeof(PhotonContribOrigin);
if (!(pmap -> contribOrg = realloc(
pmap -> contribOrg,
pmap -> numContribOrg * sizeof(PhotonContribOrigin)
)))
error(SYSTEM, "failed contrib photon origin alloc in buildOrigins");
rewind(orgHeap [heap]);
if (fread(
pmap -> contribOrg + orgOfs [heap], sizeof(PhotonContribOrigin),
heapLen, orgHeap [heap]
) != heapLen)
error(SYSTEM, "failed reading contrib photon origin in buildOrigins");
fclose(orgHeap [heap]);
unlink(orgHeapFname [heap]);
}
return pmap -> numContribOrg;
}
/* Defs for photon emission counter array passed by sub-processes to parent
* via shared memory */
typedef unsigned long PhotonContribCnt;
/* Indices for photon emission counter array: num photons stored and num
* emitted per source */
#define PHOTONCNT_NUMPHOT 0
#define PHOTONCNT_NUMEMIT(n) (1 + n)
static void preComputeContrib (PhotonMap *pmap)
/* Precompute irradiance from global photons for final gathering for
a random subset of finalGather * pmap -> numPhotons photons, and builds
the photon map, discarding the original photons. */
/* !!! NOTE: PRECOMPUTATION WITH OOC CURRENTLY WITHOUT CACHE !!! */
{
unsigned long i, numPreComp;
unsigned j;
PhotonIdx pIdx;
Photon photon;
RAY ray;
PhotonMap nuPmap;
repComplete = numPreComp = finalGather * pmap -> numPhotons;
if (verbose) {
sprintf(errmsg,
"\nPrecomputing irradiance for %ld global photons\n",
numPreComp);
eputs(errmsg);
#if NIX
fflush(stderr);
#endif
}
/* Copy photon map for precomputed photons */
memcpy(&nuPmap, pmap, sizeof(PhotonMap));
/* Zero counters, init new heap and extents */
nuPmap.numPhotons = 0;
initPhotonHeap(&nuPmap);
for (j = 0; j < 3; j++) {
nuPmap.minPos [j] = FHUGE;
nuPmap.maxPos [j] = -FHUGE;
}
/* Record start time, baby */
repStartTime = time(NULL);
#ifdef SIGCONT
signal(SIGCONT, pmapPreCompReport);
#endif
repProgress = 0;
photonRay(NULL, &ray, PRIMARY, NULL);
ray.ro = NULL;
for (i = 0; i < numPreComp; i++) {
/* Get random photon from stratified distribution in source heap to
* avoid duplicates and clustering */
pIdx = firstPhoton(pmap) +
(unsigned long)((i + pmapRandom(pmap -> randState)) /
finalGather);
getPhoton(pmap, pIdx, &photon);
/* Init dummy photon ray with intersection at photon position */
VCOPY(ray.rop, photon.pos);
for (j = 0; j < 3; j++)
ray.ron [j] = photon.norm [j] / 127.0;
/* Get density estimate at photon position */
photonDensity(pmap, &ray, ray.rcol);
/* Append photon to new heap from ray */
newPhoton(&nuPmap, &ray);
/* Update progress */
repProgress++;
if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
pmapPreCompReport();
#ifdef SIGCONT
else signal(SIGCONT, pmapPreCompReport);
#endif
}
/* Flush heap */
flushPhotonHeap(&nuPmap);
#ifdef SIGCONT
signal(SIGCONT, SIG_DFL);
#endif
/* Trash original pmap, replace with precomputed one */
deletePhotons(pmap);
memcpy(pmap, &nuPmap, sizeof(PhotonMap));
if (verbose) {
eputs("\nRebuilding precomputed photon map\n");
#if NIX
fflush(stderr);
#endif
}
/* Rebuild underlying data structure, destroying heap */
buildPhotonMap(pmap, NULL, NULL, 1);
}
void distribPhotonContrib (PhotonMap* pm, unsigned numProc)
{
EmissionMap emap;
char errmsg2 [128], shmFname [PMAP_TMPFNLEN];
unsigned srcIdx, proc;
int shmFile, stat, pid;
double *srcFlux, /* Emitted flux per light source */
srcDistribTarget; /* Target photon count per source */
PhotonContribCnt *photonCnt; /* Photon emission counter array */
unsigned photonCntSize = sizeof(PhotonContribCnt) *
PHOTONCNT_NUMEMIT(nsources);
FILE **primaryHeap = NULL;
char **primaryHeapFname = NULL;
PhotonPrimaryIdx *primaryOfs = NULL;
if (!pm)
error(USER, "no photon map defined in distribPhotonContrib");
if (!nsources)
error(USER, "no light sources in distribPhotonContrib");
if (nsources > MAXMODLIST)
error(USER, "too many light sources in distribPhotonContrib");
/* Allocate photon flux per light source; this differs for every
* source as all sources contribute the same number of distributed
* photons (srcDistribTarget), hence the number of photons emitted per
* source does not correlate with its emitted flux. The resulting flux
* per photon is therefore adjusted individually for each source. */
if (!(srcFlux = calloc(nsources, sizeof(double))))
error(SYSTEM, "can't allocate source flux in distribPhotonContrib");
/* ===================================================================
* INITIALISATION - Set up emission and scattering funcs
* =================================================================== */
emap.samples = NULL;
emap.src = NULL;
emap.maxPartitions = MAXSPART;
emap.partitions = (unsigned char*)malloc(emap.maxPartitions >> 1);
if (!emap.partitions)
error(USER, "can't allocate source partitions in distribPhotonContrib");
/* Initialise contrib photon map */
initPhotonMap(pm, PMAP_TYPE_CONTRIB);
initPhotonHeap(pm);
initPhotonEmissionFuncs();
initPhotonScatterFuncs();
/* Per-subprocess / per-source target counts */
pm -> distribTarget /= numProc;
srcDistribTarget = nsources ? (double)pm -> distribTarget / nsources : 0;
if (!pm -> distribTarget)
error(INTERNAL, "no photons to distribute in distribPhotonContrib");
/* Get photon ports from modifier list */
getPhotonPorts(photonPortList);
/* Get photon sensor modifiers */
getPhotonSensors(photonSensorList);
#if NIX
/* Set up shared mem for photon counters (zeroed by ftruncate) */
strcpy(shmFname, PMAP_TMPFNAME);
shmFile = mkstemp(shmFname);
if (shmFile < 0 || ftruncate(shmFile, photonCntSize) < 0)
error(SYSTEM, "failed shared mem init in distribPhotonContrib");
photonCnt = mmap(NULL, photonCntSize, PROT_READ | PROT_WRITE,
MAP_SHARED, shmFile, 0);
if (photonCnt == MAP_FAILED)
error(SYSTEM, "failed shared mem mapping in distribPhotonContrib");
#else
/* Allocate photon counters statically on Windoze */
if (!(photonCnt = malloc(photonCntSize)))
error(SYSTEM, "failed trivial malloc in distribPhotonContrib");
for (srcIdx = 0; srcIdx < PHOTONCNT_NUMEMIT(nsources); srcIdx++)
photonCnt [srcIdx] = 0;
#endif /* NIX */
if (verbose) {
sprintf(errmsg, "\nIntegrating flux from %d sources", nsources);
if (photonPorts) {
sprintf(errmsg2, " via %d ports", numPhotonPorts);
strcat(errmsg, errmsg2);
}
strcat(errmsg, "\n");
eputs(errmsg);
}
/* =============================================================
* FLUX INTEGRATION - Get total flux emitted from sources/ports
* ============================================================= */
for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
unsigned portCnt = 0;
srcFlux [srcIdx] = 0;
emap.src = source + srcIdx;
do { /* Need at least one iteration if no ports! */
emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt
: NULL;
photonPartition [emap.src -> so -> otype] (&emap);
if (verbose) {
sprintf(errmsg, "\tIntegrating flux from source %s ",
source [srcIdx].so -> oname);
if (emap.port) {
sprintf(errmsg2, "via port %s ",
photonPorts [portCnt].so -> oname);
strcat(errmsg, errmsg2);
}
sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions);
strcat(errmsg, errmsg2);
eputs(errmsg);
#if NIX
fflush(stderr);
#endif
}
for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
emap.partitionCnt++) {
initPhotonEmission(&emap, pdfSamples);
srcFlux [srcIdx] += colorAvg(emap.partFlux);
}
portCnt++;
} while (portCnt < numPhotonPorts);
if (srcFlux [srcIdx] < FTINY) {
sprintf(errmsg, "source %s has zero emission",
source [srcIdx].so -> oname);
error(WARNING, errmsg);
}
}
/* Allocate & init per-subprocess primary heap files */
primaryHeap = calloc(numProc, sizeof(FILE*));
primaryHeapFname = calloc(numProc, sizeof(char*));
primaryOfs = calloc(numProc, sizeof(PhotonPrimaryIdx));
if (!primaryHeap || !primaryHeapFname || !primaryOfs)
error(SYSTEM, "failed primary heap allocation in "
"distribPhotonContrib");
for (proc = 0; proc < numProc; proc++) {
primaryHeapFname [proc] = malloc(PMAP_TMPFNLEN);
if (!primaryHeapFname [proc])
error(SYSTEM, "failed primary heap file allocation in "
"distribPhotonContrib");
mktemp(strcpy(primaryHeapFname [proc], PMAP_TMPFNAME));
if (!(primaryHeap [proc] = fopen(primaryHeapFname [proc], "w+b")))
error(SYSTEM, "failed opening primary heap file in "
"distribPhotonContrib");
}
/* Record start time for progress reports */
repStartTime = time(NULL);
if (verbose) {
sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc);
eputs(errmsg);
}
/* MAIN LOOP */
for (proc = 0; proc < numProc; proc++) {
#if NIX
if (!(pid = fork())) {
/* SUBPROCESS ENTERS HERE; opened and mmapped files inherited */
#else
if (1) {
/* No subprocess under Windoze */
#endif
/* Local photon counters for this subprocess */
unsigned long lastNumPhotons = 0, localNumEmitted = 0;
double photonFluxSum = 0; /* Accum. photon flux */
/* Seed RNGs from PID for decorellated photon distribution */
pmapSeed(randSeed + proc, partState);
pmapSeed(randSeed + (proc + 1) % numProc, emitState);
pmapSeed(randSeed + (proc + 2) % numProc, cntState);
pmapSeed(randSeed + (proc + 3) % numProc, mediumState);
pmapSeed(randSeed + (proc + 4) % numProc, scatterState);
pmapSeed(randSeed + (proc + 5) % numProc, rouletteState);
#ifdef PMAP_SIGUSR
{
double partNumEmit;
unsigned long partEmitCnt;
double srcPhotonFlux, avgPhotonFlux;
unsigned portCnt, passCnt, prePassCnt;
float srcPreDistrib;
double srcNumEmit; /* # to emit from source */
unsigned long srcNumDistrib; /* # stored */
void sigUsrDiags()
/* Loop diags via SIGUSR1 */
{
sprintf(
errmsg,
"********************* Proc %d Diags *********************\n"
"srcIdx = %d (%s)\nportCnt = %d (%s)\npassCnt = %d\n"
"srcFlux = %f\nsrcPhotonFlux = %f\navgPhotonFlux = %f\n"
"partNumEmit = %f\npartEmitCnt = %lu\n\n",
proc, srcIdx, findmaterial(source [srcIdx].so) -> oname,
portCnt, photonPorts [portCnt].so -> oname,
passCnt, srcFlux [srcIdx], srcPhotonFlux, avgPhotonFlux,
partNumEmit, partEmitCnt
);
eputs(errmsg);
fflush(stderr);
}
}
#endif
#ifdef PMAP_SIGUSR
signal(SIGUSR1, sigUsrDiags);
#endif
#ifdef DEBUG_PMAP
/* Output child process PID after random delay to prevent corrupted
* console output due to race condition */
usleep(1e6 * pmapRandom(rouletteState));
fprintf(
stderr,
"Proc %d: PID = %d (waiting 10 sec to attach debugger...)\n"
proc, getpid()
);
/* Allow time for debugger to attach to child process */
sleep(10);
#endif
/* =============================================================
* 2-PASS PHOTON DISTRIBUTION
* Pass 1 (pre): emit fraction of target photon count
* Pass 2 (main): based on outcome of pass 1, estimate remaining
* number of photons to emit to approximate target
* count
* ============================================================= */
for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
#ifndef PMAP_SIGUSR
unsigned portCnt, passCnt = 0, prePassCnt = 0;
float srcPreDistrib = preDistrib;
double srcNumEmit = 0; /* # to emit from source */
unsigned long srcNumDistrib = pm -> numPhotons; /* # stored */
#else
passCnt = prePassCnt = 0;
srcPreDistrib = preDistrib;
srcNumEmit = 0; /* # to emit from source */
srcNumDistrib = pm -> numPhotons; /* # stored */
#endif
if (srcFlux [srcIdx] < FTINY)
continue;
while (passCnt < 2) {
if (!passCnt) {
/* INIT PASS 1 */
if (++prePassCnt > maxPreDistrib) {
/* Warn if no photons contributed after sufficient
* iterations; only output from subprocess 0 to reduce
* console clutter */
if (!proc) {
sprintf(errmsg,
"source %s: too many prepasses, skipped",
source [srcIdx].so -> oname);
error(WARNING, errmsg);
}
break;
}
/* Num to emit is fraction of target count */
srcNumEmit = srcPreDistrib * srcDistribTarget;
}
else {
/* INIT PASS 2 */
#ifndef PMAP_SIGUSR
double srcPhotonFlux, avgPhotonFlux;
#endif
/* Based on the outcome of the predistribution we can now
* figure out how many more photons we have to emit from
* the current source to meet the target count,
* srcDistribTarget. This value is clamped to 0 in case
* the target has already been exceeded in pass 1.
* srcNumEmit and srcNumDistrib is the number of photons
* emitted and distributed (stored) from the current
* source in pass 1, respectively. */
srcNumDistrib = pm -> numPhotons - srcNumDistrib;
srcNumEmit *= srcNumDistrib ?
max(srcDistribTarget/srcNumDistrib, 1) - 1 : 0;
if (!srcNumEmit)
/* No photons left to distribute in main pass */
break;
srcPhotonFlux = srcFlux [srcIdx] / srcNumEmit;
avgPhotonFlux = photonFluxSum / (srcIdx + 1);
if (avgPhotonFlux > FTINY &&
srcPhotonFlux / avgPhotonFlux < FTINY) {
/* Skip source if its photon flux is grossly below the
* running average, indicating negligible contributions
* at the expense of excessive distribution time; only
* output from subproc 0 to reduce console clutter */
if (!proc) {
sprintf(
errmsg,
"source %s: itsy bitsy photon flux, skipped",
source [srcIdx].so -> oname
);
error(WARNING, errmsg);
}
srcNumEmit = 0; /* Or just break??? */
}
/* Update sum of photon flux per light source */
photonFluxSum += srcPhotonFlux;
}
portCnt = 0;
do { /* Need at least one iteration if no ports! */
emap.src = source + srcIdx;
emap.port = emap.src -> sflags & SDISTANT ?
photonPorts + portCnt : NULL;
photonPartition [emap.src -> so -> otype] (&emap);
if (verbose && !proc) {
/* Output from subproc 0 only to avoid race condition
* on console I/O */
if (!passCnt)
sprintf(
errmsg, "\tPREPASS %d on source %s ",
prePassCnt, source [srcIdx].so -> oname
);
else
sprintf(
errmsg, "\tMAIN PASS on source %s ",
source [srcIdx].so -> oname
);
if (emap.port) {
sprintf(
errmsg2, "via port %s ",
photonPorts [portCnt].so -> oname
);
strcat(errmsg, errmsg2);
}
sprintf(
errmsg2, "(%lu partitions)\n", emap.numPartitions
);
strcat(errmsg, errmsg2);
eputs(errmsg);
#if NIX
fflush(stderr);
#endif
}
for (
emap.partitionCnt = 0;
emap.partitionCnt < emap.numPartitions;
emap.partitionCnt++
) {
#ifndef PMAP_SIGUSR
double partNumEmit;
unsigned long partEmitCnt;
#endif
/* Get photon origin within current source partishunn
* and build emission map */
photonOrigin [emap.src -> so -> otype] (&emap);
initPhotonEmission(&emap, pdfSamples);
/* Number of photons to emit from ziss partishunn;
* scale according to its normalised contribushunn to
* the emitted source flux */
partNumEmit = srcNumEmit * colorAvg(emap.partFlux) /
srcFlux [srcIdx];
partEmitCnt = (unsigned long)partNumEmit;
/* Probabilistically account for fractional photons */
if (pmapRandom(cntState) < partNumEmit - partEmitCnt)
partEmitCnt++;
/* Update local and shared global emission counter */
photonCnt [PHOTONCNT_NUMEMIT(srcIdx)] += partEmitCnt;
localNumEmitted += partEmitCnt;
/* Integer counter avoids FP rounding errors during
* iteration */
while (partEmitCnt--) {
RAY photonRay;
/* Emit photon according to PDF (if any), allocate
* associated primary ray, and trace through scene
* until absorbed/leaked; emitPhoton() sets the
* emitting light source index in photonRay */
emitPhoton(&emap, &photonRay);
#if 1
if (emap.port)
/* !!! PHOTON PORT REJECTION SAMPLING HACK: set
* !!! photon port as fake hit object for
* !!! primary ray to check for intersection in
* !!! tracePhoton() */
photonRay.ro = emap.port -> so;
#endif
newPhotonOrigin(pm, &photonRay, primaryHeap[proc]);
/* Set subprocess index in photonRay for post-
* distrib primary index linearisation; this is
* propagated with the primary index in photonRay
* and set for photon hits by newPhoton() */
PMAP_SETRAYPROC(&photonRay, proc);
tracePhoton(&photonRay);
}
/* Update shared global photon count */
photonCnt [PHOTONCNT_NUMPHOT] += pm -> numPhotons -
lastNumPhotons;
lastNumPhotons = pm -> numPhotons;
#if !NIX
/* Synchronous progress report on Windoze */
if (
!proc && photonRepTime > 0 &&
time(NULL) >= repLastTime + photonRepTime
) {
unsigned s;
repComplete = pm -> distribTarget * numProc;
repProgress = photonCnt [PHOTONCNT_NUMPHOT];
for (repEmitted = 0, s = 0; s < nsources; s++)
repEmitted += photonCnt [PHOTONCNT_NUMEMIT(s)];
pmapDistribReport();
}
#endif
}
portCnt++;
} while (portCnt < numPhotonPorts);
if (pm -> numPhotons == srcNumDistrib) {
/* Double predistrib factor in case no photons were stored
* for this source and redo pass 1 */
srcPreDistrib *= 2;
}
else {
/* Now do pass 2 */
passCnt++;
}
}
}
/* Flush heap buffa one final time to prevent data corruption */
flushPhotonHeap(pm);
/* Flush final photon primary to primary heap file */
newPhotonPrimary(pm, NULL, primaryHeap [proc]);
/* Heap files closed automatically on exit
fclose(pm -> heap);
fclose(primaryHeap [proc]); */
#ifdef DEBUG_PMAP
sprintf(
errmsg, "Proc %d total %ld photons\n", proc, pm -> numPhotons
);
eputs(errmsg);
fflush(stderr);
#endif
#ifdef PMAP_SIGUSR
signal(SIGUSR1, SIG_DFL);
#endif
#if NIX
/* Terminate subprocess */
exit(0);
#endif
}
else if (pid < 0)
error(SYSTEM, "failed to fork subprocess in distribPhotonContrib");
}
#if NIX
/* PARENT PROCESS CONTINUES HERE */
#ifdef SIGCONT
/* Enable progress report signal handler */
signal(SIGCONT, pmapDistribReport);
#endif
/* Wait for subprocesses to complete while reporting progress */
proc = numProc;
while (proc) {
while (waitpid(-1, &stat, WNOHANG) > 0) {
/* Subprocess exited; check status */
if (!WIFEXITED(stat) || WEXITSTATUS(stat))
error(USER, "failed photon distribution");
--proc;
}
/* Nod off for a bit and update progress */
sleep(1);
/* Asynchronous progress report from shared subprocess counters */
repComplete = pm -> distribTarget * numProc;
repProgress = photonCnt [PHOTONCNT_NUMPHOT];
for (repEmitted = 0, srcIdx = 0; srcIdx < nsources; srcIdx++)
repEmitted += photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
/* Get global photon count from shmem updated by subprocs */
pm -> numPhotons = photonCnt [PHOTONCNT_NUMPHOT];
if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
pmapDistribReport();
#ifdef SIGCONT
else signal(SIGCONT, pmapDistribReport);
#endif
}
#endif /* NIX */
/* ================================================================
* POST-DISTRIBUTION - Set photon flux and build kd-tree, etc.
* ================================================================ */
#ifdef SIGCONT
/* Reset signal handler */
signal(SIGCONT, SIG_DFL);
#endif
free(emap.samples);
if (!pm -> numPhotons)
error(USER, "empty contribution photon map");
/* Load per-subprocess primary rays into pm -> primary array */
/* Dumb compilers apparently need the char** cast */
pm -> numPrimary = buildPrimaries(
pm, primaryHeap, (char**)primaryHeapFname, primaryOfs, numProc
);
if (!pm -> numPrimary)
error(INTERNAL, "no primary rays in contribution photon map");
/* Set photon flux per source */
for (srcIdx = 0; srcIdx < nsources; srcIdx++)
srcFlux [srcIdx] /= photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
#if NIX
/* Photon counters no longer needed, unmap shared memory */
munmap(photonCnt, sizeof(*photonCnt));
close(shmFile);
unlink(shmFname);
#else
free(photonCnt);
#endif
if (verbose) {
eputs("\nBuilding contribution photon map...\n");
#if NIX
fflush(stderr);
#endif
}
/* Build underlying data structure; heap is destroyed */
buildPhotonMap(pm, srcFlux, primaryOfs, numProc);
/* Free per-subprocess primary heap files */
for (proc = 0; proc < numProc; proc++)
free(primaryHeapFname [proc]);
free(primaryHeapFname);
free(primaryHeap);
free(primaryOfs);
if (verbose)
eputs("\n");
}

Event Timeline