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 (2 weeks, 5 days ago) by greg
Branch: MAIN
CVS Tags: HEAD
Changes since 2.8: +5 -7 lines
Log Message:
perf: Minor improvement

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.9 static const char RCSid[] = "$Id: RtraceSimulManager.cpp,v 2.8 2024/05/02 22:10:43 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 greg 2.7 // Call-back for trace output
121     void
122 greg 2.1 RtraceSimulManager::RTracer(RAY *r)
123     {
124     (*ourRTsimMan->traceCall)(r, ourRTsimMan->tcData);
125     }
126    
127 greg 2.6 // Call-back for FIFO output
128     int
129     RtraceSimulManager::Rfifout(RAY *r)
130     {
131     return (*ourRTsimMan->cookedCall)(r, ourRTsimMan->ccData);
132     }
133    
134 greg 2.1 // 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 greg 2.4 if (misMatch & RTdoFIFO && FlushQueue() < 0)
156     return false;
157 greg 2.1 curFlags = rtFlags;
158 greg 2.6 // update callbacks
159     if (traceCall)
160 greg 2.1 trace = RTracer;
161 greg 2.6 else if (trace == RTracer)
162 greg 2.1 trace = NULL;
163 greg 2.6 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 greg 2.1 ourRTsimMan = NULL;
169 greg 2.6 } else if (ourRTsimMan != this) {
170     if (ourRTsimMan)
171     error(WARNING, "Competing top-level simulation managers?");
172     ourRTsimMan = this;
173 greg 2.1 }
174     return true;
175     }
176    
177     extern "C" int m_normal(OBJREC *m, RAY *r);
178    
179 greg 2.6 // compute irradiance rather than radiance
180 greg 2.1 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 greg 2.6 // compute first ray intersection only
197 greg 2.1 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 greg 2.8 error(INTERNAL, "EnqueueBundle() called in castonly mode without cookedCall");
221 greg 2.1
222     if (!UpdateMode()) // update rendering mode if requested
223     return -1;
224    
225 greg 2.9 if (rID0 && curFlags&RTdoFIFO)
226     error(INTERNAL, "Ray number assignment unsupported with FIFO");
227    
228 greg 2.1 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 greg 2.9 res.rno = rID0 ? (lastRayID = rID0++) : ++lastRayID;
234 greg 2.1 if (curFlags & RTimmIrrad)
235     res.revf = rayirrad;
236     else if (castonly)
237     res.revf = raycast;
238 greg 2.4 double d = normalize(res.rdir);
239     bool sendRes = (cookedCall != NULL);
240 greg 2.1 if (d > 0) { // direction vector is valid?
241     if (curFlags & RTlimDist)
242     res.rmax = d;
243 greg 2.7 if (((curFlags&RTdoFIFO) != 0) & (ray_pnprocs > 0)) {
244     if (ray_fifo_in(&res) < 0)
245     return -1;
246 greg 2.4 sendRes = false;
247 greg 2.6 } else
248     sendRes &= ProcessRay(&res);
249 greg 2.1 } else if (ThreadsAvailable() < NThreads() &&
250 greg 2.4 FlushQueue() < 0)
251 greg 2.1 return -1;
252 greg 2.6 // may be dummy ray
253     if (sendRes && (*cookedCall)(&res, ccData) < 0)
254     return -1;
255 greg 2.3 nqueued++;
256 greg 2.1 }
257     return nqueued;
258     }
259    
260     // Finish pending rays and complete callbacks
261 greg 2.4 int
262 greg 2.1 RtraceSimulManager::FlushQueue()
263     {
264 greg 2.7 if (curFlags & RTdoFIFO) {
265     if (ray_pnprocs)
266     return ray_fifo_flush();
267     return 0;
268     }
269 greg 2.4 int nsent = 0;
270     RAY res;
271    
272     while (WaitResult(&res)) {
273     if (!cookedCall) continue;
274 greg 2.6 int rv = (*cookedCall)(&res, ccData);
275     if (rv < 0) return -1;
276     nsent += rv;
277 greg 2.4 }
278     return nsent;
279 greg 2.1 }