Opencl:从_常量复制到_全局内存

Opencl:从_常量复制到_全局内存,opencl,intel,nvidia,Opencl,Intel,Nvidia,我有两个内核(它们都只运行一次,因此示例中globalWorkSize为1): 第一个内核(kernel\u Calc())计算一些值并将它们存储在\u全局内存中。在本例中,它计算(设置转换矩阵,转换三维空间中的点)转换矩阵并转换origo inline float4 mul( const float4 M[ 4 ], const float4 v) { float4 r; r.x = dot( v, M[ 0 ] ); r.y = dot( v, M[ 1 ] );

我有两个内核(它们都只运行一次,因此示例中globalWorkSize为1):

第一个内核(
kernel\u Calc()
)计算一些值并将它们存储在
\u全局
内存中。在本例中,它计算(设置转换矩阵,转换三维空间中的点)转换矩阵并转换origo

inline 
float4 mul( const float4 M[ 4 ], const float4 v)
{
   float4 r;
   r.x = dot( v, M[ 0 ] );
   r.y = dot( v, M[ 1 ] );
   r.z = dot( v, M[ 2 ] );
   r.w = dot( v, M[ 3 ] );
   return r;
}

__kernel
void kernel_Calc( __global float4* g_TransformationMatrices, __global float3* g_Point3D )
{
    __private float4 transformationMatrix[ 4 ];

    transformationMatrix [ 0 ] = (float4) ( 1.0f, 0.0f, 0.0f, 0.0f );
    transformationMatrix [ 1 ] = (float4) ( 0.0f, 1.0f, 0.0f, 10.0f );
    transformationMatrix [ 2 ] = (float4) ( 0.0f, 0.0f, 1.0f, 0.0f );
    transformationMatrix [ 3 ] = (float4) ( 0.0f, 0.0f, 0.0f, 1.0f );

    g_TransformationMatrices[ 0 ] = transformationMatrix[ 0 ];
    g_TransformationMatrices[ 1 ] = transformationMatrix[ 1 ];
    g_TransformationMatrices[ 2 ] = transformationMatrix[ 2 ];
    g_TransformationMatrices[ 3 ] = transformationMatrix[ 3 ];


    float4 point4D = (float4) ( 0.0f, 0.0f, 0.0f, 1.0f );
    float4 point4DTransformed = mul( transformationMatrix, point4D);

    g_Point3D[ 0 ] = (float3) ( point4DTransformed.x / point4DTransformed.w ,
                                point4DTransformed.y / point4DTransformed.w ,
                                point4DTransformed.z / point4DTransformed.w );
}
在主机端,我使用
clEnqueueCopyBuffer()
函数将计算出的
\uuuu全局
缓冲区复制到
\uu常量
缓冲区(
CL\u MEM\u只读
缓冲区)。(我这样做是因为我希望从
\uuu常量
内存读取的速度比从
\uu全局
内存读取的速度快。使用此功能可以在设备端完成缓冲区复制,而无需将
\uu全局
复制回主机,然后将其复制到
\uu常量

第二个内核(
kernel\u Test()
)尝试将计算出的值加载到可在主机端读取的
\uuu global
变量(
\uu global float4*Test
)中。
sizeStruct
是一个用户定义的结构,它只包含一个整数(这是矩阵和转换点的数目)。第二个和第三个参数是
\u常量
内存中的缓冲区,这些缓冲区被
clEnqueueCopyBuffer()
函数填满

struct sizeStruct
{
    int m_Size;
};

__kernel 
void kernel_Test( __constant struct sizeStruct* c_SS,
                  __constant float4* c_TransformationMatrices,
                  __constant float3* c_Points3D,
                  __global float4 *test )
{                   
    test[ 0 ] = c_TransformationMatrices[ 0 ];
    test[ 1 ] = c_TransformationMatrices[ 1 ];
    test[ 2 ] = c_TransformationMatrices[ 2 ];
    test[ 3 ] = c_TransformationMatrices[ 3 ];
}
问题是,当我运行程序时,测试变量包含以下内容:

1.000000, 0.000000, 0.000000, 0.000000
0.000000, 0.000000, 0.000000, 0.000000
0.000000, 0.000000, 0.000000, 0.000000
0.000000, 0.000000, 0.000000, 0.000000
但它应包括:

1.000000, 0.000000, 0.000000, 0.000000
0.000000, 1.000000, 0.000000, 10.000000
0.000000, 0.000000, 1.000000, 0.000000
0.000000, 0.000000, 0.000000, 1.000000
我检查了
\u常量
变量(通过将它们复制到主机内存),它们包含正确的数据。代码是我程序的简化版本。这就是它可能包含不必要的操作和参数的原因。这个例子已经过测试,并按照我所描述的那样工作

更有趣的是,当我将
\uuu常量float3*c_Points3D
内核参数更改为
\uu全局float3*c_Points3D
内核参数时(但仍然使用用
clEnqueueCopyBuffer()函数填充的只读缓冲区),它工作得很好。当我删除
\u常量struct sizeStruct*c\u SS
参数时,它也会起作用。 因此,内核测试的参数的地址空间似乎有问题,但问题出现在
\uu常量
->
\uu全局
copy

我正在nvidia geforce gtx 690上运行该程序,但我可以将设备(和平台)更改为intel i7-3930k(使用intel sdk)。使用intel-i7 cpu,一切正常,内核代码没有任何更改

Q1:为什么会出现这种奇怪的行为?有人知道我做错了什么吗

Q2:使用
cl\u mem\u read\u
创建缓冲区并与
\u global
地址空间限定符一起使用是否合法

Q1:为什么会出现这种奇怪的行为?有人知道我做错了什么吗

我想不出什么明显的问题,你能给出一个在Windows上编译的完整的最低限度的工作示例吗?我想在AMD Radeon GPU上测试

Q2:使用cl\u mem\u read\u创建缓冲区并与\u全局地址空间限定符一起使用是否合法


是的,这是合法的,尽管您需要添加
const
以指定缓冲区为只读,请参阅OpenCL 1.2规范的第6.5.1节。

谢谢您的回答。我在这里上传了测试项目(VS2010):您的代码在我的AMD Radeon HD 6970上正常工作。稍后我将测试一些Nvidia卡。Nvidia卡在OpenCL中对向量的支持非常糟糕,float4可能是问题的根本原因。AMDs FFT实现也会发生同样的情况,它们使用float2,代码在Intel CPU和AMD GPU上运行良好,但在NVIDIA卡上运行不好。