关于将数据从CPU传至kernel

  • 1 replies
  • 2725 views
关于将数据从CPU传至kernel
« 于: 五月 30, 2018, 04:20:38 pm »
不知道是不是因为CPU上包含了自定义的结构体在gpu上换成了float3的原因,测试打印数据的时候位置全部移了一格。
这个是CPU端的代码:
   cl_mem inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(Scene), (void *)scene, &err);
   if (err != CL_SUCCESS) {
      printf("Couldn't create a inputBuffer object\n");
      exit(1);
   }
   err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &inputBuffer);
   if (err != CL_SUCCESS) {
      printf("Couldn't set the kernel 0 argument\n");
      exit(1);
   }
这个是scene的结构体:

typedef struct Scene
{
   Point cameraPosition;               // camera location
   float cameraRotation;               // direction camera points
    float cameraFieldOfView;            // field of view for the camera

   float exposure;                     // image exposure

   unsigned int skyboxMaterialId;

   // scene object counts
   unsigned int numMaterials;
   unsigned int numSpheres;
   unsigned int numTriangles;
   unsigned int numLights;

   // scene objects
   Material* materialContainer;   
   Sphere* sphereContainer;
   Triangle* triangleContainer;
   Light* lightContainer;
} Scene;
其中material,sphere,triangle,light是另外的结构体,point是装了3个float的结构体,在cl文件里重新声明为float3,其他的都没变。

(无标题)
« 回复 #1 于: 五月 30, 2018, 05:18:46 pm »
Hi, RoaTheChaos,

你的代码已经阅读, 请注意你存在多处理解和概念上的BUG:

(1) OpenCL因为要兼容多种硬件, 它们具有不同的访存对齐性要求, 因此float3被规范定义成没有最后一个分量的float4, 这意味着在OpenCL中:

大小: sizeof(float3) == 16 //不是你认为的12!
对齐性要求: float3 MUST be aligned to 16B边界! 不是你认为的对齐到4B的边界.

这点是和CUDA的显著区别. 来自CUDA的人要特别注意点和OpenCL的区别.

(2)OpenCL规范不约定Host Compiler和设备端的Struct的内存中的layout一致性.
这是因为OpenCL要针对多种不同的Host C Compiler, 而每种Host C Compiler甚至可能互相之间就布局不同.
甚至更为严重的, Host Compiler根本就不是C编译器, 连struct这个概念都没有.
这就是为何所说的, struct不能在host和device间传递. 否则将导致未定义的结果.

这点也是来自CUDA的人经常犯错的一点. 因为CUDA要求了这一点. Host编译器和设备端的struct编译结果相同. 但是OpenCL却从来没有约定这一点.

(3)在OpenCL 2.0之前, 指针在Device上和Host上不能等价. 例如sizeof(void *)可能在host和device上是两种不同的结果. 甚至OpenCL 1.2根本可能就没有一个扁平的内存布局(segmented).

建议的解决方案:
(A) 不使用struct. 在OpenCL的设备端和主机端传递struct本身就是一个错误.
(B) 凑合勉强使用. 但修补你的struct使它尽量在Host和Device间以致.
例如如果你这里其他元素都能布局一致(特别小心指针). 而已经定位问题在Point上, 可以考虑尽量通过1个4B的元素(例如float或者int)的padding, 来修补成一致.

但(B)方案不建议. 这只能凑合, 依然有潜伏的BUG. 特别是当你更换编译环境的时候.

Regards,
屠戮人神.