1 use mesa_rust_gen::*; 2 3 use std::{ 4 marker::PhantomData, 5 mem, 6 ptr::{self, NonNull}, 7 }; 8 9 use super::context::PipeContext; 10 11 #[derive(PartialEq, Eq, Hash)] 12 #[repr(transparent)] 13 pub struct PipeResource { 14 pipe: NonNull<pipe_resource>, 15 } 16 17 const PIPE_RESOURCE_FLAG_RUSTICL_IS_USER: u32 = PIPE_RESOURCE_FLAG_FRONTEND_PRIV; 18 19 // SAFETY: pipe_resource is considered a thread safe type 20 unsafe impl Send for PipeResource {} 21 unsafe impl Sync for PipeResource {} 22 23 /// A thread safe wrapper around [pipe_image_view]. It's purpose is to increase the reference count 24 /// on the [pipe_resource] this view belongs to. 25 #[repr(transparent)] 26 pub struct PipeImageView { 27 pub(super) pipe: pipe_image_view, 28 } 29 30 impl PipeImageView { new(pipe: pipe_image_view) -> Self31 fn new(pipe: pipe_image_view) -> Self { 32 unsafe { pipe_resource_reference(&mut ptr::null_mut(), pipe.resource) } 33 Self { pipe: pipe } 34 } 35 slice_to_pipe(slice: &[PipeImageView]) -> &[pipe_image_view]36 pub fn slice_to_pipe(slice: &[PipeImageView]) -> &[pipe_image_view] { 37 // SAFETY: `PipeImageView` is a transparent wrapper around `pipe_image_view`, so transmute 38 // on the slice is safe. 39 unsafe { mem::transmute(slice) } 40 } 41 } 42 43 impl Drop for PipeImageView { drop(&mut self)44 fn drop(&mut self) { 45 unsafe { pipe_resource_reference(&mut self.pipe.resource, ptr::null_mut()) } 46 } 47 } 48 49 // SAFETY: pipe_image_view is just static data around a pipe_resource, which itself is a thread-safe 50 // type. 51 unsafe impl Send for PipeImageView {} 52 unsafe impl Sync for PipeImageView {} 53 54 // Image dimensions provide by application to be used in both 55 // image and sampler views when image is created from buffer 56 #[derive(PartialEq, Eq)] 57 pub struct AppImgInfo { 58 row_stride: u32, 59 width: u32, 60 height: u32, 61 } 62 63 impl AppImgInfo { new(row_stride: u32, width: u32, height: u32) -> AppImgInfo64 pub fn new(row_stride: u32, width: u32, height: u32) -> AppImgInfo { 65 AppImgInfo { 66 row_stride: row_stride, 67 width: width, 68 height: height, 69 } 70 } 71 } 72 73 impl PipeResource { new(res: *mut pipe_resource, is_user: bool) -> Option<Self>74 pub(super) fn new(res: *mut pipe_resource, is_user: bool) -> Option<Self> { 75 let mut res = NonNull::new(res)?; 76 77 if is_user { 78 unsafe { 79 res.as_mut().flags |= PIPE_RESOURCE_FLAG_RUSTICL_IS_USER; 80 } 81 } 82 83 Some(Self { pipe: res }) 84 } 85 pipe(&self) -> *mut pipe_resource86 pub(super) fn pipe(&self) -> *mut pipe_resource { 87 self.pipe.as_ptr() 88 } 89 as_ref(&self) -> &pipe_resource90 fn as_ref(&self) -> &pipe_resource { 91 // SAFETY: it contains a valid pointer 92 unsafe { self.pipe.as_ref() } 93 } 94 width(&self) -> u3295 pub fn width(&self) -> u32 { 96 self.as_ref().width0 97 } 98 height(&self) -> u1699 pub fn height(&self) -> u16 { 100 self.as_ref().height0 101 } 102 depth(&self) -> u16103 pub fn depth(&self) -> u16 { 104 self.as_ref().depth0 105 } 106 array_size(&self) -> u16107 pub fn array_size(&self) -> u16 { 108 self.as_ref().array_size 109 } 110 is_buffer(&self) -> bool111 pub fn is_buffer(&self) -> bool { 112 self.as_ref().target() == pipe_texture_target::PIPE_BUFFER 113 } 114 is_linear(&self) -> bool115 pub fn is_linear(&self) -> bool { 116 self.as_ref().bind & PIPE_BIND_LINEAR != 0 117 } 118 is_staging(&self) -> bool119 pub fn is_staging(&self) -> bool { 120 self.as_ref().usage() == pipe_resource_usage::PIPE_USAGE_STAGING 121 } 122 is_user(&self) -> bool123 pub fn is_user(&self) -> bool { 124 self.as_ref().flags & PIPE_RESOURCE_FLAG_RUSTICL_IS_USER != 0 125 } 126 pipe_image_view(&self, read_write: bool, host_access: u16) -> PipeImageView127 pub fn pipe_image_view(&self, read_write: bool, host_access: u16) -> PipeImageView { 128 debug_assert!(!self.is_buffer()); 129 130 let pipe = self.as_ref(); 131 let shader_access = if read_write { 132 PIPE_IMAGE_ACCESS_READ_WRITE 133 } else { 134 PIPE_IMAGE_ACCESS_WRITE 135 } as u16; 136 137 let mut tex = pipe_image_view__bindgen_ty_1__bindgen_ty_1::default(); 138 tex.set_level(0); 139 tex.set_first_layer(0); 140 if pipe.target() == pipe_texture_target::PIPE_TEXTURE_3D { 141 tex.set_last_layer((pipe.depth0 - 1).into()); 142 } else { 143 tex.set_last_layer(pipe.array_size.saturating_sub(1).into()); 144 } 145 146 PipeImageView::new(pipe_image_view { 147 resource: self.pipe(), 148 format: pipe.format(), 149 access: host_access, 150 shader_access: shader_access, 151 u: pipe_image_view__bindgen_ty_1 { tex: tex }, 152 }) 153 } 154 pipe_image_view_1d_buffer( &self, format: pipe_format, read_write: bool, host_access: u16, size: u32, ) -> PipeImageView155 pub fn pipe_image_view_1d_buffer( 156 &self, 157 format: pipe_format, 158 read_write: bool, 159 host_access: u16, 160 size: u32, 161 ) -> PipeImageView { 162 debug_assert!(self.is_buffer()); 163 164 let shader_access = if read_write { 165 PIPE_IMAGE_ACCESS_READ_WRITE 166 } else { 167 PIPE_IMAGE_ACCESS_WRITE 168 } as u16; 169 170 PipeImageView::new(pipe_image_view { 171 resource: self.pipe(), 172 format: format, 173 access: host_access, 174 shader_access: shader_access, 175 u: pipe_image_view__bindgen_ty_1 { 176 buf: pipe_image_view__bindgen_ty_1__bindgen_ty_2 { 177 offset: 0, 178 size: size, 179 }, 180 }, 181 }) 182 } 183 pipe_image_view_2d_buffer( &self, format: pipe_format, read_write: bool, host_access: u16, app_img_info: &AppImgInfo, ) -> PipeImageView184 pub fn pipe_image_view_2d_buffer( 185 &self, 186 format: pipe_format, 187 read_write: bool, 188 host_access: u16, 189 app_img_info: &AppImgInfo, 190 ) -> PipeImageView { 191 debug_assert!(self.is_buffer()); 192 193 let shader_access = if read_write { 194 PIPE_IMAGE_ACCESS_READ_WRITE 195 } else { 196 PIPE_IMAGE_ACCESS_WRITE 197 } as u16; 198 199 PipeImageView::new(pipe_image_view { 200 resource: self.pipe(), 201 format: format, 202 access: PIPE_IMAGE_ACCESS_TEX2D_FROM_BUFFER as u16 | host_access, 203 shader_access: shader_access, 204 u: pipe_image_view__bindgen_ty_1 { 205 tex2d_from_buf: pipe_image_view__bindgen_ty_1__bindgen_ty_3 { 206 offset: 0, 207 row_stride: app_img_info.row_stride as u16, 208 width: app_img_info.width as u16, 209 height: app_img_info.height as u16, 210 }, 211 }, 212 }) 213 } 214 pipe_sampler_view_template(&self) -> pipe_sampler_view215 pub fn pipe_sampler_view_template(&self) -> pipe_sampler_view { 216 debug_assert!(!self.is_buffer()); 217 218 let mut res = pipe_sampler_view::default(); 219 unsafe { 220 u_sampler_view_default_template(&mut res, self.pipe(), self.as_ref().format()); 221 } 222 223 res 224 } 225 pipe_sampler_view_template_1d_buffer( &self, format: pipe_format, size: u32, ) -> pipe_sampler_view226 pub fn pipe_sampler_view_template_1d_buffer( 227 &self, 228 format: pipe_format, 229 size: u32, 230 ) -> pipe_sampler_view { 231 debug_assert!(self.is_buffer()); 232 233 let mut res = pipe_sampler_view::default(); 234 unsafe { 235 u_sampler_view_default_template(&mut res, self.pipe(), format); 236 } 237 238 // write the entire union field because u_sampler_view_default_template might have left it 239 // in an undefined state. 240 res.u.buf = pipe_sampler_view__bindgen_ty_2__bindgen_ty_2 { 241 offset: 0, 242 size: size, 243 }; 244 245 res 246 } 247 pipe_sampler_view_template_2d_buffer( &self, format: pipe_format, app_img_info: &AppImgInfo, ) -> pipe_sampler_view248 pub fn pipe_sampler_view_template_2d_buffer( 249 &self, 250 format: pipe_format, 251 app_img_info: &AppImgInfo, 252 ) -> pipe_sampler_view { 253 debug_assert!(self.is_buffer()); 254 255 let mut res = pipe_sampler_view::default(); 256 unsafe { 257 u_sampler_view_default_template(&mut res, self.pipe(), format); 258 } 259 260 // write the entire union field because u_sampler_view_default_template might have left it 261 // in an undefined state. 262 res.u.tex2d_from_buf = pipe_sampler_view__bindgen_ty_2__bindgen_ty_3 { 263 offset: 0, 264 row_stride: app_img_info.row_stride as u16, 265 width: app_img_info.width as u16, 266 height: app_img_info.height as u16, 267 }; 268 res.set_is_tex2d_from_buf(true); 269 270 res 271 } 272 } 273 274 impl Drop for PipeResource { drop(&mut self)275 fn drop(&mut self) { 276 unsafe { pipe_resource_reference(&mut self.pipe.as_ptr(), ptr::null_mut()) } 277 } 278 } 279 280 /// Wrapper around gallium's pipe_sampler_view. 281 /// 282 /// It deals with the refcounting and frees the object automatically if not needed anymore. 283 #[repr(transparent)] 284 pub struct PipeSamplerView<'c, 'r> { 285 view: NonNull<pipe_sampler_view>, 286 // the pipe_sampler_view object references both a context and a resource. 287 _ctx: PhantomData<&'c PipeContext>, 288 _res: PhantomData<&'r PipeResource>, 289 } 290 291 impl<'c, 'r> PipeSamplerView<'c, 'r> { new( ctx: &'c PipeContext, res: &'r PipeResource, template: &pipe_sampler_view, ) -> Option<Self>292 pub fn new( 293 ctx: &'c PipeContext, 294 res: &'r PipeResource, 295 template: &pipe_sampler_view, 296 ) -> Option<Self> { 297 let view = unsafe { 298 ctx.pipe().as_ref().create_sampler_view.unwrap()( 299 ctx.pipe().as_ptr(), 300 res.pipe(), 301 template, 302 ) 303 }; 304 305 let view = NonNull::new(view)?; 306 unsafe { 307 debug_assert_eq!(view.as_ref().context, ctx.pipe().as_ptr()); 308 debug_assert_eq!(view.as_ref().texture, res.pipe()); 309 } 310 311 Some(Self { 312 view: view, 313 _ctx: PhantomData, 314 _res: PhantomData, 315 }) 316 } 317 as_pipe(views: &mut [Self]) -> *mut *mut pipe_sampler_view318 pub(crate) fn as_pipe(views: &mut [Self]) -> *mut *mut pipe_sampler_view { 319 // We are transparent over *mut pipe_sample_view, so this is sound. 320 views.as_mut_ptr().cast() 321 } 322 } 323 324 impl Drop for PipeSamplerView<'_, '_> { drop(&mut self)325 fn drop(&mut self) { 326 unsafe { 327 pipe_sampler_view_reference(&mut ptr::null_mut(), self.view.as_ptr()); 328 } 329 } 330 } 331