我在教程中看到过这两个版本,但我找不到它们的优点和缺点。哪一个是合适的?
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);
VS
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL);
感谢。
[更新]
我在第二个示例中添加了CL_MEM_COPY_HOST_PTR,
以使其正确。
答案 0 :(得分:9)
在我使用OpenCL期间,我发现了
之间非常重要的区别cl_mem CT = clCreateImage3DContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , Volume_format, X, Y, Z, rowPitch, slicePitch, sourceData, &error);
和
cl_mem CT = clCreateImage3D(Context, CL_MEM_READ_ONLY , Volume_format, X, Y, Z, 0, 0, 0, &error);
error = clEnqueueWriteImage(CommandQue, CT, CL_TRUE, origin, region, rowPitch, slicePitch, sourceData, 0, 0, 0);
对于第一种方法,OpenCL会将主机指针不直接复制到GPU。首先,它会在主机上分配第二个临时缓冲区,如果你把像CT这样的大东西加载到GPU上会导致问题。在短时间内,所需的内存是CT大小的两倍。此功能也不会复制数据。它在参数设置期间被复制到使用3D图像对象的内核函数。
第二种方法直接将数据复制到GPU。 OpenCL没有进行额外的分配。我认为这对于普通缓冲对象可能是相同的。
答案 1 :(得分:6)
我假设inputdata不是NULL。
在这种情况下,第二种方法根本不起作用,因为规范说明,clCreateBuffer返回NULL并出现错误,如果:
CL_INVALID_HOST_PTR如果host_ptr为NULL并且在标志中设置了CL_MEM_USE_HOST_PTR或CL_MEM_COPY_HOST_PTR,或者host_ptr不是NULL但是在标志中没有设置CL_MEM_COPY_HOST_PTR或CL_MEM_USE_HOST_PTR。
所以你的意思是
clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);
或
clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);
第一个应该与您展示的第一个方法大致相同,而第二个实际上不会复制数据,而是使用提供的内存位置进行缓冲存储(缓存部分或全部缓存)设备内存)。这两者中哪一个更好取决于使用场景。
Personaly我更喜欢使用第一步分配缓冲区的两步方法,然后用writeToBuffer填充它,因为我发现更容易看到发生了什么(当然一步可能更快(或者它可能不会,这只是一个猜))
答案 2 :(得分:3)
第一种方法的优点是“clEnqueueWriteBuffer”允许您将事件分配给缓冲区的副本。因此,假设您想要使用GPU_Profiling选项测量将数据复制到GPU所需的时间,您可以使用第一种方法,但不能使用第二种方法。
第二种方法更紧凑,更易于阅读,并且需要更少的代码行。
答案 3 :(得分:2)
我遇到的一个主要区别是:
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);
第一组命令将创建一个空缓冲区并在命令队列中排队命令以填充缓冲区。
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL)
第二个命令将创建缓冲区并立即填充。请注意,此参数列表中没有命令队列,因此它现在使用输入数据的内容。
如果您已经运行了CL代码并且源指针依赖于命令队列中的前一个命令完成(例如,排队读取先前的输出缓冲区),那么您肯定想要使用第一种方法。如果您尝试在单个命令中创建并填充缓冲区,则最终会出现一个竞争条件,在该条件下,缓冲区内容将无法在完成先前的缓冲区读取时正常等待。
答案 4 :(得分:1)
这两者之间的主要区别在于第一个在设备上分配内存然后将数据复制到该内存。第二个只分配。
或者您的意思是clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);
?