31个版本

0.9.5 2023年12月22日
0.9.4 2023年11月5日
0.9.3 2023年5月11日
0.9.2 2022年12月30日
0.1.0 2020年12月31日

#22 in 图形API

Download history 605/week @ 2024-04-06 555/week @ 2024-04-13 621/week @ 2024-04-20 461/week @ 2024-04-27 686/week @ 2024-05-04 581/week @ 2024-05-11 547/week @ 2024-05-18 546/week @ 2024-05-25 496/week @ 2024-06-01 524/week @ 2024-06-08 410/week @ 2024-06-15 495/week @ 2024-06-22 243/week @ 2024-06-29 236/week @ 2024-07-06 407/week @ 2024-07-13 371/week @ 2024-07-20

1,293 每月下载量
30 个工具包中使用 (5 直接)

Apache-2.0

315KB
6K SLoC

opencl3

crates.io docs.io OpenCL 3.0 License Rust

Khronos OpenCL API的Rust实现。

描述

OpenCL 3.0 API的相对简单、基于对象的模型。
它建立在cl3工具包之上,该工具包为OpenCL C API提供了功能接口。

OpenCL (开放计算语言)是一个用于跨异构设备(包括:CPU、GPU、DSP、FPGA和其他处理器或硬件加速器)进行通用并行编程的框架。它通常被视为Nvidia专有计算统一设备架构CUDA的开源替代品,用于在GPU上进行通用计算,请参阅GPGPU

OpenCL 3.0是一个统一规范,在之前的OpenCL版本中添加了很少的新功能。
它规定所有OpenCL 1.2功能都是强制性的,而所有OpenCL 2.x和3.0功能现在是可选的。

特性

这个库具有以下特性:

设计

该库基于对象,大多数 OpenCL 对象都由 Rust 结构体表示。例如,OpenCL 的 cl_device_idDevice 结构体表示,它提供获取设备信息的方法,而不是使用带有相关 cl_device_info 值的 clGetDeviceInfo 调用。

OpenCL Context
OpenCL 上下文类图

结构体方法比在 cl3 中的独立函数更易使用,因为它们将 InfoType 枚举转换为由 clGetDeviceInfo 调用返回的 cl_device_info 值的正确基础类型。

几乎所有结构体都实现了 Drop 特性以释放其对应的 OpenCL 对象。例外是 PlatformDevice,它们不需要释放。请参阅 文档

OpenCL 版本和扩展的 API 由 Rust 功能(如 "CL_VERSION_2_0" 和 "cl_khr_gl_sharing")控制。要启用 OpenCL 版本,必须启用该版本的特性和 所有 之前的 OpenCL 版本的特性,例如对于 "CL_VERSION_2_0";还必须启用 "CL_VERSION_1_1" 和 "CL_VERSION_1_2"。

默认特性为 "CL_VERSION_1_1","CL_VERSION_1_2" 和 "CL_VERSION_2_0"。

对于由启用的 OpenCL 版本弃用的 OpenCL API 函数(例如,当 "CL_VERSION_2_0" 启用时,clCreateCommandQueue 被弃用),Rust 将给出弃用警告。

使用

确保已安装 OpenCL 可安装客户端驱动程序(ICD)和相应的 OpenCL 硬件驱动程序,详见 OpenCL 安装

opencl3 默认支持 OpenCL 1.2 和 2.0 ICD 加载器。如果您有 OpenCL 2.0 ICD 加载器,则只需将以下内容添加到项目 Cargo.toml 文件中:

[dependencies]
opencl3 = "0.9"

如果您的 OpenCL ICD 加载器支持更高版本的 OpenCL,则将相应的功能添加到 opencl3 中,例如对于 OpenCL 3.0 ICD 加载器,将以下内容添加到项目 Cargo.toml 文件中:

[dependencies.opencl3]
version = "0.9"
features = ["CL_VERSION_2_1", "CL_VERSION_2_2", "CL_VERSION_3_0"]

也可以通过添加其功能来启用 OpenCL 扩展和 serde 支持,例如:

[dependencies.opencl3]
version = "0.9"
features = ["cl_khr_gl_sharing", "cl_khr_dx9_media_sharing", "serde"]

有关使用 OpenCL 的背景信息,请参阅 OpenCL 指南OpenCL 描述

示例

示例 目录中有示例。测试还提供了如何使用该库的示例,例如:请参阅 platformdevicecontextintegration_testopencl2_kernel_test

该库旨在支持事件和 OpenCL 2 功能,例如共享虚拟内存(SVM)和内置工作组函数。它还提供了可选的 serde 支持。

const PROGRAM_SOURCE: &str = r#"
kernel void inclusive_scan_int (global int* output,
                                global int const* values)
{
    int sum = 0;
    size_t lid = get_local_id(0);
    size_t lsize = get_local_size(0);

    size_t num_groups = get_num_groups(0);
    for (size_t i = 0u; i < num_groups; ++i)
    {
        size_t lidx = i * lsize + lid;
        int value = work_group_scan_inclusive_add(values[lidx]);
        output[lidx] = sum + value;

        sum += work_group_broadcast(value, lsize - 1);
    }
}"#;

const KERNEL_NAME: &str = "inclusive_scan_int";

// Create a Context on an OpenCL device
let context = Context::from_device(&device).expect("Context::from_device failed");

// Build the OpenCL program source and create the kernel.
let program = Program::create_and_build_from_source(&context, PROGRAM_SOURCE, CL_STD_2_0)
    .expect("Program::create_and_build_from_source failed");

let kernel = Kernel::create(&program, KERNEL_NAME).expect("Kernel::create failed");

// Create a command_queue on the Context's device
let queue = CommandQueue::create_default_with_properties(
    &context,
    CL_QUEUE_PROFILING_ENABLE,
    0,
)
.expect("CommandQueue::create_default_with_properties failed");

// The input data
const ARRAY_SIZE: usize = 8;
const VALUE_ARRAY: &str = "[3,2,5,9,7,1,4,2]";

// Create an OpenCL SVM vector
let mut test_values = SvmVec::<cl_int>::new(&context);

// Handle test_values if device only supports CL_DEVICE_SVM_COARSE_GRAIN_BUFFER
if !test_values.is_fine_grained() {
    // SVM_COARSE_GRAIN_BUFFER needs to know the size of the data to allocate the SVM
    test_values = SvmVec::<cl_int>::allocate(&context, ARRAY_SIZE).expect("SVM allocation failed");
    // Map the SVM for a SVM_COARSE_GRAIN_BUFFER
    unsafe { queue.enqueue_svm_map(CL_BLOCKING, CL_MAP_WRITE, &mut test_values, &[])? };
    // Clear the SVM for the deserializer
    test_values.clear();
}

ExtendSvmVec(&mut test_values)
    .deserialize(&mut deserializer)
    .expect("Error deserializing the VALUE_ARRAY JSON string.");

// Make test_values immutable
let test_values = test_values;

// Unmap test_values if not a CL_MEM_SVM_FINE_GRAIN_BUFFER
if !test_values.is_fine_grained() {
    let unmap_test_values_event = unsafe { queue.enqueue_svm_unmap(&test_values, &[])? };
    unmap_test_values_event.wait()?;
}

// The output data, an OpenCL SVM vector
let mut results =
    SvmVec::<cl_int>::allocate(&context, ARRAY_SIZE).expect("SVM allocation failed");

// Run the kernel on the input data
let sum_kernel_event = unsafe {
    ExecuteKernel::new(&kernel)
        .set_arg_svm(results.as_mut_ptr())
        .set_arg_svm(test_values.as_ptr())
        .set_global_work_size(ARRAY_SIZE)
        .enqueue_nd_range(&queue)?
};

// Wait for the kernel to complete execution on the device
kernel_event.wait()?;

// Map results if not a CL_MEM_SVM_FINE_GRAIN_BUFFER
if !results.is_fine_grained() {
    unsafe { queue.enqueue_svm_map(CL_BLOCKING, CL_MAP_READ, &mut results, &[])? };
}

// Convert SVM results to json
let json_results = serde_json::to_string(&results).unwrap();
println!("json results: {}", json_results);

// Unmap results if not a CL_MEM_SVM_FINE_GRAIN_BUFFER
if !results.is_fine_grained() {
    let unmap_results_event = unsafe { queue.enqueue_svm_unmap(&results, &[])? };
    unmap_results_event.wait()?;
}

上述示例取自:opencl2serde.rs

测试

该软件包包含单元测试、文档测试和集成测试。
测试会运行平台和设备信息函数(等等),以便提供关于系统OpenCL功能的有用信息。

建议以单线程模式运行测试,因为当多线程运行时,其中一些可能会相互干扰,例如。

cargo test -- --test-threads=1 --show-output

集成测试被标记为ignore,因此请使用以下命令来运行它们

cargo test -- --test-threads=1 --show-output --ignored

近期更改

自库的0.1版本以来,API已经发生了相当大的变化,目的是使库更一致且易于使用。

SvmVec最近已更改以支持serde反序列化。它还在版本0.5.0中更改,以更好地支持粗粒度缓冲区共享虚拟内存,因为Nvidia现在支持它,请参阅Nvidia OpenCL

在版本0.6.0中,从底层的cl3软件包和该软件包中删除了Info枚举,以便将来可以使用当前未定义的新值从OpenCL设备读取数据。

在版本0.8.0中,对于被启用的OpenCL版本废弃的OpenCL API函数给出弃用警告,例如,当启用"CL_VERSION_2_0"时,clCreateCommandQueue已被废弃。

在版本0.9.0中,许多OpenCL API函数被声明为unsafe,因为如果调用不当可能会引起未定义的行为。

有关其他更改的信息,请参阅版本

贡献

如果您想通过代码或文档进行贡献,贡献指南是开始的最佳位置。如果您有任何问题,请随时提问。但请遵守我们的行为准则

许可证

根据Khronos Group OpenCL,许可协议为Apache License,版本2.0。
您可以在以下位置获得许可证的副本:https://apache.ac.cn/licenses/LICENSE-2.0

您故意提交给包含在作品中的任何贡献,均应按照上述Apache-2.0许可证中的定义进行许可,除非您明确表示否则,无需任何额外条款或条件。

OpenCL和OpenCL标志是Apple Inc.的商标,由Khronos Group许可使用。

依赖项

~1–1.6MB
~35K SLoC