Opencl:从__constant复制到__global内存

时间:2013-07-27 09:22:53

标签: opencl intel nvidia

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

第一个内核(kernel_Calc())计算一些值并将它们存储在__global内存中。在此示例中,它计算(设置转换矩阵,用于转换3D空间中的点)转换矩阵并转换原点。

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 );
}

在主机端,我将计算出的__global缓冲区复制到具有__constant功能的CL_MEM_READ_ONLY缓冲区(clEnqueueCopyBuffer()缓冲区)中。 (我之所以这样做是因为我希望从__constant内存中读取的内容比从__global内存中读取的内容要快。缓冲区副本可以在设备端使用此功能完成,而无需复制{{1} }返回主机,然后将其复制到__global。)

第二个内核(__constant)尝试将计算出的值加载到kernel_Test()变量(__global)中,该变量可以在主机端读取。 __global float4* test是用户定义的结构,它只包含一个整数(这是矩阵和变换点的数量)。第二个和第三个参数是sizeStruct内存中填充了__constant函数的缓冲区。

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 变量(通过将它们复制到主机内存中),它们包含正确的数据。代码是我程序的简化版本。这就是它可能包含不必要的操作和参数的原因。该示例已经过测试,可以按照我的描述进行操作。

当我将__constant内核参数更改为__constant float3* c_Points3D内核参数(但仍然使用填充了__global float3* c_Points3D函数的read_only缓冲区)时更有趣,它工作正常。当我删除clEnqueueCopyBuffer()参数时,它也有效。 所以看起来kernel_Test参数的地址空间有问题,但问题出现在__constant struct sizeStruct* c_SS - > __constant副本。

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

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

Q2:使用__global创建缓冲区并使用cl_mem_read_only地址空间限定符是否合法?

1 个答案:

答案 0 :(得分:0)

  

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

没有任何明显的想法,你能发布一个在Windows上编译的完整的最小工作示例吗?我想测试AMD Radeon GPU。

  

Q2:使用cl_mem_read_only创建缓冲区并使用__global地址空间限定符是否合法?

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