1 use crate::api::icd::*; 2 use crate::api::types::DeleteContextCB; 3 use crate::core::device::*; 4 use crate::core::format::*; 5 use crate::core::gl::*; 6 use crate::core::memory::*; 7 use crate::core::util::*; 8 use crate::impl_cl_type_trait; 9 10 use mesa_rust::pipe::resource::*; 11 use mesa_rust::pipe::screen::ResourceType; 12 use mesa_rust_gen::*; 13 use mesa_rust_util::properties::Properties; 14 use rusticl_opencl_gen::*; 15 16 use std::alloc::Layout; 17 use std::collections::BTreeMap; 18 use std::collections::HashMap; 19 use std::convert::TryInto; 20 use std::mem; 21 use std::os::raw::c_void; 22 use std::sync::Arc; 23 use std::sync::Mutex; 24 25 pub struct Context { 26 pub base: CLObjectBase<CL_INVALID_CONTEXT>, 27 pub devs: Vec<&'static Device>, 28 pub properties: Properties<cl_context_properties>, 29 pub dtors: Mutex<Vec<DeleteContextCB>>, 30 pub svm_ptrs: Mutex<BTreeMap<usize, Layout>>, 31 pub gl_ctx_manager: Option<GLCtxManager>, 32 } 33 34 impl_cl_type_trait!(cl_context, Context, CL_INVALID_CONTEXT); 35 36 impl Context { new( devs: Vec<&'static Device>, properties: Properties<cl_context_properties>, gl_ctx_manager: Option<GLCtxManager>, ) -> Arc<Context>37 pub fn new( 38 devs: Vec<&'static Device>, 39 properties: Properties<cl_context_properties>, 40 gl_ctx_manager: Option<GLCtxManager>, 41 ) -> Arc<Context> { 42 Arc::new(Self { 43 base: CLObjectBase::new(RusticlTypes::Context), 44 devs: devs, 45 properties: properties, 46 dtors: Mutex::new(Vec::new()), 47 svm_ptrs: Mutex::new(BTreeMap::new()), 48 gl_ctx_manager: gl_ctx_manager, 49 }) 50 } 51 create_buffer( &self, size: usize, user_ptr: *mut c_void, copy: bool, res_type: ResourceType, ) -> CLResult<HashMap<&'static Device, Arc<PipeResource>>>52 pub fn create_buffer( 53 &self, 54 size: usize, 55 user_ptr: *mut c_void, 56 copy: bool, 57 res_type: ResourceType, 58 ) -> CLResult<HashMap<&'static Device, Arc<PipeResource>>> { 59 let adj_size: u32 = size.try_into().map_err(|_| CL_OUT_OF_HOST_MEMORY)?; 60 let mut res = HashMap::new(); 61 for &dev in &self.devs { 62 let mut resource = None; 63 64 if !user_ptr.is_null() && !copy { 65 resource = dev.screen().resource_create_buffer_from_user( 66 adj_size, 67 user_ptr, 68 PIPE_BIND_GLOBAL, 69 ) 70 } 71 72 if resource.is_none() { 73 resource = dev 74 .screen() 75 .resource_create_buffer(adj_size, res_type, PIPE_BIND_GLOBAL) 76 } 77 78 let resource = resource.ok_or(CL_OUT_OF_RESOURCES); 79 res.insert(dev, Arc::new(resource?)); 80 } 81 82 if !user_ptr.is_null() { 83 res.iter() 84 .filter(|(_, r)| copy || !r.is_user) 85 .map(|(d, r)| { 86 d.helper_ctx() 87 .exec(|ctx| ctx.buffer_subdata(r, 0, user_ptr, size.try_into().unwrap())) 88 }) 89 .for_each(|f| f.wait()); 90 } 91 92 Ok(res) 93 } 94 create_texture( &self, desc: &cl_image_desc, format: &cl_image_format, user_ptr: *mut c_void, copy: bool, res_type: ResourceType, ) -> CLResult<HashMap<&'static Device, Arc<PipeResource>>>95 pub fn create_texture( 96 &self, 97 desc: &cl_image_desc, 98 format: &cl_image_format, 99 user_ptr: *mut c_void, 100 copy: bool, 101 res_type: ResourceType, 102 ) -> CLResult<HashMap<&'static Device, Arc<PipeResource>>> { 103 let pipe_format = format.to_pipe_format().unwrap(); 104 105 let width = desc 106 .image_width 107 .try_into() 108 .map_err(|_| CL_OUT_OF_HOST_MEMORY)?; 109 let height = desc 110 .image_height 111 .try_into() 112 .map_err(|_| CL_OUT_OF_HOST_MEMORY)?; 113 let depth = desc 114 .image_depth 115 .try_into() 116 .map_err(|_| CL_OUT_OF_HOST_MEMORY)?; 117 let array_size = desc 118 .image_array_size 119 .try_into() 120 .map_err(|_| CL_OUT_OF_HOST_MEMORY)?; 121 let target = cl_mem_type_to_texture_target(desc.image_type); 122 123 let mut res = HashMap::new(); 124 for &dev in &self.devs { 125 let mut resource = None; 126 let enable_bind_as_image = 127 (dev.formats[format][&desc.image_type] as u32 & CL_MEM_WRITE_ONLY) != 0; 128 129 // we can't specify custom pitches/slices, so this won't work for non 1D images 130 if !user_ptr.is_null() && !copy && desc.image_type == CL_MEM_OBJECT_IMAGE1D { 131 resource = dev.screen().resource_create_texture_from_user( 132 width, 133 height, 134 depth, 135 array_size, 136 target, 137 pipe_format, 138 user_ptr, 139 enable_bind_as_image, 140 ) 141 } 142 143 if resource.is_none() { 144 resource = dev.screen().resource_create_texture( 145 width, 146 height, 147 depth, 148 array_size, 149 target, 150 pipe_format, 151 res_type, 152 enable_bind_as_image, 153 ) 154 } 155 156 let resource = resource.ok_or(CL_OUT_OF_RESOURCES); 157 res.insert(dev, Arc::new(resource?)); 158 } 159 160 if !user_ptr.is_null() { 161 let bx = desc.bx()?; 162 let stride = desc.row_pitch()?; 163 let layer_stride = desc.slice_pitch(); 164 165 res.iter() 166 .filter(|(_, r)| copy || !r.is_user) 167 .map(|(d, r)| { 168 d.helper_ctx() 169 .exec(|ctx| ctx.texture_subdata(r, &bx, user_ptr, stride, layer_stride)) 170 }) 171 .for_each(|f| f.wait()); 172 } 173 174 Ok(res) 175 } 176 177 /// Returns the max allocation size supported by all devices max_mem_alloc(&self) -> u64178 pub fn max_mem_alloc(&self) -> u64 { 179 self.devs 180 .iter() 181 .map(|dev| dev.max_mem_alloc()) 182 .min() 183 .unwrap() 184 } 185 has_svm_devs(&self) -> bool186 pub fn has_svm_devs(&self) -> bool { 187 self.devs.iter().any(|dev| dev.svm_supported()) 188 } 189 add_svm_ptr(&self, ptr: usize, layout: Layout)190 pub fn add_svm_ptr(&self, ptr: usize, layout: Layout) { 191 self.svm_ptrs.lock().unwrap().insert(ptr, layout); 192 } 193 find_svm_alloc(&self, ptr: usize) -> Option<(*const c_void, Layout)>194 pub fn find_svm_alloc(&self, ptr: usize) -> Option<(*const c_void, Layout)> { 195 let lock = self.svm_ptrs.lock().unwrap(); 196 if let Some((&base, layout)) = lock.range(..=ptr).next_back() { 197 // SAFETY: we really just do some pointer math here... 198 unsafe { 199 let base = base as *const c_void; 200 // we check if ptr is within [base..base+size) 201 // means we can check if ptr - (base + size) < 0 202 if ptr < (base.add(layout.size()) as usize) { 203 return Some((base, *layout)); 204 } 205 } 206 } 207 None 208 } 209 remove_svm_ptr(&self, ptr: usize) -> Option<Layout>210 pub fn remove_svm_ptr(&self, ptr: usize) -> Option<Layout> { 211 self.svm_ptrs.lock().unwrap().remove(&ptr) 212 } 213 import_gl_buffer( &self, handle: u32, modifier: u64, image_type: cl_mem_object_type, gl_target: cl_GLenum, format: pipe_format, gl_props: GLMemProps, ) -> CLResult<HashMap<&'static Device, Arc<PipeResource>>>214 pub fn import_gl_buffer( 215 &self, 216 handle: u32, 217 modifier: u64, 218 image_type: cl_mem_object_type, 219 gl_target: cl_GLenum, 220 format: pipe_format, 221 gl_props: GLMemProps, 222 ) -> CLResult<HashMap<&'static Device, Arc<PipeResource>>> { 223 let mut res = HashMap::new(); 224 let target = cl_mem_type_to_texture_target_gl(image_type, gl_target); 225 226 for dev in &self.devs { 227 let resource = dev 228 .screen() 229 .resource_import_dmabuf( 230 handle, 231 modifier, 232 target, 233 format, 234 gl_props.stride, 235 gl_props.width, 236 gl_props.height, 237 gl_props.depth, 238 gl_props.array_size, 239 ) 240 .ok_or(CL_OUT_OF_RESOURCES)?; 241 242 res.insert(*dev, Arc::new(resource)); 243 } 244 245 Ok(res) 246 } 247 } 248 249 impl Drop for Context { drop(&mut self)250 fn drop(&mut self) { 251 let cbs = mem::take(self.dtors.get_mut().unwrap()); 252 for cb in cbs.into_iter().rev() { 253 cb.call(self); 254 } 255 } 256 } 257