1 // Copyright 2020 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! gfxstream: Handles 3D virtio-gpu hypercalls using gfxstream. 6 //! 7 //! External code found at <https://android.googlesource.com/device/generic/vulkan-cereal/>. 8 9 #![cfg(feature = "gfxstream")] 10 11 use std::mem::size_of; 12 use std::os::raw::c_char; 13 use std::os::raw::c_int; 14 use std::os::raw::c_uchar; 15 use std::os::raw::c_uint; 16 use std::os::raw::c_void; 17 use std::ptr::null; 18 use std::ptr::null_mut; 19 use std::sync::Arc; 20 21 use data_model::VolatileSlice; 22 23 use crate::generated::virgl_renderer_bindings::iovec; 24 use crate::generated::virgl_renderer_bindings::virgl_box; 25 use crate::generated::virgl_renderer_bindings::virgl_renderer_resource_create_args; 26 use crate::renderer_utils::*; 27 use crate::rutabaga_core::RutabagaComponent; 28 use crate::rutabaga_core::RutabagaContext; 29 use crate::rutabaga_core::RutabagaResource; 30 use crate::rutabaga_os::FromRawDescriptor; 31 use crate::rutabaga_os::IntoRawDescriptor; 32 use crate::rutabaga_os::RawDescriptor; 33 use crate::rutabaga_os::SafeDescriptor; 34 use crate::rutabaga_utils::*; 35 36 // User data, for custom use by renderer. An example is VirglCookie which includes a fence 37 // handler and render server descriptor. 38 const STREAM_RENDERER_PARAM_USER_DATA: u64 = 1; 39 40 // Bitwise flags for the renderer. 41 const STREAM_RENDERER_PARAM_RENDERER_FLAGS: u64 = 2; 42 43 // Reserved to replace write_fence / write_context_fence. 44 #[allow(dead_code)] 45 const STREAM_RENDERER_PARAM_FENCE_CALLBACK: u64 = 3; 46 47 // Callback for writing a fence. 48 const STREAM_RENDERER_PARAM_WRITE_FENCE_CALLBACK: u64 = 4; 49 type StreamRendererParamWriteFenceCallback = 50 unsafe extern "C" fn(cookie: *mut c_void, fence_id: u32); 51 52 // Callback for writing a fence with context. 53 const STREAM_RENDERER_PARAM_WRITE_CONTEXT_FENCE_CALLBACK: u64 = 5; 54 type StreamRendererParamWriteContextFenceCallback = 55 unsafe extern "C" fn(cookie: *mut c_void, fence_id: u64, ctx_id: u32, ring_idx: u8); 56 57 // Window 0's width. 58 const STREAM_RENDERER_PARAM_WIN0_WIDTH: u64 = 6; 59 60 // Window 0's height. 61 const STREAM_RENDERER_PARAM_WIN0_HEIGHT: u64 = 7; 62 63 #[repr(C)] 64 #[derive(Clone, Copy, Debug)] 65 pub struct StreamRendererParam { 66 key: u64, 67 value: u64, 68 } 69 70 #[repr(C)] 71 #[derive(Copy, Clone, Default)] 72 pub struct stream_renderer_handle { 73 pub os_handle: i64, 74 pub handle_type: u32, 75 } 76 77 #[repr(C)] 78 #[derive(Copy, Clone, Default)] 79 pub struct stream_renderer_vulkan_info { 80 pub memory_index: u32, 81 pub device_uuid: [u8; 16], 82 pub driver_uuid: [u8; 16], 83 } 84 85 #[allow(non_camel_case_types)] 86 pub type stream_renderer_create_blob = ResourceCreateBlob; 87 88 extern "C" { 89 // Entry point for the stream renderer. stream_renderer_init( stream_renderer_params: *mut StreamRendererParam, num_params: u64, ) -> c_int90 fn stream_renderer_init( 91 stream_renderer_params: *mut StreamRendererParam, 92 num_params: u64, 93 ) -> c_int; 94 95 // Shutdown entry point for the renderer. gfxstream_backend_teardown()96 fn gfxstream_backend_teardown(); 97 98 // virtio-gpu-3d ioctl functions (begin) 99 100 // In gfxstream, the resource create/transfer ioctls correspond to creating buffers for API 101 // forwarding and the notification of new API calls forwarded by the guest, unless they 102 // correspond to minigbm resource targets (PIPE_TEXTURE_2D), in which case they create globally 103 // visible shared GL textures to support gralloc. pipe_virgl_renderer_resource_create( args: *mut virgl_renderer_resource_create_args, iov: *mut iovec, num_iovs: u32, ) -> c_int104 fn pipe_virgl_renderer_resource_create( 105 args: *mut virgl_renderer_resource_create_args, 106 iov: *mut iovec, 107 num_iovs: u32, 108 ) -> c_int; 109 pipe_virgl_renderer_resource_unref(res_handle: u32)110 fn pipe_virgl_renderer_resource_unref(res_handle: u32); pipe_virgl_renderer_context_destroy(handle: u32)111 fn pipe_virgl_renderer_context_destroy(handle: u32); pipe_virgl_renderer_transfer_read_iov( handle: u32, ctx_id: u32, level: u32, stride: u32, layer_stride: u32, box_: *mut virgl_box, offset: u64, iov: *mut iovec, iovec_cnt: c_int, ) -> c_int112 fn pipe_virgl_renderer_transfer_read_iov( 113 handle: u32, 114 ctx_id: u32, 115 level: u32, 116 stride: u32, 117 layer_stride: u32, 118 box_: *mut virgl_box, 119 offset: u64, 120 iov: *mut iovec, 121 iovec_cnt: c_int, 122 ) -> c_int; pipe_virgl_renderer_transfer_write_iov( handle: u32, ctx_id: u32, level: c_int, stride: u32, layer_stride: u32, box_: *mut virgl_box, offset: u64, iovec: *mut iovec, iovec_cnt: c_uint, ) -> c_int123 fn pipe_virgl_renderer_transfer_write_iov( 124 handle: u32, 125 ctx_id: u32, 126 level: c_int, 127 stride: u32, 128 layer_stride: u32, 129 box_: *mut virgl_box, 130 offset: u64, 131 iovec: *mut iovec, 132 iovec_cnt: c_uint, 133 ) -> c_int; pipe_virgl_renderer_submit_cmd( commands: *mut c_void, ctx_id: i32, dword_count: i32, ) -> c_int134 fn pipe_virgl_renderer_submit_cmd( 135 commands: *mut c_void, 136 ctx_id: i32, 137 dword_count: i32, 138 ) -> c_int; pipe_virgl_renderer_resource_attach_iov( res_handle: c_int, iov: *mut iovec, num_iovs: c_int, ) -> c_int139 fn pipe_virgl_renderer_resource_attach_iov( 140 res_handle: c_int, 141 iov: *mut iovec, 142 num_iovs: c_int, 143 ) -> c_int; pipe_virgl_renderer_resource_detach_iov( res_handle: c_int, iov: *mut *mut iovec, num_iovs: *mut c_int, )144 fn pipe_virgl_renderer_resource_detach_iov( 145 res_handle: c_int, 146 iov: *mut *mut iovec, 147 num_iovs: *mut c_int, 148 ); pipe_virgl_renderer_create_fence(client_fence_id: c_int, ctx_id: u32) -> c_int149 fn pipe_virgl_renderer_create_fence(client_fence_id: c_int, ctx_id: u32) -> c_int; pipe_virgl_renderer_ctx_attach_resource(ctx_id: c_int, res_handle: c_int)150 fn pipe_virgl_renderer_ctx_attach_resource(ctx_id: c_int, res_handle: c_int); pipe_virgl_renderer_ctx_detach_resource(ctx_id: c_int, res_handle: c_int)151 fn pipe_virgl_renderer_ctx_detach_resource(ctx_id: c_int, res_handle: c_int); pipe_virgl_renderer_get_cap_set(set: u32, max_ver: *mut u32, max_size: *mut u32)152 fn pipe_virgl_renderer_get_cap_set(set: u32, max_ver: *mut u32, max_size: *mut u32); pipe_virgl_renderer_fill_caps(set: u32, version: u32, caps: *mut c_void)153 fn pipe_virgl_renderer_fill_caps(set: u32, version: u32, caps: *mut c_void); 154 stream_renderer_flush_resource_and_readback( res_handle: u32, x: u32, y: u32, width: u32, height: u32, pixels: *mut c_uchar, max_bytes: u32, )155 fn stream_renderer_flush_resource_and_readback( 156 res_handle: u32, 157 x: u32, 158 y: u32, 159 width: u32, 160 height: u32, 161 pixels: *mut c_uchar, 162 max_bytes: u32, 163 ); stream_renderer_create_blob( ctx_id: u32, res_handle: u32, create_blob: *const stream_renderer_create_blob, iovecs: *const iovec, num_iovs: u32, handle: *const stream_renderer_handle, ) -> c_int164 fn stream_renderer_create_blob( 165 ctx_id: u32, 166 res_handle: u32, 167 create_blob: *const stream_renderer_create_blob, 168 iovecs: *const iovec, 169 num_iovs: u32, 170 handle: *const stream_renderer_handle, 171 ) -> c_int; 172 stream_renderer_export_blob(res_handle: u32, handle: *mut stream_renderer_handle) -> c_int173 fn stream_renderer_export_blob(res_handle: u32, handle: *mut stream_renderer_handle) -> c_int; stream_renderer_resource_map( res_handle: u32, map: *mut *mut c_void, out_size: *mut u64, ) -> c_int174 fn stream_renderer_resource_map( 175 res_handle: u32, 176 map: *mut *mut c_void, 177 out_size: *mut u64, 178 ) -> c_int; stream_renderer_resource_unmap(res_handle: u32) -> c_int179 fn stream_renderer_resource_unmap(res_handle: u32) -> c_int; stream_renderer_resource_map_info(res_handle: u32, map_info: *mut u32) -> c_int180 fn stream_renderer_resource_map_info(res_handle: u32, map_info: *mut u32) -> c_int; stream_renderer_vulkan_info( res_handle: u32, vulkan_info: *mut stream_renderer_vulkan_info, ) -> c_int181 fn stream_renderer_vulkan_info( 182 res_handle: u32, 183 vulkan_info: *mut stream_renderer_vulkan_info, 184 ) -> c_int; stream_renderer_context_create( handle: u32, nlen: u32, name: *const c_char, context_init: u32, ) -> c_int185 fn stream_renderer_context_create( 186 handle: u32, 187 nlen: u32, 188 name: *const c_char, 189 context_init: u32, 190 ) -> c_int; stream_renderer_context_create_fence(fence_id: u64, ctx_id: u32, ring_idx: u8) -> c_int191 fn stream_renderer_context_create_fence(fence_id: u64, ctx_id: u32, ring_idx: u8) -> c_int; 192 } 193 194 /// The virtio-gpu backend state tracker which supports accelerated rendering. 195 pub struct Gfxstream {} 196 197 struct GfxstreamContext { 198 ctx_id: u32, 199 fence_handler: RutabagaFenceHandler, 200 } 201 202 impl RutabagaContext for GfxstreamContext { submit_cmd(&mut self, commands: &mut [u8]) -> RutabagaResult<()>203 fn submit_cmd(&mut self, commands: &mut [u8]) -> RutabagaResult<()> { 204 if commands.len() % size_of::<u32>() != 0 { 205 return Err(RutabagaError::InvalidCommandSize(commands.len())); 206 } 207 let dword_count = (commands.len() / size_of::<u32>()) as i32; 208 // Safe because the context and buffer are valid and gfxstream will have been 209 // initialized if there are Context instances. 210 let ret = unsafe { 211 pipe_virgl_renderer_submit_cmd( 212 commands.as_mut_ptr() as *mut c_void, 213 self.ctx_id as i32, 214 dword_count, 215 ) 216 }; 217 ret_to_res(ret) 218 } 219 attach(&mut self, resource: &mut RutabagaResource)220 fn attach(&mut self, resource: &mut RutabagaResource) { 221 // The context id and resource id must be valid because the respective instances ensure 222 // their lifetime. 223 unsafe { 224 pipe_virgl_renderer_ctx_attach_resource( 225 self.ctx_id as i32, 226 resource.resource_id as i32, 227 ); 228 } 229 } 230 detach(&mut self, resource: &RutabagaResource)231 fn detach(&mut self, resource: &RutabagaResource) { 232 // The context id and resource id must be valid because the respective instances ensure 233 // their lifetime. 234 unsafe { 235 pipe_virgl_renderer_ctx_detach_resource( 236 self.ctx_id as i32, 237 resource.resource_id as i32, 238 ); 239 } 240 } 241 component_type(&self) -> RutabagaComponentType242 fn component_type(&self) -> RutabagaComponentType { 243 RutabagaComponentType::Gfxstream 244 } 245 context_create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()>246 fn context_create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()> { 247 if fence.ring_idx as u32 == 1 { 248 self.fence_handler.call(fence); 249 return Ok(()); 250 } 251 252 // Safe becase only integers are given to gfxstream, not memory. 253 let ret = unsafe { 254 stream_renderer_context_create_fence(fence.fence_id, fence.ctx_id, fence.ring_idx) 255 }; 256 257 ret_to_res(ret) 258 } 259 } 260 261 impl Drop for GfxstreamContext { drop(&mut self)262 fn drop(&mut self) { 263 // The context is safe to destroy because nothing else can be referencing it. 264 unsafe { 265 pipe_virgl_renderer_context_destroy(self.ctx_id); 266 } 267 } 268 } 269 270 impl Gfxstream { init( display_width: u32, display_height: u32, gfxstream_flags: GfxstreamFlags, fence_handler: RutabagaFenceHandler, ) -> RutabagaResult<Box<dyn RutabagaComponent>>271 pub fn init( 272 display_width: u32, 273 display_height: u32, 274 gfxstream_flags: GfxstreamFlags, 275 fence_handler: RutabagaFenceHandler, 276 ) -> RutabagaResult<Box<dyn RutabagaComponent>> { 277 let cookie: *mut VirglCookie = Box::into_raw(Box::new(VirglCookie { 278 render_server_fd: None, 279 fence_handler: Some(fence_handler.clone()), 280 })); 281 282 let mut stream_renderer_params = [ 283 StreamRendererParam { 284 key: STREAM_RENDERER_PARAM_USER_DATA, 285 value: cookie as u64, 286 }, 287 StreamRendererParam { 288 key: STREAM_RENDERER_PARAM_RENDERER_FLAGS, 289 value: gfxstream_flags.into(), 290 }, 291 StreamRendererParam { 292 key: STREAM_RENDERER_PARAM_WRITE_FENCE_CALLBACK, 293 value: write_fence as StreamRendererParamWriteFenceCallback as usize as u64, 294 }, 295 StreamRendererParam { 296 key: STREAM_RENDERER_PARAM_WRITE_CONTEXT_FENCE_CALLBACK, 297 value: write_context_fence as StreamRendererParamWriteContextFenceCallback as usize 298 as u64, 299 }, 300 StreamRendererParam { 301 key: STREAM_RENDERER_PARAM_WIN0_WIDTH, 302 value: display_width as u64, 303 }, 304 StreamRendererParam { 305 key: STREAM_RENDERER_PARAM_WIN0_HEIGHT, 306 value: display_height as u64, 307 }, 308 ]; 309 310 unsafe { 311 ret_to_res(stream_renderer_init( 312 stream_renderer_params.as_mut_ptr(), 313 stream_renderer_params.len() as u64, 314 ))?; 315 } 316 317 Ok(Box::new(Gfxstream {})) 318 } 319 map_info(&self, resource_id: u32) -> RutabagaResult<u32>320 fn map_info(&self, resource_id: u32) -> RutabagaResult<u32> { 321 let mut map_info = 0; 322 // Safe because `map_info` is a local stack variable owned by us. 323 let ret = unsafe { stream_renderer_resource_map_info(resource_id, &mut map_info) }; 324 ret_to_res(ret)?; 325 326 Ok(map_info) 327 } 328 vulkan_info(&self, resource_id: u32) -> RutabagaResult<VulkanInfo>329 fn vulkan_info(&self, resource_id: u32) -> RutabagaResult<VulkanInfo> { 330 let mut vulkan_info: stream_renderer_vulkan_info = Default::default(); 331 // Safe because `vulkan_info` is a local stack variable owned by us. 332 let ret = unsafe { stream_renderer_vulkan_info(resource_id, &mut vulkan_info) }; 333 ret_to_res(ret)?; 334 335 Ok(VulkanInfo { 336 memory_idx: vulkan_info.memory_index, 337 device_id: DeviceId { 338 device_uuid: vulkan_info.device_uuid, 339 driver_uuid: vulkan_info.driver_uuid, 340 }, 341 }) 342 } 343 export_blob(&self, resource_id: u32) -> RutabagaResult<Arc<RutabagaHandle>>344 fn export_blob(&self, resource_id: u32) -> RutabagaResult<Arc<RutabagaHandle>> { 345 let mut stream_handle: stream_renderer_handle = Default::default(); 346 let ret = unsafe { stream_renderer_export_blob(resource_id as u32, &mut stream_handle) }; 347 ret_to_res(ret)?; 348 349 // Safe because the handle was just returned by a successful gfxstream call so it must be 350 // valid and owned by us. 351 let raw_descriptor = stream_handle.os_handle as RawDescriptor; 352 let handle = unsafe { SafeDescriptor::from_raw_descriptor(raw_descriptor) }; 353 354 Ok(Arc::new(RutabagaHandle { 355 os_handle: handle, 356 handle_type: stream_handle.handle_type, 357 })) 358 } 359 } 360 361 impl Drop for Gfxstream { drop(&mut self)362 fn drop(&mut self) { 363 // SAFETY: Safe because Gfxstream was succesfully initialized. 364 unsafe { 365 gfxstream_backend_teardown(); 366 } 367 } 368 } 369 370 impl RutabagaComponent for Gfxstream { get_capset_info(&self, capset_id: u32) -> (u32, u32)371 fn get_capset_info(&self, capset_id: u32) -> (u32, u32) { 372 let mut version = 0; 373 let mut size = 0; 374 // Safe because gfxstream is initialized by now and properly size stack variables are 375 // used for the pointers. 376 unsafe { 377 pipe_virgl_renderer_get_cap_set(capset_id, &mut version, &mut size); 378 } 379 (version, size) 380 } 381 get_capset(&self, capset_id: u32, version: u32) -> Vec<u8>382 fn get_capset(&self, capset_id: u32, version: u32) -> Vec<u8> { 383 let (_, max_size) = self.get_capset_info(capset_id); 384 let mut buf = vec![0u8; max_size as usize]; 385 // Safe because gfxstream is initialized by now and the given buffer is sized properly 386 // for the given cap id/version. 387 unsafe { 388 pipe_virgl_renderer_fill_caps(capset_id, version, buf.as_mut_ptr() as *mut c_void); 389 } 390 391 buf 392 } 393 create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()>394 fn create_fence(&mut self, fence: RutabagaFence) -> RutabagaResult<()> { 395 let ret = unsafe { pipe_virgl_renderer_create_fence(fence.fence_id as i32, fence.ctx_id) }; 396 ret_to_res(ret) 397 } 398 create_3d( &self, resource_id: u32, resource_create_3d: ResourceCreate3D, ) -> RutabagaResult<RutabagaResource>399 fn create_3d( 400 &self, 401 resource_id: u32, 402 resource_create_3d: ResourceCreate3D, 403 ) -> RutabagaResult<RutabagaResource> { 404 let mut args = virgl_renderer_resource_create_args { 405 handle: resource_id, 406 target: resource_create_3d.target, 407 format: resource_create_3d.format, 408 bind: resource_create_3d.bind, 409 width: resource_create_3d.width, 410 height: resource_create_3d.height, 411 depth: resource_create_3d.depth, 412 array_size: resource_create_3d.array_size, 413 last_level: resource_create_3d.last_level, 414 nr_samples: resource_create_3d.nr_samples, 415 flags: resource_create_3d.flags, 416 }; 417 418 // Safe because gfxstream is initialized by now, and the return value is checked before 419 // returning a new resource. The backing buffers are not supplied with this call. 420 let ret = unsafe { pipe_virgl_renderer_resource_create(&mut args, null_mut(), 0) }; 421 ret_to_res(ret)?; 422 423 Ok(RutabagaResource { 424 resource_id, 425 handle: None, 426 blob: false, 427 blob_mem: 0, 428 blob_flags: 0, 429 map_info: None, 430 info_2d: None, 431 info_3d: None, 432 vulkan_info: None, 433 backing_iovecs: None, 434 component_mask: 1 << (RutabagaComponentType::Gfxstream as u8), 435 }) 436 } 437 attach_backing( &self, resource_id: u32, vecs: &mut Vec<RutabagaIovec>, ) -> RutabagaResult<()>438 fn attach_backing( 439 &self, 440 resource_id: u32, 441 vecs: &mut Vec<RutabagaIovec>, 442 ) -> RutabagaResult<()> { 443 let ret = unsafe { 444 pipe_virgl_renderer_resource_attach_iov( 445 resource_id as i32, 446 vecs.as_mut_ptr() as *mut iovec, 447 vecs.len() as i32, 448 ) 449 }; 450 ret_to_res(ret) 451 } 452 detach_backing(&self, resource_id: u32)453 fn detach_backing(&self, resource_id: u32) { 454 unsafe { 455 pipe_virgl_renderer_resource_detach_iov( 456 resource_id as i32, 457 std::ptr::null_mut(), 458 std::ptr::null_mut(), 459 ); 460 } 461 } 462 unref_resource(&self, resource_id: u32)463 fn unref_resource(&self, resource_id: u32) { 464 // The resource is safe to unreference destroy because no user of these bindings can still 465 // be holding a reference. 466 unsafe { 467 pipe_virgl_renderer_resource_unref(resource_id); 468 } 469 } 470 transfer_write( &self, ctx_id: u32, resource: &mut RutabagaResource, transfer: Transfer3D, ) -> RutabagaResult<()>471 fn transfer_write( 472 &self, 473 ctx_id: u32, 474 resource: &mut RutabagaResource, 475 transfer: Transfer3D, 476 ) -> RutabagaResult<()> { 477 if transfer.is_empty() { 478 return Ok(()); 479 } 480 481 let mut transfer_box = VirglBox { 482 x: transfer.x, 483 y: transfer.y, 484 z: transfer.z, 485 w: transfer.w, 486 h: transfer.h, 487 d: transfer.d, 488 }; 489 490 // Safe because only stack variables of the appropriate type are used. 491 let ret = unsafe { 492 pipe_virgl_renderer_transfer_write_iov( 493 resource.resource_id, 494 ctx_id, 495 transfer.level as i32, 496 transfer.stride, 497 transfer.layer_stride, 498 &mut transfer_box as *mut VirglBox as *mut virgl_box, 499 transfer.offset, 500 null_mut(), 501 0, 502 ) 503 }; 504 ret_to_res(ret) 505 } 506 transfer_read( &self, ctx_id: u32, resource: &mut RutabagaResource, transfer: Transfer3D, buf: Option<VolatileSlice>, ) -> RutabagaResult<()>507 fn transfer_read( 508 &self, 509 ctx_id: u32, 510 resource: &mut RutabagaResource, 511 transfer: Transfer3D, 512 buf: Option<VolatileSlice>, 513 ) -> RutabagaResult<()> { 514 if transfer.is_empty() { 515 return Ok(()); 516 } 517 518 let mut transfer_box = VirglBox { 519 x: transfer.x, 520 y: transfer.y, 521 z: transfer.z, 522 w: transfer.w, 523 h: transfer.h, 524 d: transfer.d, 525 }; 526 527 let mut iov = RutabagaIovec { 528 base: null_mut(), 529 len: 0, 530 }; 531 532 let (iovecs, num_iovecs) = match buf { 533 Some(buf) => { 534 iov.base = buf.as_ptr() as *mut c_void; 535 iov.len = buf.size() as usize; 536 (&mut iov as *mut RutabagaIovec as *mut iovec, 1) 537 } 538 None => (null_mut(), 0), 539 }; 540 541 // Safe because only stack variables of the appropriate type are used. 542 let ret = unsafe { 543 pipe_virgl_renderer_transfer_read_iov( 544 resource.resource_id, 545 ctx_id, 546 transfer.level, 547 transfer.stride, 548 transfer.layer_stride, 549 &mut transfer_box as *mut VirglBox as *mut virgl_box, 550 transfer.offset, 551 iovecs, 552 num_iovecs, 553 ) 554 }; 555 ret_to_res(ret) 556 } 557 resource_flush(&self, resource: &mut RutabagaResource) -> RutabagaResult<()>558 fn resource_flush(&self, resource: &mut RutabagaResource) -> RutabagaResult<()> { 559 unsafe { 560 stream_renderer_flush_resource_and_readback( 561 resource.resource_id, 562 0, 563 0, 564 0, 565 0, 566 null_mut(), 567 0, 568 ); 569 } 570 Ok(()) 571 } 572 create_blob( &mut self, ctx_id: u32, resource_id: u32, resource_create_blob: ResourceCreateBlob, mut iovec_opt: Option<Vec<RutabagaIovec>>, handle_opt: Option<RutabagaHandle>, ) -> RutabagaResult<RutabagaResource>573 fn create_blob( 574 &mut self, 575 ctx_id: u32, 576 resource_id: u32, 577 resource_create_blob: ResourceCreateBlob, 578 mut iovec_opt: Option<Vec<RutabagaIovec>>, 579 handle_opt: Option<RutabagaHandle>, 580 ) -> RutabagaResult<RutabagaResource> { 581 let mut iovec_ptr = null_mut(); 582 let mut num_iovecs = 0; 583 if let Some(ref mut iovecs) = iovec_opt { 584 iovec_ptr = iovecs.as_mut_ptr(); 585 num_iovecs = iovecs.len() as u32; 586 } 587 588 let mut handle_ptr = null(); 589 let mut stream_handle: stream_renderer_handle = Default::default(); 590 if let Some(handle) = handle_opt { 591 stream_handle.handle_type = handle.handle_type; 592 stream_handle.os_handle = handle.os_handle.into_raw_descriptor() as i64; 593 handle_ptr = &stream_handle; 594 } 595 596 let ret = unsafe { 597 stream_renderer_create_blob( 598 ctx_id, 599 resource_id, 600 &resource_create_blob as *const stream_renderer_create_blob, 601 iovec_ptr as *const iovec, 602 num_iovecs, 603 handle_ptr as *const stream_renderer_handle, 604 ) 605 }; 606 607 ret_to_res(ret)?; 608 609 Ok(RutabagaResource { 610 resource_id, 611 handle: self.export_blob(resource_id).ok(), 612 blob: true, 613 blob_mem: resource_create_blob.blob_mem, 614 blob_flags: resource_create_blob.blob_flags, 615 map_info: self.map_info(resource_id).ok(), 616 info_2d: None, 617 info_3d: None, 618 vulkan_info: self.vulkan_info(resource_id).ok(), 619 backing_iovecs: iovec_opt, 620 component_mask: 1 << (RutabagaComponentType::Gfxstream as u8), 621 }) 622 } 623 map(&self, resource_id: u32) -> RutabagaResult<RutabagaMapping>624 fn map(&self, resource_id: u32) -> RutabagaResult<RutabagaMapping> { 625 let mut map: *mut c_void = null_mut(); 626 let mut size: u64 = 0; 627 628 // Safe because the Stream renderer wraps and validates use of vkMapMemory. 629 let ret = unsafe { stream_renderer_resource_map(resource_id, &mut map, &mut size) }; 630 if ret != 0 { 631 return Err(RutabagaError::MappingFailed(ret)); 632 } 633 Ok(RutabagaMapping { 634 ptr: map as u64, 635 size, 636 }) 637 } 638 unmap(&self, resource_id: u32) -> RutabagaResult<()>639 fn unmap(&self, resource_id: u32) -> RutabagaResult<()> { 640 let ret = unsafe { stream_renderer_resource_unmap(resource_id) }; 641 ret_to_res(ret) 642 } 643 create_context( &self, ctx_id: u32, context_init: u32, context_name: Option<&str>, fence_handler: RutabagaFenceHandler, ) -> RutabagaResult<Box<dyn RutabagaContext>>644 fn create_context( 645 &self, 646 ctx_id: u32, 647 context_init: u32, 648 context_name: Option<&str>, 649 fence_handler: RutabagaFenceHandler, 650 ) -> RutabagaResult<Box<dyn RutabagaContext>> { 651 let mut name: &str = "gpu_renderer"; 652 if let Some(name_string) = context_name.filter(|s| s.len() > 0) { 653 name = name_string; 654 } 655 656 // Safe because gfxstream is initialized by now and the context name is statically 657 // allocated. The return value is checked before returning a new context. 658 let ret = unsafe { 659 stream_renderer_context_create( 660 ctx_id, 661 name.len() as u32, 662 name.as_ptr() as *const c_char, 663 context_init, 664 ) 665 }; 666 ret_to_res(ret)?; 667 Ok(Box::new(GfxstreamContext { 668 ctx_id, 669 fence_handler, 670 })) 671 } 672 } 673