| 1 |
/* RCSid $Id: RcontribSimulManager.h,v 2.13 2025/10/23 16:33:39 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 |
/// Free an RcontribMod
|
| 112 |
extern lut_free_t FreeRcMod;
|
| 113 |
|
| 114 |
/*
|
| 115 |
* General RcontribSimulManager class operation:
|
| 116 |
*
|
| 117 |
* 1) Call LoadOctree(), then alter the header as desired
|
| 118 |
* 2) Set number of spectral samples (NCSAMP) and call SetDataFormat()
|
| 119 |
* 3) Set xres and yres to desired dimensions (xres>0 for picture output)
|
| 120 |
* 4) Call AddModifier() and AddModFile() to indicate tracked modifiers
|
| 121 |
* 5) Set outOp and cdsF according to desired output/recovery
|
| 122 |
* 6) Set desired computation flags via SetFlag()
|
| 123 |
* 7) Call PrepOutput() to open output channels
|
| 124 |
* 8) Call SetThreadCount() to fork children if desired
|
| 125 |
* 9) Set accum to the number of ray samples per record
|
| 126 |
* 10) Call ComputeRecord() with accum ray samples
|
| 127 |
* 11) Continue until GetRowMax() records have been sent
|
| 128 |
* 12) Call Cleanup()
|
| 129 |
*
|
| 130 |
* The order of some of these calls may be changed. Technically, the octree
|
| 131 |
* may be loaded anytime before PrepOutput() is called. Also, SetThreadCount()
|
| 132 |
* may be called anytime *after* PrepOutput(), and may be interleaved with
|
| 133 |
* calls to ComputeRecord(). The accum setting may be changed at any time.
|
| 134 |
* Finally, it is possible to restart the output using ResetRow(), and
|
| 135 |
* a zero argument will rewind to the beginning, whence all records
|
| 136 |
* may be recalculated. The previous output rows are not zeroed or deleted,
|
| 137 |
* but are overwritten as the calculation proceeds from the new starting point.
|
| 138 |
* However, the output file(s) will indicate in the NROWS= line in the header
|
| 139 |
* that only the newly calculated rows are present. If you wish to start over
|
| 140 |
* with a different set of modifiers or outputs, call ClearModifiers() instead,
|
| 141 |
* which keeps the current octree in memory. This call also returns to single
|
| 142 |
* process mode if any children were running.
|
| 143 |
*
|
| 144 |
* It is not possible to write to standard output, but the output
|
| 145 |
* model is quite flexible thanks to the RdataShare polymorphic class.
|
| 146 |
* The current default output class creates a shared, memory-mapped file,
|
| 147 |
* which is the most efficient object on most systems.
|
| 148 |
*
|
| 149 |
* ASCII output is not supported, so full data recovery is.
|
| 150 |
*/
|
| 151 |
|
| 152 |
/// Output channel opening options: new/exclusive, overwrite if exists, or recover data
|
| 153 |
enum RCOutputOp {RCOnew=0, RCOforce, RCOrecover};
|
| 154 |
|
| 155 |
/// Converts above to RdataShare open flags (may be adjusted by calling program)
|
| 156 |
extern int RSDOflags[];
|
| 157 |
|
| 158 |
/// Call-back function type to create named data channel (freed using "delete" operator)
|
| 159 |
typedef RdataShare * RcreateDataShareF(const char *name, RCOutputOp op, size_t siz);
|
| 160 |
|
| 161 |
/// Provided data share function
|
| 162 |
extern RcreateDataShareF fileDataShare, mapDataShare;
|
| 163 |
|
| 164 |
#ifndef defDataShare
|
| 165 |
#define defDataShare mapDataShare // default data share creator
|
| 166 |
#endif
|
| 167 |
|
| 168 |
/// Modifiable ray-tracing flags for rcontrib
|
| 169 |
#define RCcontrib (RTmask+1) // compute contributions? (r.t. coefficients)
|
| 170 |
#define RCmask (RTlimDist|RTimmIrrad|RCcontrib)
|
| 171 |
|
| 172 |
/// rcontrib-like simulation manager (at most one such object)
|
| 173 |
class RcontribSimulManager : protected RtraceSimulManager {
|
| 174 |
protected:
|
| 175 |
static RayReportCall RctCall; // our callback for traced rays
|
| 176 |
ABitMap rowsDone; // bit mask of completed rows
|
| 177 |
mutable uint32 nrDone; // current contiguous #rows done
|
| 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 |
nrDone = 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 nrDone = rInPos;
|
| 314 |
nrDone = rowsDone.Find(nrDone, false);
|
| 315 |
if (nrDone == ABMend)
|
| 316 |
nrDone = rowsDone.Length();
|
| 317 |
return nrDone;
|
| 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 |
nrDone = 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 */
|