我在OpenCL设备(GPU)上创建了一个缓冲区,从主机我需要知道全局设备上的指针地址,以便我可以将该设备上的地址放在另一个缓冲区中,这样内核就可以了从包含第一个缓冲区地址的缓冲区中读取,然后它可以访问该缓冲区的内容。
如果这让我感到困惑,那就是我想要做的事情:我创建一个包含代表2D图像的通用浮动缓冲区,然后从主机创建一个所有的todo列表我的内核需要绘制的东西,哪些行,哪些圈子,哪些图像......所以从该列表中内核必须知道在哪里找到该图像,但是对该图像的引用不能作为内核参数传递,因为该内核根据列表所说的内容,可能不会绘制任何图像或一千个不同的图像,因此必须在该缓冲区中引用它作为内核的待办事项列表。
为此,我尝试在创建获取缓冲区的图像缓冲区后创建一个调用内核的函数,并在另一个缓冲区中将全局设备上的地址作为ulong返回,然后主机将该值存储在64中位整数,如下所示:
uint64_t get_clmem_device_address(clctx_t *clctx, cl_mem buf)
{
const char kernel_source[] =
"kernel void get_global_ptr_address(global void *ptr, global ulong *devaddr) \n"
"{ \n"
" *devaddr = (ulong) ptr; \n"
"} \n";
int32_t i;
cl_int ret;
static int init=1;
static cl_program program;
static cl_kernel kernel;
size_t global_work_size[1];
static cl_mem ret_buffer;
uint64_t devaddr;
if (init)
{
init=0;
ret = build_cl_program(clctx, &program, kernel_source);
ret = create_cl_kernel(clctx, program, &kernel, "get_global_ptr_address");
ret_buffer = clCreateBuffer(clctx->context, CL_MEM_WRITE_ONLY, 1*sizeof(uint64_t), NULL, &ret);
}
if (kernel==NULL)
return ;
// Run the kernel
ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), &buf);
ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), &ret_buffer);
global_work_size[0] = 1;
ret = clEnqueueNDRangeKernel(clctx->command_queue, kernel, 1, NULL, global_work_size, NULL, 0, NULL, NULL); // enqueue the kernel
ret = clEnqueueReadBuffer(clctx->command_queue, ret_buffer, CL_FALSE, 0, 1*sizeof(uint64_t), &devaddr, 0, NULL, NULL); // copy the value
ret = clFlush(clctx->command_queue);
clFinish(clctx->command_queue);
return devaddr;
}
显然这是有效的(它确实会返回一个数字,虽然它很难知道它是否正确)但是我把这个devaddr
(主机上的64位整数) )在内核用来知道该做什么的todo列表缓冲区中,然后在必要时(根据列表)内核调用下面的函数,le
这里是指向todo列表中相关条目的指针,64位地址是第一个元素:
float4 blit_sprite(global uint *le, float4 pv)
{
const int2 p = (int2) (get_global_id(0), get_global_id(1));
ulong devaddr;
global float4 *im;
int2 im_dim;
devaddr = ((global ulong *) le)[0]; // global address for the start of the image as a ulong
im_dim.x = le[2];
im_dim.y = le[3];
im = (global float4 *) devaddr; // ulong is turned into a proper global pointer
if (p.x < im_dim.x)
if (p.y < im_dim.y)
pv += im[p.y * im_dim.x + p.x]; // this gives me a CL_OUT_OF_RESOURCES error, even when changing it to im[0]
return pv;
}
但是很大的意外,这不起作用,它给了我一个CL_OUT_OF_RESOURCES错误,我认为这意味着我的实际上它有效,当我使用两种不同的上下文时,它没有工作。但它仍然非常笨拙。im
指针不是有效的。
有什么不那么奇怪的方式来做我想做的事情吗?
答案 0 :(得分:1)
OpenCL标准并不保证内核对象不会在内核调用之间进行物理重新分配。因此,原始设备端地址仅在单个内核NDRange中有效。这就是为什么OpenCL内存对象在主机端表示为透明结构指针的原因之一。
但是,您可以将偏移量保存到内存对象的第一个内核中的第一个字节,并将其传递给第二个内核。每次启动内核时,您都将获得内核中的实际设备端地址。通过保存的移位值增加它。那将是完美的&#34;合法&#34;。