VaryingRef< T > Class Template Reference

#include <varyingref.h>

List of all members.

Public Member Functions

 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)
T & operator* () const
T & operator[] (int i) const
T * ptr () 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 rever 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.


Constructor & Destructor Documentation

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.

template<class T>
VaryingRef< T >::VaryingRef ( T &  ptr  )  [inline]

Construct a uniform VaryingRef from a single value.


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.

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

Is this reference pointing nowhere?

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?

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?

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.

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

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

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.

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.

template<class T>
const VaryingRef& VaryingRef< T >::operator= ( T &  ptr  )  [inline]

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

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.

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

Return the raw pointer underneath.

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

Return the raw step underneath.


The documentation for this class was generated from the following file:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Tue Oct 27 06:30:41 2009 for OpenImageIO by  doxygen 1.6.1