ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RtraceSimulManager.cpp
Revision: 2.6
Committed: Tue Apr 30 23:16:23 2024 UTC (12 months ago) by greg
Branch: MAIN
Changes since 2.5: +65 -58 lines
Log Message:
feat(rxtrace): Added multi-processing and spectral color

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.6 static const char RCSid[] = "$Id: RtraceSimulManager.cpp,v 2.5 2024/03/12 16:54:51 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * RtraceSimulManager.cpp
6     *
7     * Rtrace simulation manager class implementation
8     *
9     * Created by Greg Ward on 2/2/2023.
10     */
11    
12 greg 2.5 #include <unistd.h>
13 greg 2.1 #include "RtraceSimulManager.h"
14     #include "source.h"
15    
16     // Load octree and prepare renderer
17     bool
18     RadSimulManager::LoadOctree(const char *octn)
19     {
20     if (octname) { // already running?
21     if (octn && !strcmp(octn, octname))
22     return true;
23 greg 2.6 Cleanup();
24 greg 2.1 }
25     if (!octn)
26     return false;
27    
28     ray_init((char *)octn);
29     return true;
30     }
31    
32 greg 2.5 // How many processors are available?
33 greg 2.2 int
34     RadSimulManager::GetNCores()
35     {
36 greg 2.6 return sysconf(_SC_NPROCESSORS_ONLN);
37 greg 2.2 }
38    
39 greg 2.1 // Set number of computation threads (0 => #cores)
40     int
41     RadSimulManager::SetThreadCount(int nt)
42     {
43 greg 2.6 if (!Ready())
44     return 0;
45    
46     if (nt <= 0) nt = castonly ? 1 : GetNCores();
47    
48     if (nt == 1)
49     ray_pclose(ray_pnprocs);
50     else if (nt < ray_pnprocs)
51     ray_pclose(ray_pnprocs - nt);
52     else if (nt > ray_pnprocs)
53     ray_popen(nt - ray_pnprocs);
54 greg 2.5
55 greg 2.6 return NThreads();
56 greg 2.1 }
57    
58 greg 2.4 // Assign ray to subthread (fails if NThreads()<2)
59     bool
60     RadSimulManager::SplitRay(RAY *r)
61     {
62 greg 2.6 if (!ray_pnprocs || ThreadsAvailable() < 1)
63 greg 2.4 return false;
64    
65 greg 2.6 return (ray_psend(r) > 0);
66 greg 2.4 }
67    
68     // Process a ray (in subthread), optional result
69     bool
70     RadSimulManager::ProcessRay(RAY *r)
71     {
72 greg 2.6 if (!Ready()) return false;
73    
74     if (!ray_pnprocs) { // single-threaded mode?
75 greg 2.4 samplendx++;
76     rayvalue(r);
77     return true;
78     }
79 greg 2.6 int rv = ray_pqueue(r);
80     if (rv < 0) {
81     error(WARNING, "ray tracing process(es) died");
82 greg 2.4 return false;
83     }
84 greg 2.6 return (rv > 0);
85 greg 2.4 }
86    
87     // Wait for next result (or fail)
88     bool
89     RadSimulManager::WaitResult(RAY *r)
90     {
91 greg 2.6 if (!ray_pnprocs)
92     return false;
93    
94     return (ray_presult(r, 0) > 0);
95 greg 2.4 }
96    
97 greg 2.1 // Close octree, free data, return status
98     int
99 greg 2.3 RadSimulManager::Cleanup(bool everything)
100 greg 2.1 {
101 greg 2.6 if (!ray_pnprocs)
102 greg 2.5 ray_pdone(everything);
103     else
104     ray_done(everything);
105 greg 2.1 return 0;
106     }
107    
108     // How many threads are currently unoccupied?
109     int
110     RadSimulManager::ThreadsAvailable() const
111     {
112 greg 2.6 if (!ray_pnprocs) return 1;
113    
114 greg 2.5 return ray_pnidle;
115 greg 2.1 }
116    
117     // Global pointer to simulation manager for trace call-back (only one)
118     static const RtraceSimulManager * ourRTsimMan = NULL;
119    
120     void // static call-back
121     RtraceSimulManager::RTracer(RAY *r)
122     {
123     (*ourRTsimMan->traceCall)(r, ourRTsimMan->tcData);
124     }
125    
126 greg 2.6 // Call-back for FIFO output
127     int
128     RtraceSimulManager::Rfifout(RAY *r)
129     {
130     return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
131     }
132    
133 greg 2.1 // Check for changes to render flags & adjust accordingly
134     bool
135     RtraceSimulManager::UpdateMode()
136     {
137     rtFlags &= RTmask;
138     if (!cookedCall)
139     rtFlags &= ~RTdoFIFO;
140     if (!traceCall)
141     rtFlags &= ~RTtraceSources;
142     if (rtFlags & RTimmIrrad)
143     rtFlags &= ~RTlimDist;
144    
145     int misMatch = rtFlags ^ curFlags;
146     // updates based on toggled flags
147     if (misMatch & RTtraceSources) {
148     if (rtFlags & RTtraceSources) {
149     for (int sn = 0; sn < nsources; sn++)
150     source[sn].sflags |= SFOLLOW;
151     } else // cannot undo this...
152     rtFlags |= RTtraceSources;
153     }
154 greg 2.4 if (misMatch & RTdoFIFO && FlushQueue() < 0)
155     return false;
156 greg 2.1 curFlags = rtFlags;
157 greg 2.6 // update callbacks
158     if (traceCall)
159 greg 2.1 trace = RTracer;
160 greg 2.6 else if (trace == RTracer)
161 greg 2.1 trace = NULL;
162 greg 2.6 if (rtFlags & RTdoFIFO)
163     ray_fifo_out = Rfifout;
164     else if (ray_fifo_out == Rfifout)
165     ray_fifo_out = NULL;
166     if ((trace != RTracer) & (ray_fifo_out != Rfifout)) {
167 greg 2.1 ourRTsimMan = NULL;
168 greg 2.6 } else if (ourRTsimMan != this) {
169     if (ourRTsimMan)
170     error(WARNING, "Competing top-level simulation managers?");
171     ourRTsimMan = this;
172 greg 2.1 }
173     return true;
174     }
175    
176     extern "C" int m_normal(OBJREC *m, RAY *r);
177    
178 greg 2.6 // compute irradiance rather than radiance
179 greg 2.1 static void
180     rayirrad(RAY *r)
181     {
182     /* pretend we hit surface */
183     r->rxt = r->rot = 1e-5;
184     VSUM(r->rop, r->rorg, r->rdir, r->rot);
185     r->ron[0] = -r->rdir[0];
186     r->ron[1] = -r->rdir[1];
187     r->ron[2] = -r->rdir[2];
188     r->rod = 1.0;
189     /* compute result */
190     r->revf = raytrace;
191     m_normal(&Lamb, r);
192     r->revf = rayirrad;
193     }
194    
195 greg 2.6 // compute first ray intersection only
196 greg 2.1 static void
197     raycast(RAY *r)
198     {
199     if (!localhit(r, &thescene)) {
200     if (r->ro == &Aftplane) { /* clipped */
201     r->ro = NULL;
202     r->rot = FHUGE;
203     } else
204     sourcehit(r);
205     }
206     }
207    
208     // Add ray bundle to queue w/ optional 1st ray ID
209     int
210     RtraceSimulManager::EnqueueBundle(const FVECT orig_direc[], int n, RNUMBER rID0)
211     {
212     int nqueued = 0;
213     RAY res;
214    
215     if (!Ready())
216     return -1;
217    
218     if (castonly && !cookedCall)
219     error(CONSISTENCY, "EnqueueBundle() called in castonly mode without cookedCall");
220    
221     if (!UpdateMode()) // update rendering mode if requested
222     return -1;
223    
224     while (n-- > 0) { // queue each ray
225     VCOPY(res.rorg, orig_direc[0]);
226     VCOPY(res.rdir, orig_direc[1]);
227     orig_direc += 2;
228     rayorigin(&res, PRIMARY, NULL, NULL);
229     if (rID0) res.rno = rID0++;
230     else res.rno = ++lastRayID;
231     if (curFlags & RTimmIrrad)
232     res.revf = rayirrad;
233     else if (castonly)
234     res.revf = raycast;
235 greg 2.4 double d = normalize(res.rdir);
236     bool sendRes = (cookedCall != NULL);
237 greg 2.1 if (d > 0) { // direction vector is valid?
238     if (curFlags & RTlimDist)
239     res.rmax = d;
240 greg 2.6 if (curFlags & RTdoFIFO) {
241     ray_fifo_in(&res);
242 greg 2.4 sendRes = false;
243 greg 2.6 } else
244     sendRes &= ProcessRay(&res);
245 greg 2.1 } else if (ThreadsAvailable() < NThreads() &&
246 greg 2.4 FlushQueue() < 0)
247 greg 2.1 return -1;
248 greg 2.6 // may be dummy ray
249     if (sendRes && (*cookedCall)(&res, ccData) < 0)
250     return -1;
251 greg 2.3 nqueued++;
252 greg 2.1 }
253     return nqueued;
254     }
255    
256     // Finish pending rays and complete callbacks
257 greg 2.4 int
258 greg 2.1 RtraceSimulManager::FlushQueue()
259     {
260 greg 2.6 if (curFlags & RTdoFIFO)
261     return ray_fifo_flush();
262    
263 greg 2.4 int nsent = 0;
264     RAY res;
265    
266     while (WaitResult(&res)) {
267     if (!cookedCall) continue;
268 greg 2.6 int rv = (*cookedCall)(&res, ccData);
269     if (rv < 0) return -1;
270     nsent += rv;
271 greg 2.4 }
272     return nsent;
273 greg 2.1 }