#![allow(clippy::missing_safety_doc)]
pub use cl3::context;
use super::Result;
use super::device::Device;
#[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
use super::device::SubDevice;
#[allow(unused_imports)]
use cl3::dx9_media_sharing;
#[cfg(any(feature = "cl_khr_d3d10_sharing", feature = "dynamic"))]
#[allow(unused_imports)]
use cl3::d3d10;
#[cfg(any(feature = "cl_khr_d3d11_sharing", feature = "dynamic"))]
#[allow(unused_imports)]
use cl3::d3d11;
#[allow(unused_imports)]
use cl3::egl;
#[allow(unused_imports)]
use cl3::ext;
#[allow(unused_imports)]
use cl3::gl;
#[allow(unused_imports)]
use cl3::types::{
cl_context, cl_context_info, cl_context_properties, cl_device_id, cl_device_svm_capabilities,
cl_device_type, cl_event, cl_image_format, cl_mem, cl_mem_flags, cl_mem_object_type, cl_uint,
};
use libc::{c_char, c_void, intptr_t, size_t};
use std::ptr;
#[cfg(any(feature = "cl_khr_gl_sharing", feature = "dynamic"))]
#[allow(clippy::as_ptr_cast_mut)]
pub fn get_current_device_for_gl_context_khr(
properties: &[cl_context_properties],
) -> Result<cl_device_id> {
let device = intptr_t::from(gl::get_gl_context_info_khr(
properties.as_ptr() as *mut cl_context_properties,
gl::CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR,
)?) as cl_device_id;
Ok(device)
}
#[cfg(any(feature = "cl_khr_gl_sharing", feature = "dynamic"))]
#[allow(clippy::as_ptr_cast_mut)]
pub fn get_devices_for_gl_context_khr(
properties: &[cl_context_properties],
) -> Result<Vec<cl_device_id>> {
let dev_ptrs: Vec<intptr_t> = gl::get_gl_context_info_khr(
properties.as_ptr() as *mut cl_context_properties,
gl::CL_DEVICES_FOR_GL_CONTEXT_KHR,
)?
.into();
let devices = dev_ptrs
.iter()
.map(|ptr| *ptr as cl_device_id)
.collect::<Vec<cl_device_id>>();
Ok(devices)
}
#[derive(Debug)]
pub struct Context {
context: cl_context,
devices: Vec<cl_device_id>,
}
impl From<Context> for cl_context {
fn from(value: Context) -> Self {
value.context
}
}
impl Drop for Context {
fn drop(&mut self) {
self.devices.clear();
unsafe { context::release_context(self.context).expect("Error: clReleaseContext") };
}
}
unsafe impl Send for Context {}
unsafe impl Sync for Context {}
impl Context {
fn new(context: cl_context, devices: &[cl_device_id]) -> Self {
Self {
context,
devices: devices.to_vec(),
}
}
pub const fn get(&self) -> cl_context {
self.context
}
pub fn from_devices(
devices: &[cl_device_id],
properties: &[cl_context_properties],
pfn_notify: Option<unsafe extern "C" fn(*const c_char, *const c_void, size_t, *mut c_void)>,
user_data: *mut c_void,
) -> Result<Self> {
let properties_ptr = if !properties.is_empty() {
properties.as_ptr()
} else {
ptr::null()
};
let context = context::create_context(devices, properties_ptr, pfn_notify, user_data)?;
Ok(Self::new(context, devices))
}
pub fn from_device(device: &Device) -> Result<Self> {
let devices: Vec<cl_device_id> = vec![device.id()];
let properties = Vec::<cl_context_properties>::default();
Self::from_devices(&devices, &properties, None, ptr::null_mut())
}
#[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
pub fn from_sub_devices(
sub_devices: &[SubDevice],
properties: &[cl_context_properties],
pfn_notify: Option<unsafe extern "C" fn(*const c_char, *const c_void, size_t, *mut c_void)>,
user_data: *mut c_void,
) -> Result<Self> {
let devices = sub_devices
.iter()
.map(|dev| dev.id())
.collect::<Vec<cl_device_id>>();
Self::from_devices(&devices, properties, pfn_notify, user_data)
}
pub fn from_device_type(
device_type: cl_device_type,
properties: &[cl_context_properties],
pfn_notify: Option<unsafe extern "C" fn(*const c_char, *const c_void, size_t, *mut c_void)>,
user_data: *mut c_void,
) -> Result<Self> {
let properties_ptr = if !properties.is_empty() {
properties.as_ptr()
} else {
ptr::null()
};
let context =
context::create_context_from_type(device_type, properties_ptr, pfn_notify, user_data)?;
let dev_ptrs: Vec<intptr_t> =
context::get_context_info(context, context::CL_CONTEXT_DEVICES)?.into();
let devices = dev_ptrs
.iter()
.map(|ptr| *ptr as cl_device_id)
.collect::<Vec<cl_device_id>>();
Ok(Self::new(context, &devices))
}
pub fn get_svm_mem_capability(&self) -> cl_device_svm_capabilities {
let device = Device::new(self.devices[0]);
let mut svm_capability = device.svm_mem_capability();
for index in 1..self.devices.len() {
let device = Device::new(self.devices[index]);
svm_capability &= device.svm_mem_capability();
}
svm_capability
}
pub fn get_supported_image_formats(
&self,
flags: cl_mem_flags,
image_type: cl_mem_object_type,
) -> Result<Vec<cl_image_format>> {
Ok(cl3::memory::get_supported_image_formats(
self.context,
flags,
image_type,
)?)
}
#[cfg(any(feature = "cl_arm_import_memory", feature = "dynamic"))]
pub unsafe fn import_memory_arm(
&self,
flags: cl_mem_flags,
properties: *const ext::cl_import_properties_arm,
memory: *mut c_void,
size: size_t,
) -> Result<cl_mem> {
unsafe {
Ok(ext::import_memory_arm(
self.context,
flags,
properties,
memory,
size,
)?)
}
}
#[allow(clippy::missing_const_for_fn)]
pub fn devices(&self) -> &[cl_device_id] {
&self.devices
}
pub fn default_device(&self) -> cl_device_id {
self.devices[0]
}
pub fn num_devices(&self) -> cl_uint {
self.devices.len() as cl_uint
}
#[cfg(any(feature = "CL_VERSION_3_0", feature = "dynamic"))]
#[inline]
pub fn set_destructor_callback(
&self,
pfn_notify: Option<unsafe extern "C" fn(cl_context, *mut c_void)>,
user_data: *mut c_void,
) -> Result<()> {
context::set_context_destructor_callback(self.context, pfn_notify, user_data)
.map_err(Into::into)
}
pub fn reference_count(&self) -> Result<cl_uint> {
Ok(context::get_context_info(self.context, context::CL_CONTEXT_REFERENCE_COUNT)?.into())
}
pub fn properties(&self) -> Result<Vec<intptr_t>> {
Ok(context::get_context_info(self.context, context::CL_CONTEXT_PROPERTIES)?.into())
}
pub fn get_data(&self, param_name: cl_context_info) -> Result<Vec<u8>> {
Ok(context::get_context_data(self.context, param_name)?)
}
#[cfg(any(feature = "cl_khr_terminate_context", feature = "dynamic"))]
pub unsafe fn terminate(&self) -> Result<()> {
unsafe { Ok(ext::terminate_context_khr(self.context)?) }
}
#[cfg(any(feature = "cl_khr_gl_sharing", feature = "dynamic"))]
pub fn create_event_from_gl_sync_khr(&self, sync: gl::cl_GLsync) -> Result<cl_event> {
Ok(gl::create_event_from_gl_sync_khr(self.context, sync)?)
}
#[cfg(any(feature = "cl_khr_egl_event", feature = "dynamic"))]
pub unsafe fn create_event_from_egl_sync_khr(
&self,
sync: egl::CLeglSyncKHR,
display: egl::CLeglDisplayKHR,
) -> Result<cl_event> {
unsafe {
Ok(egl::create_event_from_egl_sync_khr(
self.context,
sync,
display,
)?)
}
}
#[cfg(any(feature = "cl_khr_semaphore", feature = "dynamic"))]
pub fn create_semaphore_with_properties_khr(
&self,
sema_props: *const ext::cl_semaphore_properties_khr,
) -> Result<cl_mem> {
Ok(ext::create_semaphore_with_properties_khr(
self.context,
sema_props,
)?)
}
#[cfg(any(
feature = "cl_khr_dx9_media_sharing",
feature = "cl_intel_dx9_media_sharing",
feature = "dynamic"
))]
pub fn get_supported_dx9_media_surface_formats_intel(
&self,
flags: cl_mem_flags,
image_type: cl_mem_object_type,
plane: cl_uint,
) -> Result<Vec<cl_uint>> {
Ok(unsafe {
dx9_media_sharing::get_supported_dx9_media_surface_formats_intel(
self.context,
flags,
image_type,
plane,
)
}?)
}
#[cfg(any(feature = "cl_khr_d3d10_sharing", feature = "dynamic"))]
pub fn get_supported_d3d10_texture_formats_intel(
&self,
flags: cl_mem_flags,
image_type: cl_mem_object_type,
) -> Result<Vec<cl_uint>> {
Ok(unsafe {
d3d10::get_supported_d3d10_texture_formats_intel(self.context, flags, image_type)
}?)
}
#[cfg(any(feature = "cl_khr_d3d11_sharing", feature = "dynamic"))]
pub fn get_supported_d3d11_texture_formats_intel(
&self,
flags: cl_mem_flags,
image_type: cl_mem_object_type,
plane: cl_uint,
) -> Result<Vec<cl_uint>> {
Ok(unsafe {
d3d11::get_supported_d3d11_texture_formats_intel(self.context, flags, image_type, plane)
}?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::device::Device;
use crate::platform::get_platforms;
use cl3::device::CL_DEVICE_TYPE_GPU;
use cl3::info_type::InfoType;
use cl3::memory::{CL_MEM_OBJECT_IMAGE2D, CL_MEM_READ_WRITE};
#[test]
fn test_context() {
let platforms = get_platforms().unwrap();
assert!(0 < platforms.len());
let platform = &platforms[0];
let devices = platform.get_devices(CL_DEVICE_TYPE_GPU).unwrap();
assert!(0 < devices.len());
let device = Device::new(devices[0]);
let context = Context::from_device(&device).unwrap();
println!(
"CL_DEVICE_SVM_CAPABILITIES: {:X}",
context.get_svm_mem_capability()
);
println!(
"clGetSupportedImageFormats:\norder: data_type {}",
InfoType::VecImageFormat(
context
.get_supported_image_formats(CL_MEM_READ_WRITE, CL_MEM_OBJECT_IMAGE2D)
.unwrap()
)
);
println!(
"CL_CONTEXT_REFERENCE_COUNT: {}",
context.reference_count().unwrap()
);
println!("CL_CONTEXT_PROPERTIES: {:?}", context.properties().unwrap());
}
#[test]
fn test_context_from_device_type() {
let properties = Vec::<cl_context_properties>::default();
let context =
Context::from_device_type(CL_DEVICE_TYPE_GPU, &properties, None, ptr::null_mut());
match context {
Ok(value) => {
println!("Context num devices: {}", value.num_devices())
}
Err(e) => println!("OpenCL error, Context::from_device_type: {}", e),
}
}
}