mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-10-25 21:39:48 +00:00
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>
This commit is contained in:
parent
ba7c6035f8
commit
f89e0b50e2
3 changed files with 122 additions and 5 deletions
|
@ -920,4 +920,21 @@ impl Backend {
|
|||
None => GpuResponse::ErrInvalidContextId,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_fence(&mut self, ctx_id: u32, fence_id: u32) -> GpuResponse {
|
||||
// There is a mismatch of ordering that is intentional.
|
||||
// This create_fence matches the other functions in Backend, yet
|
||||
// the renderer matches the virgl interface.
|
||||
match self.renderer.create_fence(fence_id, ctx_id) {
|
||||
Ok(_) => GpuResponse::OkNoData,
|
||||
Err(e) => {
|
||||
error!("failed to create fence: {}", e);
|
||||
GpuResponse::ErrUnspec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fence_poll(&mut self) -> u32 {
|
||||
self.renderer.poll()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }) => {
|
||||
|
|
|
@ -12,6 +12,7 @@ mod generated;
|
|||
mod pipe_format_fourcc;
|
||||
mod command_buffer;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
|
@ -144,10 +145,32 @@ impl Box3 {
|
|||
}
|
||||
}
|
||||
|
||||
struct FenceState {
|
||||
latest_fence: u32,
|
||||
}
|
||||
impl FenceState {
|
||||
pub fn write(&mut self, latest_fence: u32) {
|
||||
if latest_fence > self.latest_fence {
|
||||
self.latest_fence = latest_fence;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VirglCookie {
|
||||
display: EGLDisplay,
|
||||
egl_config: EGLConfig,
|
||||
egl_funcs: EGLFunctions,
|
||||
fence_state: Rc<RefCell<FenceState>>,
|
||||
}
|
||||
|
||||
extern "C" fn write_fence(cookie: *mut c_void,
|
||||
fence: u32) {
|
||||
assert!(!cookie.is_null());
|
||||
let cookie = unsafe { &*(cookie as *mut VirglCookie) };
|
||||
|
||||
// Track the most recent fence.
|
||||
let mut fence_state = cookie.fence_state.borrow_mut();
|
||||
fence_state.write(fence);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn create_gl_context(cookie: *mut c_void,
|
||||
|
@ -187,7 +210,7 @@ unsafe extern "C" fn destroy_gl_context(cookie: *mut c_void, ctx: virgl_renderer
|
|||
const VIRGL_RENDERER_CALLBACKS: &virgl_renderer_callbacks =
|
||||
&virgl_renderer_callbacks {
|
||||
version: 1,
|
||||
write_fence: None,
|
||||
write_fence: Some(write_fence),
|
||||
create_gl_context: Some(create_gl_context),
|
||||
destroy_gl_context: Some(destroy_gl_context),
|
||||
make_current: Some(make_current),
|
||||
|
@ -305,6 +328,7 @@ pub struct Renderer {
|
|||
no_sync_send: PhantomData<*mut ()>,
|
||||
egl_funcs: EGLFunctions,
|
||||
display: EGLDisplay,
|
||||
fence_state: Rc<RefCell<FenceState>>,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
|
@ -361,10 +385,14 @@ impl Renderer {
|
|||
// Otherwise, Resource and Context would become invalid because their lifetime is not tied
|
||||
// to the Renderer instance. Doing so greatly simplifies the ownership for users of this
|
||||
// library.
|
||||
|
||||
let fence_state = Rc::new(RefCell::new(FenceState { latest_fence: 0 }));
|
||||
|
||||
let cookie: *mut VirglCookie = Box::into_raw(Box::new(VirglCookie {
|
||||
display,
|
||||
egl_config,
|
||||
egl_funcs: egl_funcs.clone(),
|
||||
fence_state: Rc::clone(&fence_state),
|
||||
}));
|
||||
|
||||
// Safe because EGL was properly initialized before here..
|
||||
|
@ -401,7 +429,8 @@ impl Renderer {
|
|||
Ok(Renderer {
|
||||
no_sync_send: PhantomData,
|
||||
egl_funcs,
|
||||
display
|
||||
display,
|
||||
fence_state
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -553,6 +582,18 @@ impl Renderer {
|
|||
image
|
||||
})
|
||||
}
|
||||
|
||||
pub fn poll(&self) -> u32 {
|
||||
unsafe { virgl_renderer_poll() };
|
||||
self.fence_state.borrow().latest_fence
|
||||
}
|
||||
|
||||
pub fn create_fence(&mut self, fence_id: u32, ctx_id: u32) -> Result<()> {
|
||||
let ret = unsafe {
|
||||
virgl_renderer_create_fence(fence_id as i32, ctx_id)
|
||||
};
|
||||
ret_to_res(ret)
|
||||
}
|
||||
}
|
||||
|
||||
/// A context in which resources can be attached/detached and commands can be submitted.
|
||||
|
|
Loading…
Reference in a new issue