ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RcontribSimulManager.h
Revision: 2.9
Committed: Tue Dec 24 20:57:13 2024 UTC (4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +2 -2 lines
Log Message:
fix(rxcontrib): Turn off memory sharing before releasing octree

File Contents

# User Rev Content
1 greg 2.9 /* RCSid $Id: RcontribSimulManager.h,v 2.8 2024/12/03 17:39:42 greg Exp $ */
2 greg 2.1 /*
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 greg 2.2 class RcontribSimulManager; // need forward decl
29 greg 2.1
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 greg 2.6 * 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 greg 2.1 *
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 greg 2.6 * may be called anytime *after* PrepOutput(), and may be interleaved with
138 greg 2.1 * 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 greg 2.7 * 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 greg 2.1 *
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 greg 2.3 enum RCOutputOp {RCOnew=0, RCOforce, RCOrecover};
159 greg 2.1
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 greg 2.2 /// Modifiable ray-tracing flags for rcontrib
170 greg 2.6 #define RCcontrib (RTmask+1) // compute contributions? (r.t. coefficients)
171     #define RCmask (RTlimDist|RTimmIrrad|RCcontrib)
172 greg 2.1
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 greg 2.6 int xres, yres; // output (picture) size
196 greg 2.1 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     rtFlags = RTtraceSources;
211     SetTraceCall(&RctCall, this);
212     outOp = RCOnew;
213     cdsF = &defDataShare;
214 greg 2.6 xres = yres = 0;
215 greg 2.1 accum = 1;
216     }
217     ~RcontribSimulManager() {
218 greg 2.7 if (nkids >= 0) ClearModifiers();
219 greg 2.1 }
220 greg 2.2 /// Check modifiable ray-tracing computation flag(s)
221     bool HasFlag(int fl) const {
222     return ((rtFlags & RCmask & fl) != 0);
223     }
224     /// Set/reset modifiable ray-tracing computation flag(s)
225     bool SetFlag(int fl, bool val = true) {
226     if (!(fl &= RCmask)) return false;
227     if (val) rtFlags |= fl;
228     else rtFlags &= ~fl;
229     return true;
230     }
231 greg 2.1 /// Load octree and prepare renderer
232     bool LoadOctree(const char *octn) {
233     return RtraceSimulManager::LoadOctree(octn);
234     }
235     /// Prepare header from previous input (or clear)
236     bool NewHeader(const char *inspec=NULL) {
237     return RtraceSimulManager::NewHeader(inspec);
238     }
239     /// Add a string to header (adds newline if none)
240     bool AddHeader(const char *str) {
241     return RtraceSimulManager::AddHeader(str);
242     }
243     /// Append program line to header
244     bool AddHeader(int ac, char *av[]) {
245     return RtraceSimulManager::AddHeader(ac, av);
246     }
247     /// Get current header length in bytes
248     int GetHeadLen() const {
249     return RtraceSimulManager::GetHeadLen();
250     }
251     /// Get header lines if any
252     const char * GetHeadStr() const {
253     return RtraceSimulManager::GetHeadStr();
254     }
255     /// Look for specific header keyword, return value
256     const char * GetHeadStr(const char *key, bool inOK = false) const {
257     return RtraceSimulManager::GetHeadStr(key, inOK);
258     }
259     /// Set output format ('f', 'd', or 'c'), call before mods
260     bool SetDataFormat(int ty);
261     /// Get current format (and element size in bytes)
262     int GetFormat(int *siz = NULL) const {
263     if (siz) *siz = dsiz;
264     return dtyp;
265     }
266     /// Add a modifier and arguments, create output(s)
267     bool AddModifier(const char *modn, const char *outspec,
268     const char *prms = NULL,
269     const char *binval = NULL, int bincnt = 1);
270     /// Add a file of modifiers with associated arguments
271     bool AddModFile(const char *modfn, const char *outspec,
272     const char *prms = NULL,
273     const char *binval = NULL, int bincnt = 1);
274 greg 2.2 /// Get named rcontrib output (or list)
275     const RcontribOutput * GetOutput(const char *nm = NULL) const {
276     if (!nm) return outList;
277     const RcontribOutput * op = outList;
278     while (op && strcmp(op->GetName(), nm))
279     op = op->next;
280     return op;
281     }
282 greg 2.1 /// Open output channels and return # completed rows
283     int PrepOutput();
284     /// Are we ready to compute some records?
285     bool Ready() const {
286 greg 2.4 return (rowsDone.Length() > 0) & (accum > 0);
287 greg 2.1 }
288     /// Set number of computation threads (0 => #cores)
289     int SetThreadCount(int nt = 0);
290     /// Check thread count (1 means no multi-processing)
291     int NThreads() const {
292     return nkids + !nkids;
293     }
294     /// What is maximum row?
295     int GetRowMax() const {
296     if (!outList) return yres * (xres + !xres);
297     return outList->nRows;
298     }
299     /// Get current row count (# rows sent for computation)
300     int GetRowCount() const {
301     return rInPos;
302     }
303     /// Get # rows completed
304     int GetRowFinished() const {
305     if (!nkids) return rInPos;
306     uint32 nDone = rowsDone.Find(0, false);
307     if (nDone == ABMend)
308     return rowsDone.Length();
309     return nDone;
310     }
311     /// Add a ray/bundle to compute next record (n=accum)
312     int ComputeRecord(const FVECT orig_direc[]);
313     /// Finish pending rays if multi-processing
314     bool FlushQueue() {
315     if (nkids <= 0) return true;
316     while (GetChild(true) >= 0)
317     ;
318     return true;
319     }
320 greg 2.7 /// Rewind calculation (previous results unchanged)
321     bool ResetRow(int r);
322     /// Clear the modifiers and close all outputs
323     void ClearModifiers() {
324 greg 2.1 if (rowsDone.Length()) {
325     SetThreadCount(1);
326     rowsDone.NewBitMap(0);
327     }
328     lu_done(&modLUT);
329     delete outList; outList = NULL;
330     nChan = 0;
331 greg 2.7 }
332     /// Close octree, free data, return status
333     int Cleanup(bool everything = false) {
334     ClearModifiers();
335 greg 2.9 cow_doneshare();
336 greg 2.1 return RtraceSimulManager::Cleanup(everything);
337     }
338     };
339    
340 greg 2.8 extern const char * formstr(int f); // string from format
341    
342 greg 2.1 #endif /* RcontribSimulManager_h */