opencl3 0.12.3

A Rust implementation of the Khronos OpenCL 3.0 API and extensions.
Documentation
// Copyright (c) 2023 Via Technology Ltd. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use cl3::ext::CL_IMAGE_FORMAT_NOT_SUPPORTED;
use cl3::memory::{CL_MEM_OBJECT_IMAGE2D, CL_MEM_WRITE_ONLY, CL_RGBA, CL_UNSIGNED_INT8};
use cl3::types::{CL_NON_BLOCKING, cl_image_desc, cl_image_format};
use libc::c_void;
use opencl3::Result;
use opencl3::command_queue::{CL_QUEUE_PROFILING_ENABLE, CommandQueue};
use opencl3::context::Context;
use opencl3::device::{CL_DEVICE_TYPE_GPU, Device};
use opencl3::kernel::{ExecuteKernel, Kernel};
use opencl3::memory::Image;
use opencl3::program::{CL_STD_2_0, Program};
use opencl3::types::cl_event;

const PROGRAM_SOURCE: &str = r#"
kernel void colorize(write_only image2d_t image)
{
    const size_t x = get_global_id(0);
    const size_t y = get_global_id(1);
    write_imageui(image, (int2)(x, y), (uint4)(x, y, 0, 255));
}"#;

const KERNEL_NAME: &str = "colorize";

fn main() -> Result<()> {
    // Find a usable platform and device for this application
    let platforms = opencl3::platform::get_platforms()?;
    let platform = platforms.first().expect("no OpenCL platforms");
    let device = *platform
        .get_devices(CL_DEVICE_TYPE_GPU)?
        .first()
        .expect("no device found in platform");
    let device = Device::new(device);

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

    // Print some information about the device
    println!(
        "CL_DEVICE_IMAGE_SUPPORT: {:?}",
        device.image_support().unwrap()
    );
    println!(
        "CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS: {:?}",
        device.max_read_write_image_args().unwrap()
    );
    println!(
        "CL_DEVICE_MAX_READ_IMAGE_ARGS: {:?}",
        device.max_read_image_args().unwrap()
    );
    println!(
        "CL_DEVICE_MAX_WRITE_IMAGE_ARGS: {:?}",
        device.max_write_image_args().unwrap()
    );
    println!(
        "CL_DEVICE_MAX_SAMPLERS: {:?}",
        device.max_device_samples().unwrap()
    );
    let supported_formats =
        context.get_supported_image_formats(CL_MEM_WRITE_ONLY, CL_MEM_OBJECT_IMAGE2D)?;
    if supported_formats
        .iter()
        .filter(|f| {
            f.image_channel_order == CL_RGBA && f.image_channel_data_type == CL_UNSIGNED_INT8
        })
        .count()
        <= 0
    {
        println!("Device does not support CL_RGBA with CL_UNSIGNED_INT8 for CL_MEM_WRITE_ONLY!");
        return Err(CL_IMAGE_FORMAT_NOT_SUPPORTED.into());
    }

    // 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");

    // Create an image
    let mut image = unsafe {
        Image::create(
            &context,
            CL_MEM_WRITE_ONLY,
            &cl_image_format {
                image_channel_order: CL_RGBA,
                image_channel_data_type: CL_UNSIGNED_INT8,
            },
            &cl_image_desc {
                image_type: CL_MEM_OBJECT_IMAGE2D,
                image_width: 10 as usize,
                image_height: 10 as usize,
                image_depth: 1,
                image_array_size: 1,
                image_row_pitch: 0,
                image_slice_pitch: 0,
                num_mip_levels: 0,
                num_samples: 0,
                buffer: std::ptr::null_mut(),
            },
            std::ptr::null_mut(),
        )
        .expect("Image::create failed")
    };

    // Run the kernel on the input data
    let kernel_event = unsafe {
        ExecuteKernel::new(&kernel)
            .set_arg(&image)
            .set_global_work_sizes(&[10usize, 10usize])
            .enqueue_nd_range(&queue)?
    };

    let mut events: Vec<cl_event> = Vec::default();
    events.push(kernel_event.get());

    // Fill the middle of the image with a solid color
    let fill_color = [11u32, 22u32, 33u32, 44u32];
    let fill_event = unsafe {
        queue.enqueue_fill_image(
            &mut image,
            fill_color.as_ptr() as *const c_void,
            &[3usize, 3usize, 0usize] as *const usize,
            &[4usize, 4usize, 1usize] as *const usize,
            &events,
        )?
    };

    let mut events: Vec<cl_event> = Vec::default();
    events.push(fill_event.get());

    // Read the image data from the device
    let mut image_data = [0u8; 10 * 10 * 4];
    let read_event = unsafe {
        queue.enqueue_read_image(
            &image,
            CL_NON_BLOCKING,
            &[0usize, 0usize, 0usize] as *const usize,
            &[10usize, 10usize, 1usize] as *const usize,
            0,
            0,
            image_data.as_mut_ptr() as *mut c_void,
            &events,
        )?
    };

    // Wait for the read_event to complete.
    read_event.wait()?;

    // Print the image data
    println!("image_data: ");
    for y in 0..10 {
        for x in 0..10 {
            let offset = (y * 10 + x) * 4;
            print!(
                "({:>3}, {:>3}, {:>3}, {:>3}) ",
                image_data[offset],
                image_data[offset + 1],
                image_data[offset + 2],
                image_data[offset + 3]
            );
        }
        println!();
    }

    Ok(())
}