我有以下OpenCL内核,高斯模糊
__constant sampler_t sampler =
CLK_NORMALIZED_COORDS_FALSE |
CLK_ADDRESS_CLAMP_TO_EDGE |
CLK_FILTER_NEAREST;
__constant float gaussian_kernel[3][3] = {
{0.0625f, 0.125f, 0.0625f},
{0.125f, 0.25f, 0.125f},
{0.0625f, 0.125f, 0.0625f} };
void kernel gaussian_blur(
read_only image2d_t input_image,
write_only image2d_t output_image) {
int x = get_global_id(0);
int y = get_global_id(1);
int2 coords[9] = {
{ x - 1, y - 1 }, { x, y - 1 }, { x + 1, y - 1 },
{ x - 1, y }, { x, y }, { x + 1, y },
{ x - 1, y + 1 }, { x, y + 1 }, { x + 1, y + 1 }
};
float4 pixel_value = { 0.f, 0.f, 0.f, 0.f };
for(int i = 0; i < 3; ++i) {
for(int j = 0; j < 3; ++j) {
int index = i * 3 + j;
float4 blurred =
as_float4(read_imageui(input_image, sampler, coords[index]));
pixel_value.x += (blurred.x * gaussian_kernel[i][j]);
pixel_value.y += (blurred.y * gaussian_kernel[i][j]);
pixel_value.z += (blurred.z * gaussian_kernel[i][j]);
pixel_value.w += (blurred.w * gaussian_kernel[i][j]);
}
}
uint4 final_value = as_uint4(pixel_value);
write_imageui(output_image, coords[4], final_value);
}
Run Code Online (Sandbox Code Playgroud)
当我指定要用作CPU的设备时,模糊效果正常.这是设备选择代码
std::vector<cl::Platform> all_platforms;
cl::Platform::get(&all_platforms);
if(all_platforms.size() == 0) {
std::cerr << "No platforms available" <<std::endl;
exit(-1);
}
cl::Platform default_platform = all_platforms[0];
std::vector<cl::Device> all_devices;
default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);
if(all_devices.size() == 0) {
std::cerr << "No device found" << std::endl;
exit(-1);
}
cl::Device default_device = all_devices[1]; //Changing this index to 0 uses my graphics card
Run Code Online (Sandbox Code Playgroud)
现在,如果default_device设置为GPU,则程序仅输出空图像.相关的图像设置代码是(注意input
是a Magick::Image
和in_pixels
堆分配的数组unsigned short
):
cl::ImageFormat format(CL_RGBA, CL_UNSIGNED_INT16);
cl::Image2D input_image_buffer;
input.write(0, 0,
input.baseColumns(), input.baseRows(), "RGBA", Magick::ShortPixel, in_pixels);
input_image_buffer = cl::Image2D(
context,
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
format,
input.baseColumns(),
input.baseRows(),
0,
in_pixels,
&cl_error);
cl::Image2D output_image_buffer;
output_image_buffer = cl::Image2D(
context,
CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
format,
input.baseColumns(),
input.baseRows(),
0,
out_pixels,
&cl_error);
Run Code Online (Sandbox Code Playgroud)
内核设置/图像输出代码(gaussian_program
当然没有错误构建)
cl::Kernel gaussian_kernel(gaussian_program, "gaussian_blur");
cl::CommandQueue queue(context, default_device, 0, &cl_error);
cl::size_t<3> origin;
cl::size_t<3> size;
origin[0] = 0;
origin[1] = 0;
origin[2] = 0;
size[0] = input.baseColumns();
size[1] = input.baseRows();
size[2] = 1;
cl_error = gaussian_kernel.setArg(0, input_image_buffer);
cl_error = gaussian_kernel.setArg(1, output_image_buffer);
cl::NDRange range(input.baseColumns(), input.baseRows());
cl_error = queue.enqueueNDRangeKernel(
gaussian_kernel,
cl::NullRange,
range,
cl::NullRange);
queue.finish();
try{
output.read(
input.baseColumns(),
input.baseRows(),
"RGBA", Magick::ShortPixel, out_pixels);
}
catch(Magick::Exception& ex) {
std::cerr << "A Magick error occured while writing the pixel cache: " <<
std::endl << ex.what() << std::endl;
return false;
}
Run Code Online (Sandbox Code Playgroud)
现在,我为此示例的目的删除了大量错误检查,但原始代码在每次OpenCL调用后检查cl_error,并且从不发出错误信号.代码在CPU上按预期执行,但代码在GPU上执行时图像为空.
我一开始怀疑是同步问题(queue.finish()
即使在CPU上也需要调用这个精确的目的),但是在尝试序列化执行时乱丢代码cl::finish()
或queue.finish()
调用代码根本没有帮助.
有什么我显然做错了吗?这个OpenCL内核是否有可能在GPU上出现故障而在CPU上出现故障?
为了记录,我使用AMD APP SDK OpenCL实现和Radeon HD 7970在Ubuntu 13.04上.
那么,你从哪里读取GPU的图像?
您使用标志分配输入图像 CL_MEM_COPY_HOST_PTR
仅当host_ptr不为NULL时,此标志才有效.如果指定,则表示应用程序希望OpenCL实现为内存对象分配内存,并从host_ptr引用的内存中复制数据.
和你的输出图像 CL_MEM_USE_HOST_PTR
仅当host_ptr不为NULL时,此标志才有效.如果指定,则表示应用程序希望OpenCL实现使用host_ptr引用的内存作为内存对象的存储位.
允许OpenCL实现将host_ptr指向的缓冲区内容缓存在设备内存中.在设备上执行内核时,可以使用此缓存副本.
对使用相同host_ptr或重叠主机区域创建的多个缓冲区对象进行操作的OpenCL命令的结果被视为未定义.
您的分配没有任何问题,但是您从未告诉OpenCL实现将内存写入已使用的设备并将该内存读回主机主内存.这可能适用于CPU,因为内存已经在其设备内存(主内存)中,但GPU无法运行.
OpenCL c ++绑定提供cl::enqueueWriteImage(/*params*/);
和cl::enqueueReadImage(/*params*/);
向设备写入和读取图像缓冲区.