clEnqueueCopyBufferRect 是如何工作的

How clEnqueueCopyBufferRect is working?

本文关键字:工作 何工作 clEnqueueCopyBufferRect      更新时间:2023-10-16

我需要了解clEnqueueCopyBufferRect是如何工作的。例如,我需要从 4x4 区域(让它成为 int 数组)复制 3x3 区域,原点为 (1,1)。我有两个建议:

  1. 它只是复制大小与矩形 3x3 区域的大小匹配的线性区域,因此结果是:

    1 1 1 1     0 0 0 0
    1 1 1 1  -> 0 1 1 1
    1 1 1 1     1 1 1 1
    1 1 1 1     1 1 0 0
    
  2. 或者它复制矩形区域,结果是:

    1 1 1 1     0 0 0 0
    1 1 1 1  -> 0 1 1 1
    1 1 1 1     0 1 1 1
    1 1 1 1     0 1 1 1
    

为了检查这一点,我使用了下一个示例代码:

int main(int argc, char * argv[])
{
std::vector<Platform> platforms;
Platform::get(&platforms);
cl::Platform platform = platforms[0];
cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform(), 0}; 
cl::Context context(CL_DEVICE_TYPE_GPU,cps);
std::string kr_str = "__kernel void StepKernel(__global int* in) { in[get_global_id(1)*4 + get_global_id(0)] = 1;}";
Program program=cl::Program(
    context,
    cl::Program::Sources(
      1,
      std::make_pair(kr_str.c_str(),kr_str.length()+1)
    )
  );
std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
std::vector<cl::Device> device(1,devices[0]);
program.build(device);
cl::Kernel kernel = cl::Kernel(program, "StepKernel");
cl::CommandQueue queue(
      context,
      device[0],
      CL_NONE
    );  
cl::Buffer in_buffer_on_device(
        context,
        CL_MEM_READ_WRITE,
        16*sizeof(int)
    );
cl::Buffer out_buffer_on_host(
        context,
        CL_MEM_READ_WRITE|CL_MEM_ALLOC_HOST_PTR,
        16*sizeof(int)
    );
void *ptr_on_host = 
queue.enqueueMapBuffer(
    out_buffer_on_host,
    CL_BLOCKING,
    CL_MAP_WRITE|CL_MAP_READ,
    0, 16*sizeof(int),
    NULL, NULL
);
for(int k = 0; k < 4; k++)
  for(int i = 0; i < 4; i++)
    static_cast<int*>(ptr_on_host)[k*4 + i] = 0;        
cl::size_t<3> origin, region;
origin[0]=0; origin[1]=0; origin[2]=0;
region[0]=4*sizeof(int); region[1]=4; region[2]=1;
Event evt;
queue.enqueueCopyBufferRect(
  out_buffer_on_host,
  in_buffer_on_device,          
  origin, origin, region,
  sizeof(int)*4,sizeof(int)*4*4,sizeof(int)*4,sizeof(int)*4*4,
  NULL,
  &evt
);
evt.wait();
kernel.setArg(0,in_buffer_on_device);
queue.enqueueNDRangeKernel(
            kernel, 
            cl::NDRange( 0, 0), 
            cl::NDRange( 4, 4), 
            cl::NullRange, 
            NULL,
            &evt
);
evt.wait();
origin[0]=1*sizeof(int); origin[1]=1; origin[2]=0;
region[0]=3*sizeof(int); region[1]=3; region[2]=1;
queue.enqueueCopyBufferRect(                
  in_buffer_on_device,
  out_buffer_on_host,               
  origin, origin, region,
  sizeof(int)*4,sizeof(int)*4*4,sizeof(int)*4,sizeof(int)*4*4,
  NULL,
  &evt
);  
evt.wait();
for(int k = 0; k < 4; k++)
{
  for(int i = 0; i < 4; i++)
  {
    std::cout << static_cast<int*>(ptr_on_host)[k*4 + i]<< "t";
  }
  std::cout << std::endl;
}
return 0;
}

输出是:

0   0   0   0   
0   1   1   1   
1   1   1   1   
1   1   0   0

因此,如果我没有做任何错误,CL 会复制线性区域。所以这样的行为对我来说毫无用处。

它复制矩形区域。否则,它作为 API 将毫无用处。