HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
varyingref.h
Go to the documentation of this file.
1 /*
2  Copyright 2008 Larry Gritz and the other authors and contributors.
3  All Rights Reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  * Neither the name of the software's owners nor the names of its
14  contributors may be used to endorse or promote products derived from
15  this software without specific prior written permission.
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28  (This is the Modified BSD License)
29 */
30 
31 
32 /// @file varyingref.h
33 /// @Brief Define the VaryingRef class.
34 
35 #pragma once
36 
38 
40 
41 /// VaryingRef is a templated class (on class T) that holds either a
42 /// pointer to a single T value, or an "array" of T values, each
43 /// separated by a certain number of bytes. For those versed in the
44 /// lingo of SIMD shading, this encapsulates 'uniform' and 'varying'
45 /// references.
46 ///
47 /// Suppose you have a computation 'kernel' that is performing an
48 /// operation while looping over several computation 'points.' Each of
49 /// the several operands of the kernel may either be a 'uniform' value
50 /// (identical for each point), or 'varying' (having a potentially
51 /// different value for each point).
52 ///
53 /// Here is a concrete example. Suppose you have the following function:
54 /// \code
55 /// void add (int n, float *a, float *b, float *result) {
56 /// for (int i = 0; i < n; ++i)
57 /// result[i] = a[i] + b[i];
58 /// }
59 /// \endcode
60 ///
61 /// But if the caller of this function has only a single b value (let's
62 /// say, you always want to add 3 to every a[i]), you would be forced
63 /// to replicate an entire array full of 3's in order to call the function.
64 ///
65 /// Instead, we may wish to generalize the function so that each operand
66 /// may rever to EITHER a single value or an array of values, without
67 /// making the code more complicated. We can do this with VaryingRef:
68 /// \code
69 /// void add (int n, VaryingRef<float> a, VaryingRef<float> b,
70 /// float *result) {
71 /// for (int i = 0; i < n; ++i)
72 /// result[i] = a[i] + b[i];
73 /// }
74 /// \endcode
75 ///
76 /// VaryingRef overloads operator [] to properly decode whether it is
77 /// uniform (point to the one value) or varying (index the right array
78 /// element). It also overloads the increment operator ++ and the pointer
79 /// indirection operator '*', so you could also write the function
80 /// equivalently as:
81 /// \code
82 /// void add (int n, VaryingRef<float> a, VaryingRef<float> b,
83 /// float *result) {
84 /// for (int i = 0; i < n; ++i, ++a, ++b) // note increments
85 /// result[i] = (*a) + (*b);
86 /// }
87 /// \endcode
88 ///
89 /// An example of calling this function would be:
90 /// \code
91 /// float a[n];
92 /// float b; // just 1 value
93 /// float result[n];
94 /// add (n, VaryingRef<float>(a,sizeof(a[0])),
95 /// VaryingRef<float>(b), result);
96 /// \endcode
97 ///
98 /// In this example, we're passing a truly varying 'a' (signified by
99 /// giving a step size from element to element), but a uniform 'b' (signified
100 /// by no step size, or a step size of zero).
101 ///
102 /// There are Varying() and Uniform() templated functions that provide
103 /// a helpful shorthand:
104 /// \code
105 /// add (n, Varying(a), Uniform(b), result);
106 /// \endcode
107 ///
108 /// Now let's take it a step further and fully optimize the 'add' function
109 /// for when both operands are uniform:
110 /// \code
111 /// void add (int n, VaryingRef<float> a, VaryingRef<float> b,
112 /// VaryingRef<float> result) {
113 /// if (a.is_uniform() && b.is_uniform()) {
114 /// float r = (*a) + (*b);
115 /// for (int i = 0; i < n; ++i)
116 /// result[i] = r;
117 /// } else {
118 /// // One or both are varying
119 /// for (int i = 0; i < n; ++i, ++a, ++b)
120 /// result[i] = (*a) + (*b);
121 /// }
122 /// }
123 /// \endcode
124 /// This is the basis for handling uniform and varying values efficiently
125 /// inside a SIMD shading system.
126 
127 template<class T> class VaryingRef {
128 public:
129  VaryingRef() { init(0, 0); }
130 
131  /// Construct a VaryingRef either of a single value pointed to by ptr
132  /// (if step == 0 or no step is provided), or of a varying set of
133  /// values beginning with ptr and with successive values every 'step'
134  /// bytes.
135  VaryingRef(void* ptr_, int step_ = 0) { init((T*)ptr_, step_); }
136 
137  /// Construct a uniform VaryingRef from a single value.
138  ///
139  VaryingRef(T& ptr_) { init(&ptr_, 0); }
140 
141  /// Initialize this VaryingRef to either of a single value pointed
142  /// to by ptr (if step == 0 or no step is provided), or of a varying
143  /// set of values beginning with ptr and with successive values
144  /// every 'step' bytes.
145  void init(T* ptr_, int step_ = 0)
146  {
147  m_ptr = ptr_;
148  m_step = step_;
149  }
150 
151  /// Initialize this VaryingRef to be uniform and point to a particular
152  /// value reference.
153  const VaryingRef& operator=(T& ptr_)
154  {
155  init(&ptr_);
156  return *this;
157  }
158 
159  /// Is this reference pointing nowhere?
160  ///
161  bool is_null() const { return (m_ptr == 0); }
162 
163  /// Cast to void* returns the pointer, but the real purpose is so
164  /// you can use a VaryingRef as if it were a 'bool' value in a test.
165  operator void*() const { return m_ptr; }
166 
167  /// Is this VaryingRef referring to a varying value, signified by
168  /// having a nonzero step size between elements?
169  bool is_varying() const { return (m_step != 0); }
170 
171  /// Is this VaryingRef referring to a uniform value, signified by
172  /// having a step size of zero between elements?
173  bool is_uniform() const { return (m_step == 0); }
174 
175  /// Pre-increment: If this VaryingRef is varying, increment its
176  /// pointer to the next element in the series, but don't change
177  /// anything if it's uniform. In either case, return a reference to
178  /// its new state.
180  { // Prefix form ++i
181  char* p = (char*)m_ptr;
182  p += m_step;
183  m_ptr = (T*)p;
184  return *this;
185  }
186  /// Post-increment: If this VaryingRef is varying, increment its
187  /// pointer to the next element in the series, but don't change
188  /// anything if it's uniform. No value is returned, so it's not
189  /// legal to do 'bar = foo++' if foo and bar are VaryingRef's.
190  void operator++(int)
191  { // Postfix form i++ : return nothing to avoid copy
192  // VaryingRef<T> tmp = *this;
193  char* p = (char*)m_ptr;
194  p += m_step;
195  m_ptr = (T*)p;
196  // return tmp;
197  }
198 
199  /// Pointer indirection will return the first value currently
200  /// pointed to by this VaryingRef.
201  T& operator*() const { return *m_ptr; }
202 
203  /// Array indexing operator will return a reference to the single
204  /// element if *this is uniform, or to the i-th element of the
205  /// series if *this is varying.
206  T& operator[](int i) const { return *(T*)((char*)m_ptr + i * m_step); }
207 
208  /// Return the raw pointer underneath.
209  ///
210  T* ptr() const { return m_ptr; }
211 
212  /// Return the raw step underneath.
213  ///
214  int step() const { return m_step; }
215 
216 private:
217  T* m_ptr; ///< Pointer to value
218  int m_step; ///< Distance between successive values -- in BYTES!
219 };
220 
221 
222 
223 /// Helper function wraps a varying reference with default step size.
224 ///
225 template<class T>
228 {
229  return VaryingRef<T>(x, sizeof(T));
230 }
231 
232 /// Helper function wraps a uniform reference.
233 ///
234 template<class T>
237 {
238  return VaryingRef<T>(x, 0);
239 }
240 
241 /// Helper function wraps a uniform reference.
242 ///
243 template<class T>
246 {
247  return VaryingRef<T>(&x, 0);
248 }
249 
250 
VaryingRef< T > Uniform(T *x)
Definition: varyingref.h:236
VaryingRef< T > Varying(T *x)
Definition: varyingref.h:227
bool is_null() const
Definition: varyingref.h:161
VaryingRef(T &ptr_)
Definition: varyingref.h:139
GLint GLint GLint GLint GLint x
Definition: glew.h:1252
T * ptr() const
Definition: varyingref.h:210
VaryingRef(void *ptr_, int step_=0)
Definition: varyingref.h:135
VaryingRef & operator++()
Definition: varyingref.h:179
GLfloat GLfloat p
Definition: glew.h:16321
void operator++(int)
Definition: varyingref.h:190
T & operator[](int i) const
Definition: varyingref.h:206
T & operator*() const
Definition: varyingref.h:201
void init(T *ptr_, int step_=0)
Definition: varyingref.h:145
bool is_uniform() const
Definition: varyingref.h:173
#define OIIO_NAMESPACE_END
Definition: oiioversion.h:66
const VaryingRef & operator=(T &ptr_)
Definition: varyingref.h:153
int step() const
Definition: varyingref.h:214
#define OIIO_NAMESPACE_BEGIN
Definition: oiioversion.h:65
bool is_varying() const
Definition: varyingref.h:169