RenderMan  26.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
RixRNG.h
Go to the documentation of this file.
1 /*
2 # ------------------------------------------------------------------------------
3 #
4 # Copyright (c) 2021 Pixar. All rights reserved.
5 #
6 # The information in this file (the "Software") is provided for the exclusive
7 # use of the software licensees of Pixar ("Licensees"). Licensees have the
8 # right to incorporate the Software into other products for use by other
9 # authorized software licensees of Pixar, without fee. Except as expressly
10 # permitted herein, the Software may not be disclosed to third parties, copied
11 # or duplicated in any form, in whole or in part, without the prior written
12 # permission of Pixar.
13 #
14 # The copyright notices in the Software and this entire statement, including the
15 # above license grant, this restriction and the following disclaimer, must be
16 # included in all copies of the Software, in whole or in part, and all permitted
17 # derivative works of the Software, unless such copies or derivative works are
18 # solely in the form of machine-executable object code generated by a source
19 # language processor.
20 #
21 # PIXAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL PIXAR BE
23 # LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
25 # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. IN NO CASE WILL
27 # PIXAR'S TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR IN CONNECTION WITH
28 # THE USE OR PERFORMANCE OF THIS SOFTWARE EXCEED $50.
29 #
30 # Pixar
31 # 1200 Park Ave
32 # Emeryville CA 94608
33 #
34 # ------------------------------------------------------------------------------
35 */
36 
37 
38 #ifndef RixRNG_h
39 #define RixRNG_h
40 
41 #include <cassert> // for assert
42 #include "prmanapi.h" // IWYU pragma: keep // for PRMAN_INLINE
43 #include "RiTypesHelper.h" // for RtFloat2, RtFloat3
44 
56 
57 #include "RixRNGInline.h" // IWYU pragma: export
58 
59 class RixRNG
60 {
61 public:
62 
63  // A bit pattern used to create new RixRNG domains. An empty scoped enum
64  // is used to make this distinct from unsigned int for type-safety.
65  // Use an explicit cast to create a value of this type, e.g.:
66  // static_cast<RixRNG::Scramble>(0xfa1afe1)
67  enum class Scramble : unsigned {};
68 
76  struct SampleCtx
77  {
78  unsigned patternid; // bit pattern used to select a sample sequence
79  unsigned patternidEmit; // bit pattern used to select a sample sequence for photon emission
80  unsigned sampleid; // sample number
81 
90  SampleCtx NewDomain(Scramble scramble) const
91  {
92  const unsigned oldPatternid = patternid;
93  SampleCtx newd = *this;
94  // Scramble lower 16 bits and shift old pattern table by 11 pixels
95  newd.patternid =
96  RixRNGUtils::shufflePattern(oldPatternid + static_cast<unsigned>(scramble));
97  newd.patternid = ((oldPatternid+0xb0000) & 0xffff0000) | (newd.patternid & 0xffff);
98  assert(newd.patternid != oldPatternid);
99  return newd;
100  }
101 
116  SampleCtx NewDomainDistrib(Scramble scramble, unsigned newsampleid) const
117  {
118  const unsigned oldPatternid = patternid;
119  SampleCtx newd;
120  // Scramble lower 16 bits and shift old pattern table by 11 pixels
121  newd.patternid =
122  RixRNGUtils::shufflePattern(oldPatternid + static_cast<unsigned>(scramble), sampleid);
123  newd.patternid = ((oldPatternid+0xb0000) & 0xffff0000) | (newd.patternid & 0xffff);
124  newd.sampleid = newsampleid;
125  return newd;
126  }
127 
140  SampleCtx NewDomainSplit(Scramble scramble, unsigned newnumsamples) const
141  {
142  const unsigned oldPatternid = patternid;
143  SampleCtx newd = *this;
144  // Scramble lower 16 bits and shift old pattern table by 11 pixels
145  newd.patternid =
146  RixRNGUtils::shufflePattern(oldPatternid + static_cast<unsigned>(scramble));
147  newd.patternid = ((oldPatternid+0xb0000) & 0xffff0000) | (newd.patternid & 0xffff);
148  newd.sampleid *= newnumsamples;
149  return newd;
150  }
151  }; // end of struct SampleCtx
152 
153  // Overrideable implementation
154  class Generator
155  {
156  public:
158  virtual ~Generator() {}
159 
160  // Generator functions to draw a single sample from a sequence.
161  // The parameter 'i' is for sample generators that need the shading context index
162  // to keep track of internal data. (The default PMJ Generator does not need it.)
163  virtual float Sample1D(const SampleCtx& rCtx, unsigned i) const = 0;
164  virtual RtFloat2 Sample2D(const SampleCtx& rCtx, unsigned i) const = 0;
165  virtual RtFloat2 ScrambledSample2D(const SampleCtx& rCtx, unsigned i) const = 0;
166  virtual RtFloat3 Sample3D(const SampleCtx& rCtx, unsigned i) const = 0;
167 
168  // Generator functions to draw multiple samples, each from a different sequence
169  virtual void MultiSample1D(
170  unsigned n,
171  const SampleCtx* rCtx,
172  float* xis) const = 0;
173  virtual void MultiSample2D(
174  unsigned n,
175  const SampleCtx* rCtx,
176  RtFloat2* xis) const = 0;
177  virtual void MultiScrambledSample2D(
178  unsigned n,
179  const SampleCtx* rCtx,
180  RtFloat2* xis) const = 0;
181  virtual void MultiSample3D(
182  unsigned n,
183  const SampleCtx* rCtx,
184  RtFloat3* xis) const = 0;
185  };
186 
187 // Default implementation
188 #include "RixRNGProgressive.h" // IWYU pragma: export
189 
190 public:
191 
192  // RixRNG constructors
193 
194  RixRNG(Generator const *imp, unsigned scaSize = 0)
195  : numPts(scaSize), sampleCtxArray(0), impl(imp)
196  {
197  }
198 
199  // Construct a new RixRNG, with specified number of points and SampleCtx
200  // memory block.
201  RixRNG(Generator const *imp, unsigned scaSize, SampleCtx* sca)
202  : numPts(scaSize), sampleCtxArray(sca), impl(imp)
203  {
204  }
205 
206  // Construct a RixRNG based on another, but with a new number of points
207  // and SampleCtx memory block.
208  RixRNG(RixRNG const* parent, unsigned scaSize, SampleCtx* sca)
209  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
210  {
211  }
212 
213  // Construct a RixRNG based on another, but with a new SampleCtx memory block.
214  // (Same as constructor above, except parameter order.)
215  RixRNG(RixRNG const* parent, SampleCtx* sca, unsigned scaSize)
216  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
217  {
218  }
219 
220  // Construct a RixRNG based on another, but with a new SampleCtx memory
221  // block. Derivation of the new SampleCtx domain uses NewDomains(), ie.
222  // no trajectory splitting and no independent distribution.
223  // WARNING: if your parent RNG is of a different size, do not use
224  // this routine.
225  RixRNG(RixRNG const* parent, SampleCtx* sca, unsigned scaSize, Scramble scramble)
226  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
227  {
228  // Ensure that the new RixRNG isn't larger than the parent.
229  // If the new one is larger we'll read uninitialized memory in NewDomains().
230  assert(scaSize <= parent->numPts);
231 
232  parent->NewDomains(scramble, this);
233  }
234 
235  // Construct a RixRNG based on another, but with a new SampleCtx memory
236  // block. Derivation of the new SampleCtx domain uses trajectory splitting
237  // by calling NewDomainsSplit(). If nsamps=1 then there is no
238  // actual splitting; in that case, it's the same as calling the function
239  // above.
240  // WARNING: if your parent RNG is of a different size, do not use
241  // this routine.
242  RixRNG(RixRNG const* parent, SampleCtx* sca, unsigned scaSize, Scramble scramble, unsigned nsamps)
243  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
244  {
245  // Ensure that the new RixRNG isn't larger than the parent.
246  // If the new one is larger we'll read uninitialized memory in NewDomainsSplit().
247  assert(scaSize <= parent->numPts);
248 
249  parent->NewDomainsSplit(scramble, nsamps, this);
250  }
251 
252  // Construct a RixRNG based on another, but with a new SampleCtx memory
253  // block. Derivation of the new SampleCtx domain generates a new distribution
254  // if doDistrib = true, and ordinary path tracing if false.
255  // WARNING: if your parent RNG is of a different size, do not use
256  // this routine.
258  RixRNG const* parent,
259  SampleCtx* sca, // sample context array
260  unsigned scaSize, // size of sample context array
261  Scramble scramble,
262  unsigned sampleid, // only used if doDistrib is true
263  bool doDistrib)
264  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
265  {
266  // Ensure that the new RixRNG isn't larger than the parent.
267  // If the new one is larger we'll read uninitialized memory in NewDomains().
268  assert(scaSize <= parent->numPts);
269 
270  if (doDistrib) {
271  parent->NewDomainsDistrib(scramble, sampleid, this);
272  } else {
273  parent->NewDomains(scramble, this);
274  }
275  }
276 
277  // Construct a single-element RNG based on another, need new SampleCtx
278  // memory and an offset into parent's sample array.
279  RixRNG GetSlice(SampleCtx* sca, unsigned index) const
280  {
281  RixRNG result(this->impl);
282  result.numPts = 1;
283  result.sampleCtxArray = sca;
284  result.sampleCtxArray[0] = this->sampleCtxArray[index];
285  return result;
286  }
287 
288  virtual ~RixRNG() {}
289 
290  unsigned numPts; // number of elements in sampleCtxArray[]
291  SampleCtx* sampleCtxArray; // sample contexts: pattern ids and sample ids
292  Generator const *impl; // implementation of sample generator
293 
294  SampleCtx& GetSampleCtx(unsigned i) { return sampleCtxArray[i]; }
295 
296  // The 'Generate' family of interfaces assumes caller will generate
297  // a sequence of samples based on a SampleCtx obtained from the
298  // renderer. Generate functions increment the sampleid; Draw functions
299  // do not.
300 
301  // Generate a sample from the sequence and increment sample id
302  float GenerateSample1D(unsigned i) const
303  {
304  float f = impl->Sample1D(sampleCtxArray[i], i); // second param is ignored for PMJ
306  return f;
307  }
308 
309  RtFloat2 GenerateSample2D(unsigned i) const
310  {
311  RtFloat2 f2 = impl->Sample2D(sampleCtxArray[i], i); // second param is ignored for PMJ
313  return f2;
314  }
315 
316  RtFloat2 GenerateScrambledSample2D(unsigned i) const
317  {
318  RtFloat2 f2 = impl->ScrambledSample2D(sampleCtxArray[i], i); // second param is ignored for PMJ
320  return f2;
321  }
322 
323  RtFloat3 GenerateSample3D(unsigned i) const
324  {
325  RtFloat3 f3 = impl->Sample3D(sampleCtxArray[i], i); // second param is ignored for PMJ
327  return f3;
328  }
329 
330  // Generate a sample from the sequence and increment sample id
331  float GenerateSample1D(SampleCtx& c, unsigned i) const
332  {
333  float f = impl->Sample1D(c, i); // second param is ignored for PMJ
334  c.sampleid++;
335  return f;
336  }
337 
338  RtFloat2 GenerateSample2D(SampleCtx& c, unsigned i) const
339  {
340  RtFloat2 f2 = impl->Sample2D(c, i); // second param is ignored for PMJ
341  c.sampleid++;
342  return f2;
343  }
344 
345  RtFloat2 GenerateScrambledSample2D(SampleCtx& c, unsigned i) const
346  {
347  RtFloat2 f2 = impl->ScrambledSample2D(c, i); // second param is ignored for PMJ
348  c.sampleid++;
349  return f2;
350  }
351 
352  RtFloat3 GenerateSample3D(SampleCtx& c, unsigned i) const
353  {
354  RtFloat3 f3 = impl->Sample3D(c, i); // second param is ignored for PMJ
355  c.sampleid++;
356  return f3;
357  }
358 
359  // Generate numPts samples (each from a different sequence) and increment sample ids
360  void GenerateSamples1D(float* xis) const
361  {
364  }
365 
366  void GenerateSamples2D(RtFloat2* xis) const
367  {
370  }
371 
372  void GenerateScrambledSamples2D(RtFloat2* xis) const
373  {
376  }
377 
378  void GenerateSamples3D(RtFloat3* xis) const
379  {
382  }
383 
384  // Draw a sample from the sequence
385  float DrawSample1D(unsigned i) const
386  {
387  return impl->Sample1D(sampleCtxArray[i], i); // second param is ignored for PMJ
388  }
389 
390  RtFloat2 DrawSample2D(unsigned i) const
391  {
392  return impl->Sample2D(sampleCtxArray[i], i); // second param is ignored for PMJ
393  }
394 
395  RtFloat2 DrawScrambledSample2D(unsigned i) const
396  {
397  return impl->ScrambledSample2D(sampleCtxArray[i], i); // second param is ignored for PMJ
398  }
399 
400  RtFloat3 DrawSample3D(unsigned i) const
401  {
402  return impl->Sample3D(sampleCtxArray[i], i); // second param is ignored for PMJ
403  }
404 
405  // Draw a sample from the sequence
406  float DrawSample1D(const SampleCtx& c, unsigned i) const
407  {
408  return impl->Sample1D(c, i); // second param is ignored for PMJ
409  }
410 
411  RtFloat2 DrawSample2D(const SampleCtx& c, unsigned i) const
412  {
413  return impl->Sample2D(c, i); // second param is ignored for PMJ
414  }
415 
416  RtFloat2 DrawScrambledSample2D(const SampleCtx& c, unsigned i) const
417  {
418  return impl->ScrambledSample2D(c, i); // second param is ignored for PMJ
419  }
420 
421  RtFloat3 DrawSample3D(const SampleCtx& c, unsigned i) const
422  {
423  return impl->Sample3D(c, i); // second param is ignored for PMJ
424  }
425 
426  // Draw numPts samples (each from a different sequence)
427  void DrawSamples1D(float* xis) const
428  {
430  }
431 
432  void DrawSamples2D(RtFloat2* xis) const
433  {
435  }
436 
437  void DrawSamples3D(RtFloat3* xis) const
438  {
440  }
441 
442  // Increment all sampleids
443  void IncrementSampleIds() const
444  {
445  for (unsigned i = 0; i < numPts; ++i)
446  sampleCtxArray[i].sampleid++;
447  }
448 
449  // Setting up new random domains
450  SampleCtx NewDomain(unsigned i, Scramble scramble) const
451  {
452  return sampleCtxArray[i].NewDomain(scramble);
453  }
454 
455  SampleCtx NewDomainDistrib(unsigned i, Scramble scramble,
456  unsigned newsampleid) const
457  {
458  return sampleCtxArray[i].NewDomainDistrib(scramble, newsampleid);
459  }
460 
461  SampleCtx NewDomainSplit(unsigned i, Scramble scramble,
462  unsigned newnumsamples) const
463  {
464  return sampleCtxArray[i].NewDomainSplit(scramble, newnumsamples);
465  }
466 
467  // Multi-point versions of NewDomain() functions.
468  // Setting up new random domains for all sampleCtxs.
469  // These generate new patternids in-place.
470  void NewDomains(Scramble scramble) const
471  {
472  for (unsigned i = 0; i < numPts; i++) {
473  sampleCtxArray[i] = sampleCtxArray[i].NewDomain(scramble);
474  }
475  }
476 
477  void NewDomainsDistrib(Scramble scramble, unsigned newsampleid) const
478  {
479  for (unsigned i = 0; i < numPts; i++) {
480  sampleCtxArray[i] =
481  sampleCtxArray[i].NewDomainDistrib(scramble, newsampleid);
482  }
483  }
484 
485  void NewDomainsSplit(Scramble scramble, unsigned newnumsamples) const
486  {
487  for (unsigned i = 0; i < numPts; i++) {
488  sampleCtxArray[i] =
489  sampleCtxArray[i].NewDomainSplit(scramble, newnumsamples);
490  }
491  }
492 
493  // More multi-point versions of NewDomain() functions.
494  // Setting up new random domains for all sampleCtxs.
495  // (To facilitate future more efficient simd implementations.)
496  // These ones require the new RixRNG to have a size smaller or equal to the
497  // current ("parent") one.
498  void NewDomains(Scramble scramble, RixRNG *newRng) const
499  {
500  unsigned minNumPts = newRng->numPts < numPts ? newRng->numPts : numPts;
501  for (unsigned i = 0; i < minNumPts; i++) {
502  newRng->sampleCtxArray[i] = sampleCtxArray[i].NewDomain(scramble);
503  }
504  newRng->numPts = minNumPts;
505  }
506 
507  void NewDomainsDistrib(Scramble scramble, unsigned newsampleid,
508  RixRNG *newRng) const
509  {
510  unsigned minNumPts = newRng->numPts < numPts ? newRng->numPts : numPts;
511  for (unsigned i = 0; i < minNumPts; i++) {
512  newRng->sampleCtxArray[i] =
513  sampleCtxArray[i].NewDomainDistrib(scramble, newsampleid);
514  }
515  newRng->numPts = minNumPts;
516  }
517 
518  void NewDomainsSplit(Scramble scramble, unsigned newnumsamples,
519  RixRNG *newRng) const
520  {
521  unsigned minNumPts = newRng->numPts < numPts ? newRng->numPts : numPts;
522  for (unsigned i = 0; i < minNumPts; i++) {
523  newRng->sampleCtxArray[i] =
524  sampleCtxArray[i].NewDomainSplit(scramble, newnumsamples);
525  }
526  newRng->numPts = minNumPts;
527  }
529 };
530 
531 #endif