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