ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RtraceSimulManager.cpp
Revision: 2.5
Committed: Tue Mar 12 16:54:51 2024 UTC (13 months, 3 weeks ago) by greg
Branch: MAIN
Changes since 2.4: +24 -10 lines
Log Message:
perf: added datavector() call for quicker spectral interpolation

File Contents

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