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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: RtraceSimulManager.cpp,v 2.5 2024/03/12 16:54:51 greg Exp $";
3 #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 #include <unistd.h>
13 #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 Cleanup();
24 }
25 if (!octn)
26 return false;
27
28 ray_init((char *)octn);
29 return true;
30 }
31
32 // How many processors are available?
33 int
34 RadSimulManager::GetNCores()
35 {
36 return sysconf(_SC_NPROCESSORS_ONLN);
37 }
38
39 // Set number of computation threads (0 => #cores)
40 int
41 RadSimulManager::SetThreadCount(int nt)
42 {
43 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
55 return NThreads();
56 }
57
58 // Assign ray to subthread (fails if NThreads()<2)
59 bool
60 RadSimulManager::SplitRay(RAY *r)
61 {
62 if (!ray_pnprocs || ThreadsAvailable() < 1)
63 return false;
64
65 return (ray_psend(r) > 0);
66 }
67
68 // Process a ray (in subthread), optional result
69 bool
70 RadSimulManager::ProcessRay(RAY *r)
71 {
72 if (!Ready()) return false;
73
74 if (!ray_pnprocs) { // single-threaded mode?
75 samplendx++;
76 rayvalue(r);
77 return true;
78 }
79 int rv = ray_pqueue(r);
80 if (rv < 0) {
81 error(WARNING, "ray tracing process(es) died");
82 return false;
83 }
84 return (rv > 0);
85 }
86
87 // Wait for next result (or fail)
88 bool
89 RadSimulManager::WaitResult(RAY *r)
90 {
91 if (!ray_pnprocs)
92 return false;
93
94 return (ray_presult(r, 0) > 0);
95 }
96
97 // Close octree, free data, return status
98 int
99 RadSimulManager::Cleanup(bool everything)
100 {
101 if (!ray_pnprocs)
102 ray_pdone(everything);
103 else
104 ray_done(everything);
105 return 0;
106 }
107
108 // How many threads are currently unoccupied?
109 int
110 RadSimulManager::ThreadsAvailable() const
111 {
112 if (!ray_pnprocs) return 1;
113
114 return ray_pnidle;
115 }
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 // Call-back for FIFO output
127 int
128 RtraceSimulManager::Rfifout(RAY *r)
129 {
130 return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
131 }
132
133 // 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 if (misMatch & RTdoFIFO && FlushQueue() < 0)
155 return false;
156 curFlags = rtFlags;
157 // update callbacks
158 if (traceCall)
159 trace = RTracer;
160 else if (trace == RTracer)
161 trace = NULL;
162 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 ourRTsimMan = NULL;
168 } else if (ourRTsimMan != this) {
169 if (ourRTsimMan)
170 error(WARNING, "Competing top-level simulation managers?");
171 ourRTsimMan = this;
172 }
173 return true;
174 }
175
176 extern "C" int m_normal(OBJREC *m, RAY *r);
177
178 // compute irradiance rather than radiance
179 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 // compute first ray intersection only
196 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 double d = normalize(res.rdir);
236 bool sendRes = (cookedCall != NULL);
237 if (d > 0) { // direction vector is valid?
238 if (curFlags & RTlimDist)
239 res.rmax = d;
240 if (curFlags & RTdoFIFO) {
241 ray_fifo_in(&res);
242 sendRes = false;
243 } else
244 sendRes &= ProcessRay(&res);
245 } else if (ThreadsAvailable() < NThreads() &&
246 FlushQueue() < 0)
247 return -1;
248 // may be dummy ray
249 if (sendRes && (*cookedCall)(&res, ccData) < 0)
250 return -1;
251 nqueued++;
252 }
253 return nqueued;
254 }
255
256 // Finish pending rays and complete callbacks
257 int
258 RtraceSimulManager::FlushQueue()
259 {
260 if (curFlags & RTdoFIFO)
261 return ray_fifo_flush();
262
263 int nsent = 0;
264 RAY res;
265
266 while (WaitResult(&res)) {
267 if (!cookedCall) continue;
268 int rv = (*cookedCall)(&res, ccData);
269 if (rv < 0) return -1;
270 nsent += rv;
271 }
272 return nsent;
273 }