Lammar's picture

Cloo, C# to OpenCL struct transfer trouble

All compile and run normally, but it looks like the triangle data is corrupted.
In kernel I have struct:

typedef struct
{
	float3 a, b, c;
	float3 ambient, diffuse, specular;
} Triangle;
...
__kernel void Main(__write_only image2d_t image, __global Triangle * triangles, const float trianglesCount)
{
	Triangle tri = triangles[0];
	...

And in host code:

public struct RGB
{
	public float R, G, B;
 
	public RGB(float n) : this(n, n, n) { }
 
	public RGB(float R, float G, float B)
	{
		this.R = R;
		this.G = G;
		this.B = B;
	}
}
 
public struct Triangle
{
	public Vector3 a, b, c;
	public RGB ambient, diffuse, specular;
 
	public Triangle(Vector3 a, Vector3 b, Vector3 c) : this(a, b, c, new RGB(), new RGB(), new RGB()) { }
 
	public Triangle(Vector3 a, Vector3 b, Vector3 c, RGB ambient, RGB diffuse, RGB specular)
	{
		this.a = a;
		this.b = b;
		this.c = c;
		this.ambient = ambient;
		this.diffuse = diffuse;
		this.specular = specular;
	}
}

Rendering loop:

triangles = new ComputeBuffer<CL.Triangle>(CL.context, ComputeMemoryFlags.ReadOnly, new CL.Triangle[]
{
	new CL.Triangle(new Vector3(), new Vector3(0, 1, 0), new Vector3(0, 0, 1), new CL.RGB(1, 0, 0), new CL.RGB(), new CL.RGB())
});
...
kernel.SetMemoryArgument(1, triangles);

What's wrong in my code?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
nythrix's picture

Looks like struct alignment problems. Try swapping float3's for float4's.

Lammar's picture

Fixed!

I added ComputeMemoryFlags.UseHostPointer flag to buffer flags and offsets to struct:

triangles = new ComputeBuffer<CL.Triangle>(CL.context, ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.UseHostPointer, new CL.Triangle[] { ... });
 
...
 
[StructLayout(LayoutKind.Explicit)]
public struct RGB
{
 [MarshalAs(UnmanagedType.R4), FieldOffset(0)]
 public float R;
 [MarshalAs(UnmanagedType.R4), FieldOffset(4)]
 public float G;
 [MarshalAs(UnmanagedType.R4), FieldOffset(8)]
 public float B;
 
 ...
}
 
[StructLayout(LayoutKind.Explicit)]
public struct Triangle
{
 [FieldOffset(0)]
 public Vector3 a;
 [FieldOffset(16)]
 public Vector3 b;
 [FieldOffset(32)]
 public Vector3 c;
 [FieldOffset(48)]
 public RGB ambient;
 [FieldOffset(64)]
 public RGB diffuse;
 [FieldOffset(80)]
 public RGB specular;
 [MarshalAs(UnmanagedType.R4), FieldOffset(96)]
 public float specularPower;
 
 ...
}
Lammar's picture

But then I try to transfer more than one triangle and have problems again. It looks as structures overlap each other.

nythrix's picture

UseHostPointer is NOT safe under a compacting garbage collector environment (much less with a temporary array :). Use CopyHostPointer instead.

Robmaister's picture

You can avoid that mess of FieldOffsetAttributes by using the "Pack" property of StructLayoutAttribute:

[StructLayout(LayoutKind.Sequential, Pack = 1)]

Will pack the struct on 1-byte boundaries instead of 4.

Lammar's picture

Fxed last problem by specifying struct size