blob: 93e3ce619c47efeb29b0e369fe716b37e89bace6 [file] [log] [blame]
Zach Reizner3a8100a2017-09-13 19:15:43 -07001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Implementation for the transport agnostic virtio-gpu protocol, including display and rendering.
6
7use std::cell::RefCell;
8use std::collections::btree_map::Entry;
9use std::collections::BTreeMap as Map;
10use std::os::unix::io::AsRawFd;
11use std::rc::Rc;
Zach Reiznere9717c42018-06-14 17:58:37 -070012use std::usize;
Zach Reizner3a8100a2017-09-13 19:15:43 -070013
14use data_model::*;
15
Zach Reizneraa575662018-08-15 10:46:32 -070016use msg_socket::{MsgReceiver, MsgSender};
David Tolnay633426a2019-04-12 12:18:35 -070017use sys_util::{error, GuestAddress, GuestMemory};
Zach Reizner3a8100a2017-09-13 19:15:43 -070018
David Tolnay4c706a22019-04-12 11:48:03 -070019use gpu_buffer::{Buffer, Device, Flags, Format};
20use gpu_display::*;
21use gpu_renderer::{
Zach Reizner55a9e502018-10-03 10:22:32 -070022 format_fourcc as renderer_fourcc, Box3, Context as RendererContext, Image as RendererImage,
23 Renderer, Resource as GpuRendererResource, ResourceCreateArgs,
24};
Zach Reizner3a8100a2017-09-13 19:15:43 -070025
Zach Reiznerc5899292018-09-05 10:23:46 -070026use super::protocol::{
27 GpuResponse, GpuResponsePlaneInfo, VIRTIO_GPU_CAPSET_VIRGL, VIRTIO_GPU_CAPSET_VIRGL2,
28};
David Tolnaydc63ca92019-04-12 11:54:28 -070029use crate::virtio::resource_bridge::*;
Zach Reizner3a8100a2017-09-13 19:15:43 -070030
31const DEFAULT_WIDTH: u32 = 1280;
32const DEFAULT_HEIGHT: u32 = 1024;
33
34/// Trait for virtio-gpu resources allocated by the guest.
35trait VirglResource {
36 /// The width in pixels of this resource.
37 fn width(&self) -> u32;
38
39 /// The height in pixels of this resource.
40 fn height(&self) -> u32;
41
42 /// Associates the backing for this resource with the given guest memory.
43 fn attach_guest_backing(&mut self, mem: &GuestMemory, vecs: Vec<(GuestAddress, usize)>);
44
45 /// Removes associated memory for this resource previously made with `attach_guest_backing`.
46 fn detach_guest_backing(&mut self);
47
48 /// Returns the GPU `Buffer` for this resource, if it has one.
49 fn buffer(&self) -> Option<&Buffer> {
50 None
51 }
52
53 /// Returns the renderer's concrete `GpuRendererResource` for this resource, if it has one.
54 fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> {
55 None
56 }
57
58 /// Returns an import ID for this resource onto the given display, if successful.
59 fn import_to_display(&mut self, _display: &Rc<RefCell<GpuDisplay>>) -> Option<u32> {
60 None
61 }
62
63 /// Copies the given rectangle of pixels from guest memory, using the backing specified from a
64 /// call to `attach_guest_backing`.
Zach Reizner55a9e502018-10-03 10:22:32 -070065 fn write_from_guest_memory(
66 &mut self,
67 x: u32,
68 y: u32,
69 width: u32,
70 height: u32,
71 src_offset: u64,
72 mem: &GuestMemory,
73 );
Zach Reizner3a8100a2017-09-13 19:15:43 -070074
75 /// Reads from the given rectangle of pixels in the resource to the `dst` slice of memory.
76 fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice);
77}
78
79impl VirglResource for GpuRendererResource {
80 fn width(&self) -> u32 {
81 match self.get_info() {
82 Ok(info) => info.width,
83 Err(_) => 0,
84 }
85 }
86 fn height(&self) -> u32 {
87 match self.get_info() {
88 Ok(info) => info.height,
89 Err(_) => 0,
90 }
91 }
92
93 fn attach_guest_backing(&mut self, mem: &GuestMemory, vecs: Vec<(GuestAddress, usize)>) {
94 if let Err(e) = self.attach_backing(&vecs[..], mem) {
95 error!("failed to attach backing to resource: {}", e);
96 }
97 }
98
99 fn detach_guest_backing(&mut self) {
100 self.detach_backing();
101 }
102
103 fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> {
104 Some(self)
105 }
106
Zach Reizner55a9e502018-10-03 10:22:32 -0700107 fn write_from_guest_memory(
108 &mut self,
109 x: u32,
110 y: u32,
111 width: u32,
112 height: u32,
113 src_offset: u64,
114 _mem: &GuestMemory,
115 ) {
116 let res = self.transfer_write(
117 None,
118 0,
119 0,
120 0,
121 Box3 {
122 x,
123 y,
124 z: 0,
125 w: width,
126 h: height,
127 d: 0,
128 },
129 src_offset,
130 );
Zach Reizner3a8100a2017-09-13 19:15:43 -0700131 if let Err(e) = res {
Zach Reizner55a9e502018-10-03 10:22:32 -0700132 error!(
133 "failed to write to resource (x={} y={} w={} h={}, src_offset={}): {}",
134 x, y, width, height, src_offset, e
135 );
Zach Reizner3a8100a2017-09-13 19:15:43 -0700136 }
137 }
138
139 fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice) {
Zach Reizner55a9e502018-10-03 10:22:32 -0700140 let res = GpuRendererResource::read_to_volatile(
141 self,
142 None,
143 0,
144 0,
145 0,
146 Box3 {
147 x,
148 y,
149 z: 0,
150 w: width,
151 h: height,
152 d: 0,
153 },
154 0,
155 dst,
156 );
Zach Reizner3a8100a2017-09-13 19:15:43 -0700157 if let Err(e) = res {
158 error!("failed to read from resource: {}", e);
159 }
160 }
161}
162
163/// A buffer backed with a `gpu_buffer::Buffer`.
164struct BackedBuffer {
165 display_import: Option<(Rc<RefCell<GpuDisplay>>, u32)>,
166 backing: Vec<(GuestAddress, usize)>,
167 buffer: Buffer,
David Rileyaf9d7ed2018-05-22 15:37:22 -0700168 gpu_renderer_resource: Option<GpuRendererResource>,
David Rileyba7c6032018-05-17 17:08:16 -0700169 _image: Option<RendererImage>,
David Rileyaf9d7ed2018-05-22 15:37:22 -0700170}
171
172impl BackedBuffer {
Zach Reizner55a9e502018-10-03 10:22:32 -0700173 fn new_renderer_registered(
174 buffer: Buffer,
175 gpu_renderer_resource: GpuRendererResource,
176 image: RendererImage,
177 ) -> BackedBuffer {
David Rileyaf9d7ed2018-05-22 15:37:22 -0700178 BackedBuffer {
179 display_import: None,
180 backing: Vec::new(),
181 buffer,
182 gpu_renderer_resource: Some(gpu_renderer_resource),
David Rileyba7c6032018-05-17 17:08:16 -0700183 _image: Some(image),
David Rileyaf9d7ed2018-05-22 15:37:22 -0700184 }
185 }
Zach Reizner3a8100a2017-09-13 19:15:43 -0700186}
187
188impl From<Buffer> for BackedBuffer {
189 fn from(buffer: Buffer) -> BackedBuffer {
190 BackedBuffer {
191 display_import: None,
192 backing: Vec::new(),
193 buffer,
David Rileyaf9d7ed2018-05-22 15:37:22 -0700194 gpu_renderer_resource: None,
David Rileyba7c6032018-05-17 17:08:16 -0700195 _image: None,
Zach Reizner3a8100a2017-09-13 19:15:43 -0700196 }
197 }
198}
199
200impl VirglResource for BackedBuffer {
201 fn width(&self) -> u32 {
202 self.buffer.width()
203 }
204
205 fn height(&self) -> u32 {
206 self.buffer.height()
207 }
208
David Riley64cc43d2018-10-17 16:01:48 -0700209 fn attach_guest_backing(&mut self, mem: &GuestMemory, vecs: Vec<(GuestAddress, usize)>) {
210 self.backing = vecs.clone();
211 if let Some(ref mut resource) = self.gpu_renderer_resource {
212 if let Err(e) = resource.attach_backing(&vecs[..], mem) {
213 error!("failed to attach backing to BackBuffer resource: {}", e);
214 }
215 }
Zach Reizner3a8100a2017-09-13 19:15:43 -0700216 }
217
218 fn detach_guest_backing(&mut self) {
David Riley64cc43d2018-10-17 16:01:48 -0700219 if let Some(ref mut resource) = self.gpu_renderer_resource {
220 resource.detach_backing();
221 }
222 self.backing.clear();
Zach Reizner3a8100a2017-09-13 19:15:43 -0700223 }
224
David Rileyaf9d7ed2018-05-22 15:37:22 -0700225 fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> {
226 self.gpu_renderer_resource.as_mut()
227 }
228
Zach Reizner3a8100a2017-09-13 19:15:43 -0700229 fn buffer(&self) -> Option<&Buffer> {
230 Some(&self.buffer)
231 }
232
233 fn import_to_display(&mut self, display: &Rc<RefCell<GpuDisplay>>) -> Option<u32> {
234 if let Some((ref self_display, import)) = self.display_import {
235 if Rc::ptr_eq(&self_display, display) {
236 return Some(import);
237 }
238 }
239 let dmabuf = match self.buffer.export_plane_fd(0) {
240 Ok(dmabuf) => dmabuf,
241 Err(e) => {
242 error!("failed to get dmabuf for scanout: {}", e);
243 return None;
244 }
245 };
246
Zach Reizner55a9e502018-10-03 10:22:32 -0700247 match display.borrow_mut().import_dmabuf(
248 dmabuf.as_raw_fd(),
249 0, /* offset */
250 self.buffer.stride(),
251 self.buffer.format_modifier(),
252 self.buffer.width(),
253 self.buffer.height(),
254 self.buffer.format().into(),
255 ) {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700256 Ok(import_id) => {
257 self.display_import = Some((display.clone(), import_id));
258 Some(import_id)
259 }
260 Err(e) => {
David Tolnayb4bd00f2019-02-12 17:51:26 -0800261 error!("failed to import dmabuf for display: {}", e);
Zach Reizner3a8100a2017-09-13 19:15:43 -0700262 None
263 }
264 }
265 }
266
Zach Reizner55a9e502018-10-03 10:22:32 -0700267 fn write_from_guest_memory(
268 &mut self,
269 x: u32,
270 y: u32,
271 width: u32,
272 height: u32,
273 src_offset: u64,
274 mem: &GuestMemory,
275 ) {
Zach Reiznere9717c42018-06-14 17:58:37 -0700276 if src_offset >= usize::MAX as u64 {
Zach Reizner55a9e502018-10-03 10:22:32 -0700277 error!(
278 "failed to write to resource with given offset: {}",
279 src_offset
280 );
281 return;
Zach Reiznere9717c42018-06-14 17:58:37 -0700282 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700283 let res = self.buffer.write_from_sg(
284 x,
285 y,
286 width,
287 height,
288 0, // plane
289 src_offset as usize,
290 self.backing
291 .iter()
292 .map(|&(addr, len)| mem.get_slice(addr.offset(), len as u64).unwrap_or_default()),
293 );
Zach Reizner3a8100a2017-09-13 19:15:43 -0700294 if let Err(e) = res {
David Tolnayb4bd00f2019-02-12 17:51:26 -0800295 error!("failed to write to resource from guest memory: {}", e)
Zach Reizner3a8100a2017-09-13 19:15:43 -0700296 }
297 }
298
299 fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice) {
300 if let Err(e) = self.buffer.read_to_volatile(x, y, width, height, 0, dst) {
David Tolnayb4bd00f2019-02-12 17:51:26 -0800301 error!("failed to copy resource: {}", e);
Zach Reizner3a8100a2017-09-13 19:15:43 -0700302 }
303 }
304}
305
306/// The virtio-gpu backend state tracker.
307///
308/// Commands from the virtio-gpu protocol can be submitted here using the methods, and they will be
309/// realized on the hardware. Most methods return a `GpuResponse` that indicate the success,
310/// failure, or requested data for the given command.
311pub struct Backend {
312 display: Rc<RefCell<GpuDisplay>>,
313 device: Device,
314 renderer: Renderer,
David Tolnayfdac5ed2019-03-08 16:56:14 -0800315 resources: Map<u32, Box<dyn VirglResource>>,
Zach Reizner3a8100a2017-09-13 19:15:43 -0700316 contexts: Map<u32, RendererContext>,
317 scanout_surface: Option<u32>,
318 cursor_surface: Option<u32>,
319 scanout_resource: u32,
320 cursor_resource: u32,
321}
322
323impl Backend {
324 /// Creates a new backend for virtio-gpu that realizes all commands using the given `device` for
325 /// allocating buffers, `display` for showing the results, and `renderer` for submitting
326 /// rendering commands.
327 pub fn new(device: Device, display: GpuDisplay, renderer: Renderer) -> Backend {
328 Backend {
329 display: Rc::new(RefCell::new(display)),
330 device,
331 renderer,
332 resources: Default::default(),
333 contexts: Default::default(),
334 scanout_surface: None,
335 cursor_surface: None,
336 scanout_resource: 0,
337 cursor_resource: 0,
338 }
339 }
340
341 /// Gets a reference to the display passed into `new`.
342 pub fn display(&self) -> &Rc<RefCell<GpuDisplay>> {
343 &self.display
344 }
345
346 /// Processes the internal `display` events and returns `true` if the main display was closed.
347 pub fn process_display(&mut self) -> bool {
348 let mut display = self.display.borrow_mut();
349 display.dispatch_events();
350 self.scanout_surface
351 .map(|s| display.close_requested(s))
352 .unwrap_or(false)
353 }
354
Zach Reizneraa575662018-08-15 10:46:32 -0700355 pub fn process_resource_bridge(&self, resource_bridge: &ResourceResponseSocket) {
356 let request = match resource_bridge.recv() {
357 Ok(msg) => msg,
358 Err(e) => {
David Tolnayb4bd00f2019-02-12 17:51:26 -0800359 error!("error receiving resource bridge request: {}", e);
Zach Reizneraa575662018-08-15 10:46:32 -0700360 return;
361 }
362 };
363
364 let response = match request {
365 ResourceRequest::GetResource { id } => self
366 .resources
367 .get(&id)
368 .and_then(|resource| resource.buffer())
369 .and_then(|buffer| buffer.export_plane_fd(0).ok())
370 .map(|fd| ResourceResponse::Resource(fd))
371 .unwrap_or(ResourceResponse::Invalid),
372 };
373
374 if let Err(e) = resource_bridge.send(&response) {
David Tolnayb4bd00f2019-02-12 17:51:26 -0800375 error!("error sending resource bridge request: {}", e);
Zach Reizneraa575662018-08-15 10:46:32 -0700376 }
377 }
378
Zach Reizner3a8100a2017-09-13 19:15:43 -0700379 /// Gets the list of supported display resolutions as a slice of `(width, height)` tuples.
380 pub fn display_info(&self) -> &[(u32, u32)] {
381 &[(DEFAULT_WIDTH, DEFAULT_HEIGHT)]
382 }
383
384 /// Creates a 2D resource with the given properties and associated it with the given id.
Zach Reizner55a9e502018-10-03 10:22:32 -0700385 pub fn create_resource_2d(
386 &mut self,
387 id: u32,
388 width: u32,
389 height: u32,
390 fourcc: u32,
391 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700392 if id == 0 {
393 return GpuResponse::ErrInvalidResourceId;
394 }
395 match self.resources.entry(id) {
396 Entry::Vacant(slot) => {
Zach Reizner55a9e502018-10-03 10:22:32 -0700397 let res = self.device.create_buffer(
398 width,
399 height,
400 Format::from(fourcc),
401 Flags::empty().use_scanout(true).use_linear(true),
402 );
Zach Reizner3a8100a2017-09-13 19:15:43 -0700403 match res {
404 Ok(res) => {
405 slot.insert(Box::from(BackedBuffer::from(res)));
406 GpuResponse::OkNoData
407 }
408 Err(_) => {
409 error!("failed to create renderer resource {}", fourcc);
410 GpuResponse::ErrUnspec
411 }
412 }
413 }
414 Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
415 }
416 }
417
418 /// Removes the guest's reference count for the given resource id.
419 pub fn unref_resource(&mut self, id: u32) -> GpuResponse {
420 match self.resources.remove(&id) {
421 Some(_) => GpuResponse::OkNoData,
422 None => GpuResponse::ErrInvalidResourceId,
423 }
424 }
425
426 /// Sets the given resource id as the source of scanout to the display.
427 pub fn set_scanout(&mut self, id: u32) -> GpuResponse {
428 let mut display = self.display.borrow_mut();
429 if id == 0 {
430 if let Some(surface) = self.scanout_surface.take() {
431 display.release_surface(surface);
432 }
433 self.scanout_resource = 0;
434 if let Some(surface) = self.cursor_surface.take() {
435 display.release_surface(surface);
436 }
437 self.cursor_resource = 0;
438 GpuResponse::OkNoData
439 } else if self.resources.get_mut(&id).is_some() {
440 self.scanout_resource = id;
441
442 if self.scanout_surface.is_none() {
443 match display.create_surface(None, DEFAULT_WIDTH, DEFAULT_HEIGHT) {
444 Ok(surface) => self.scanout_surface = Some(surface),
David Tolnayb4bd00f2019-02-12 17:51:26 -0800445 Err(e) => error!("failed to create display surface: {}", e),
Zach Reizner3a8100a2017-09-13 19:15:43 -0700446 }
447 }
448 GpuResponse::OkNoData
449 } else {
450 GpuResponse::ErrInvalidResourceId
451 }
452 }
453
Zach Reizner55a9e502018-10-03 10:22:32 -0700454 fn flush_resource_to_surface(
455 &mut self,
456 resource_id: u32,
457 surface_id: u32,
458 x: u32,
459 y: u32,
460 width: u32,
461 height: u32,
462 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700463 let resource = match self.resources.get_mut(&resource_id) {
464 Some(r) => r,
465 None => return GpuResponse::ErrInvalidResourceId,
466 };
467
468 if let Some(import_id) = resource.import_to_display(&self.display) {
469 self.display.borrow_mut().flip_to(surface_id, import_id);
470 return GpuResponse::OkNoData;
471 }
472
473 // Import failed, fall back to a copy.
474 let display = self.display.borrow_mut();
475 // Prevent overwriting a buffer that is currently being used by the compositor.
476 if display.next_buffer_in_use(surface_id) {
477 return GpuResponse::OkNoData;
478 }
479 let fb = match display.framebuffer_memory(surface_id) {
480 Some(fb) => fb,
481 None => {
482 error!("failed to access framebuffer for surface {}", surface_id);
483 return GpuResponse::ErrUnspec;
484 }
485 };
486
487 resource.read_to_volatile(x, y, width, height, fb);
488 display.flip(surface_id);
489
490 GpuResponse::OkNoData
491 }
492
493 /// Flushes the given rectangle of pixels of the given resource to the display.
Zach Reizner55a9e502018-10-03 10:22:32 -0700494 pub fn flush_resource(
495 &mut self,
496 id: u32,
497 x: u32,
498 y: u32,
499 width: u32,
500 height: u32,
501 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700502 if id == 0 {
503 return GpuResponse::OkNoData;
504 }
505
506 let mut response = GpuResponse::OkNoData;
507
508 if id == self.scanout_resource {
509 if let Some(surface_id) = self.scanout_surface {
510 response = self.flush_resource_to_surface(id, surface_id, x, y, width, height);
511 }
512 }
513
514 if response != GpuResponse::OkNoData {
515 return response;
516 }
517
518 if id == self.cursor_resource {
519 if let Some(surface_id) = self.cursor_surface {
520 response = self.flush_resource_to_surface(id, surface_id, x, y, width, height);
521 }
522 }
523
David Tolnay5bbbf612018-12-01 17:49:30 -0800524 response
Zach Reizner3a8100a2017-09-13 19:15:43 -0700525 }
526
527 /// Copes the given rectangle of pixels of the given resource's backing memory to the host side
528 /// resource.
Zach Reizner55a9e502018-10-03 10:22:32 -0700529 pub fn transfer_to_resource_2d(
530 &mut self,
531 id: u32,
532 x: u32,
533 y: u32,
534 width: u32,
535 height: u32,
536 src_offset: u64,
537 mem: &GuestMemory,
538 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700539 match self.resources.get_mut(&id) {
540 Some(res) => {
Zach Reiznere9717c42018-06-14 17:58:37 -0700541 res.write_from_guest_memory(x, y, width, height, src_offset, mem);
Zach Reizner3a8100a2017-09-13 19:15:43 -0700542 GpuResponse::OkNoData
543 }
544 None => GpuResponse::ErrInvalidResourceId,
545 }
546 }
547
548 /// Attaches backing memory to the given resource, represented by a `Vec` of `(address, size)`
549 /// tuples in the guest's physical address space.
Zach Reizner55a9e502018-10-03 10:22:32 -0700550 pub fn attach_backing(
551 &mut self,
552 id: u32,
553 mem: &GuestMemory,
554 vecs: Vec<(GuestAddress, usize)>,
555 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700556 match self.resources.get_mut(&id) {
557 Some(resource) => {
558 resource.attach_guest_backing(mem, vecs);
559 GpuResponse::OkNoData
560 }
561 None => GpuResponse::ErrInvalidResourceId,
562 }
563 }
564
565 /// Detaches any backing memory from the given resource, if there is any.
566 pub fn detach_backing(&mut self, id: u32) -> GpuResponse {
567 match self.resources.get_mut(&id) {
568 Some(resource) => {
569 resource.detach_guest_backing();
570 GpuResponse::OkNoData
571 }
572 None => GpuResponse::ErrInvalidResourceId,
573 }
574 }
575
576 /// Updates the cursor's memory to the given id, and sets its position to the given coordinates.
577 pub fn update_cursor(&mut self, id: u32, x: u32, y: u32) -> GpuResponse {
578 if id == 0 {
579 if let Some(surface) = self.cursor_surface.take() {
580 self.display.borrow_mut().release_surface(surface);
581 }
582 self.cursor_resource = 0;
583 GpuResponse::OkNoData
584 } else if let Some(resource) = self.resources.get_mut(&id) {
585 self.cursor_resource = id;
586 if self.cursor_surface.is_none() {
Zach Reizner55a9e502018-10-03 10:22:32 -0700587 match self.display.borrow_mut().create_surface(
588 self.scanout_surface,
589 resource.width(),
590 resource.height(),
591 ) {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700592 Ok(surface) => self.cursor_surface = Some(surface),
593 Err(e) => {
David Tolnayb4bd00f2019-02-12 17:51:26 -0800594 error!("failed to create cursor surface: {}", e);
Zach Reizner3a8100a2017-09-13 19:15:43 -0700595 return GpuResponse::ErrUnspec;
596 }
597 }
598 }
599
600 let cursor_surface = self.cursor_surface.unwrap();
Zach Reizner55a9e502018-10-03 10:22:32 -0700601 self.display.borrow_mut().set_position(cursor_surface, x, y);
Zach Reizner3a8100a2017-09-13 19:15:43 -0700602
603 // Gets the resource's pixels into the display by importing the buffer.
604 if let Some(import_id) = resource.import_to_display(&self.display) {
Zach Reizner55a9e502018-10-03 10:22:32 -0700605 self.display.borrow_mut().flip_to(cursor_surface, import_id);
Zach Reizner3a8100a2017-09-13 19:15:43 -0700606 return GpuResponse::OkNoData;
607 }
608
609 // Importing failed, so try copying the pixels into the surface's slower shared memory
610 // framebuffer.
611 if let Some(buffer) = resource.buffer() {
Zach Reizner55a9e502018-10-03 10:22:32 -0700612 if let Some(fb) = self.display.borrow_mut().framebuffer_memory(cursor_surface) {
613 if let Err(e) =
614 buffer.read_to_volatile(0, 0, buffer.width(), buffer.height(), 0, fb)
615 {
David Tolnayb4bd00f2019-02-12 17:51:26 -0800616 error!("failed to copy resource to cursor: {}", e);
Zach Reizner3a8100a2017-09-13 19:15:43 -0700617 return GpuResponse::ErrInvalidParameter;
618 }
619 }
620 self.display.borrow_mut().flip(cursor_surface);
621 }
622 GpuResponse::OkNoData
623 } else {
624 GpuResponse::ErrInvalidResourceId
625 }
626 }
627
628 /// Moves the cursor's position to the given coordinates.
629 pub fn move_cursor(&mut self, x: u32, y: u32) -> GpuResponse {
630 if let Some(cursor_surface) = self.cursor_surface {
631 if let Some(scanout_surface) = self.scanout_surface {
632 let display = self.display.borrow_mut();
633 display.set_position(cursor_surface, x, y);
634 display.commit(scanout_surface);
635 }
636 }
637 GpuResponse::OkNoData
638 }
639
640 /// Gets the renderer's capset information associated with `index`.
641 pub fn get_capset_info(&self, index: u32) -> GpuResponse {
Gurchetan Singh046df602018-10-02 16:07:26 -0700642 let id = match index {
643 0 => VIRTIO_GPU_CAPSET_VIRGL,
644 1 => VIRTIO_GPU_CAPSET_VIRGL2,
645 _ => return GpuResponse::ErrInvalidParameter,
646 };
647 let (version, size) = self.renderer.get_cap_set_info(id);
648 GpuResponse::OkCapsetInfo { id, version, size }
Zach Reizner3a8100a2017-09-13 19:15:43 -0700649 }
650
651 /// Gets the capset of `version` associated with `id`.
652 pub fn get_capset(&self, id: u32, version: u32) -> GpuResponse {
653 GpuResponse::OkCapset(self.renderer.get_cap_set(id, version))
654 }
655
656 /// Creates a fresh renderer context with the given `id`.
657 pub fn create_renderer_context(&mut self, id: u32) -> GpuResponse {
658 if id == 0 {
659 return GpuResponse::ErrInvalidContextId;
660 }
661 match self.contexts.entry(id) {
662 Entry::Occupied(_) => GpuResponse::ErrInvalidContextId,
Zach Reizner55a9e502018-10-03 10:22:32 -0700663 Entry::Vacant(slot) => match self.renderer.create_context(id) {
664 Ok(ctx) => {
665 slot.insert(ctx);
666 GpuResponse::OkNoData
Zach Reizner3a8100a2017-09-13 19:15:43 -0700667 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700668 Err(e) => {
669 error!("failed to create renderer ctx: {}", e);
670 GpuResponse::ErrUnspec
671 }
672 },
Zach Reizner3a8100a2017-09-13 19:15:43 -0700673 }
674 }
675
676 /// Destorys the renderer context associated with `id`.
677 pub fn destroy_renderer_context(&mut self, id: u32) -> GpuResponse {
678 match self.contexts.remove(&id) {
679 Some(_) => GpuResponse::OkNoData,
680 None => GpuResponse::ErrInvalidContextId,
681 }
682 }
683
684 /// Attaches the indicated resource to the given context.
685 pub fn context_attach_resource(&mut self, ctx_id: u32, res_id: u32) -> GpuResponse {
Zach Reizner55a9e502018-10-03 10:22:32 -0700686 match (
687 self.contexts.get_mut(&ctx_id),
688 self.resources
689 .get_mut(&res_id)
690 .and_then(|res| res.gpu_renderer_resource()),
691 ) {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700692 (Some(ctx), Some(res)) => {
693 ctx.attach(res);
694 GpuResponse::OkNoData
695 }
696 (None, _) => GpuResponse::ErrInvalidContextId,
697 (_, None) => GpuResponse::ErrInvalidResourceId,
698 }
699 }
700
701 /// detaches the indicated resource to the given context.
702 pub fn context_detach_resource(&mut self, ctx_id: u32, res_id: u32) -> GpuResponse {
Zach Reizner55a9e502018-10-03 10:22:32 -0700703 match (
704 self.contexts.get_mut(&ctx_id),
705 self.resources
706 .get_mut(&res_id)
707 .and_then(|res| res.gpu_renderer_resource()),
708 ) {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700709 (Some(ctx), Some(res)) => {
710 ctx.detach(res);
711 GpuResponse::OkNoData
712 }
713 (None, _) => GpuResponse::ErrInvalidContextId,
714 (_, None) => GpuResponse::ErrInvalidResourceId,
715 }
716 }
717
David Rileyaf9d7ed2018-05-22 15:37:22 -0700718 pub fn validate_args_as_fourcc(args: ResourceCreateArgs) -> Option<u32> {
Zach Reizner55a9e502018-10-03 10:22:32 -0700719 if args.depth == 1 && args.array_size == 1 && args.last_level == 0 && args.nr_samples == 0 {
David Rileyaf9d7ed2018-05-22 15:37:22 -0700720 renderer_fourcc(args.format)
721 } else {
722 None
723 }
724 }
725
Zach Reizner3a8100a2017-09-13 19:15:43 -0700726 /// Creates a 3D resource with the given properties and associated it with the given id.
Zach Reizner55a9e502018-10-03 10:22:32 -0700727 pub fn resource_create_3d(
728 &mut self,
729 id: u32,
730 target: u32,
731 format: u32,
732 bind: u32,
733 width: u32,
734 height: u32,
735 depth: u32,
736 array_size: u32,
737 last_level: u32,
738 nr_samples: u32,
739 flags: u32,
740 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700741 if id == 0 {
742 return GpuResponse::ErrInvalidResourceId;
743 }
David Rileyaf9d7ed2018-05-22 15:37:22 -0700744
745 let create_args = ResourceCreateArgs {
746 handle: id,
747 target,
748 format,
749 bind,
750 width,
751 height,
752 depth,
753 array_size,
754 last_level,
755 nr_samples,
756 flags,
757 };
758
Zach Reizner3a8100a2017-09-13 19:15:43 -0700759 match self.resources.entry(id) {
760 Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
Zach Reizner55a9e502018-10-03 10:22:32 -0700761 Entry::Vacant(slot) => match Backend::validate_args_as_fourcc(create_args) {
762 Some(fourcc) => {
763 let buffer = match self.device.create_buffer(
764 width,
765 height,
766 Format::from(fourcc),
Gurchetan Singh5aaa63f2019-03-25 17:24:52 -0700767 Flags::empty().use_scanout(true).use_rendering(true),
Zach Reizner55a9e502018-10-03 10:22:32 -0700768 ) {
769 Ok(buffer) => buffer,
770 Err(e) => {
771 error!("failed to create buffer for 3d resource {}: {}", format, e);
772 return GpuResponse::ErrUnspec;
David Rileyaf9d7ed2018-05-22 15:37:22 -0700773 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700774 };
775
776 let dma_buf_fd = match buffer.export_plane_fd(0) {
777 Ok(dma_buf_fd) => dma_buf_fd,
778 Err(e) => {
779 error!("failed to export plane fd: {}", e);
780 return GpuResponse::ErrUnspec;
781 }
782 };
783
784 let image = match self.renderer.image_from_dmabuf(
785 fourcc,
786 width,
787 height,
788 dma_buf_fd.as_raw_fd(),
789 buffer.plane_offset(0),
790 buffer.plane_stride(0),
791 ) {
792 Ok(image) => image,
793 Err(e) => {
794 error!("failed to create egl image: {}", e);
795 return GpuResponse::ErrUnspec;
796 }
797 };
798
799 let res = self.renderer.import_resource(create_args, &image);
800 match res {
801 Ok(res) => {
Zach Reiznerc5899292018-09-05 10:23:46 -0700802 let format_modifier = buffer.format_modifier();
803 let mut plane_info = Vec::with_capacity(buffer.num_planes());
804 for plane_index in 0..buffer.num_planes() {
805 plane_info.push(GpuResponsePlaneInfo {
806 stride: buffer.plane_stride(plane_index),
807 offset: buffer.plane_offset(plane_index),
808 });
809 }
David Tolnay902e7c82019-04-08 23:00:57 -0700810 let backed = BackedBuffer::new_renderer_registered(buffer, res, image);
Zach Reizner55a9e502018-10-03 10:22:32 -0700811 slot.insert(Box::new(backed));
Zach Reiznerc5899292018-09-05 10:23:46 -0700812 GpuResponse::OkResourcePlaneInfo {
813 format_modifier,
814 plane_info,
815 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700816 }
817 Err(e) => {
818 error!("failed to import renderer resource: {}", e);
819 GpuResponse::ErrUnspec
David Rileyaf9d7ed2018-05-22 15:37:22 -0700820 }
Zach Reizner3a8100a2017-09-13 19:15:43 -0700821 }
822 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700823 None => {
824 let res = self.renderer.create_resource(create_args);
825 match res {
826 Ok(res) => {
827 slot.insert(Box::new(res));
828 GpuResponse::OkNoData
829 }
830 Err(e) => {
831 error!("failed to create renderer resource: {}", e);
832 GpuResponse::ErrUnspec
833 }
834 }
835 }
836 },
Zach Reizner3a8100a2017-09-13 19:15:43 -0700837 }
838 }
839
840 /// Copes the given 3D rectangle of pixels of the given resource's backing memory to the host
841 /// side resource.
Zach Reizner55a9e502018-10-03 10:22:32 -0700842 pub fn transfer_to_resource_3d(
843 &mut self,
844 ctx_id: u32,
845 res_id: u32,
846 x: u32,
847 y: u32,
848 z: u32,
849 width: u32,
850 height: u32,
851 depth: u32,
852 level: u32,
853 stride: u32,
854 layer_stride: u32,
855 offset: u64,
856 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700857 let ctx = match ctx_id {
858 0 => None,
Zach Reizner55a9e502018-10-03 10:22:32 -0700859 id => match self.contexts.get(&id) {
860 None => return GpuResponse::ErrInvalidContextId,
861 ctx => ctx,
862 },
Zach Reizner3a8100a2017-09-13 19:15:43 -0700863 };
864 match self.resources.get_mut(&res_id) {
Zach Reizner55a9e502018-10-03 10:22:32 -0700865 Some(res) => match res.gpu_renderer_resource() {
866 Some(res) => {
867 let transfer_box = Box3 {
868 x,
869 y,
870 z,
871 w: width,
872 h: height,
873 d: depth,
874 };
875 let res =
876 res.transfer_write(ctx, level, stride, layer_stride, transfer_box, offset);
877 match res {
878 Ok(_) => GpuResponse::OkNoData,
879 Err(e) => {
880 error!("failed to transfer to host: {}", e);
881 GpuResponse::ErrUnspec
Zach Reizner3a8100a2017-09-13 19:15:43 -0700882 }
883 }
Zach Reizner3a8100a2017-09-13 19:15:43 -0700884 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700885 None => GpuResponse::ErrInvalidResourceId,
886 },
Zach Reizner3a8100a2017-09-13 19:15:43 -0700887 None => GpuResponse::ErrInvalidResourceId,
888 }
889 }
890
891 /// Copes the given rectangle of pixels from the resource to the given resource's backing
892 /// memory.
Zach Reizner55a9e502018-10-03 10:22:32 -0700893 pub fn transfer_from_resource_3d(
894 &mut self,
895 ctx_id: u32,
896 res_id: u32,
897 x: u32,
898 y: u32,
899 z: u32,
900 width: u32,
901 height: u32,
902 depth: u32,
903 level: u32,
904 stride: u32,
905 layer_stride: u32,
906 offset: u64,
907 ) -> GpuResponse {
Zach Reizner3a8100a2017-09-13 19:15:43 -0700908 let ctx = match ctx_id {
909 0 => None,
Zach Reizner55a9e502018-10-03 10:22:32 -0700910 id => match self.contexts.get(&id) {
911 None => return GpuResponse::ErrInvalidContextId,
912 ctx => ctx,
913 },
Zach Reizner3a8100a2017-09-13 19:15:43 -0700914 };
915 match self.resources.get_mut(&res_id) {
Zach Reizner55a9e502018-10-03 10:22:32 -0700916 Some(res) => match res.gpu_renderer_resource() {
917 Some(res) => {
918 let transfer_box = Box3 {
919 x,
920 y,
921 z,
922 w: width,
923 h: height,
924 d: depth,
925 };
926 let res =
927 res.transfer_read(ctx, level, stride, layer_stride, transfer_box, offset);
928 match res {
929 Ok(_) => GpuResponse::OkNoData,
930 Err(e) => {
931 error!("failed to transfer from host: {}", e);
932 GpuResponse::ErrUnspec
Zach Reizner3a8100a2017-09-13 19:15:43 -0700933 }
934 }
Zach Reizner3a8100a2017-09-13 19:15:43 -0700935 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700936 None => GpuResponse::ErrInvalidResourceId,
937 },
Zach Reizner3a8100a2017-09-13 19:15:43 -0700938 None => GpuResponse::ErrInvalidResourceId,
939 }
940 }
941
942 /// Submits a command buffer to the given rendering context.
943 pub fn submit_command(&mut self, ctx_id: u32, commands: &mut [u8]) -> GpuResponse {
944 match self.contexts.get_mut(&ctx_id) {
Zach Reizner55a9e502018-10-03 10:22:32 -0700945 Some(ctx) => match ctx.submit(&mut commands[..]) {
946 Ok(_) => GpuResponse::OkNoData,
947 Err(e) => {
948 error!("failed to submit command buffer: {}", e);
949 GpuResponse::ErrUnspec
Zach Reizner3a8100a2017-09-13 19:15:43 -0700950 }
Zach Reizner55a9e502018-10-03 10:22:32 -0700951 },
Zach Reizner3a8100a2017-09-13 19:15:43 -0700952 None => GpuResponse::ErrInvalidContextId,
953 }
954 }
David Rileyf89e0b52018-05-17 17:14:42 -0700955
956 pub fn create_fence(&mut self, ctx_id: u32, fence_id: u32) -> GpuResponse {
957 // There is a mismatch of ordering that is intentional.
958 // This create_fence matches the other functions in Backend, yet
959 // the renderer matches the virgl interface.
960 match self.renderer.create_fence(fence_id, ctx_id) {
961 Ok(_) => GpuResponse::OkNoData,
962 Err(e) => {
963 error!("failed to create fence: {}", e);
964 GpuResponse::ErrUnspec
965 }
966 }
967 }
968
969 pub fn fence_poll(&mut self) -> u32 {
970 self.renderer.poll()
971 }
David Rileyc9ce2da2018-05-22 15:36:31 -0700972
973 pub fn force_ctx_0(&mut self) {
974 self.renderer.force_ctx_0();
975 }
Zach Reizner3a8100a2017-09-13 19:15:43 -0700976}