【发布时间】:2023-03-16 06:39:01
【问题描述】:
当我使用本地缓冲区复制 OpenCL 内核中的数据时,我遇到了意外的结果。此处提供的代码非常简单(而且无用,因为我不需要使用本地缓冲区进行此类操作),但这是类似卷积过程的第一步。
这是我的代码:
std::string implementCopyFromLocalKernel()
{
return BOOST_COMPUTE_STRINGIZE_SOURCE(
__kernel void copyFromLocal_knl(__global const float* in,
const ulong sizeX, const ulong sizeY,
const int filterRadiusX, const int filterRadiusY,
__local float* localImage,
const ulong localSizeX, const ulong localSizeY,
__global float* out)
{
// Store each work-item’s unique row and column
const int x = get_global_id(0);
const int y = get_global_id(1);
// Group size
int groupSizeX = get_local_size(0);
int groupSizeY = get_local_size(1);
// Determine the size of the work group output region
int groupIdX = get_group_id(0);
int groupIdY = get_group_id(1);
// Determine the local ID of each work item
int localX = get_local_id(0);
int localY = get_local_id(1);
// Padding
int paddingX = filterRadiusX;
int paddingY = filterRadiusY;
// Cache the data to local memory
// Copy the data for the current coordinates
localImage[localX + localY*localSizeX] = in[x + y * sizeX];
barrier(CLK_LOCAL_MEM_FENCE);
out[x + y * sizeX] = localImage[localX + localY*localSizeX];
return;
}
);
}
void copyLocalBuffer(const boost::compute::context& context, boost::compute::command_queue& queue, const boost::compute::buffer& bufInn boost::compute::buffer& bufOut, const size_t sizeX, const size_t sizeY)
{
const size_t nbPx = sizeX * sizeY;
const size_t maxSize = (sizeX > sizeY ? sizeX : sizeY);
// Prepare to launch the kernel
std::string kernel_src = implementCopyFromLocalKernel();
boost::compute::program program;
try {
program = boost::compute::program::create_with_source(kernel_src, pGpuDescription->getContext(deviceIdx));
program.build();
}
catch (const boost::compute::opencl_error& e) {
std::cout << "Error bulding program from source : " << std::endl << e.what() << std::endl
<< program.build_log() << std::endl;
return;
}
boost::compute::kernel kernel;
try {
kernel = program.create_kernel("copyFromLocal_knl");
}
catch (const boost::compute::opencl_error& e) {
std::cout << "Error creating kernel : " << std::endl << e.what() << std::endl;
return;
}
try {
int localSizeX = 16;
int localSizeY = 16;
int paddingPixelsX = 2;// 0; // <- Changing to 0 works
int paddingPixelsY = paddingPixelsX;
int localWidth = localSizeX + 2 * paddingPixelsX;
int localHeight = localSizeY + 2 * paddingPixelsY;
boost::compute::buffer localImage(context, localWidth*localHeight * sizeof(float));
kernel.set_arg(0, bufIn);
kernel.set_arg(1, sizeX);
kernel.set_arg(2, sizeY);
kernel.set_arg(3, paddingPixelsX);
kernel.set_arg(4, paddingPixelsY);
kernel.set_arg(5, localImage);
kernel.set_arg(6, localWidth);
kernel.set_arg(7, localHeight);
kernel.set_arg(8, bufOut);
}
catch (const boost::compute::opencl_error& e) {
std::cout << "Error setting kernel arguments: " << std::endl << e.what() << std::endl;
return;
}
try {
size_t origin[2] = { 0, 0 };
size_t region[2] = { 256, 256 };// { sizeX, sizeY };
size_t localSize[2] = { 16, 16 };
queue.enqueue_nd_range_kernel(kernel, 2, origin, region, localSize);
}
catch (const boost::compute::opencl_error& e) {
std::cout << "Error executing kernel : " << std::endl << e.what() << std::endl;
return;
}
}
我将代码简化为简单地复制与本地图像相关的本地坐标中的每个工作项对应的像素。因此,本地图像缓冲区的每一行都必须有2*paddingPixelsX 和2*paddingPixelsY 未使用行的未使用数据。
如果我不添加填充数据(paddingPixelsX 和paddingPixelsY = 0)它可以工作,但似乎某些工作项不会从输入缓冲区读取数据或将数据写入输出缓冲区(或本地缓冲区?)在正确的位置。而且,当我多次运行我的程序时,我从来没有得到相同的结果。
我确保线程与barrier(CLK_LOCAL_MEM_FENCE); 同步,并且每个工作项读取和写入特定数据,如果我的代码有错误,我不明白为什么没有填充不会出错。
有人有想法吗?
谢谢,
【问题讨论】:
-
我不确定在许多工作组上下文中传递本地内存缓冲区作为内核参数是否是正确的方法,因为似乎只有一个本地缓冲区实例被传递。您可以尝试在内核中实例化本地缓冲区吗?例如:
__local float localImage[16*16];. -
感谢您的帮助!我将缓冲区作为参数传递,因为我事先不知道填充,所以我不能静态分配缓冲区。不过,您指出了问题:所有工作组都使用相同的缓冲区。我需要为每个工作组设置一个专用缓冲区。
标签: c++ image-processing boost parallel-processing opencl