HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VaryingRef< T > Class Template Reference

#include <varyingref.h>

Public Member Functions

 VaryingRef ()
 
 VaryingRef (void *ptr_, int step_=0)
 
 VaryingRef (T &ptr_)
 
void init (T *ptr_, int step_=0)
 
const VaryingRefoperator= (T &ptr_)
 
bool is_null () const
 
 operator void * () const
 
bool is_varying () const
 
bool is_uniform () const
 
VaryingRefoperator++ ()
 
void operator++ (int)
 
Toperator* () const
 
Toperator[] (int i) const
 
Tptr () const
 
int step () const
 

Detailed Description

template<class T>
class VaryingRef< T >

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.

Constructor & Destructor Documentation

template<class T>
VaryingRef< T >::VaryingRef ( )
inline

Definition at line 95 of file varyingref.h.

template<class T>
VaryingRef< T >::VaryingRef ( void ptr_,
int  step_ = 0 
)
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.

template<class T>
VaryingRef< T >::VaryingRef ( T ptr_)
inline

Construct a uniform VaryingRef from a single value.

Definition at line 105 of file varyingref.h.

Member Function Documentation

template<class T>
void VaryingRef< T >::init ( T ptr_,
int  step_ = 0 
)
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.

template<class T>
bool VaryingRef< T >::is_null ( ) const
inline

Is this reference pointing nowhere?

Definition at line 127 of file varyingref.h.

template<class T>
bool VaryingRef< T >::is_uniform ( ) const
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.

template<class T>
bool VaryingRef< T >::is_varying ( ) const
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.

template<class T>
VaryingRef< T >::operator void * ( ) const
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.

template<class T>
T& VaryingRef< T >::operator* ( ) const
inline

Pointer indirection will return the first value currently pointed to by this VaryingRef.

Definition at line 167 of file varyingref.h.

template<class T>
VaryingRef& VaryingRef< T >::operator++ ( )
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.

template<class T>
void VaryingRef< T >::operator++ ( int  )
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.

template<class T>
const VaryingRef& VaryingRef< T >::operator= ( T ptr_)
inline

Initialize this VaryingRef to be uniform and point to a particular value reference.

Definition at line 119 of file varyingref.h.

template<class T>
T& VaryingRef< T >::operator[] ( int  i) const
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.

template<class T>
T* VaryingRef< T >::ptr ( ) const
inline

Return the raw pointer underneath.

Definition at line 176 of file varyingref.h.

template<class T>
int VaryingRef< T >::step ( ) const
inline

Return the raw step underneath.

Definition at line 180 of file varyingref.h.


The documentation for this class was generated from the following file: