blob: e38ab73adab677883a1b28f1e965ea7f3464334c [file]
use crate::api::icd::*;
use crate::core::device::*;
use crate::core::format::*;
use crate::core::memory::*;
use crate::core::util::*;
use crate::impl_cl_type_trait;
use mesa_rust::pipe::resource::*;
use mesa_rust::pipe::screen::ResourceType;
use mesa_rust_util::properties::Properties;
use rusticl_opencl_gen::*;
use std::collections::HashMap;
use std::convert::TryInto;
use std::os::raw::c_void;
use std::sync::Arc;
use std::sync::Mutex;
pub struct Context {
pub base: CLObjectBase<CL_INVALID_CONTEXT>,
pub devs: Vec<Arc<Device>>,
pub properties: Properties<cl_context_properties>,
pub dtors: Mutex<Vec<Box<dyn Fn(cl_context)>>>,
}
impl_cl_type_trait!(cl_context, Context, CL_INVALID_CONTEXT);
impl Context {
pub fn new(
devs: Vec<Arc<Device>>,
properties: Properties<cl_context_properties>,
) -> Arc<Context> {
Arc::new(Self {
base: CLObjectBase::new(),
devs: devs,
properties: properties,
dtors: Mutex::new(Vec::new()),
})
}
pub fn create_buffer(
&self,
size: usize,
user_ptr: *mut c_void,
copy: bool,
res_type: ResourceType,
) -> CLResult<HashMap<Arc<Device>, Arc<PipeResource>>> {
let adj_size: u32 = size.try_into().map_err(|_| CL_OUT_OF_HOST_MEMORY)?;
let mut res = HashMap::new();
for dev in &self.devs {
let mut resource = None;
if !user_ptr.is_null() && !copy {
resource = dev
.screen()
.resource_create_buffer_from_user(adj_size, user_ptr)
}
if resource.is_none() {
resource = dev.screen().resource_create_buffer(adj_size, res_type)
}
let resource = resource.ok_or(CL_OUT_OF_RESOURCES);
res.insert(Arc::clone(dev), Arc::new(resource?));
}
if !user_ptr.is_null() {
res.iter()
.filter(|(_, r)| copy || !r.is_user)
.map(|(d, r)| {
d.helper_ctx()
.exec(|ctx| ctx.buffer_subdata(r, 0, user_ptr, size.try_into().unwrap()))
})
.for_each(|f| f.wait());
}
Ok(res)
}
pub fn create_texture(
&self,
desc: &cl_image_desc,
format: &cl_image_format,
user_ptr: *mut c_void,
copy: bool,
res_type: ResourceType,
) -> CLResult<HashMap<Arc<Device>, Arc<PipeResource>>> {
let width = desc
.image_width
.try_into()
.map_err(|_| CL_OUT_OF_HOST_MEMORY)?;
let height = desc
.image_height
.try_into()
.map_err(|_| CL_OUT_OF_HOST_MEMORY)?;
let depth = desc
.image_depth
.try_into()
.map_err(|_| CL_OUT_OF_HOST_MEMORY)?;
let array_size = desc
.image_array_size
.try_into()
.map_err(|_| CL_OUT_OF_HOST_MEMORY)?;
let target = cl_mem_type_to_texture_target(desc.image_type);
let format = format.to_pipe_format().unwrap();
let mut res = HashMap::new();
for dev in &self.devs {
let mut resource = None;
// we can't specify custom pitches/slices, so this won't work for non 1D images
if !user_ptr.is_null() && !copy && desc.image_type == CL_MEM_OBJECT_IMAGE1D {
resource = dev.screen().resource_create_texture_from_user(
width, height, depth, array_size, target, format, user_ptr,
)
}
if resource.is_none() {
resource = dev.screen().resource_create_texture(
width, height, depth, array_size, target, format, res_type,
)
}
let resource = resource.ok_or(CL_OUT_OF_RESOURCES);
res.insert(Arc::clone(dev), Arc::new(resource?));
}
if !user_ptr.is_null() {
let bx = desc.bx()?;
let stride = desc.row_pitch()?;
let layer_stride = desc.slice_pitch()?;
res.iter()
.filter(|(_, r)| copy || !r.is_user)
.map(|(d, r)| {
d.helper_ctx()
.exec(|ctx| ctx.texture_subdata(r, &bx, user_ptr, stride, layer_stride))
})
.for_each(|f| f.wait());
}
Ok(res)
}
}
impl Drop for Context {
fn drop(&mut self) {
let cl = cl_context::from_ptr(self);
self.dtors
.lock()
.unwrap()
.iter()
.rev()
.for_each(|cb| cb(cl));
}
}