ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RcontribSimulManager.h
Revision: 2.10
Committed: Thu Jan 2 16:16:49 2025 UTC (3 months, 4 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.9: +21 -4 lines
Log Message:
fix(rxtrace,rxcontrib): Improvements and bug fixes in flag initialization, handling of light source tracing

File Contents

# Content
1 /* RCSid $Id: RcontribSimulManager.h,v 2.9 2024/12/24 20:57:13 greg Exp $ */
2 /*
3 * RcontribSimulManager.h
4 *
5 * Rcontrib simulation manager class declaration
6 *
7 * Created by Greg Ward on 10/11/2024.
8 */
9
10 #ifndef RcontribSimulManager_h
11 #define RcontribSimulManager_h
12
13 #include "RtraceSimulManager.h"
14 #include "RdataShare.h"
15 #include "lookup.h"
16 #include "rtprocess.h"
17
18 /*
19 * As with other single-object classes, many global variable affect
20 * behavior. Besides rendering parameters, there are spectral parameters
21 * and output dimensions taken from the environment.
22 *
23 * NOTE: "record" and "row" are used interchangeably throughout.
24 */
25
26 extern char RCCONTEXT[]; // global rcontrib context
27
28 class RcontribSimulManager; // need forward decl
29
30 /// Shared data object for record output (includes header; may be write-only)
31 class RcontribOutput {
32 RcontribOutput * next; // next in sorted list
33 char * ofname; // output file name
34 uint32 rowCountPos; // row count position in header
35 void * rowp; // current row memory
36 bool NewHeader(const RcontribSimulManager *rcp);
37 int CheckHeader(const RcontribSimulManager *rcp);
38 public:
39 RdataShare * rData; // data sharing object
40 size_t rowBytes; // byte count per row
41 const char * omod; // single modifier (or NULL)
42 int32 obin; // single output bin (or -1)
43 uint32 begData; // start of data (type-aligned)
44 int32 curRow; // current output row
45 uint32 nRows; // total number of rows
46 RcontribOutput(const char *fnm = NULL) {
47 next = NULL;
48 omod = NULL;
49 obin = -1;
50 rData = NULL;
51 ofname = savqstr(fnm);
52 rowBytes = 0;
53 nRows = 0;
54 rowp = NULL; curRow = -1;
55 }
56 ~RcontribOutput() {
57 DoneRow();
58 delete rData;
59 delete next;
60 freeqstr(ofname);
61 }
62 /// Return output channel name
63 const char * GetName() const {
64 if (rData) return rData->GetName();
65 return ofname;
66 }
67 /// Update output row count
68 bool SetRowsDone(int r) {
69 if (!rData | (0 >= r) | (r > nRows)) return false;
70 char * rbuf = (char *)rData->GetMemory(rowCountPos, 17, 0);
71 sprintf(rbuf, "%-16d", r);
72 rbuf[16] = '\n'; // replaces nul byte
73 return rData->ReleaseMemory(rbuf, RDSwrite);
74 }
75 /// Get buffer for indicated row (contents may be random)
76 void * GetRow(int r) {
77 if (!rData | (r < 0)) return NULL;
78 if (r != curRow) {
79 DoneRow();
80 if (r < nRows)
81 rowp = rData->GetMemory(begData + r*rowBytes,
82 rowBytes, 0);
83 if (rowp) curRow = r;
84 }
85 return rowp;
86 }
87 /// Current row with byte offset
88 void * InsertionP(int coffset) const {
89 if (!rowp | (coffset < 0) | (coffset >= rowBytes))
90 return NULL;
91 return (char *)rowp + coffset;
92 }
93 /// Release current row, writing contents
94 void DoneRow() {
95 if (rowp) rData->ReleaseMemory(rowp, RDSwrite);
96 rowp = NULL; curRow = -1;
97 }
98 /// Get next in list
99 const RcontribOutput * Next() const {
100 return next;
101 }
102 RcontribOutput * Next() {
103 return next;
104 }
105 /// RcontribSimulManager gets full access
106 friend class RcontribSimulManager;
107 };
108
109 typedef double DCOLORV; // color accumulator type
110
111 /// Modifier channel for recording contributions (no constructor/destructor)
112 struct RcontribMod;
113
114 /// Allocate rcontrib accumulator
115 extern RcontribMod * NewRcMod(const char *prms = NULL, const char *binexpr = NULL, int ncbins = 1);
116 /// Free an RcontribMod
117 extern lut_free_t FreeRcMod;
118
119 /*
120 * General RcontribSimulManager class operation:
121 *
122 * 1) Call LoadOctree(), then alter the header as desired
123 * 2) Set number of spectral samples (NCSAMP) and call SetDataFormat()
124 * 3) Set xres and yres to desired dimensions (xres>0 for picture output)
125 * 4) Call AddModifier() and AddModFile() to indicate tracked modifiers
126 * 5) Set outOp and cdsF according to desired output/recovery
127 * 6) Set desired computation flags via SetFlag()
128 * 7) Call PrepOutput() to open output channels
129 * 8) Call SetThreadCount() to fork children if desired
130 * 9) Set accum to the number of ray samples per record
131 * 10) Call ComputeRecord() with accum ray samples
132 * 11) Continue until GetRowMax() records have been sent
133 * 12) Call Cleanup()
134 *
135 * The order of some of these calls may be changed. Technically, the octree
136 * may be loaded anytime before PrepOutput() is called. Also, SetThreadCount()
137 * may be called anytime *after* PrepOutput(), and may be interleaved with
138 * calls to ComputeRecord(). The accum setting may be changed at any time.
139 * Finally, it is possible to restart the output using ResetRow(), and
140 * a zero argument will rewind to the beginning, whence all records
141 * may be recalculated. The previous output rows are not zeroed or deleted,
142 * but are overwritten as the calculation proceeds from the new starting point.
143 * However, the output file(s) will indicate in the NROWS= line in the header
144 * that only the newly calculated rows are present. If you wish to start over
145 * with a different set of modifiers or outputs, call ClearModifiers() instead,
146 * which keeps the current octree in memory. This call also returns to single
147 * process mode if any children were running.
148 *
149 * It is not possible to write to standard output, but the output
150 * model is quite flexible thanks to the RdataShare polymorphic class.
151 * The current default output class creates a shared, memory-mapped file,
152 * which is the most efficient object on most systems.
153 *
154 * ASCII output is not supported, so full data recovery is.
155 */
156
157 /// Output channel opening options: new/exclusive, overwrite if exists, or recover data
158 enum RCOutputOp {RCOnew=0, RCOforce, RCOrecover};
159
160 /// Converts above to RdataShare open flags (may be adjusted by calling program)
161 extern int RSDOflags[];
162
163 /// Call-back function type to create named data channel (freed using "delete" operator)
164 typedef RdataShare * RcreateDataShareF(const char *name, RCOutputOp op, size_t siz);
165
166 /// Our default data share function
167 extern RcreateDataShareF defDataShare;
168
169 /// Modifiable ray-tracing flags for rcontrib
170 #define RCcontrib (RTmask+1) // compute contributions? (r.t. coefficients)
171 #define RCmask (RTlimDist|RTimmIrrad|RCcontrib)
172
173 /// rcontrib-like simulation manager (at most one such object)
174 class RcontribSimulManager : protected RtraceSimulManager {
175 protected:
176 static RayReportCall RctCall; // our callback for traced rays
177 ABitMap rowsDone; // bit mask of completed rows
178 uint32 rInPos; // which row (record) is next on input?
179 uby8 nChan; // NCSAMP setting for this calculation
180 char dtyp; // data type ('f', 'd', or 'c')
181 uint16 dsiz; // N-component element size in bytes
182 RcontribOutput * outList; // ordered list of output channels
183 LUTAB modLUT; // modifier lookup table
184 SUBPROC * kid; // array of child processes
185 int32 * kidRow; // row assigned to each child
186 int nkids; // child process count (-1 in child)
187 bool UpdateRowsDone(int r);
188 int GetChild(bool forceWait = false);
189 bool StartKids(int n2go);
190 int StopKids(int n2end = 0);
191 void RunChild();
192 public:
193 RCOutputOp outOp; // output operation
194 RcreateDataShareF * cdsF; // data share creator
195 int xres, yres; // output (picture) size
196 uint32 accum; // # rays to accumulate per record
197 RcontribSimulManager(const char *octn = NULL)
198 : RtraceSimulManager(NULL, NULL, octn) {
199 rInPos = 0;
200 nChan = 0;
201 dtyp = 'f';
202 dsiz = 0;
203 outList = NULL;
204 memset(&modLUT, 0, sizeof(modLUT));
205 modLUT.hashf = lu_shash;
206 modLUT.keycmp = strcmp;
207 modLUT.freek = efree;
208 modLUT.freed = FreeRcMod;
209 kid = NULL; kidRow = NULL; nkids = 0;
210 outOp = RCOnew;
211 cdsF = &defDataShare;
212 xres = yres = 0;
213 accum = 1;
214 if (octname) {
215 SetTraceCall(&RctCall, this);
216 rtFlags |= RTtraceSources;
217 UpdateMode();
218 }
219 }
220 ~RcontribSimulManager() {
221 if (nkids >= 0) ClearModifiers();
222 }
223 /// Check modifiable ray-tracing computation flag(s)
224 bool HasFlag(int fl) const {
225 return ((rtFlags & RCmask & fl) != 0);
226 }
227 /// Set/reset modifiable ray-tracing computation flag(s)
228 bool SetFlag(int fl, bool val = true) {
229 if (!(fl &= RCmask)) return false;
230 if (val) rtFlags |= fl;
231 else rtFlags &= ~fl;
232 return true;
233 }
234 /// Load octree and prepare renderer
235 bool LoadOctree(const char *octn) {
236 if (octname) Cleanup(false);
237 if (!RtraceSimulManager::LoadOctree(octn))
238 return false;
239 SetTraceCall(&RctCall, this);
240 rtFlags |= RTtraceSources;
241 return UpdateMode();
242 }
243 /// Prepare header from previous input (or clear)
244 bool NewHeader(const char *inspec=NULL) {
245 return RtraceSimulManager::NewHeader(inspec);
246 }
247 /// Add a string to header (adds newline if none)
248 bool AddHeader(const char *str) {
249 return RtraceSimulManager::AddHeader(str);
250 }
251 /// Append program line to header
252 bool AddHeader(int ac, char *av[]) {
253 return RtraceSimulManager::AddHeader(ac, av);
254 }
255 /// Get current header length in bytes
256 int GetHeadLen() const {
257 return RtraceSimulManager::GetHeadLen();
258 }
259 /// Get header lines if any
260 const char * GetHeadStr() const {
261 return RtraceSimulManager::GetHeadStr();
262 }
263 /// Look for specific header keyword, return value
264 const char * GetHeadStr(const char *key, bool inOK = false) const {
265 return RtraceSimulManager::GetHeadStr(key, inOK);
266 }
267 /// Set output format ('f', 'd', or 'c'), call before mods
268 bool SetDataFormat(int ty);
269 /// Get current format (and element size in bytes)
270 int GetFormat(int *siz = NULL) const {
271 if (siz) *siz = dsiz;
272 return dtyp;
273 }
274 /// Add a modifier and arguments, create output(s)
275 bool AddModifier(const char *modn, const char *outspec,
276 const char *prms = NULL,
277 const char *binval = NULL, int bincnt = 1);
278 /// Add a file of modifiers with associated arguments
279 bool AddModFile(const char *modfn, const char *outspec,
280 const char *prms = NULL,
281 const char *binval = NULL, int bincnt = 1);
282 /// Get named rcontrib output (or list)
283 const RcontribOutput * GetOutput(const char *nm = NULL) const {
284 if (!nm) return outList;
285 const RcontribOutput * op = outList;
286 while (op && strcmp(op->GetName(), nm))
287 op = op->next;
288 return op;
289 }
290 /// Open output channels and return # completed rows
291 int PrepOutput();
292 /// Are we ready to compute some records?
293 bool Ready() const {
294 return (rowsDone.Length() > 0) & (accum > 0);
295 }
296 /// Set number of computation threads (0 => #cores)
297 int SetThreadCount(int nt = 0);
298 /// Check thread count (1 means no multi-processing)
299 int NThreads() const {
300 return nkids + !nkids;
301 }
302 /// What is maximum row?
303 int GetRowMax() const {
304 if (!outList) return yres * (xres + !xres);
305 return outList->nRows;
306 }
307 /// Get current row count (# rows sent for computation)
308 int GetRowCount() const {
309 return rInPos;
310 }
311 /// Get # rows completed
312 int GetRowFinished() const {
313 if (!nkids) return rInPos;
314 uint32 nDone = rowsDone.Find(0, false);
315 if (nDone == ABMend)
316 return rowsDone.Length();
317 return nDone;
318 }
319 /// Add a ray/bundle to compute next record (n=accum)
320 int ComputeRecord(const FVECT orig_direc[]);
321 /// Finish pending rays if multi-processing
322 bool FlushQueue() {
323 if (nkids <= 0) return true;
324 while (GetChild(true) >= 0)
325 ;
326 return true;
327 }
328 /// Rewind calculation (previous results unchanged)
329 bool ResetRow(int r);
330 /// Clear the modifiers and close all outputs
331 void ClearModifiers() {
332 if (rowsDone.Length()) {
333 SetThreadCount(1);
334 rowsDone.NewBitMap(0);
335 rInPos = 0;
336 }
337 lu_done(&modLUT);
338 delete outList; outList = NULL;
339 nChan = 0;
340 }
341 /// Close octree, free data, return status
342 int Cleanup(bool everything = false) {
343 ClearModifiers();
344 cow_doneshare();
345 if (everything) {
346 dtyp = 'f';
347 outOp = RCOnew;
348 cdsF = &defDataShare;
349 xres = yres = 0;
350 accum = 1;
351 rtFlags &= ~RCmask;
352 }
353 return RtraceSimulManager::Cleanup(everything);
354 }
355 };
356
357 extern const char * formstr(int f); // string from format
358
359 #endif /* RcontribSimulManager_h */