crosvm/gpu_display/src/gpu_display_stub.rs
Robert Tarasov bb95fc4512 gpu_display/wayland: Added keyboard and pointing devices
Added preliminary version of keyboard and pointing device routine
for wayland implementation. The pointing input is wired as a multi
touch device. Due to the fact that wayland client is callback based,
all the necessary incoming events are serialized and stashed in the
temp circular buffer and then processed afterwards from the main event
loop.

Known issues:

1. Mouse input can't be properly wired inside the guest as a mouse
   device without pointer locking, but this is not what we want. The
   approach emulates it as a multitouch device, but, of course, it
   implies limitations in functionality.  Limitations include cursor
   in the VM that doesn't move in unison with the host cursor.

2. I kept the mouse cursor surface since it's not decided yet which
   approach for handling pointing input device will be used (see #1).

   Removing the mouse surface in the guest would remove the lagging
   guest cursor.  The alternatives to the multi-touch device are:

   "- Relative mice (e.g. a typical PC mouse). These are relative
      devices, meaning they send deltas from the current cursor
      position.  Some apps like games rely on these events.

    - Touchscreens (multitouch, single touch). These are absolute
      devices, and are much easier to implement seamless guest/host
      input for.

    - Touchpads (these are absolute devices). I'm not sure these are
      really compelling for any use case." -nkgold@

3. This code is for POC purpose only, so there are still lot of minor
   issues and negligence in it.

Looking forward for your comments and proposals.

BUG=b:177939148
TEST=crosvm $ARGS \
      --display-window-keyboard \
      --display-window-mouse \
      --gpu=3d,glx=false,egl=true \
      --wayland-sock=/run/user/1000/wayland-0 \
      $OTHER_ARGS

Change-Id: If4a9b73b8da4e0cc52fa619bbd6e5588ccdb7874
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2688439
Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
2021-06-15 03:14:07 +00:00

120 lines
3 KiB
Rust

// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::{
DisplayT, GpuDisplayError, GpuDisplayFramebuffer, GpuDisplayResult, GpuDisplaySurface,
SurfaceType,
};
use base::{AsRawDescriptor, Event, RawDescriptor};
use data_model::VolatileSlice;
#[allow(dead_code)]
struct Buffer {
width: u32,
height: u32,
bytes_per_pixel: u32,
bytes: Vec<u8>,
}
impl Drop for Buffer {
fn drop(&mut self) {}
}
impl Buffer {
fn as_volatile_slice(&mut self) -> VolatileSlice {
VolatileSlice::new(self.bytes.as_mut_slice())
}
fn stride(&self) -> usize {
(self.bytes_per_pixel as usize) * (self.width as usize)
}
fn bytes_per_pixel(&self) -> usize {
self.bytes_per_pixel as usize
}
}
struct StubSurface {
width: u32,
height: u32,
buffer: Option<Buffer>,
}
impl StubSurface {
/// Gets the buffer at buffer_index, allocating it if necessary.
fn lazily_allocate_buffer(&mut self) -> Option<&mut Buffer> {
if self.buffer.is_none() {
// XRGB8888
let bytes_per_pixel = 4;
let bytes_total = (self.width as u64) * (self.height as u64) * (bytes_per_pixel as u64);
self.buffer = Some(Buffer {
width: self.width,
height: self.height,
bytes_per_pixel,
bytes: vec![0; bytes_total as usize],
});
}
self.buffer.as_mut()
}
}
impl GpuDisplaySurface for StubSurface {
fn framebuffer(&mut self) -> Option<GpuDisplayFramebuffer> {
let framebuffer = self.lazily_allocate_buffer()?;
let framebuffer_stride = framebuffer.stride() as u32;
let framebuffer_bytes_per_pixel = framebuffer.bytes_per_pixel() as u32;
Some(GpuDisplayFramebuffer::new(
framebuffer.as_volatile_slice(),
framebuffer_stride,
framebuffer_bytes_per_pixel,
))
}
}
impl Drop for StubSurface {
fn drop(&mut self) {}
}
pub struct DisplayStub {
/// This event is never triggered and is used solely to fulfill AsRawDescriptor.
event: Event,
}
impl DisplayStub {
pub fn new() -> GpuDisplayResult<DisplayStub> {
let event = Event::new().map_err(|_| GpuDisplayError::CreateEvent)?;
Ok(DisplayStub { event })
}
}
impl DisplayT for DisplayStub {
fn create_surface(
&mut self,
parent_surface_id: Option<u32>,
_surface_id: u32,
width: u32,
height: u32,
_surf_type: SurfaceType,
) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>> {
if parent_surface_id.is_some() {
return Err(GpuDisplayError::Unsupported);
}
Ok(Box::new(StubSurface {
width,
height,
buffer: None,
}))
}
}
impl AsRawDescriptor for DisplayStub {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.event.as_raw_descriptor()
}
}