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

Comparing ray/src/rt/RtraceSimulManager.cpp (file contents):
Revision 2.1 by greg, Wed Feb 8 17:41:48 2023 UTC vs.
Revision 2.21 by greg, Sat Nov 9 00:10:49 2024 UTC

# Line 9 | Line 9 | static const char RCSid[] = "$Id$";
9   *  Created by Greg Ward on 2/2/2023.
10   */
11  
12 + #include <unistd.h>
13 + #include <ctype.h>
14   #include "RtraceSimulManager.h"
15   #include "source.h"
16  
15 extern int      castonly;       // doing ray-casting only?
16
17   // Load octree and prepare renderer
18   bool
19   RadSimulManager::LoadOctree(const char *octn)
# Line 23 | Line 23 | RadSimulManager::LoadOctree(const char *octn)
23                          return true;
24                  Cleanup();
25          }
26 <        if (!octn)
26 >        if (!octn)              // don't support stdin octree
27                  return false;
28  
29 +        NewHeader(octn);        // get octree header
30          ray_init((char *)octn);
31          return true;
32   }
33  
34 + // callback function for loading header
35 + static int
36 + add2header(char *str, void *p)
37 + {
38 +        if (isheadid(str))
39 +                return 0;
40 +        if (isformat(str))
41 +                return 0;
42 +
43 +        return (*(RadSimulManager *)p).AddHeader(str);
44 + }
45 +
46 + // Prepare header from previous input (or clear)
47 + // Normally called during octree load
48 + bool
49 + RadSimulManager::NewHeader(const char *inspec)
50 + {
51 +        if (hlen) {
52 +                free(header); header = NULL; hlen = 0;
53 +        }
54 +        if (!inspec || !*inspec)
55 +                return false;
56 +        if (inspec[0] == '!')           // save command as header?
57 +                return AddHeader(inspec+1);
58 +                                        // attempt to read from file
59 +        FILE    *fp = fopen(inspec, "rb");
60 +        if (!fp) return false;
61 +        bool    ok = (getheader(fp, add2header, this) >= 0);
62 +        fclose(fp);
63 +        return ok;
64 + }
65 +
66 + // Add a string to header (adds newline if missing)
67 + bool
68 + RadSimulManager::AddHeader(const char *str)
69 + {
70 +        if (!str) return false;
71 +        int     len = strlen(str);
72 +        while (len && (str[len-1] == '\n') | (str[len-1] == '\r'))
73 +                --len;                  // don't copy EOL(s)
74 +        if (!len)
75 +                return false;
76 +        if (hlen)
77 +                header = (char *)realloc(header, hlen+len+2);
78 +        else
79 +                header = (char *)malloc(len+2);
80 +        if (!header) {
81 +                hlen = 0;               // XXX should report?
82 +                return false;
83 +        }
84 +        memcpy(header+hlen, str, len);
85 +        hlen += len;
86 +        header[hlen++] = '\n';          // add single EOL
87 +        header[hlen] = '\0';
88 +        return true;
89 + }
90 +
91 + // helper function to check for white-space and quotations
92 + static int
93 + check_special(const char *s)
94 + {
95 +        int     space_found = 0;
96 +
97 +        while (*s) {
98 +                if ((*s == '"') | (*s == '\''))
99 +                        return *s;      // quotes have priority
100 +                if (isspace(*s))
101 +                        space_found = *s;
102 +                s++;
103 +        }
104 +        return space_found;
105 + }
106 +
107 + // Append program line to header
108 + bool
109 + RadSimulManager::AddHeader(int ac, char *av[])
110 + {
111 +        if ((ac <= 0) | !av) return false;
112 +        int     len = 0;
113 +        int     n;
114 +        for (n = 0; n < ac; n++) {
115 +                if (!av[n]) return false;
116 +                len += strlen(av[n]) + 3;
117 +        }
118 +        if (hlen)                       // add to header
119 +                header = (char *)realloc(header, hlen+len+1);
120 +        else
121 +                header = (char *)malloc(len+1);
122 +
123 +        for (n = 0; n < ac; n++) {
124 +                int     c = check_special(av[n]);
125 +                len = strlen(av[n]);
126 +                if (c | !len) {         // need to quote argument?
127 +                        if ((c == '"') | (c == '\n')) c = '\'';
128 +                        else c = '"';
129 +                        header[hlen++] = c;
130 +                        strcpy(header+hlen, av[n]);
131 +                        hlen += len;
132 +                        header[hlen++] = c;
133 +                } else {
134 +                        strcpy(header+hlen, av[n]);
135 +                        hlen += len;
136 +                }
137 +                header[hlen++] = ' ';
138 +        }
139 +        header[hlen-1] = '\n';          // terminate line
140 +        header[hlen] = '\0';
141 +        return true;
142 + }
143 +
144 + // Look for specific header keyword, return value
145 + const char *
146 + RadSimulManager::GetHeadStr(const char *key, bool inOK) const
147 + {
148 +        if (!key | !hlen || strchr(key, '\n'))
149 +                return NULL;
150 +        if (inOK)                       // skip leading spaces?
151 +                while (isspace(*key)) key++;
152 +
153 +        const int       klen = strlen(key);
154 +        if (!klen)
155 +                return NULL;
156 +        const char *    cp = header;
157 +        while (*cp) {
158 +                if (inOK) {             // skip leading spaces?
159 +                        while (isspace(*cp) && *cp++ != '\n')
160 +                                ;
161 +                        if (cp[-1] == '\n')
162 +                                continue;
163 +                }
164 +                if (!strncmp(cp, key, klen))
165 +                        return cp+klen; // found it!
166 +
167 +                while (*cp && *cp++ != '\n')
168 +                        ;
169 +        }
170 +        return NULL;
171 + }
172 +
173 + // How many processors are available?
174 + int
175 + RadSimulManager::GetNCores()
176 + {
177 +        return sysconf(_SC_NPROCESSORS_ONLN);
178 + }
179 +
180   // Set number of computation threads (0 => #cores)
181   int
182   RadSimulManager::SetThreadCount(int nt)
183   {
184 <        return nThreads = 1;    // XXX temporary
184 >        if (!Ready())
185 >                return 0;
186 >
187 >        if (nt <= 0) nt = castonly ? 1 : GetNCores();
188 >
189 >        if (nt == 1)
190 >                ray_pclose(ray_pnprocs);
191 >        else if (nt < ray_pnprocs)
192 >                ray_pclose(ray_pnprocs - nt);
193 >        else if (nt > ray_pnprocs)
194 >                ray_popen(nt - ray_pnprocs);
195 >
196 >        return NThreads();
197   }
198  
199 + // Assign ray to subthread (fails if NThreads()<2)
200 + bool
201 + RadSimulManager::SplitRay(RAY *r)
202 + {
203 +        if (!ray_pnprocs || ThreadsAvailable() < 1)
204 +                return false;
205 +
206 +        return (ray_psend(r) > 0);
207 + }
208 +
209 + // Process a ray (in subthread), optional result
210 + bool
211 + RadSimulManager::ProcessRay(RAY *r)
212 + {
213 +        if (!Ready()) return false;
214 +
215 +        if (!ray_pnprocs) {     // single-threaded mode?
216 +                samplendx++;
217 +                rayvalue(r);
218 +                return true;
219 +        }
220 +        int     rv = ray_pqueue(r);
221 +        if (rv < 0) {
222 +                error(WARNING, "ray tracing process(es) died");
223 +                return false;
224 +        }
225 +        return (rv > 0);
226 + }
227 +
228 + // Wait for next result (or fail)
229 + bool
230 + RadSimulManager::WaitResult(RAY *r)
231 + {
232 +        if (!ray_pnprocs)
233 +                return false;
234 +
235 +        return (ray_presult(r, 0) > 0);
236 + }
237 +
238   // Close octree, free data, return status
239   int
240 < RadSimulManager::Cleanup()
240 > RadSimulManager::Cleanup(bool everything)
241   {
242 <        ray_done(0);
242 >        if (ray_pnprocs < 0)
243 >                return 0;               // skip in child process
244 >        NewHeader();
245 >        if (!ray_pnprocs)
246 >                ray_done(everything);
247 >        else
248 >                ray_pdone(everything);
249          return 0;
250   }
251  
# Line 49 | Line 253 | RadSimulManager::Cleanup()
253   int
254   RadSimulManager::ThreadsAvailable() const
255   {
256 <        return 1;       // XXX temporary
256 >        if (!ray_pnprocs) return 1;
257 >
258 >        return ray_pnidle;
259   }
260  
261   // Global pointer to simulation manager for trace call-back (only one)
262   static const RtraceSimulManager *       ourRTsimMan = NULL;
263  
264 < void    // static call-back
264 > // Call-back for trace output
265 > void
266   RtraceSimulManager::RTracer(RAY *r)
267   {
268          (*ourRTsimMan->traceCall)(r, ourRTsimMan->tcData);
269   }
270  
271 + // Call-back for FIFO output
272 + int
273 + RtraceSimulManager::Rfifout(RAY *r)
274 + {
275 +        return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
276 + }
277 +
278   // Check for changes to render flags & adjust accordingly
279   bool
280   RtraceSimulManager::UpdateMode()
281   {
68        rtFlags &= RTmask;
282          if (!cookedCall)
283                  rtFlags &= ~RTdoFIFO;
284          if (!traceCall)
# Line 73 | Line 286 | RtraceSimulManager::UpdateMode()
286          if (rtFlags & RTimmIrrad)
287                  rtFlags &= ~RTlimDist;
288  
289 <        int     misMatch = rtFlags ^ curFlags;
289 >        int     misMatch = (rtFlags ^ curFlags) & RTmask;
290                                  // updates based on toggled flags
291 <        if (misMatch & RTtraceSources) {
291 >        if (((misMatch & RTtraceSources) != 0) & (nsources > 0)) {
292 >                int     nt = NThreads();
293 >                if (nt > 1) {
294 >                        if (FlushQueue() < 0)
295 >                                return false;
296 >                        SetThreadCount(1);
297 >                }
298 >                int     sn = nsources;
299                  if (rtFlags & RTtraceSources) {
300 <                        for (int sn = 0; sn < nsources; sn++)
300 >                        srcFollowed.NewBitMap(nsources);
301 >                        while (sn--) {
302 >                                if (source[sn].sflags & SFOLLOW)
303 >                                        continue;
304                                  source[sn].sflags |= SFOLLOW;
305 <                } else          // cannot undo this...
306 <                        rtFlags |= RTtraceSources;
305 >                                srcFollowed.Set(sn);
306 >                        }
307 >                } else {
308 >                        while (sn--)
309 >                                if (srcFollowed.Check(sn))
310 >                                        source[sn].sflags &= ~SFOLLOW;
311 >                        srcFollowed.NewBitMap(0);
312 >                }
313 >                if (nt > 1) SetThreadCount(nt);
314          }
315 <        if (misMatch & RTdoFIFO) {
316 <                if (!FlushQueue())
87 <                        return false;
88 <        }
315 >        if (misMatch & RTdoFIFO && FlushQueue() < 0)
316 >                return false;
317          curFlags = rtFlags;
318 <                                // update trace callback
319 <        if (traceCall) {
92 <                if (ourRTsimMan && ourRTsimMan != this)
93 <                        error(WARNING, "Competing top-level simulation managers?");
94 <                ourRTsimMan = this;
318 >                                // update callbacks
319 >        if (traceCall)
320                  trace = RTracer;
321 <        } else if (ourRTsimMan == this) {
321 >        else if (trace == RTracer)
322                  trace = NULL;
323 +        if (rtFlags & RTdoFIFO)
324 +                ray_fifo_out = Rfifout;
325 +        else if (ray_fifo_out == Rfifout)
326 +                ray_fifo_out = NULL;
327 +        if ((trace != RTracer) & (ray_fifo_out != Rfifout)) {
328                  ourRTsimMan = NULL;
329 +        } else if (ourRTsimMan != this) {
330 +                if (ourRTsimMan)
331 +                        error(WARNING, "Competing top-level simulation managers?");
332 +                ourRTsimMan = this;
333          }
334          return true;
335   }
336  
337   extern "C" int  m_normal(OBJREC *m, RAY *r);
338  
339 < /* compute irradiance rather than radiance */
339 > // compute irradiance rather than radiance
340   static void
341   rayirrad(RAY *r)
342   {
# Line 119 | Line 353 | rayirrad(RAY *r)
353          r->revf = rayirrad;
354   }
355  
356 < /* compute first ray intersection only */
356 > // compute first ray intersection only
357   static void
358   raycast(RAY *r)
359   {
# Line 143 | Line 377 | RtraceSimulManager::EnqueueBundle(const FVECT orig_dir
377                  return -1;
378  
379          if (castonly && !cookedCall)
380 <                error(CONSISTENCY, "EnqueueBundle() called in castonly mode without cookedCall");
380 >                error(INTERNAL, "EnqueueBundle() called in castonly mode without cookedCall");
381  
382          if (!UpdateMode())              // update rendering mode if requested
383                  return -1;
384  
385 +        if (rID0 && curFlags&RTdoFIFO)
386 +                error(INTERNAL, "Ray number assignment unsupported with FIFO");
387 +
388          while (n-- > 0) {               // queue each ray
152                double  d;
389                  VCOPY(res.rorg, orig_direc[0]);
390                  VCOPY(res.rdir, orig_direc[1]);
391 +                res.rmax = .0;
392                  orig_direc += 2;
393                  rayorigin(&res, PRIMARY, NULL, NULL);
394 <                if (rID0) res.rno = rID0++;
158 <                else res.rno = ++lastRayID;
394 >                res.rno = rID0 ? (lastRayID = rID0++) : ++lastRayID;
395                  if (curFlags & RTimmIrrad)
396                          res.revf = rayirrad;
397                  else if (castonly)
398                          res.revf = raycast;
399 <                d = normalize(res.rdir);
400 <                if (d > 0) {            // direction vector is valid?
399 >                double  d = normalize(res.rdir);
400 >                bool    sendRes = (cookedCall != NULL);
401 >                if (d > .0) {           // direction vector is valid?
402                          if (curFlags & RTlimDist)
403                                  res.rmax = d;
404 <                        samplendx++;
405 <                        rayvalue(&res);         // XXX single-threaded for now
406 <                        ++nqueued;
404 >                        if (((curFlags&RTdoFIFO) != 0) & (ray_pnprocs > 0)) {
405 >                                if (ray_fifo_in(&res) < 0)
406 >                                        return -1;
407 >                                sendRes = false;
408 >                        } else
409 >                                sendRes &= ProcessRay(&res);
410                  } else if (ThreadsAvailable() < NThreads() &&
411 <                                !FlushQueue())
411 >                                FlushQueue() < 0)
412                          return -1;
413 <                if (cookedCall)
414 <                        (*cookedCall)(&res, ccData);
413 >                                        // may be dummy ray
414 >                if (sendRes && (*cookedCall)(&res, ccData) < 0)
415 >                        return -1;
416 >                nqueued++;
417          }
418          return nqueued;
419   }
420  
421   // Finish pending rays and complete callbacks
422 < bool
422 > int
423   RtraceSimulManager::FlushQueue()
424   {
425 <        return true;            // XXX no-op for now
425 >        if (curFlags & RTdoFIFO) {
426 >                if (ray_pnprocs)
427 >                        return ray_fifo_flush();
428 >                return 0;
429 >        }
430 >        int     nsent = 0;
431 >        RAY     res;
432 >
433 >        while (WaitResult(&res)) {
434 >                if (!cookedCall) continue;
435 >                int     rv = (*cookedCall)(&res, ccData);
436 >                if (rv < 0) return -1;
437 >                nsent += rv;
438 >        }
439 >        return nsent;
440   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines