• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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