Here are the limitations on C++ AMP with respect to classes and functions etc. You are also limited to a subset of supported C++ types but I don't think that is the issue here.
References and pointers (to a compatible type) may be used locally but cannot be captured by a lambda. Function pointers, pointer-to-pointer, and the like are not allowed; neither are static or global variables.
Classes must meet more rules if you wish to use instances of them. They must have no virtual functions or virtual inheritance. Constructors, destructors, and other nonvirtual functions are allowed. The member variables must all be of compatible types, which could of course include instances of other classes as long as those classes meet the same rules. The actual code in your amp-compatible function is not running on a CPU and therefore can’t do certain things that you might be used to doing:
- recursion
- pointer casting
- use of virtual functions
- new or delete
- RTTI or dynamic casting
- goto
- throw, try, or catch
- access to globals or statics
- inline assembler
This is taken from my book and I apologize because it is misleading. What isn't made clear is that this applies to classes that you wish to pass to AMP kernels as data. Not to classes that have restrict(amp)
methods on them. This is only supported for static methods because it is not possible to share the class this
pointer with the GPU as it refers to an object instance on the CPU.
So the following is an example of a class that meets the above requirements and can be passed to an AMP kernel:
class stuff
{
public:
int a;
stuff(int v) : a(v) { }
};
stuff
also meets the requirements for supported types as int
is supported by AMP.
The following class uses stuff
in an array_view
:
class test_case
{
public:
test_case()
{
}
static int amp_method(int a) restrict(amp, cpu)
{
return a * a;
};
void test_amp()
{
concurrency::array_view<stuff, 1> data(100);
concurrency::parallel_for_each(data.extent,
[data](concurrency::index<1> idx) restrict(amp)
{
data[idx].a = amp_method(data[idx].a);
});
data.synchronize();
};
void test_cpu()
{
std::vector<int> data(100, 0);
for (auto& d : data)
{
d = amp_method(d);
}
}
};
If you remove the static
modifier on amp_method
then you get the following error on VS 2013.
warning C4573: the usage of 'test_tools_tests::test_case::amp_method' requires the compiler to capture
this
but the current default capture mode does not allow it
You may see something different in 2012. One of the weaknesses of the first AMP release was it's errors. This has improved in 2013.
On reflection this all seems really reasonable. How could I pass this
to the GPU when it refers to code running on the CPU?
Note that restrict
cannot be applied to classes.
Thanks for highlighting this issue. I guess I should update the book errata.