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

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.5 static const char RCSid[] = "$Id: RtraceSimulManager.cpp,v 2.4 2023/08/02 00:04:31 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     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 greg 2.3 Cleanup(false);
26 greg 2.1 }
27     if (!octn)
28     return false;
29    
30     ray_init((char *)octn);
31     return true;
32     }
33    
34 greg 2.5 // How many processors are available?
35 greg 2.2 int
36     RadSimulManager::GetNCores()
37     {
38 greg 2.5 return sysconf(_NPROCESSORS_ONLN);
39 greg 2.2 }
40    
41 greg 2.1 // Set number of computation threads (0 => #cores)
42     int
43     RadSimulManager::SetThreadCount(int nt)
44     {
45 greg 2.5 if (nt <= 0) nt = GetNCores();
46    
47     return nThreads = nt;
48 greg 2.1 }
49    
50 greg 2.4 // 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 greg 2.5 int rv = ray_psend(r);
58     if (rv < 0)
59     nThreads = 1; // someone died
60     return (rv > 0);
61 greg 2.4 }
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 greg 2.5
81     return SplitRay(&toDo); // queue up new ray & return old
82 greg 2.4 }
83    
84     // Wait for next result (or fail)
85     bool
86     RadSimulManager::WaitResult(RAY *r)
87     {
88 greg 2.5 int rv = ray_presult(r, 0);
89     if (rv < 0)
90     nThreads = 1; // someone died
91     return (rv > 0);
92 greg 2.4 }
93    
94 greg 2.1 // Close octree, free data, return status
95     int
96 greg 2.3 RadSimulManager::Cleanup(bool everything)
97 greg 2.1 {
98 greg 2.5 if (NThreads() > 1)
99     ray_pdone(everything);
100     else
101     ray_done(everything);
102 greg 2.1 return 0;
103     }
104    
105     // How many threads are currently unoccupied?
106     int
107     RadSimulManager::ThreadsAvailable() const
108     {
109 greg 2.5 if (NThreads() == 1) return 1;
110     return ray_pnidle;
111 greg 2.1 }
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 greg 2.4 if (misMatch & RTdoFIFO && FlushQueue() < 0)
144     return false;
145 greg 2.1 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 greg 2.4 // 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 greg 2.1 // 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 greg 2.4 double d = normalize(res.rdir);
226     bool sendRes = (cookedCall != NULL);
227 greg 2.1 if (d > 0) { // direction vector is valid?
228     if (curFlags & RTlimDist)
229     res.rmax = d;
230 greg 2.4 if ((sendRes &= ProcessRay(&res)) &&
231     rtFlags & RTdoFIFO && NThreads() > 1) {
232     if (QueueResult(res) < 0)
233     return -1;
234     sendRes = false;
235     }
236 greg 2.1 } else if (ThreadsAvailable() < NThreads() &&
237 greg 2.4 FlushQueue() < 0)
238 greg 2.1 return -1;
239 greg 2.5
240 greg 2.4 if (sendRes) // may be dummy ray
241 greg 2.1 (*cookedCall)(&res, ccData);
242 greg 2.3 nqueued++;
243 greg 2.1 }
244     return nqueued;
245     }
246    
247     // Finish pending rays and complete callbacks
248 greg 2.4 int
249 greg 2.1 RtraceSimulManager::FlushQueue()
250     {
251 greg 2.4 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 greg 2.1 }