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.13 by greg, Sat Aug 3 15:38:06 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);        // 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')
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, const 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   // How many processors are available?
145   int
146   RadSimulManager::GetNCores()
147   {
148 <        return sysconf(_NPROCESSORS_ONLN);
148 >        return sysconf(_SC_NPROCESSORS_ONLN);
149   }
150  
151   // Set number of computation threads (0 => #cores)
152   int
153   RadSimulManager::SetThreadCount(int nt)
154   {
155 <        if (nt <= 0) nt = GetNCores();
155 >        if (!Ready())
156 >                return 0;
157  
158 <        return nThreads = nt;
158 >        if (nt <= 0) nt = castonly ? 1 : GetNCores();
159 >
160 >        if (nt == 1)
161 >                ray_pclose(ray_pnprocs);
162 >        else if (nt < ray_pnprocs)
163 >                ray_pclose(ray_pnprocs - nt);
164 >        else if (nt > ray_pnprocs)
165 >                ray_popen(nt - ray_pnprocs);
166 >
167 >        return NThreads();
168   }
169  
170   // Assign ray to subthread (fails if NThreads()<2)
171   bool
172   RadSimulManager::SplitRay(RAY *r)
173   {
174 <        if (NThreads() < 2 || ThreadsAvailable() < 1)
174 >        if (!ray_pnprocs || ThreadsAvailable() < 1)
175                  return false;
176  
177 <        int     rv = ray_psend(r);
58 <        if (rv < 0)
59 <                nThreads = 1;   // someone died
60 <        return (rv > 0);
177 >        return (ray_psend(r) > 0);
178   }
179  
180   // Process a ray (in subthread), optional result
181   bool
182   RadSimulManager::ProcessRay(RAY *r)
183   {
184 <        if (!r || !Ready()) return false;
185 <        if (NThreads() < 2) {   // single-threaded mode?
184 >        if (!Ready()) return false;
185 >
186 >        if (!ray_pnprocs) {     // single-threaded mode?
187                  samplendx++;
188                  rayvalue(r);
189                  return true;
190          }
191 <        if (ThreadsAvailable() >= 1) {
192 <                SplitRay(r);    // queue not yet full
191 >        int     rv = ray_pqueue(r);
192 >        if (rv < 0) {
193 >                error(WARNING, "ray tracing process(es) died");
194                  return false;
195          }
196 <        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
196 >        return (rv > 0);
197   }
198  
199   // Wait for next result (or fail)
200   bool
201   RadSimulManager::WaitResult(RAY *r)
202   {
203 <        int     rv = ray_presult(r, 0);
204 <        if (rv < 0)
205 <                nThreads = 1;   // someone died
206 <        return (rv > 0);
203 >        if (!ray_pnprocs)
204 >                return false;
205 >
206 >        return (ray_presult(r, 0) > 0);
207   }
208  
209   // Close octree, free data, return status
210   int
211   RadSimulManager::Cleanup(bool everything)
212   {
213 <        if (NThreads() > 1)
214 <                ray_pdone(everything);
100 <        else
213 >        NewHeader();
214 >        if (!ray_pnprocs)
215                  ray_done(everything);
216 +        else
217 +                ray_pdone(everything);
218          return 0;
219   }
220  
# Line 106 | Line 222 | RadSimulManager::Cleanup(bool everything)
222   int
223   RadSimulManager::ThreadsAvailable() const
224   {
225 <        if (NThreads() == 1) return 1;
225 >        if (!ray_pnprocs) return 1;
226 >
227          return ray_pnidle;
228   }
229  
230   // Global pointer to simulation manager for trace call-back (only one)
231   static const RtraceSimulManager *       ourRTsimMan = NULL;
232  
233 < void    // static call-back
233 > // Call-back for trace output
234 > void
235   RtraceSimulManager::RTracer(RAY *r)
236   {
237          (*ourRTsimMan->traceCall)(r, ourRTsimMan->tcData);
238   }
239  
240 + // Call-back for FIFO output
241 + int
242 + RtraceSimulManager::Rfifout(RAY *r)
243 + {
244 +        return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
245 + }
246 +
247   // Check for changes to render flags & adjust accordingly
248   bool
249   RtraceSimulManager::UpdateMode()
# Line 143 | Line 268 | RtraceSimulManager::UpdateMode()
268          if (misMatch & RTdoFIFO && FlushQueue() < 0)
269                  return false;
270          curFlags = rtFlags;
271 <                                // update trace callback
272 <        if (traceCall) {
148 <                if (ourRTsimMan && ourRTsimMan != this)
149 <                        error(WARNING, "Competing top-level simulation managers?");
150 <                ourRTsimMan = this;
271 >                                // update callbacks
272 >        if (traceCall)
273                  trace = RTracer;
274 <        } else if (ourRTsimMan == this) {
274 >        else if (trace == RTracer)
275                  trace = NULL;
276 +        if (rtFlags & RTdoFIFO)
277 +                ray_fifo_out = Rfifout;
278 +        else if (ray_fifo_out == Rfifout)
279 +                ray_fifo_out = NULL;
280 +        if ((trace != RTracer) & (ray_fifo_out != Rfifout)) {
281                  ourRTsimMan = NULL;
282 +        } else if (ourRTsimMan != this) {
283 +                if (ourRTsimMan)
284 +                        error(WARNING, "Competing top-level simulation managers?");
285 +                ourRTsimMan = this;
286          }
287          return true;
288   }
289  
290   extern "C" int  m_normal(OBJREC *m, RAY *r);
291  
292 < /* compute irradiance rather than radiance */
292 > // compute irradiance rather than radiance
293   static void
294   rayirrad(RAY *r)
295   {
# Line 175 | Line 306 | rayirrad(RAY *r)
306          r->revf = rayirrad;
307   }
308  
309 < /* compute first ray intersection only */
309 > // compute first ray intersection only
310   static void
311   raycast(RAY *r)
312   {
# Line 188 | Line 319 | raycast(RAY *r)
319          }
320   }
321  
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
322   // Add ray bundle to queue w/ optional 1st ray ID
323   int
324   RtraceSimulManager::EnqueueBundle(const FVECT orig_direc[], int n, RNUMBER rID0)
# Line 206 | Line 330 | RtraceSimulManager::EnqueueBundle(const FVECT orig_dir
330                  return -1;
331  
332          if (castonly && !cookedCall)
333 <                error(CONSISTENCY, "EnqueueBundle() called in castonly mode without cookedCall");
333 >                error(INTERNAL, "EnqueueBundle() called in castonly mode without cookedCall");
334  
335          if (!UpdateMode())              // update rendering mode if requested
336                  return -1;
337  
338 +        if (rID0 && curFlags&RTdoFIFO)
339 +                error(INTERNAL, "Ray number assignment unsupported with FIFO");
340 +
341          while (n-- > 0) {               // queue each ray
342                  VCOPY(res.rorg, orig_direc[0]);
343                  VCOPY(res.rdir, orig_direc[1]);
344                  orig_direc += 2;
345                  rayorigin(&res, PRIMARY, NULL, NULL);
346 <                if (rID0) res.rno = rID0++;
220 <                else res.rno = ++lastRayID;
346 >                res.rno = rID0 ? (lastRayID = rID0++) : ++lastRayID;
347                  if (curFlags & RTimmIrrad)
348                          res.revf = rayirrad;
349                  else if (castonly)
350                          res.revf = raycast;
351                  double  d = normalize(res.rdir);
352                  bool    sendRes = (cookedCall != NULL);
353 <                if (d > 0) {            // direction vector is valid?
353 >                if (d > .0) {           // direction vector is valid?
354                          if (curFlags & RTlimDist)
355                                  res.rmax = d;
356 <                        if ((sendRes &= ProcessRay(&res)) &&
357 <                                        rtFlags & RTdoFIFO && NThreads() > 1) {
232 <                                if (QueueResult(res) < 0)
356 >                        if (((curFlags&RTdoFIFO) != 0) & (ray_pnprocs > 0)) {
357 >                                if (ray_fifo_in(&res) < 0)
358                                          return -1;
359                                  sendRes = false;
360 <                        }
360 >                        } else
361 >                                sendRes &= ProcessRay(&res);
362                  } else if (ThreadsAvailable() < NThreads() &&
363                                  FlushQueue() < 0)
364                          return -1;
365 <
366 <                if (sendRes)            // may be dummy ray
367 <                        (*cookedCall)(&res, ccData);
365 >                                        // may be dummy ray
366 >                if (sendRes && (*cookedCall)(&res, ccData) < 0)
367 >                        return -1;
368                  nqueued++;
369          }
370          return nqueued;
# Line 248 | Line 374 | RtraceSimulManager::EnqueueBundle(const FVECT orig_dir
374   int
375   RtraceSimulManager::FlushQueue()
376   {
377 +        if (curFlags & RTdoFIFO) {
378 +                if (ray_pnprocs)
379 +                        return ray_fifo_flush();
380 +                return 0;
381 +        }
382          int     nsent = 0;
383          RAY     res;
384  
385          while (WaitResult(&res)) {
386                  if (!cookedCall) continue;
387 <                if (rtFlags & RTdoFIFO) {
388 <                        int     ns = QueueResult(res);
389 <                        if (ns < 0) return ns;
259 <                        nsent += ns;
260 <                } else {
261 <                        (*cookedCall)(&res, ccData);
262 <                        nsent++;
263 <                }
387 >                int     rv = (*cookedCall)(&res, ccData);
388 >                if (rv < 0) return -1;
389 >                nsent += rv;
390          }
391          return nsent;
392   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines