Using Vector3D and Quaternion in Kernel

Dec 22, 2014 at 7:59 PM
I am pretty new developer in CUDA. I have done few simple programs in CUDA but this one is my first attempt to solve a real problem by CUDA. I have a heavy geometry calculation and I would like to implement it on GPU. I've noticed that all of parameters of kernel are basic datatypes however I need Vector3D and Quaternion structures such that they could be compatible with my C# application. Basically my C# application creates 10,000 3D vectors in each frame and I want to pass them through GPU to take care of some calculations and returns a double value. Do you think it is possible in ManagedCUDA? if so, how come?!

Dec 22, 2014 at 10:20 PM

It's no problem to pass complex data structures to cuda kernels. The only restriction is, that they need to be defined as "struct" and not as "class" in C# (value types and not reference types in .net-speech...) and that they consist only of value types (other structs or primitive datatypes, no class members).
So in Cuda you define your struct for example like:
struct Quaternion
    float x0;
    float x1;
    float x2;
    float x3;
and use it in a kernel like
extern "C" __global__ void myKernel(Quaternion* dataArray, Quaternion dataSingle, ...)
in C# you define the structure in exactly the same way: they must be identical or you will end up with garbage data:
public struct Quaternion
    public float x0;
    public float x1;
    public float x2;
    public float x3;

    public Quaternion(float a, float b, float c, float d)
        x0 = a; x1 = b;     x2 = c; x3 = d;
note the structure attribute to force it to a specific data layout. If you have a simple data layout, like these four floats, LayoutKind.Sequential is good enough, but if you have mixed datatypes, make sure the layout from C# and Cuda really matches.

Once you have your structure defined in C#, you can of course use it like any other primitive type or complex type already defined in managedCuda:
CudaDeviceVariable<Quaternion> quats_d = new CudaDeviceVariable<Quaternion>(10000);
myKernel.Run(quats_d.DevicePointer, new Quaternion(1, 2, 3, 4));
Quaternion[] quats_h = quats_d;