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 mesa_rust_util::ptr::TrackedPointers; 15 use rusticl_opencl_gen::*; 16 17 use std::alloc::Layout; 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 svm_ptrs: Mutex<TrackedPointers<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(TrackedPointers::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, usize)>194 pub fn find_svm_alloc(&self, ptr: usize) -> Option<(*const c_void, usize)> { 195 self.svm_ptrs 196 .lock() 197 .unwrap() 198 .find_alloc(ptr) 199 .map(|(ptr, layout)| (ptr as *const c_void, layout.size())) 200 } 201 remove_svm_ptr(&self, ptr: usize) -> Option<Layout>202 pub fn remove_svm_ptr(&self, ptr: usize) -> Option<Layout> { 203 self.svm_ptrs.lock().unwrap().remove(ptr) 204 } 205 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>>>206 pub fn import_gl_buffer( 207 &self, 208 handle: u32, 209 modifier: u64, 210 image_type: cl_mem_object_type, 211 gl_target: cl_GLenum, 212 format: pipe_format, 213 gl_props: GLMemProps, 214 ) -> CLResult<HashMap<&'static Device, Arc<PipeResource>>> { 215 let mut res = HashMap::new(); 216 let target = cl_mem_type_to_texture_target_gl(image_type, gl_target); 217 218 for dev in &self.devs { 219 let resource = dev 220 .screen() 221 .resource_import_dmabuf( 222 handle, 223 modifier, 224 target, 225 format, 226 gl_props.stride, 227 gl_props.width, 228 gl_props.height, 229 gl_props.depth, 230 gl_props.array_size, 231 ) 232 .ok_or(CL_OUT_OF_RESOURCES)?; 233 234 res.insert(*dev, Arc::new(resource)); 235 } 236 237 Ok(res) 238 } 239 } 240 241 impl Drop for Context { drop(&mut self)242 fn drop(&mut self) { 243 let cbs = mem::take(self.dtors.get_mut().unwrap()); 244 for cb in cbs.into_iter().rev() { 245 cb.call(self); 246 } 247 } 248 } 249