ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc3.c
Revision: 2.1
Committed: Sat Jun 9 07:16:47 2012 UTC (11 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Created rcontrib program (eventually to replace rtcontrib)

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Accumulate ray contributions for a set of materials
6 * Controlling process for multiple children
7 */
8
9 #include "rcontrib.h"
10 #include "platform.h"
11 #include "rtprocess.h"
12 #include "selcall.h"
13
14 /* Modifier contribution queue (results waiting to be output) */
15 typedef struct s_binq {
16 int ndx; /* index for this entry */
17 int n2add; /* number left to add */
18 struct s_binq *next; /* next in queue */
19 MODCONT *mca[1]; /* contrib. array (extends struct) */
20 } BINQ;
21
22 static BINQ *out_bq = NULL; /* output bin queue */
23 static BINQ *free_bq = NULL; /* free queue entries */
24
25 static SUBPROC kida[MAXPROCESS]; /* child processes */
26
27
28 /* Get new (empty) bin queue entry */
29 static BINQ *
30 new_binq()
31 {
32 BINQ *bp = free_bq;
33 int i;
34
35 if (bp != NULL) { /* something already available? */
36 free_bq = bp->next;
37 bp->next = NULL;
38 bp->n2add = accumulate-1;
39 return(bp);
40 }
41 /* else allocate fresh */
42 bp = (BINQ *)malloc(sizeof(BINQ)+(nmods-1)*sizeof(MODCONT *));
43 if (bp == NULL)
44 goto memerr;
45 for (i = nmods; i--; ) {
46 MODCONT *mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
47 bp->mca[i] = (MODCONT *)malloc(sizeof(MODCONT) +
48 sizeof(DCOLOR)*(mp->nbins-1));
49 if (bp->mca[i] == NULL)
50 goto memerr;
51 memcpy(bp->mca[i], mp, sizeof(MODCONT)-sizeof(DCOLOR));
52 /* memset(bp->mca[i]->cbin, 0, sizeof(DCOLOR)*mp->nbins); */
53 }
54 bp->ndx = 0;
55 bp->n2add = accumulate-1;
56 bp->next = NULL;
57 return(bp);
58 memerr:
59 error(SYSTEM, "out of memory in new_binq()");
60 return(NULL);
61 }
62
63
64 /* Free a bin queue entry */
65 static void
66 free_binq(BINQ *bp)
67 {
68 int i;
69
70 if (bp == NULL) { /* signal to release our free list */
71 while ((bp = free_bq) != NULL) {
72 free_bq = bp->next;
73 for (i = nmods; i--; )
74 free(bp->mca[i]);
75 /* Note: we don't own bp->mca[i]->binv */
76 free(bp);
77 }
78 return;
79 }
80 /* clear sums for next use */
81 /* for (i = nmods; i--; )
82 memset(bp->mca[i]->cbin, 0, sizeof(DCOLOR)*bp->mca[i]->nbins);
83 */
84 bp->ndx = 0;
85 bp->next = free_bq; /* push onto free list */
86 free_bq = bp;
87 }
88
89
90 /* Add modifier values to accumulation record in queue and clear */
91 void
92 queue_modifiers()
93 {
94 MODCONT *mpin, *mpout;
95 int i, j;
96
97 if ((accumulate > 0) | (out_bq == NULL))
98 error(CONSISTENCY, "bad call to queue_modifiers()");
99
100 for (i = nmods; i--; ) {
101 mpin = (MODCONT *)lu_find(&modconttab,modname[i])->data;
102 mpout = out_bq->mca[i];
103 for (j = mpout->nbins; j--; )
104 addcolor(mpout->cbin[j], mpin->cbin[j]);
105 memset(mpin->cbin, 0, sizeof(DCOLOR)*mpin->nbins);
106 }
107 }
108
109
110 /* Sum one modifier record into another (doesn't update n2add) */
111 static void
112 add_modbin(BINQ *dst, BINQ *src)
113 {
114 int i, j;
115
116 for (i = nmods; i--; ) {
117 MODCONT *mpin = src->mca[i];
118 MODCONT *mpout = dst->mca[i];
119 for (j = mpout->nbins; j--; )
120 addcolor(mpout->cbin[j], mpin->cbin[j]);
121 }
122 }
123
124
125 /* Queue output, catching up with and freeing FIFO entries when possible */
126 static int
127 queue_output(BINQ *bp)
128 {
129 int nout = 0;
130 BINQ *b_last, *b_cur;
131 int i;
132
133 if (accumulate <= 0) { /* just accumulating? */
134 if (out_bq == NULL) {
135 bp->next = NULL;
136 out_bq = bp;
137 } else {
138 add_modbin(out_bq, bp);
139 free_binq(bp);
140 }
141 return(0);
142 }
143 b_last = NULL; /* else insert in output queue */
144 for (b_cur = out_bq; b_cur != NULL && b_cur->ndx < bp->ndx;
145 b_cur = b_cur->next)
146 b_last = b_cur;
147 if (b_last != NULL) {
148 bp->next = b_cur;
149 b_last->next = bp;
150 } else {
151 bp->next = out_bq;
152 out_bq = bp;
153 }
154 if (accumulate > 1) { /* merge accumulation entries */
155 b_cur = out_bq;
156 while (b_cur->next != NULL) {
157 if (b_cur->n2add <= 0 ||
158 (b_cur->ndx-1)/accumulate !=
159 (b_cur->next->ndx-1)/accumulate) {
160 b_cur = b_cur->next;
161 continue;
162 }
163 add_modbin(b_cur, b_cur->next);
164 b_cur->n2add--;
165 b_last = b_cur->next;
166 b_cur->next = b_last->next;
167 b_last->next = NULL;
168 free_binq(b_last);
169 }
170 }
171 /* output ready results */
172 while (out_bq != NULL && (out_bq->ndx == lastdone+1) & !out_bq->n2add) {
173 b_cur = out_bq; /* pop off first entry */
174 out_bq = b_cur->next;
175 b_cur->next = NULL;
176 for (i = 0; i < nmods; i++) /* output record */
177 mod_output(b_cur->mca[i]);
178 end_record();
179 free_binq(b_cur); /* free this entry */
180 lastdone += accumulate;
181 ++nout;
182 }
183 return(nout);
184 }
185
186
187 /* Put a zero record in results queue */
188 void
189 zero_record(int ndx)
190 {
191 BINQ *bp = new_binq();
192 int i;
193
194 for (i = nmods; i--; )
195 memset(bp->mca[i]->cbin, 0, sizeof(DCOLOR)*bp->mca[i]->nbins);
196 bp->ndx = ndx;
197 queue_output(bp);
198 }
199
200
201 /* callback to set output spec to NULL (stdout) */
202 static int
203 set_stdout(const LUENT *le, void *p)
204 {
205 (*(MODCONT *)le->data).outspec = NULL;
206 return(0);
207 }
208
209
210 /* Start child processes if we can */
211 int
212 in_rchild()
213 {
214 #ifdef _WIN32
215 error(WARNING, "multiprocessing unsupported -- running solo");
216 nproc = 1;
217 return(1);
218 #else
219 /* try to fork ourselves */
220 while (nchild < nproc) {
221 int p0[2], p1[2];
222 int pid;
223 /* prepare i/o pipes */
224 if (pipe(p0) < 0 || pipe(p1) < 0)
225 error(SYSTEM, "pipe() call failed!");
226 pid = fork(); /* fork parent process */
227 if (pid == 0) { /* if in child, set up & return true */
228 close(p0[1]); close(p1[0]);
229 dup2(p0[0], 0); close(p0[0]);
230 dup2(p1[1], 1); close(p1[1]);
231 inpfmt = (sizeof(RREAL)==sizeof(double)) ? 'd' : 'f';
232 outfmt = 'd';
233 header = 0;
234 waitflush = xres = 1;
235 yres = 0;
236 raysleft = 0;
237 account = accumulate = 1;
238 lu_doall(&modconttab, set_stdout, NULL);
239 nchild = -1;
240 return(1); /* child return value */
241 }
242 if (pid < 0)
243 error(SYSTEM, "fork() call failed!");
244 /* connect our pipes */
245 close(p0[0]); close(p1[1]);
246 kida[nchild].r = p1[0];
247 kida[nchild].w = p0[1];
248 kida[nchild].pid = pid;
249 kida[nchild].running = -1;
250 ++nchild;
251 }
252 return(0); /* parent return value */
253 #endif
254 }
255
256
257 /* Close child processes */
258 void
259 end_children()
260 {
261 int status;
262
263 while (nchild-- > 0)
264 if ((status = close_process(&kida[nchild])) > 0) {
265 sprintf(errmsg,
266 "rendering process returned bad status (%d)",
267 status);
268 error(WARNING, errmsg);
269 }
270 }
271
272
273 /* Wait for the next available child */
274 static int
275 next_child_nq(int force_wait)
276 {
277 fd_set readset, errset;
278 int i, j, n, nr;
279
280 if (!force_wait) /* see if there's one free */
281 for (i = nchild; i--; )
282 if (kida[i].running < 0)
283 return(i);
284 /* prepare select() call */
285 FD_ZERO(&readset); FD_ZERO(&errset);
286 n = nr = 0;
287 for (i = nchild; i--; ) {
288 if (kida[i].running > 0) {
289 FD_SET(kida[i].r, &readset);
290 ++nr;
291 }
292 FD_SET(kida[i].r, &errset);
293 if (kida[i].r >= n)
294 n = kida[i].r + 1;
295 }
296 if (!nr) /* nothing going on */
297 return(-1);
298 if (nr > 1) { /* call select if multiple busy */
299 errno = 0;
300 if (select(n, &readset, NULL, &errset, NULL) < 0)
301 error(SYSTEM, "select call error in next_child_nq()");
302 } else
303 FD_ZERO(&errset);
304 n = -1; /* read results from child(ren) */
305 for (i = nchild; i--; ) {
306 BINQ *bq;
307 if (FD_ISSET(kida[i].r, &errset))
308 error(USER, "rendering process died");
309 if (!FD_ISSET(kida[i].r, &readset))
310 continue;
311 bq = new_binq(); /* get results holder */
312 bq->ndx = kida[i].running;
313 /* read from child */
314 for (j = 0; j < nmods; j++) {
315 n = sizeof(DCOLOR)*bq->mca[j]->nbins;
316 nr = readbuf(kida[i].r, (char *)bq->mca[j]->cbin, n);
317 if (nr != n)
318 error(SYSTEM, "read error from render process");
319 }
320 queue_output(bq); /* put results in output queue */
321 kida[i].running = -1; /* mark child as available */
322 n = i;
323 }
324 return(n); /* last available child */
325 }
326
327
328 /* Run parental oversight loop */
329 void
330 parental_loop()
331 {
332 static int ignore_warning_given = 0;
333 FVECT orgdir[2];
334 double d;
335 /* load rays from stdin & process */
336 #ifdef getc_unlocked
337 flockfile(stdin); /* avoid lock/unlock overhead */
338 #endif
339 while (getvec(orgdir[0]) == 0 && getvec(orgdir[1]) == 0) {
340 d = normalize(orgdir[1]);
341 /* asking for flush? */
342 if ((d == 0.0) & (accumulate != 1)) {
343 if (!ignore_warning_given++)
344 error(WARNING,
345 "dummy ray(s) ignored during accumulation\n");
346 continue;
347 }
348 if ((d == 0.0) | (lastray+1 < lastray)) {
349 while (next_child_nq(1) >= 0)
350 ;
351 lastdone = lastray = 0;
352 }
353 if (d == 0.0) {
354 if ((yres <= 0) | (xres <= 0))
355 waitflush = 1; /* flush right after */
356 zero_record(++lastray);
357 } else { /* else assign */
358 int avail = next_child_nq(0);
359 if (writebuf(kida[avail].w, (char *)orgdir,
360 sizeof(FVECT)*2) != sizeof(FVECT)*2)
361 error(SYSTEM, "pipe write error");
362 kida[avail].running = ++lastray;
363 }
364 if (raysleft && !--raysleft)
365 break; /* preemptive EOI */
366 }
367 while (next_child_nq(1) >= 0) /* empty results queue */
368 ;
369 /* output accumulated record */
370 if (accumulate <= 0 || account < accumulate) {
371 int i;
372 if (account < accumulate) {
373 error(WARNING, "partial accumulation in final record");
374 accumulate -= account;
375 }
376 for (i = 0; i < nmods; i++)
377 mod_output(out_bq->mca[i]);
378 end_record();
379 }
380 if (raysleft)
381 error(USER, "unexpected EOF on input");
382 free_binq(NULL); /* clean up */
383 lu_done(&ofiletab);
384 }