ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RtraceSimulManager.cpp
Revision: 2.9
Committed: Fri May 3 18:01:20 2024 UTC (3 weeks, 1 day ago) by greg
Branch: MAIN
CVS Tags: HEAD
Changes since 2.8: +5 -7 lines
Log Message:
perf: Minor improvement

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: RtraceSimulManager.cpp,v 2.8 2024/05/02 22:10:43 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 // Call-back for trace output
121 void
122 RtraceSimulManager::RTracer(RAY *r)
123 {
124 (*ourRTsimMan->traceCall)(r, ourRTsimMan->tcData);
125 }
126
127 // Call-back for FIFO output
128 int
129 RtraceSimulManager::Rfifout(RAY *r)
130 {
131 return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
132 }
133
134 // Check for changes to render flags & adjust accordingly
135 bool
136 RtraceSimulManager::UpdateMode()
137 {
138 rtFlags &= RTmask;
139 if (!cookedCall)
140 rtFlags &= ~RTdoFIFO;
141 if (!traceCall)
142 rtFlags &= ~RTtraceSources;
143 if (rtFlags & RTimmIrrad)
144 rtFlags &= ~RTlimDist;
145
146 int misMatch = rtFlags ^ curFlags;
147 // updates based on toggled flags
148 if (misMatch & RTtraceSources) {
149 if (rtFlags & RTtraceSources) {
150 for (int sn = 0; sn < nsources; sn++)
151 source[sn].sflags |= SFOLLOW;
152 } else // cannot undo this...
153 rtFlags |= RTtraceSources;
154 }
155 if (misMatch & RTdoFIFO && FlushQueue() < 0)
156 return false;
157 curFlags = rtFlags;
158 // update callbacks
159 if (traceCall)
160 trace = RTracer;
161 else if (trace == RTracer)
162 trace = NULL;
163 if (rtFlags & RTdoFIFO)
164 ray_fifo_out = Rfifout;
165 else if (ray_fifo_out == Rfifout)
166 ray_fifo_out = NULL;
167 if ((trace != RTracer) & (ray_fifo_out != Rfifout)) {
168 ourRTsimMan = NULL;
169 } else if (ourRTsimMan != this) {
170 if (ourRTsimMan)
171 error(WARNING, "Competing top-level simulation managers?");
172 ourRTsimMan = this;
173 }
174 return true;
175 }
176
177 extern "C" int m_normal(OBJREC *m, RAY *r);
178
179 // compute irradiance rather than radiance
180 static void
181 rayirrad(RAY *r)
182 {
183 /* pretend we hit surface */
184 r->rxt = r->rot = 1e-5;
185 VSUM(r->rop, r->rorg, r->rdir, r->rot);
186 r->ron[0] = -r->rdir[0];
187 r->ron[1] = -r->rdir[1];
188 r->ron[2] = -r->rdir[2];
189 r->rod = 1.0;
190 /* compute result */
191 r->revf = raytrace;
192 m_normal(&Lamb, r);
193 r->revf = rayirrad;
194 }
195
196 // compute first ray intersection only
197 static void
198 raycast(RAY *r)
199 {
200 if (!localhit(r, &thescene)) {
201 if (r->ro == &Aftplane) { /* clipped */
202 r->ro = NULL;
203 r->rot = FHUGE;
204 } else
205 sourcehit(r);
206 }
207 }
208
209 // Add ray bundle to queue w/ optional 1st ray ID
210 int
211 RtraceSimulManager::EnqueueBundle(const FVECT orig_direc[], int n, RNUMBER rID0)
212 {
213 int nqueued = 0;
214 RAY res;
215
216 if (!Ready())
217 return -1;
218
219 if (castonly && !cookedCall)
220 error(INTERNAL, "EnqueueBundle() called in castonly mode without cookedCall");
221
222 if (!UpdateMode()) // update rendering mode if requested
223 return -1;
224
225 if (rID0 && curFlags&RTdoFIFO)
226 error(INTERNAL, "Ray number assignment unsupported with FIFO");
227
228 while (n-- > 0) { // queue each ray
229 VCOPY(res.rorg, orig_direc[0]);
230 VCOPY(res.rdir, orig_direc[1]);
231 orig_direc += 2;
232 rayorigin(&res, PRIMARY, NULL, NULL);
233 res.rno = rID0 ? (lastRayID = rID0++) : ++lastRayID;
234 if (curFlags & RTimmIrrad)
235 res.revf = rayirrad;
236 else if (castonly)
237 res.revf = raycast;
238 double d = normalize(res.rdir);
239 bool sendRes = (cookedCall != NULL);
240 if (d > 0) { // direction vector is valid?
241 if (curFlags & RTlimDist)
242 res.rmax = d;
243 if (((curFlags&RTdoFIFO) != 0) & (ray_pnprocs > 0)) {
244 if (ray_fifo_in(&res) < 0)
245 return -1;
246 sendRes = false;
247 } else
248 sendRes &= ProcessRay(&res);
249 } else if (ThreadsAvailable() < NThreads() &&
250 FlushQueue() < 0)
251 return -1;
252 // may be dummy ray
253 if (sendRes && (*cookedCall)(&res, ccData) < 0)
254 return -1;
255 nqueued++;
256 }
257 return nqueued;
258 }
259
260 // Finish pending rays and complete callbacks
261 int
262 RtraceSimulManager::FlushQueue()
263 {
264 if (curFlags & RTdoFIFO) {
265 if (ray_pnprocs)
266 return ray_fifo_flush();
267 return 0;
268 }
269 int nsent = 0;
270 RAY res;
271
272 while (WaitResult(&res)) {
273 if (!cookedCall) continue;
274 int rv = (*cookedCall)(&res, ccData);
275 if (rv < 0) return -1;
276 nsent += rv;
277 }
278 return nsent;
279 }