ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RtraceSimulManager.cpp
Revision: 2.7
Committed: Wed May 1 20:28:53 2024 UTC (2 weeks, 2 days ago) by greg
Branch: MAIN
Changes since 2.6: +11 -7 lines
Log Message:
fix(rxtrace): Don't call FIFO routines with single process

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: RtraceSimulManager.cpp,v 2.6 2024/04/30 23:16:23 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(CONSISTENCY, "EnqueueBundle() called in castonly mode without cookedCall");
221
222 if (!UpdateMode()) // update rendering mode if requested
223 return -1;
224
225 while (n-- > 0) { // queue each ray
226 VCOPY(res.rorg, orig_direc[0]);
227 VCOPY(res.rdir, orig_direc[1]);
228 orig_direc += 2;
229 rayorigin(&res, PRIMARY, NULL, NULL);
230 if (rID0) res.rno = rID0++;
231 else res.rno = ++lastRayID;
232 if (curFlags & RTimmIrrad)
233 res.revf = rayirrad;
234 else if (castonly)
235 res.revf = raycast;
236 double d = normalize(res.rdir);
237 bool sendRes = (cookedCall != NULL);
238 if (d > 0) { // direction vector is valid?
239 if (curFlags & RTlimDist)
240 res.rmax = d;
241 if (((curFlags&RTdoFIFO) != 0) & (ray_pnprocs > 0)) {
242 if (ray_fifo_in(&res) < 0)
243 return -1;
244 sendRes = false;
245 } else
246 sendRes &= ProcessRay(&res);
247 } else if (ThreadsAvailable() < NThreads() &&
248 FlushQueue() < 0)
249 return -1;
250 // may be dummy ray
251 if (sendRes && (*cookedCall)(&res, ccData) < 0)
252 return -1;
253 nqueued++;
254 }
255 return nqueued;
256 }
257
258 // Finish pending rays and complete callbacks
259 int
260 RtraceSimulManager::FlushQueue()
261 {
262 if (curFlags & RTdoFIFO) {
263 if (ray_pnprocs)
264 return ray_fifo_flush();
265 return 0;
266 }
267 int nsent = 0;
268 RAY res;
269
270 while (WaitResult(&res)) {
271 if (!cookedCall) continue;
272 int rv = (*cookedCall)(&res, ccData);
273 if (rv < 0) return -1;
274 nsent += rv;
275 }
276 return nsent;
277 }