我对整个OpenCL世界都很陌生,我创建了两个非常简单的内核,我试图将它们连接起来,但是我得到了相当虚假的结果。当单独运行时,它们按预期工作,但是当被打到一起时,就是我看到奇怪的结果。
因此,每个内核都是这样的
向量3噪音
__kernel void addVector3Noise( __global struct State* states, __global float3* randomVector3Values){
int stateNum = get_global_id(0);
struct State state = states[stateNum];
float3 randomVal = randomVector3Values[stateNum];
struct State newState;
newState.Vec3 = (float3)(state.Vec3.x + randomVal.x,state.Vec3.y + randomVal.y,state.Vec3.z + randomVal.z);
newState.Vec4 = state.Vec4;
states[stateNum] = newState;
}
为了测试这个,所有状态都有Vec3
[ 1.0f, 1.0f, 1.0f]
,所有随机值都相同,所以我得到的输出是一个状态数组,其值为{{1}正如我所期望的那样。
向量4噪音
[2.0f, 2.0f, 2.0f]
使用非常简单的测试数据运行它也可以提供我想要的东西。
现在将问题链接在一起就会出现问题。我按照Vector 4 noise - >的顺序调用了它们。矢量3噪音。现在,当运行Vector 4 noise Kernel时,我看到向量3的值发生了变化,并且变化似乎遵循了一种模式。
因此,在运行了向量4内核后,我希望每个状态中的向量3与插入时相同。这意味着每个状态的Vector 3值都为{{1以下是我实际看到的矢量3的结果:
__kernel void addVector4Noise(__global struct State* states,
__global float3* randomVector4Values){
int stateNum = get_global_id(0);
struct State state = states[stateNum];
float3 randomVal = randomVector4Values[stateNum];
float4 newVector4 = randomQuaternionRotation(state.Vector4, randomVal);
struct State newState;
newState.Vector3 = state.Vector3;
newState.Vector4= newVector4;
states[stateNum] = newState;
}
并且该模式在所有Vector 3值中重复出现。请注意,在内核中,只是将Vector3从先前状态复制到新状态。
这就是我使用OpenCL.Net将它们链接在一起的方式
[1.0f,1.0f,1.0f]
请原谅那里巨大的代码,但这是一个游乐场项目,我几乎只是呕吐出来的想法,所以整洁和优雅不是问题:)
提前感谢您提供的任何帮助。
修改
所以我今天早上做的第一件事就是将每个内核拉到自己的cl文件中,并确保每个内核都有自己的状态版本,只需要它的内容(分别为Vector4和Vector3),以及一个新的using语句。与新分离的Vector3噪声内核一起使用的所有gubbins。令我高兴的是,Vector4噪声内核完全按照我的预期进行,但是,当涉及到Vector3噪声时,就像之前发生的类似问题一样。仍然将[1.0,1.0,1.0]
[0.576367259,1.0,1.0]
[0.999199867,0.6448302,1.0]
[1.313311, 1.067663, 0.3307195]
[-0.08005857, 1.067663, 1.450237]
[1, 0.2340522, 1.136126]
[1, 1, 0.3025152]
[1, 1, 1]
作为随机值和起始Vector3值传递,并且它仍然没有产生我期望的输出。这次重复的模式是:
using (var env = "*".CreateCLEnvironment(DeviceType.Gpu))
{
var source = LoadProgram("kernels.cl");
var context = env.Context;
ErrorCode errorCode;
var program = Cl.CreateProgramWithSource(context, 1u, source, null, out errorCode);
CheckSuccess(errorCode);
errorCode = Cl.BuildProgram(program, (uint)env.Devices.Length, env.Devices, "-cl-opt-disable", null,
IntPtr.Zero);
if (errorCode != ErrorCode.Success)
{
var info = Cl.GetProgramBuildInfo(program, env.Devices[0], ProgramBuildInfo.Log, out errorCode).ToString();
throw new Exception(info);
}
var kernels = Cl.CreateKernelsInProgram(program, out errorCode);
CheckSuccess(errorCode);
var Vector4NoiseKernel = kernels[0];
var Vector3NoiseKernel = kernels[1];
var rnd = new Random();
var states = Enumerable.Range(1, ArrayLength)
.Select(_ => new State
{
Vector3 = new Vector3(1, 1, 1),
Vector4 = new Vector4(0.5f,0.5f,0.5f,0.5f)
})
.ToArray();
var randomVector4Values = Enumerable.Range(1, ArrayLength)
.Select(_ => new Vector3(2f, 2f, 2f))
.ToArray();
var randomVector3Values = Enumerable.Range(1, ArrayLength)
.Select(_ => new Vector3(1f, 1f, 1f))
.ToArray();
var vector4StatesBuffer = context.CreateBuffer(states, MemFlags.ReadWrite);
var randomVector4ValuesBuffer = context.CreateBuffer(randomVector4Values, MemFlags.ReadOnly);
Event ev;
Cl.SetKernelArg(vector4NoiseKernel, 0, vector4StatesBuffer);
Cl.SetKernelArg(vector4NoiseKernel, 1, randomVector4ValuesBuffer);
errorCode = Cl.EnqueueNDRangeKernel(env.CommandQueues[0], vector4NoiseKernel, 1, null
, new[] { new IntPtr(ArrayLength) }, new[] { new IntPtr(1) }, 0u, null, out ev);
errorCode.Check();
env.CommandQueues[0].ReadFromBuffer(vector4StatesBuffer, states, waitFor: ev);
var randomVector3ValuesBuffer = context.CreateBuffer(randomVector3Values, MemFlags.ReadOnly);
var vector3StatesBuffer = context.CreateBuffer(states, MemFlags.ReadWrite);
Cl.SetKernelArg(vector3NoiseKernel, 0, vector3StatesBuffer);
Cl.SetKernelArg(vector3NoiseKernel, 1, randomVector3ValuesBuffer);
errorCode = Cl.EnqueueNDRangeKernel(env.CommandQueues[0], vector3NoiseKernel, 1, null
, new[] { new IntPtr(ArrayLength) }, new[] { new IntPtr(1) }, 0u, null, out ev);
errorCode.Check();
Cl.Finish(env.CommandQueues[0]).Check();
env.CommandQueues[0].ReadFromBuffer(vector3StatesBuffer, states, waitFor: ev);
}
答案 0 :(得分:3)
在OpenCL中,3分量矢量类型占用与4分量矢量类型相同的大小。例如,float3
被定义为16字节,而不是12字节。如果您在主机上使用的数据结构(在这种情况下为Vector3
类)的大小不同,则可能会遇到问题。
您编辑的帖子中输出中的模式是三个2.0
,然后是1.0
,这表明这可能是您所看到的行为的原因。
一种解决方案是在主机端使用Vector4
代替Vector3
。
答案 1 :(得分:1)
因此,在@jprice指出C#和OpenCL类型之间的大小差异之后,我设法通过明确地声明我在C#端的结构的总大小与预期的结果一致来解决这个问题。 OpenCL方面,所以现在我的结构看起来像这样。
[StructLayout(LayoutKind.Sequential, Size = 32)]
public struct State
{
public Vector3 Vector3;
public Vector4 Vector4;
}
由于OpenCL端的float3
和float4
都是16字节,因此为包含两者的结构分配32个字节会导致正确的行为。