OpenCL越界错误

OpenCL越界错误,opencl,Opencl,此内核工作正常: __kernel void test(__global float* a_Direction, __global float* a_Output, const unsigned int a_Count) { int index = get_global_id(0); if (index < a_Count) { a_Output[index * 3 + 0] = a_Direction[index * 3 + 0] * 0.5f

此内核工作正常:

__kernel void test(__global float* a_Direction, __global float* a_Output, const unsigned int a_Count)
{
    int index = get_global_id(0);

    if (index < a_Count)
    {
        a_Output[index * 3 + 0] = a_Direction[index * 3 + 0] * 0.5f + 0.5f;
        a_Output[index * 3 + 1] = a_Direction[index * 3 + 1] * 0.5f + 0.5f;
        a_Output[index * 3 + 2] = a_Direction[index * 3 + 2] * 0.5f + 0.5f;
    }
}
\uuuuu内核无效测试(\uuuu全局浮点*a\u方向,\uuuu全局浮点*a\u输出,常量无符号整数a\u计数)
{
int index=get_global_id(0);
如果(索引
此内核会产生越界错误:

__kernel void test(__global float3* a_Direction, __global float3* a_Output, const unsigned int a_Count)
{
    int index = get_global_id(0);

    if (index < a_Count)
    {
        a_Output[index].x = a_Direction[index].x * 0.5f + 0.5f;
        a_Output[index].y = a_Direction[index].y * 0.5f + 0.5f;
        a_Output[index].z = a_Direction[index].z * 0.5f + 0.5f;
    }
}
\u内核无效测试(\u全局浮点3*a\u方向,\u全局浮点3*a\u输出,常量无符号整数a\u计数)
{
int index=get_global_id(0);
如果(索引
在我看来,他们应该做完全相同的事情。 但出于某种原因,这两种方法中只有一种有效。 我错过了什么明显的东西吗


确切的错误是:“在GeForce GTX580M(设备0)上执行CL_命令读取缓冲区时,CL_OUT OF_RESOURCES出错。

您可能遇到的问题是您分配了一个大小为n*3*sizeof(float)的缓冲区对于您的float3,但是float3的大小和对齐方式是16,而不是12。

您可能遇到的问题是您分配了一个n*3*sizeof(float)的缓冲区对于您的float3,但是float3的大小和对齐方式是16,而不是12。

@arsenm在他的/她的答案中以及@Darkzeros给出了正确的解释,但我觉得开发一点很有趣。问题是,在第二个内核中,这是一种“隐藏”对齐方式。正如第6.1.5节中的标准说明:

对于三分量矢量数据类型,数据类型的大小为4* sizeof(component)。这意味着一个3分量向量数据类型将 与4*sizeof(组件)边界对齐

让我们用一个例子来说明这一点:

假设
a_Direction
由9个浮点组成,并且您使用3个线程/工作项来处理这些元素。在第一个内核中,这没有问题:线程0将处理索引为0、1、2的元素,线程1处理元素3、4、5,最后线程2处理元素6、7、8:一切都很好

但是,对于第二个内核,假设您使用的数据结构从主机端的角度来看保持不变(即数组从0到8),线程0将处理元素0、1、2(并且还将访问元素4,因为float3类型向量的行为将类似于float4类型向量,而不做任何处理).第二个线程,即线程1不会访问元素3、4、5,但会访问元素4、5、6(和7),而不会对其执行任何操作

因此,这就是问题所在,线程2将尝试访问元素8、9、10(和11),因此超出访问范围

总而言之,由3个元素组成的向量的行为类似于由4个元素组成的向量。

现在,如果您想在不改变主机端数据结构的情况下使用向量,可以使用本标准第3.12.7节中描述的vload3和vstore3函数。如下所示:

 vstore3(vload3(index, a_Direction) * 0.5f + 0.5f, index, a_Output));
顺便说一句,您不必为以下语句而烦恼(假设正确对齐):

此语句足够了(无需为每个元素写一行):


@arsenm在他/她的回答中以及@Darkzeros中给出了正确的解释,但我觉得开发一点是有趣的。问题是,在第二个内核中,这些是发生的“隐藏”对齐。正如第6.1.5节中的标准说明:

对于三分量矢量数据类型,数据类型的大小为4* sizeof(component)。这意味着一个3分量向量数据类型将 与4*sizeof(组件)边界对齐

让我们用一个例子来说明这一点:

假设
a_Direction
由9个浮点组成,并且您使用3个线程/工作项来处理这些元素。在第一个内核中,这没有问题:线程0将处理索引为0、1、2的元素,线程1处理元素3、4、5,最后线程2处理元素6、7、8:一切都很好

但是,对于第二个内核,假设您使用的数据结构从主机端的角度来看保持不变(即数组从0到8),线程0将处理元素0、1、2(并且还将访问元素4,因为float3类型向量的行为将类似于float4类型向量,而不做任何处理).第二个线程,即线程1不会访问元素3、4、5,但会访问元素4、5、6(和7),而不会对其执行任何操作

因此,这就是问题所在,线程2将尝试访问元素8、9、10(和11),因此超出访问范围

总而言之,由3个元素组成的向量的行为类似于由4个元素组成的向量。

现在,如果您想在不改变主机端数据结构的情况下使用向量,可以使用本标准第3.12.7节中描述的vload3和vstore3函数。如下所示:

 vstore3(vload3(index, a_Direction) * 0.5f + 0.5f, index, a_Output));
顺便说一句,您不必为以下语句而烦恼(假设正确对齐):

此语句足够了(无需为每个元素写一行):


我想说一些类似的话。
sizeof(clu float)*3*n
在主机端不等于
sizeof(clu float)*n
。我想说一些类似的话。
sizeof(clu float)*3*n
在主机端不等于
sizeof(clu float)*n
a_Output[index] = a_Direction[index] * 0.5f + 0.5f;