File: Array.h

package info (click to toggle)
aqsis 1.8.2-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 18,340 kB
  • ctags: 19,671
  • sloc: cpp: 138,267; python: 12,880; ansic: 4,946; xml: 3,415; yacc: 1,887; sh: 406; makefile: 385; lex: 280
file content (208 lines) | stat: -rw-r--r-- 4,458 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#ifndef ARRAY_H_INCLUDED
#define ARRAY_H_INCLUDED

#include <boost/utility.hpp>

#include <vector>

struct SVarBase
{
	virtual bool isUniform() const = 0;
	virtual ~SVarBase() {}
};

// A trivial dynamic array "shader variable" class, designed to roughly model a
// shader data vector of type double.
class SVar : public SVarBase, boost::noncopyable
{
	private:
		double* m_a;
		int m_length;
	public:
		SVar(int length)
			: m_a(new double[length]),
			m_length(length)
		{ }
		~SVar()
		{
			delete[] m_a;
		}

		double& operator[](int i)
		{
			return m_a[i];
		}
		double operator[](int i) const
		{
			return m_a[i];
		}

		int length() const
		{
			return m_length;
		}
		virtual bool isUniform() const
		{
			return false;
		}
};

// cast to varying.
const SVar& varying(const SVarBase& sVar)
{
	return static_cast<const SVar&>(sVar);
}
SVar& varying(SVarBase& sVar)
{
	return static_cast<SVar&>(sVar);
}

class SVarUniform : public SVarBase
{
	private:
		double m_a;
	public:
		SVarUniform(double a = 0)
			: m_a(a)
		{ }

		double& value()
		{
			return m_a;
		}
		double value() const
		{
			return m_a;
		}

		virtual bool isUniform() const
		{
			return true;
		}
};

// cast to uniform.
const SVarUniform& uniform(const SVarBase& sVar)
{
	return static_cast<const SVarUniform&>(sVar);
}
SVarUniform& uniform(SVarBase& sVar)
{
	return static_cast<SVarUniform&>(sVar);
}

// Class to hold indexing arrays for optimizing differentiation.
class DiffIndex
{
	private:
		std::vector<int> m_idx1;
		std::vector<int> m_idx2;

		void initIndexVectors(int length)
		{
			m_idx1.resize(length);
			m_idx2.resize(length);
			m_idx1[0] = 0;
			m_idx2[0] = 1;
			for(int i = 1; i < length; ++i)
			{
				m_idx1[i] = i-1;
				m_idx2[i] = i;
			}
		}
	public:
		DiffIndex(int length)
			: m_idx1(length),
			m_idx2(length)
		{
			initIndexVectors(length);
		}

		double diff(const SVar& a, int i)
		{
			return a[m_idx2[i]] - a[m_idx1[i]];
		}

		int length() const
		{
			return m_idx1.size();
		}
		void setLength(int newLen)
		{
			if(length() != newLen)
			{
				initIndexVectors(newLen);
			}
		}
};

// An adaptor for shader vars which applies a difference operator to the
// underlying array elements.
template<typename SVarT>
class DiffSVar : public SVarBase
{
	private:
		// There are various possibilities for calculating difference operators
		// on a grid:
		//
		// One possibility is to compute them at construction-time, and store
		// the results in a seperate buffer. However, this is grossly
		// inefficient for cases when the shader running state has most
		// elements turned off, and probaboy would cause excessive dynamic
		// allocation / deallocation in any case.
		//
		// Another possibility is to store a reference to the underlying data,
		// and compute the derivative on-demand, directly from the 1D grid
		// index.  In 1D this isn't too bad, but in 2D it involves the very
		// expensive integer div or mod to go from the 1D grid index to the 2D
		// grid coordinates.
		//
		// It may be better for the shader execution environment to provide a
		// special "difference object", which has appropriate indexing arrays
		// describing the difference kernel at each SIMD index i.  That is,
		//
		// diff(a, i) = a[highIndex[i]] - a[lowIndex[i]];
		//
		// A prototype implementation of the idea is given in the DiffIndex
		// class, and seems to be comparably efficient to the direct
		// calculation on a 1D grid.  Throwing a mod or integer divison
		// operation in there to represent 2D considerations shows that it's
		// *much* more efficient in that case.
		const SVarT& m_a;
		static DiffIndex sm_diffIdx;
	public:
		DiffSVar(const SVarT& a)
			: m_a(a)
		{
			sm_diffIdx.setLength(m_a.length());
		}

		double operator[](int i) const
		{
			// Currently using a first-order backward difference here for
			// simplicity, but a second-order centred difference would probably
			// be better.
//			if(i > 0)
//				return m_a[i] - m_a[i-1];
//			else
//				return m_a[1] - m_a[0];
			// The alternative is to use indexing arrays.  This will be very
			// important for efficiency when it comes to two dimensional grids
			// and higher order differencing schemes.
			return sm_diffIdx.diff(m_a, i);
		}

		int length() const
		{
			return m_a.length();
		}
		virtual bool isUniform() const
		{
			return m_a.isUniform();
		}
};

template<typename SVarT>
DiffIndex DiffSVar<SVarT>::sm_diffIdx(0);

#endif // ARRAY_H_INCLUDED