OpenCL切换显卡的例子

在一些有多个显卡,比如一个核芯显卡和一个独立显卡的系统中使用显卡加速,OpenCL默认的设备可能不是性能更好的独立显卡。这时候可以用下述方法更换显卡,代码如下。本例在VS2015和OpenCL3.0下测试通过:

const string kernel = u8R"(
    kernel void reduceSum(global int* num, global int* result)
    {
        unsigned int id = get_global_id(0); 
        result[id] = 2 * num[id];
    })";

void main()
{
    cl::Platform device = cl::Platform::getDefault();
    const int which = 0; /* 指定显卡索引 */

    cl::vector<cl::Device> devs;
    device.getDevices(CL_DEVICE_TYPE_ALL, &devs);
    string name;
    devs[which].getInfo(CL_DEVICE_NAME, &name); /* 设备名称 */

    cl::Context context(devs[which]);
    cl::CommandQueue queue(context);
    cl::Program program(context, kernel);

    try {
        program.build("-cl-std=CL2.0");
    }
    catch (...) {
        cl_int buildErr = CL_SUCCESS;
        auto buildInfo = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(&buildErr);
        for (auto &pair : buildInfo) {
            std::cerr << pair.second << std::endl << std::endl;
        }
    }
    auto kernelFunc = cl::KernelFunctor<cl::Buffer, cl::Buffer>(program, "reduceSum");
    vector<int> array1(100000, 1);
    vector<int> result1(100000, 0);

    int64 t1, t2;
    t1 = getTickCount();

    cl::Buffer inputBuffer(queue, array1.begin(), array1.end(), true);
    cl::Buffer outputBuffer(queue, result1.begin(), result1.end(), false);
    kernelFunc(cl::EnqueueArgs(queue, cl::NDRange(100000)), inputBuffer, outputBuffer);
    cl::copy(queue, outputBuffer, result1.begin(), result1.end());

    t2 = getTickCount();
    qDebug() << (t2 - t1) / getTickFrequency() * 1000 << "ms" << endl;
}

本人是自学OpenCL的,一开始由于不知道cl::Buffer的构造函数和cl::copy(...)函数有多个重载可以指定Context或CommandQueue参数导致调了几天都没有测试成功。表现就是编译正确但是运行的时候核函数输出不对。这里需要注意下,OpenCL的传输数据和输入核函数的操作基本上都是基于CommandQueue的,需要指定一个命令队列。如果不指定则函数内部会取默认命令队列操作。

上述代码中的getTickCount()是OpenCV中的函数,qDebug()是Qt的输出文本的函数,如不需要可以删掉。它们不影响OpenCL的运行。

posted @ 2024-02-23 17:08  兜尼完  阅读(17)  评论(0编辑  收藏  举报