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.4 by greg, Wed Aug 2 00:04:31 2023 UTC vs.
Revision 2.23 by greg, Wed Nov 13 18:47:01 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 21 | Line 21 | RadSimulManager::LoadOctree(const char *octn)
21          if (octname) {          // already running?
22                  if (octn && !strcmp(octn, octname))
23                          return true;
24 <                Cleanup(false);
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 < // How many processors are there?
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 1;               // XXX temporary
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
45 < }
184 >        if (!Ready()) return 0;
185  
186 < // Assign ray to subthread (fails if NThreads()<2)
48 < bool
49 < RadSimulManager::SplitRay(RAY *r)
50 < {
51 <        if (NThreads() < 2 || ThreadsAvailable() < 1)
52 <                return false;
186 >        if (nt <= 0) nt = castonly ? 1 : GetNCores();
187  
188 <        return false;   // UNIMPLEMENTED
188 >        if (nt == 1)
189 >                ray_pclose(ray_pnprocs);
190 >        else if (nt < ray_pnprocs)
191 >                ray_pclose(ray_pnprocs - nt);
192 >        else if (nt > ray_pnprocs)
193 >                ray_popen(nt - ray_pnprocs);
194 >
195 >        return NThreads();
196   }
197  
198   // Process a ray (in subthread), optional result
199 < bool
199 > int
200   RadSimulManager::ProcessRay(RAY *r)
201   {
202 <        if (!r || !Ready()) return false;
203 <        if (NThreads() < 2) {   // single-threaded mode?
202 >        if (!Ready()) return -1;
203 >
204 >        if (!ray_pnprocs) {     // single-threaded mode?
205                  samplendx++;
206                  rayvalue(r);
207 <                return true;
207 >                return 1;
208          }
209 <        if (ThreadsAvailable() >= 1) {
68 <                SplitRay(r);    // queue not yet full
69 <                return false;
70 <        }
71 <        RAY     toDo = *r;
72 <        if (!WaitResult(r))     // need a free thread
73 <                return false;
74 <        SplitRay(&toDo);        // queue up new ray
75 <        return true;            // return older result
209 >        return ray_pqueue(r);
210   }
211  
212   // Wait for next result (or fail)
213   bool
214   RadSimulManager::WaitResult(RAY *r)
215   {
216 <        return false;   // UNIMPLEMENTED
216 >        if (!ray_pnprocs)
217 >                return false;
218 >
219 >        return (ray_presult(r, 0) > 0);
220   }
221  
222   // Close octree, free data, return status
223   int
224   RadSimulManager::Cleanup(bool everything)
225   {
226 <        ray_done(everything);
226 >        if (ray_pnprocs < 0)
227 >                return 0;               // skip in child process
228 >        NewHeader();
229 >        if (!ray_pnprocs)
230 >                ray_done(everything);
231 >        else
232 >                ray_pdone(everything);
233          return 0;
234   }
235  
93 // How many threads are currently unoccupied?
94 int
95 RadSimulManager::ThreadsAvailable() const
96 {
97        return 1;       // XXX temporary
98 }
99
236   // Global pointer to simulation manager for trace call-back (only one)
237   static const RtraceSimulManager *       ourRTsimMan = NULL;
238  
239 < void    // static call-back
239 > // Call-back for trace output
240 > void
241   RtraceSimulManager::RTracer(RAY *r)
242   {
243          (*ourRTsimMan->traceCall)(r, ourRTsimMan->tcData);
244   }
245  
246 + // Call-back for FIFO output
247 + int
248 + RtraceSimulManager::Rfifout(RAY *r)
249 + {
250 +        return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
251 + }
252 +
253   // Check for changes to render flags & adjust accordingly
254   bool
255   RtraceSimulManager::UpdateMode()
256   {
113        rtFlags &= RTmask;
257          if (!cookedCall)
258                  rtFlags &= ~RTdoFIFO;
259          if (!traceCall)
# Line 118 | Line 261 | RtraceSimulManager::UpdateMode()
261          if (rtFlags & RTimmIrrad)
262                  rtFlags &= ~RTlimDist;
263  
264 <        int     misMatch = rtFlags ^ curFlags;
264 >        int     misMatch = (rtFlags ^ curFlags) & RTmask;
265                                  // updates based on toggled flags
266 <        if (misMatch & RTtraceSources) {
266 >        if (((misMatch & RTtraceSources) != 0) & (nsources > 0)) {
267 >                int     nt = NThreads();
268 >                if (nt > 1) {
269 >                        if (FlushQueue() < 0)
270 >                                return false;
271 >                        SetThreadCount(1);
272 >                }
273 >                int     sn = nsources;
274                  if (rtFlags & RTtraceSources) {
275 <                        for (int sn = 0; sn < nsources; sn++)
275 >                        srcFollowed.NewBitMap(nsources);
276 >                        while (sn--) {
277 >                                if (source[sn].sflags & SFOLLOW)
278 >                                        continue;
279                                  source[sn].sflags |= SFOLLOW;
280 <                } else          // cannot undo this...
281 <                        rtFlags |= RTtraceSources;
280 >                                srcFollowed.Set(sn);
281 >                        }
282 >                } else {
283 >                        while (sn--)
284 >                                if (srcFollowed.Check(sn))
285 >                                        source[sn].sflags &= ~SFOLLOW;
286 >                        srcFollowed.NewBitMap(0);
287 >                }
288 >                if (nt > 1) SetThreadCount(nt);
289          }
290          if (misMatch & RTdoFIFO && FlushQueue() < 0)
291                  return false;
292          curFlags = rtFlags;
293 <                                // update trace callback
294 <        if (traceCall) {
135 <                if (ourRTsimMan && ourRTsimMan != this)
136 <                        error(WARNING, "Competing top-level simulation managers?");
137 <                ourRTsimMan = this;
293 >                                // update callbacks
294 >        if (traceCall)
295                  trace = RTracer;
296 <        } else if (ourRTsimMan == this) {
296 >        else if (trace == RTracer)
297                  trace = NULL;
298 +        if (rtFlags & RTdoFIFO)
299 +                ray_fifo_out = Rfifout;
300 +        else if (ray_fifo_out == Rfifout)
301 +                ray_fifo_out = NULL;
302 +        if ((trace != RTracer) & (ray_fifo_out != Rfifout)) {
303                  ourRTsimMan = NULL;
304 +        } else if (ourRTsimMan != this) {
305 +                if (ourRTsimMan)
306 +                        error(WARNING, "Competing top-level simulation managers?");
307 +                ourRTsimMan = this;
308          }
309          return true;
310   }
311  
312   extern "C" int  m_normal(OBJREC *m, RAY *r);
313  
314 < /* compute irradiance rather than radiance */
314 > // compute irradiance rather than radiance
315   static void
316   rayirrad(RAY *r)
317   {
# Line 162 | Line 328 | rayirrad(RAY *r)
328          r->revf = rayirrad;
329   }
330  
331 < /* compute first ray intersection only */
331 > // compute first ray intersection only
332   static void
333   raycast(RAY *r)
334   {
# Line 175 | Line 341 | raycast(RAY *r)
341          }
342   }
343  
178 // Add a ray result to FIFO, flushing what we can
179 int
180 RtraceSimulManager::QueueResult(const RAY &ra)
181 {
182        return 0;       // UNIMPLEMENTED
183 }
184
344   // Add ray bundle to queue w/ optional 1st ray ID
345   int
346   RtraceSimulManager::EnqueueBundle(const FVECT orig_direc[], int n, RNUMBER rID0)
# Line 189 | Line 348 | RtraceSimulManager::EnqueueBundle(const FVECT orig_dir
348          int     nqueued = 0;
349          RAY     res;
350  
351 <        if (!Ready())
193 <                return -1;
351 >        if (!Ready()) return -1;
352  
353          if (castonly && !cookedCall)
354 <                error(CONSISTENCY, "EnqueueBundle() called in castonly mode without cookedCall");
354 >                error(INTERNAL, "EnqueueBundle() called in castonly mode without cookedCall");
355  
356          if (!UpdateMode())              // update rendering mode if requested
357                  return -1;
358  
359 +        if (rID0 && curFlags&RTdoFIFO)
360 +                error(INTERNAL, "Ray number assignment unsupported with FIFO");
361 +
362          while (n-- > 0) {               // queue each ray
363                  VCOPY(res.rorg, orig_direc[0]);
364                  VCOPY(res.rdir, orig_direc[1]);
365 +                res.rmax = .0;
366                  orig_direc += 2;
367                  rayorigin(&res, PRIMARY, NULL, NULL);
368 <                if (rID0) res.rno = rID0++;
207 <                else res.rno = ++lastRayID;
368 >                res.rno = rID0 ? (lastRayID = rID0++) : ++lastRayID;
369                  if (curFlags & RTimmIrrad)
370                          res.revf = rayirrad;
371                  else if (castonly)
372                          res.revf = raycast;
373                  double  d = normalize(res.rdir);
374                  bool    sendRes = (cookedCall != NULL);
375 <                if (d > 0) {            // direction vector is valid?
375 >                if (d > .0) {           // direction vector is valid?
376                          if (curFlags & RTlimDist)
377                                  res.rmax = d;
378 <                        if ((sendRes &= ProcessRay(&res)) &&
379 <                                        rtFlags & RTdoFIFO && NThreads() > 1) {
219 <                                if (QueueResult(res) < 0)
378 >                        if (((curFlags&RTdoFIFO) != 0) & (ray_pnprocs > 0)) {
379 >                                if (ray_fifo_in(&res) < 0)
380                                          return -1;
381                                  sendRes = false;
382 +                        } else {
383 +                                int     rv = ProcessRay(&res);
384 +                                if (rv < 0)
385 +                                        return -1;
386 +                                sendRes &= (rv > 0);
387                          }
388                  } else if (ThreadsAvailable() < NThreads() &&
389                                  FlushQueue() < 0)
390                          return -1;
391 <                if (sendRes)            // may be dummy ray
392 <                        (*cookedCall)(&res, ccData);
391 >                                        // may be dummy ray
392 >                if (sendRes && (*cookedCall)(&res, ccData) < 0)
393 >                        return -1;
394                  nqueued++;
395          }
396          return nqueued;
# Line 234 | Line 400 | RtraceSimulManager::EnqueueBundle(const FVECT orig_dir
400   int
401   RtraceSimulManager::FlushQueue()
402   {
403 +        if (curFlags & RTdoFIFO) {
404 +                if (ray_pnprocs)
405 +                        return ray_fifo_flush();
406 +                return 0;
407 +        }
408          int     nsent = 0;
409          RAY     res;
410  
411          while (WaitResult(&res)) {
412                  if (!cookedCall) continue;
413 <                if (rtFlags & RTdoFIFO) {
414 <                        int     ns = QueueResult(res);
415 <                        if (ns < 0) return ns;
245 <                        nsent += ns;
246 <                } else {
247 <                        (*cookedCall)(&res, ccData);
248 <                        nsent++;
249 <                }
413 >                int     rv = (*cookedCall)(&res, ccData);
414 >                if (rv < 0) return -1;
415 >                nsent += rv;
416          }
417          return nsent;
418   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines