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