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.5 by greg, Tue Mar 12 16:54:51 2024 UTC vs.
Revision 2.12 by greg, Sat Aug 3 01:54:46 2024 UTC

# Line 10 | Line 10 | static const char RCSid[] = "$Id$";
10   */
11  
12   #include <unistd.h>
13 + #include <ctype.h>
14   #include "RtraceSimulManager.h"
15   #include "source.h"
16  
16 extern int      castonly;       // doing ray-casting only?
17
17   // Load octree and prepare renderer
18   bool
19   RadSimulManager::LoadOctree(const char *octn)
# Line 22 | 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);        // load header if we can
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 *fname)
50 + {
51 +        if (header) {
52 +                free(header); header = NULL;
53 +        }
54 +        if (!fname || fname[0] == '!')
55 +                return false;
56 +        FILE    *fp = fopen(fname, "rb");
57 +        bool    ok = (getheader(fp, add2header, this) >= 0);
58 +        fclose(fp);
59 +        return ok;
60 + }
61 +
62 + // Add a string to header (adds newline if none)
63 + bool
64 + RadSimulManager::AddHeader(const char *str)
65 + {
66 +        if (!str) return false;
67 +        int     len = strlen(str);
68 +        if (!len || str[0] == '\n') return false;
69 +        int     olen = 0;
70 +        if (header) {
71 +                olen = strlen(header);
72 +                header = (char *)realloc(header, olen+len+2);
73 +        } else
74 +                header = (char *)malloc(len+2);
75 +        if (!header) return false;
76 +        strcpy(header+olen, str);
77 +        if (str[len-1] != '\n') {
78 +                header[olen+len++] = '\n';
79 +                header[olen+len] = '\0';
80 +        }
81 +        return true;
82 + }
83 +
84 + // helper function to check for white-space and quotations
85 + static int
86 + check_special(const char *s)
87 + {
88 +        int     space_found = 0;
89 +
90 +        while (*s) {
91 +                if ((*s == '"') | (*s == '\''))
92 +                        return *s;      // quotes have priority
93 +                if (isspace(*s))
94 +                        space_found = *s;
95 +                s++;
96 +        }
97 +        return space_found;
98 + }
99 +
100 + // Append program line to header
101 + bool
102 + RadSimulManager::AddHeader(int ac, const char *av[])
103 + {
104 +        if ((ac <= 0) | !av) return false;
105 +        int     len = 0;
106 +        int     n;
107 +        for (n = 0; n < ac; n++) {
108 +                if (!av[n]) return false;
109 +                len += strlen(av[n]) + 3;
110 +        }
111 +        int     hlen = 0;
112 +        if (header) {                   // add to header
113 +                hlen = strlen(header);
114 +                header = (char *)realloc(header, hlen+len+1);
115 +        } else
116 +                header = (char *)malloc(len+1);
117 +        for (n = 0; n < ac; n++) {
118 +                int     c = check_special(av[n]);
119 +                if (c) {                // need to quote argument?
120 +                        if (c == '"') c = '\'';
121 +                        else c = '"';
122 +                        header[hlen++] = c;
123 +                        strcpy(header+hlen, av[n]);
124 +                        hlen += strlen(av[n]);
125 +                        header[hlen++] = c;
126 +                } else {
127 +                        strcpy(header+hlen, av[n]);
128 +                        hlen += strlen(av[n]);
129 +                }
130 +                header[hlen++] = ' ';
131 +        }
132 +        header[hlen-1] = '\n';          // terminate line
133 +        header[hlen] = '\0';
134 +        return true;
135 + }
136 +
137   // How many processors are available?
138   int
139   RadSimulManager::GetNCores()
140   {
141 <        return sysconf(_NPROCESSORS_ONLN);
141 >        return sysconf(_SC_NPROCESSORS_ONLN);
142   }
143  
144   // Set number of computation threads (0 => #cores)
145   int
146   RadSimulManager::SetThreadCount(int nt)
147   {
148 <        if (nt <= 0) nt = GetNCores();
148 >        if (!Ready())
149 >                return 0;
150  
151 <        return nThreads = nt;
151 >        if (nt <= 0) nt = castonly ? 1 : GetNCores();
152 >
153 >        if (nt == 1)
154 >                ray_pclose(ray_pnprocs);
155 >        else if (nt < ray_pnprocs)
156 >                ray_pclose(ray_pnprocs - nt);
157 >        else if (nt > ray_pnprocs)
158 >                ray_popen(nt - ray_pnprocs);
159 >
160 >        return NThreads();
161   }
162  
163   // Assign ray to subthread (fails if NThreads()<2)
164   bool
165   RadSimulManager::SplitRay(RAY *r)
166   {
167 <        if (NThreads() < 2 || ThreadsAvailable() < 1)
167 >        if (!ray_pnprocs || ThreadsAvailable() < 1)
168                  return false;
169  
170 <        int     rv = ray_psend(r);
58 <        if (rv < 0)
59 <                nThreads = 1;   // someone died
60 <        return (rv > 0);
170 >        return (ray_psend(r) > 0);
171   }
172  
173   // Process a ray (in subthread), optional result
174   bool
175   RadSimulManager::ProcessRay(RAY *r)
176   {
177 <        if (!r || !Ready()) return false;
178 <        if (NThreads() < 2) {   // single-threaded mode?
177 >        if (!Ready()) return false;
178 >
179 >        if (!ray_pnprocs) {     // single-threaded mode?
180                  samplendx++;
181                  rayvalue(r);
182                  return true;
183          }
184 <        if (ThreadsAvailable() >= 1) {
185 <                SplitRay(r);    // queue not yet full
184 >        int     rv = ray_pqueue(r);
185 >        if (rv < 0) {
186 >                error(WARNING, "ray tracing process(es) died");
187                  return false;
188          }
189 <        RAY     toDo = *r;
78 <        if (!WaitResult(r))     // need a free thread
79 <                return false;
80 <
81 <        return SplitRay(&toDo); // queue up new ray & return old
189 >        return (rv > 0);
190   }
191  
192   // Wait for next result (or fail)
193   bool
194   RadSimulManager::WaitResult(RAY *r)
195   {
196 <        int     rv = ray_presult(r, 0);
197 <        if (rv < 0)
198 <                nThreads = 1;   // someone died
199 <        return (rv > 0);
196 >        if (!ray_pnprocs)
197 >                return false;
198 >
199 >        return (ray_presult(r, 0) > 0);
200   }
201  
202   // Close octree, free data, return status
203   int
204   RadSimulManager::Cleanup(bool everything)
205   {
206 <        if (NThreads() > 1)
99 <                ray_pdone(everything);
100 <        else
206 >        if (!ray_pnprocs)
207                  ray_done(everything);
208 +        else
209 +                ray_pdone(everything);
210          return 0;
211   }
212  
# Line 106 | Line 214 | RadSimulManager::Cleanup(bool everything)
214   int
215   RadSimulManager::ThreadsAvailable() const
216   {
217 <        if (NThreads() == 1) return 1;
217 >        if (!ray_pnprocs) return 1;
218 >
219          return ray_pnidle;
220   }
221  
222   // Global pointer to simulation manager for trace call-back (only one)
223   static const RtraceSimulManager *       ourRTsimMan = NULL;
224  
225 < void    // static call-back
225 > // Call-back for trace output
226 > void
227   RtraceSimulManager::RTracer(RAY *r)
228   {
229          (*ourRTsimMan->traceCall)(r, ourRTsimMan->tcData);
230   }
231  
232 + // Call-back for FIFO output
233 + int
234 + RtraceSimulManager::Rfifout(RAY *r)
235 + {
236 +        return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
237 + }
238 +
239   // Check for changes to render flags & adjust accordingly
240   bool
241   RtraceSimulManager::UpdateMode()
# Line 143 | Line 260 | RtraceSimulManager::UpdateMode()
260          if (misMatch & RTdoFIFO && FlushQueue() < 0)
261                  return false;
262          curFlags = rtFlags;
263 <                                // update trace callback
264 <        if (traceCall) {
148 <                if (ourRTsimMan && ourRTsimMan != this)
149 <                        error(WARNING, "Competing top-level simulation managers?");
150 <                ourRTsimMan = this;
263 >                                // update callbacks
264 >        if (traceCall)
265                  trace = RTracer;
266 <        } else if (ourRTsimMan == this) {
266 >        else if (trace == RTracer)
267                  trace = NULL;
268 +        if (rtFlags & RTdoFIFO)
269 +                ray_fifo_out = Rfifout;
270 +        else if (ray_fifo_out == Rfifout)
271 +                ray_fifo_out = NULL;
272 +        if ((trace != RTracer) & (ray_fifo_out != Rfifout)) {
273                  ourRTsimMan = NULL;
274 +        } else if (ourRTsimMan != this) {
275 +                if (ourRTsimMan)
276 +                        error(WARNING, "Competing top-level simulation managers?");
277 +                ourRTsimMan = this;
278          }
279          return true;
280   }
281  
282   extern "C" int  m_normal(OBJREC *m, RAY *r);
283  
284 < /* compute irradiance rather than radiance */
284 > // compute irradiance rather than radiance
285   static void
286   rayirrad(RAY *r)
287   {
# Line 175 | Line 298 | rayirrad(RAY *r)
298          r->revf = rayirrad;
299   }
300  
301 < /* compute first ray intersection only */
301 > // compute first ray intersection only
302   static void
303   raycast(RAY *r)
304   {
# Line 188 | Line 311 | raycast(RAY *r)
311          }
312   }
313  
191 // Add a ray result to FIFO, flushing what we can
192 int
193 RtraceSimulManager::QueueResult(const RAY &ra)
194 {
195        return 0;       // UNIMPLEMENTED
196 }
197
314   // Add ray bundle to queue w/ optional 1st ray ID
315   int
316   RtraceSimulManager::EnqueueBundle(const FVECT orig_direc[], int n, RNUMBER rID0)
# Line 206 | Line 322 | RtraceSimulManager::EnqueueBundle(const FVECT orig_dir
322                  return -1;
323  
324          if (castonly && !cookedCall)
325 <                error(CONSISTENCY, "EnqueueBundle() called in castonly mode without cookedCall");
325 >                error(INTERNAL, "EnqueueBundle() called in castonly mode without cookedCall");
326  
327          if (!UpdateMode())              // update rendering mode if requested
328                  return -1;
329  
330 +        if (rID0 && curFlags&RTdoFIFO)
331 +                error(INTERNAL, "Ray number assignment unsupported with FIFO");
332 +
333          while (n-- > 0) {               // queue each ray
334                  VCOPY(res.rorg, orig_direc[0]);
335                  VCOPY(res.rdir, orig_direc[1]);
336                  orig_direc += 2;
337                  rayorigin(&res, PRIMARY, NULL, NULL);
338 <                if (rID0) res.rno = rID0++;
220 <                else res.rno = ++lastRayID;
338 >                res.rno = rID0 ? (lastRayID = rID0++) : ++lastRayID;
339                  if (curFlags & RTimmIrrad)
340                          res.revf = rayirrad;
341                  else if (castonly)
342                          res.revf = raycast;
343                  double  d = normalize(res.rdir);
344                  bool    sendRes = (cookedCall != NULL);
345 <                if (d > 0) {            // direction vector is valid?
345 >                if (d > .0) {           // direction vector is valid?
346                          if (curFlags & RTlimDist)
347                                  res.rmax = d;
348 <                        if ((sendRes &= ProcessRay(&res)) &&
349 <                                        rtFlags & RTdoFIFO && NThreads() > 1) {
232 <                                if (QueueResult(res) < 0)
348 >                        if (((curFlags&RTdoFIFO) != 0) & (ray_pnprocs > 0)) {
349 >                                if (ray_fifo_in(&res) < 0)
350                                          return -1;
351                                  sendRes = false;
352 <                        }
352 >                        } else
353 >                                sendRes &= ProcessRay(&res);
354                  } else if (ThreadsAvailable() < NThreads() &&
355                                  FlushQueue() < 0)
356                          return -1;
357 <
358 <                if (sendRes)            // may be dummy ray
359 <                        (*cookedCall)(&res, ccData);
357 >                                        // may be dummy ray
358 >                if (sendRes && (*cookedCall)(&res, ccData) < 0)
359 >                        return -1;
360                  nqueued++;
361          }
362          return nqueued;
# Line 248 | Line 366 | RtraceSimulManager::EnqueueBundle(const FVECT orig_dir
366   int
367   RtraceSimulManager::FlushQueue()
368   {
369 +        if (curFlags & RTdoFIFO) {
370 +                if (ray_pnprocs)
371 +                        return ray_fifo_flush();
372 +                return 0;
373 +        }
374          int     nsent = 0;
375          RAY     res;
376  
377          while (WaitResult(&res)) {
378                  if (!cookedCall) continue;
379 <                if (rtFlags & RTdoFIFO) {
380 <                        int     ns = QueueResult(res);
381 <                        if (ns < 0) return ns;
259 <                        nsent += ns;
260 <                } else {
261 <                        (*cookedCall)(&res, ccData);
262 <                        nsent++;
263 <                }
379 >                int     rv = (*cookedCall)(&res, ccData);
380 >                if (rv < 0) return -1;
381 >                nsent += rv;
382          }
383          return nsent;
384   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines