summary refs log tree commit diff
path: root/devices/src/virtio/gpu/mod.rs
diff options
context:
space:
mode:
authorDavid Riley <davidriley@chromium.org>2018-05-17 17:14:42 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-07-30 23:08:04 -0700
commitf89e0b50e20c39cc2e9b22f83de1e8fee6b8803f (patch)
treedab148d1d924098bc33dab14a2e3cf4f6252a73a /devices/src/virtio/gpu/mod.rs
parentba7c6035f8fb4b939b9c86f58c0f3009b04ebb68 (diff)
downloadcrosvm-f89e0b50e20c39cc2e9b22f83de1e8fee6b8803f.tar
crosvm-f89e0b50e20c39cc2e9b22f83de1e8fee6b8803f.tar.gz
crosvm-f89e0b50e20c39cc2e9b22f83de1e8fee6b8803f.tar.bz2
crosvm-f89e0b50e20c39cc2e9b22f83de1e8fee6b8803f.tar.lz
crosvm-f89e0b50e20c39cc2e9b22f83de1e8fee6b8803f.tar.xz
crosvm-f89e0b50e20c39cc2e9b22f83de1e8fee6b8803f.tar.zst
crosvm-f89e0b50e20c39cc2e9b22f83de1e8fee6b8803f.zip
gpu: add support for fences
BUG=None
TEST=build with --features=gpu; null_platform_test

Change-Id: Ib863c8ef3e85aa0f345c1f20be414979808b6a17
Reviewed-on: https://chromium-review.googlesource.com/1073959
Commit-Ready: David Riley <davidriley@chromium.org>
Tested-by: David Riley <davidriley@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'devices/src/virtio/gpu/mod.rs')
-rw-r--r--devices/src/virtio/gpu/mod.rs65
1 files changed, 62 insertions, 3 deletions
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
index 2b223fc..24b6fe5 100644
--- a/devices/src/virtio/gpu/mod.rs
+++ b/devices/src/virtio/gpu/mod.rs
@@ -9,14 +9,16 @@ extern crate gpu_renderer;
 mod protocol;
 mod backend;
 
-use std::rc::Rc;
 use std::cell::RefCell;
 use std::collections::VecDeque;
+use std::i64;
 use std::mem::size_of;
 use std::os::unix::io::RawFd;
+use std::rc::Rc;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
+use std::time::Duration;
 
 use data_model::*;
 
@@ -35,6 +37,7 @@ use self::backend::Backend;
 // First queue is for virtio gpu commands. Second queue is for cursor commands, which we expect
 // there to be fewer of.
 const QUEUE_SIZES: &'static [u16] = &[256, 16];
+const FENCE_POLL_MS: u64 = 1;
 
 struct QueueDescriptor {
     index: u16,
@@ -49,11 +52,18 @@ struct ReturnDescriptor {
     len: u32,
 }
 
+struct FenceDescriptor {
+    fence_id: u32,
+    len: u32,
+    desc: QueueDescriptor,
+}
+
 struct Frontend {
     ctrl_descriptors: VecDeque<QueueDescriptor>,
     cursor_descriptors: VecDeque<QueueDescriptor>,
     return_ctrl_descriptors: VecDeque<ReturnDescriptor>,
     return_cursor_descriptors: VecDeque<ReturnDescriptor>,
+    fence_descriptors: Vec<FenceDescriptor>,
     backend: Backend,
 }
 
@@ -64,6 +74,7 @@ impl Frontend {
             cursor_descriptors: Default::default(),
             return_ctrl_descriptors: Default::default(),
             return_cursor_descriptors: Default::default(),
+            fence_descriptors: Default::default(),
             backend,
         }
     }
@@ -373,17 +384,40 @@ impl Frontend {
                 let mut flags = 0;
                 if let Some(cmd) = gpu_cmd {
                     let ctrl_hdr = cmd.ctrl_hdr();
-                    // TODO: add proper fence support
                     if ctrl_hdr.flags.to_native() & VIRTIO_GPU_FLAG_FENCE != 0 {
                         fence_id = ctrl_hdr.fence_id.to_native();
                         ctx_id = ctrl_hdr.ctx_id.to_native();
                         flags = VIRTIO_GPU_FLAG_FENCE;
+
+                        let fence_resp = self.backend
+                            .create_fence(ctx_id, fence_id as u32);
+                        if fence_resp.is_err() {
+                            warn!("create_fence {} -> {:?}",
+                                  fence_id, fence_resp);
+                            resp = fence_resp;
+                        }
                     }
                 }
+
+
+                // Prepare the response now, even if it is going to wait until
+                // fence is complete.
                 match resp.encode(flags, fence_id, ctx_id, ret_desc_mem) {
                     Ok(l) => len = l,
                     Err(e) => debug!("ctrl queue response encode error: {:?}", e),
                 }
+
+                if flags & VIRTIO_GPU_FLAG_FENCE != 0 {
+                    self.fence_descriptors.push(FenceDescriptor {
+                        fence_id: fence_id as u32,
+                        len,
+                        desc,
+                    });
+
+                    return None
+                }
+
+                // No fence, respond now.
             }
         }
         Some(ReturnDescriptor {
@@ -411,6 +445,22 @@ impl Frontend {
                              .and_then(|desc| self.process_descriptor(mem, desc))
                      })
     }
+
+    fn fence_poll(&mut self) {
+        let fence_id = self.backend.fence_poll();
+        let return_descs = &mut self.return_ctrl_descriptors;
+        self.fence_descriptors.retain(|f_desc| {
+            if f_desc.fence_id > fence_id {
+                true
+            } else {
+                return_descs.push_back(ReturnDescriptor {
+                                           index: f_desc.desc.index,
+                                           len: f_desc.len
+                                       });
+                false
+            }
+        })
+    }
 }
 
 struct Worker {
@@ -462,7 +512,14 @@ impl Worker {
             };
 
         'poll: loop {
-            let events = match poll_ctx.wait() {
+            // If there are outstanding fences, wake up early to poll them.
+            let duration = if self.state.fence_descriptors.len() != 0 {
+                Duration::from_millis(FENCE_POLL_MS)
+            } else {
+                Duration::new(i64::MAX as u64, 0)
+            };
+
+            let events = match poll_ctx.wait_timeout(duration) {
                 Ok(v) => v,
                 Err(e) => {
                     error!("failed polling for events: {:?}", e);
@@ -505,6 +562,8 @@ impl Worker {
                 }
             }
 
+            self.state.fence_poll();
+
             loop {
                 match self.state.process_ctrl(&self.mem) {
                     Some(ReturnDescriptor { index, len }) => {