【问题标题】:OpenCL How to write vector of floats to image2d_tOpenCL如何将浮点向量写入image2d_t
【发布时间】:2021-09-14 17:55:51
【问题描述】:

对于我编写的 OpenCL 程序,我需要对灰度图像进行计算。这些灰度图像以 .pgm 格式存储,我将它们作为浮点向量读入我的程序。

据我了解 image2d_t 内存对象,每个像素都被编码为具有 4 个组件的 OpenCL 矢量数据类型,例如float4 与我的情况一样,其中组件 1 到 3 对 3 个颜色通道 R、G、B 中的颜色值进行编码,第四个组件对亮度或 alpha 进行编码。因此,我尝试炸毁现有图像以将其读入 image2d_t 内存对象,如下所示:

std::vector<float> A(256,0.0);
std::vector<float> A_img(1024, 0.0);

for(int i=0; i<256; i++)
{
    A_img[4*i] = A[i];
    A_img[(4*i)+3] = 1;
}

稍后在将此向量复制到 image2d_t 对象的过程中,我的设备的小端序可能会导致组件 1 和 4 被切换。我不确定。

但是,当将此图像写入我的 GPU 内存、让内核读取它、将其写入输出图像并从 GPU 内存读回时,我无法取回该图像。一个最小的工作示例(对于 OpenCL 来说总是有点长)如下:

#define CL_HPP_TARGET_OPENCL_VERSION 120
#define CL_HPP_MINIMUM_OPENCL_VERSION 120
#if defined(__APPLE__) 
#include <OpenCL/cl2.hpp>
#else 
#include <CL/cl2.hpp>
#endif
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

int main(void)
{
    // Set up platform, device and context
    std::vector<cl::Platform> platforms;
    std::vector<cl::Device> devices;
    cl::Device default_device;
    cl::Platform::get(&platforms);
    
    if (platforms.size() == 0)
    {
        std::cout << "No OpenCL platform found, check installation!" << std::endl;
        exit(-1);
    }
    platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices);
    
    if (devices.size() == 0)
    {
        std::cout << "No devices found in platform, check installation!" << std::endl;
        exit(-1);
    }
    default_device = devices[0];
    cl::Context context(default_device);
    
    std::ifstream program_file("read_write_image.cl");
    std::string program_string(std::istreambuf_iterator<char>(program_file), (std::istreambuf_iterator<char>()));
    cl::Program::Sources source { program_string };
    cl::Program dummy_program(context, source);
    if (dummy_program.build()!=CL_SUCCESS)
    {
        std::cout << "Error building: " << dummy_program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device)<< std::endl;
        exit(-1);
    }
    cl::Kernel kernel(dummy_program, "read_write_image");
    cl::CommandQueue queue(context, default_device);
    
    // Set up dummy grayscale image
    std::vector<float> A(256, 0.0);
    for(int i=0; i<256; i++)
    {
        A[i] = 255.0f - i;
        std::cout << A[i] << "  ";
    }
    std::cout << std::endl;
    
    // Blow up to float4 array
    std::vector<float> A_img(1024, 0.0);
    for(int i=0; i<256; i++)
    {
        A_img[4*i] = A[i];
        A_img[(4*i)+3] = 1;
    }
    std::vector<float> B_img(1024, 0.0);
    
    cl::ImageFormat grayscale(CL_R, CL_FLOAT);
    cl::Image2D Input_Image(context, CL_MEM_READ_ONLY, grayscale, 16, 16);
    cl::Image2D Output_Image(context, CL_MEM_WRITE_ONLY, grayscale, 16, 16);
    
    std::array<cl::size_type, 3> origin {0,0,0};
    std::array<cl::size_type, 3> region {16, 16, 1};

    queue.enqueueWriteImage(Input_Image, CL_TRUE, origin, region, 0, 0, &A_img[0]);

    kernel.setArg(0, Input_Image);
    kernel.setArg(1, Output_Image);
    
    queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(16,16), cl::NullRange, NULL); 
    queue.enqueueReadImage(Output_Image, CL_TRUE, origin, region, 0, 0, &B_img[0]);

    for(int i=0; i<1024; i++)
    {
        std::cout << B_img[i] << "  ";
    }   
    std::cout << std::endl;
    
    return EXIT_SUCCESS;
}

内核代码(要放在“read_write_image.cl”文件中)如下:

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE|CLK_ADDRESS_CLAMP|CLK_FILTER_LINEAR;

__kernel void read_write_image(read_only image2d_t input_image, write_only image2d_t output_image)
{
    int i = get_global_id(0);
    int j = get_global_id(1);
    float tmp = read_imagef(input_image, sampler, (int2) (i,j)).x;
    write_imagef(output_image, (int2) (i,j), (float4) (tmp,0,0,1));
}

这个最小的工作示例生成一个 16x16 的图像 A,它被解释为灰度图像,从左上角以白色像素开始,到右下角以黑色像素结束,然后读回图像 B我的系统完全是黑色的,即只有零。我在什么时候会出错?

【问题讨论】:

    标签: c++ image image-processing opencl gpgpu


    【解决方案1】:

    第一件事:

    • 我的系统的小端序在将数组读入图像的过程中不会恢复坐标的顺序
    • 尽管 read_imagef 和 write_imagef 与 float4s 一起使用,但并非每个 image_2dt 都是 float4 数组。从代码中删除“爆炸”部分并仅使用常规缓冲区使该示例成为一个工作示例。但是,(对图像格式的)支持似乎取决于平台,在我的 Macbook 上它不能适应这些变化,在我的 AMD 显卡上它可以工作

    这里是修改后的主机代码:

    #define CL_HPP_TARGET_OPENCL_VERSION 120
    #define CL_HPP_MINIMUM_OPENCL_VERSION 120
    #if defined(__APPLE__) 
    #include <OpenCL/cl2.hpp>
    #else 
    #include <CL/cl2.hpp>
    #endif
    #include <iostream>
    #include <string>
    #include <vector>
    #include <fstream>
    
    int main(void)
    {
        // Set up platform, device and context
        std::vector<cl::Platform> platforms;
        std::vector<cl::Device> devices;
        cl::Device default_device;
        cl::Platform::get(&platforms);
        
        if (platforms.size() == 0)
        {
            std::cout << "No OpenCL platform found, check installation!" << std::endl;
            exit(-1);
        }
        platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices);
        
        if (devices.size() == 0)
        {
            std::cout << "No devices found in platform, check installation!" << std::endl;
            exit(-1);
        }
        default_device = devices[0];
        cl::Context context(default_device);
        
        std::ifstream program_file("read_write_image.cl");
        std::string program_string(std::istreambuf_iterator<char>(program_file), (std::istreambuf_iterator<char>()));
        cl::Program::Sources source { program_string };
        cl::Program dummy_program(context, source);
        if (dummy_program.build()!=CL_SUCCESS)
        {
            std::cout << "Error building: " << dummy_program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device)<< std::endl;
            exit(-1);
        }
        cl::Kernel kernel(dummy_program, "read_write_image");
        cl::CommandQueue queue(context, default_device);
        
        // Set up dummy grayscale image
        std::vector<float> A(256, 0.0);
        for(int i=0; i<256; i++)
        {
            A[i] = 255.0f - i;
        }
        // Set up empty target image
        std::vector<float> B(256, 0.0);
        
        cl::ImageFormat grayscale(CL_R, CL_FLOAT);
        cl::Image2D Input_Image(context, CL_MEM_READ_ONLY, grayscale, 16, 16);
        cl::Image2D Output_Image(context, CL_MEM_WRITE_ONLY, grayscale, 16, 16);
        
        std::array<cl::size_type, 3> origin {0,0,0};
        std::array<cl::size_type, 3> region {16, 16, 1};
    
        queue.enqueueWriteImage(Input_Image, CL_TRUE, origin, region, 0, 0, &A[0]);
    
        kernel.setArg(0, Input_Image);
        kernel.setArg(1, Output_Image);
        
        queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(16,16), cl::NullRange, NULL); 
        queue.enqueueReadImage(Output_Image, CL_TRUE, origin, region, 0, 0, &B[0]);
    
        for(int i=0; i<256; i++)
        {
            std::cout << B[i] << "  ";
        }   
        std::cout << std::endl;
        
        return EXIT_SUCCESS;
    }
    

    内核不变。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-26
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多