HDK
|
#include <varyingref.h>
Public Member Functions | |
VaryingRef () | |
VaryingRef (void *ptr_, int step_=0) | |
VaryingRef (T &ptr_) | |
void | init (T *ptr_, int step_=0) |
const VaryingRef & | operator= (T &ptr_) |
bool | is_null () const |
operator void * () const | |
bool | is_varying () const |
bool | is_uniform () const |
VaryingRef & | operator++ () |
void | operator++ (int) |
T & | operator* () const |
T & | operator[] (int i) const |
T * | ptr () const |
int | step () const |
VaryingRef is a templated class (on class T) that holds either a pointer to a single T value, or an "array" of T values, each separated by a certain number of bytes. For those versed in the lingo of SIMD shading, this encapsulates 'uniform' and 'varying' references.
Suppose you have a computation 'kernel' that is performing an operation while looping over several computation 'points.' Each of the several operands of the kernel may either be a 'uniform' value (identical for each point), or 'varying' (having a potentially different value for each point).
Here is a concrete example. Suppose you have the following function:
void add (int n, float *a, float *b, float *result) { for (int i = 0; i < n; ++i) result[i] = a[i] + b[i]; }
But if the caller of this function has only a single b value (let's say, you always want to add 3 to every a[i]), you would be forced to replicate an entire array full of 3's in order to call the function.
Instead, we may wish to generalize the function so that each operand may refer to EITHER a single value or an array of values, without making the code more complicated. We can do this with VaryingRef:
void add (int n, VaryingRef<float> a, VaryingRef<float> b, float *result) { for (int i = 0; i < n; ++i) result[i] = a[i] + b[i]; }
VaryingRef overloads operator [] to properly decode whether it is uniform (point to the one value) or varying (index the right array element). It also overloads the increment operator ++ and the pointer indirection operator '*', so you could also write the function equivalently as:
void add (int n, VaryingRef<float> a, VaryingRef<float> b, float *result) { for (int i = 0; i < n; ++i, ++a, ++b) // note increments result[i] = (*a) + (*b); }
An example of calling this function would be:
float a[n]; float b; // just 1 value float result[n]; add (n, VaryingRef<float>(a,sizeof(a[0])), VaryingRef<float>(b), result);
In this example, we're passing a truly varying 'a' (signified by giving a step size from element to element), but a uniform 'b' (signified by no step size, or a step size of zero).
There are Varying() and Uniform() templated functions that provide a helpful shorthand:
add (n, Varying(a), Uniform(b), result);
Now let's take it a step further and fully optimize the 'add' function for when both operands are uniform:
void add (int n, VaryingRef<float> a, VaryingRef<float> b, VaryingRef<float> result) { if (a.is_uniform() && b.is_uniform()) { float r = (*a) + (*b); for (int i = 0; i < n; ++i) result[i] = r; } else { // One or both are varying for (int i = 0; i < n; ++i, ++a, ++b) result[i] = (*a) + (*b); } }
This is the basis for handling uniform and varying values efficiently inside a SIMD shading system.
Definition at line 93 of file varyingref.h.
|
inline |
Definition at line 95 of file varyingref.h.
|
inline |
Construct a VaryingRef either of a single value pointed to by ptr (if step == 0 or no step is provided), or of a varying set of values beginning with ptr and with successive values every 'step' bytes.
Definition at line 101 of file varyingref.h.
|
inline |
Construct a uniform VaryingRef from a single value.
Definition at line 105 of file varyingref.h.
|
inline |
Initialize this VaryingRef to either of a single value pointed to by ptr (if step == 0 or no step is provided), or of a varying set of values beginning with ptr and with successive values every 'step' bytes.
Definition at line 111 of file varyingref.h.
|
inline |
Is this reference pointing nowhere?
Definition at line 127 of file varyingref.h.
|
inline |
Is this VaryingRef referring to a uniform value, signified by having a step size of zero between elements?
Definition at line 139 of file varyingref.h.
|
inline |
Is this VaryingRef referring to a varying value, signified by having a nonzero step size between elements?
Definition at line 135 of file varyingref.h.
|
inline |
Cast to void* returns the pointer, but the real purpose is so you can use a VaryingRef as if it were a 'bool' value in a test.
Definition at line 131 of file varyingref.h.
|
inline |
Pointer indirection will return the first value currently pointed to by this VaryingRef.
Definition at line 167 of file varyingref.h.
|
inline |
Pre-increment: If this VaryingRef is varying, increment its pointer to the next element in the series, but don't change anything if it's uniform. In either case, return a reference to its new state.
Definition at line 145 of file varyingref.h.
|
inline |
Post-increment: If this VaryingRef is varying, increment its pointer to the next element in the series, but don't change anything if it's uniform. No value is returned, so it's not legal to do 'bar = foo++' if foo and bar are VaryingRef's.
Definition at line 156 of file varyingref.h.
|
inline |
Initialize this VaryingRef to be uniform and point to a particular value reference.
Definition at line 119 of file varyingref.h.
|
inline |
Array indexing operator will return a reference to the single element if *this is uniform, or to the i-th element of the series if *this is varying.
Definition at line 172 of file varyingref.h.
|
inline |
Return the raw pointer underneath.
Definition at line 176 of file varyingref.h.
|
inline |
Return the raw step underneath.
Definition at line 180 of file varyingref.h.