首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当将内核链接在一起时,值会随机变化。

当将内核链接在一起时,值会随机变化。
EN

Stack Overflow用户
提问于 2015-10-05 17:27:23
回答 2查看 167关注 0票数 2

我对整个OpenCL世界都很陌生,我创建了两个非常简单的内核,我试图将它们更紧密地联系在一起,但我得到的结果是相当虚假的。当单独运行时,它们会像预期的那样工作,但是当被打在一起时,我就会看到奇怪的结果。

因此,每个内核都是这样的

矢量3噪声

代码语言:javascript
复制
__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 of [ 1.0f, 1.0f, 1.0f],所有的随机值都是相同的,所以我得到的输出是一个包含值[2.0f, 2.0f, 2.0f]的状态数组,正如我所期望的那样。

矢量4噪声

代码语言:javascript
复制
__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;    
}

用非常简单的测试数据运行它也给了我我想要的东西。

现在,当把它们联系在一起时,问题就出现了。我在顺序向量4噪声->向量3噪声中调用了它们。现在,当运行向量4噪声内核时,我看到向量3值发生了变化,而且这种变化似乎遵循了一种模式。

因此,在运行了向量4内核之后,我希望每个状态下的向量3都与插入时相同。这就意味着每个州都有一个向量3的[1.0f,1.0f,1.0f]值,下面是我看到的向量3的结果:

代码语言:javascript
复制
[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]

这种模式在向量3的所有值中都会重复。注意,在内核中,它只是将Vector3从以前的状态复制到新状态。

这就是我如何使用OpenCL.Net将它们链接在一起的方法。

代码语言:javascript
复制
    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);
    }

请原谅这里的大量代码,但这是一个游乐场项目,我几乎只是想吐出一些想法,所以整洁和优雅并不是问题所在:)

预先感谢您能提供的任何帮助。

因此,我今天早上做的第一件事就是将每个内核提取到自己的cl文件中,并确保每个内核都有自己的状态版本,只包含它所需的内容(分别是和Vector3 ),以及一个新的the语句,其中包含了新分离出来的Vector3噪声内核的所有句号。对于我的joy来说,Vector4噪声内核做的和我预期的完全一样,然而,当它涉及到Vector3噪声时,一个类似于以前发生的问题。仍然将[1.0f,1.0f,1.0f]作为随机值和启动的Vector3值传递,而且它仍然没有产生我期望的输出。这一次重复的模式是:

代码语言:javascript
复制
[2.0f,2.0f,2.0f]
[1.0f,2.0f,2.0f]
[2.0f,1.0f,2.0f]
[2.0f,2.0f,1.0f]
[2.0f,2.0f,2.0f]
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-06 13:47:19

因此,在@jprice指出了C#and OpenCL类型之间的大小差异之后,我成功地解决了这个问题,在C#端显式声明了结构的总大小,使之与OpenCL端的预期大小一致,所以现在我的结构如下所示。

代码语言:javascript
复制
[StructLayout(LayoutKind.Sequential, Size = 32)]
public struct State
{
    public Vector3 Vector3;
    public Vector4 Vector4;
}

由于float3和OpenCL端的float4都是16字节,因此将32个字节分配给包含这两个字节的结构将导致正确的行为。

票数 1
EN

Stack Overflow用户

发布于 2015-10-06 12:46:45

在OpenCL中,三分量向量类型与四分量向量类型所占的大小相同.例如,float3被定义为16字节,而不是12字节.如果您在主机上使用的数据结构(本例中的Vector3类)大小不同,您可能会遇到问题。

编辑后的文章中的输出模式是三个2.0,然后是1.0,这表明这很可能是您所看到的行为的原因。

一种解决方案是在主机端使用Vector4代替Vector3

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32954410

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档