这个内核工作正常:
__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;
}
}
此内核产生越界错误:
__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;
}
}
对我来说,似乎他们都应该做同样的事情。 但由于某种原因,这两个作品中只有一个。 我错过了一些明显的东西吗?
确切的错误是:“在GeForce GTX580M(设备0)上执行CL_COMMAND_READ_BUFFER时出现CL_OUT_OF_RESOURCES错误。
答案 0 :(得分:2)
你可能遇到的问题是你为float3s分配了一个n * 3 * sizeof(float)的缓冲区,但float3的大小和对齐方式是16,而不是12。
答案 1 :(得分:2)
@arsenm在他/她的回答以及@Darkzeros给出了正确的解释,但我觉得开发一点很有意思。问题是在第二个内核中,这些是发生的“隐藏”对齐。正如标准6.1.5。中所述:
对于3分量矢量数据类型,数据类型的大小为4 * 的sizeof(组分)。这意味着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个元素的向量。
现在,如果要在主机端不使用数据结构而使用向量,可以使用v2和vstore3函数,如3.12.7节所述。标准。像那样:
vstore3(vload3(index, a_Direction) * 0.5f + 0.5f, index, a_Output));
顺便说一下,你不必费心这样的陈述(假设一个正确的对齐方式):
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;
这句话就足够了(不需要为每个元素写一行):
a_Output[index] = a_Direction[index] * 0.5f + 0.5f;