blob: 8a4e2702b493c9fc759a0b22d2dd42f6579ac610 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::Context;
use base::error;
use base::AsRawDescriptor;
use base::RawDescriptor;
use base::Tube;
use base::WaitContext;
use serde::Deserialize;
use serde::Serialize;
use crate::virtio::gpu::parameters::DisplayModeTrait;
use crate::virtio::gpu::Frontend;
use crate::virtio::gpu::ResourceBridgesTrait;
use crate::virtio::gpu::WorkerToken;
use crate::virtio::resource_bridge::ResourceRequest;
use crate::virtio::resource_bridge::ResourceResponse;
// This struct is only used for argument parsing.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum UnixDisplayModeArg {
Windowed,
}
#[derive(Clone, Debug)]
pub enum UnixDisplayMode {
Windowed { width: u32, height: u32 },
}
impl DisplayModeTrait for UnixDisplayMode {
fn get_virtual_display_size(&self) -> (u32, u32) {
match self {
Self::Windowed { width, height, .. } => (*width, *height),
}
}
}
/// Trait for Unix-specific methods of `Frontend`.
pub trait UnixFrontendExt {
/// Processes incoming requests on `resource_bridge`.
fn process_resource_bridge(&mut self, _resource_bridge: &Tube) -> anyhow::Result<()>;
}
impl UnixFrontendExt for Frontend {
fn process_resource_bridge(&mut self, resource_bridge: &Tube) -> anyhow::Result<()> {
let response = match resource_bridge.recv() {
Ok(ResourceRequest::GetBuffer { id }) => self.virtio_gpu.export_resource(id),
Ok(ResourceRequest::GetFence { seqno }) => {
// The seqno originated from self.backend, so it should fit in a u32.
match u32::try_from(seqno) {
Ok(fence_id) => self.virtio_gpu.export_fence(fence_id),
Err(_) => ResourceResponse::Invalid,
}
}
Err(e) => return Err(e).context("Error receiving resource bridge request"),
};
resource_bridge
.send(&response)
.context("Error sending resource bridge response")?;
Ok(())
}
}
/// This struct takes the ownership of resource bridges and tracks which ones should be processed.
pub(crate) struct UnixResourceBridges {
resource_bridges: Vec<Tube>,
should_process: Vec<bool>,
}
impl UnixResourceBridges {
pub fn new(resource_bridges: Vec<Tube>) -> Self {
let mut resource_bridges = Self {
resource_bridges,
should_process: Default::default(),
};
resource_bridges.reset_should_process();
resource_bridges
}
fn reset_should_process(&mut self) {
self.should_process.clear();
self.should_process
.resize(self.resource_bridges.len(), false);
}
}
impl ResourceBridgesTrait for UnixResourceBridges {
fn append_raw_descriptors(&self, rds: &mut Vec<RawDescriptor>) {
for bridge in &self.resource_bridges {
rds.push(bridge.as_raw_descriptor());
}
}
fn add_to_wait_context(&self, wait_ctx: &mut WaitContext<WorkerToken>) {
for (index, bridge) in self.resource_bridges.iter().enumerate() {
if let Err(e) = wait_ctx.add(bridge, WorkerToken::ResourceBridge { index }) {
error!("failed to add resource bridge to WaitContext: {}", e);
}
}
}
fn set_should_process(&mut self, index: usize) {
self.should_process[index] = true;
}
fn process_resource_bridges(
&mut self,
state: &mut Frontend,
wait_ctx: &mut WaitContext<WorkerToken>,
) {
for (bridge, &should_process) in self.resource_bridges.iter().zip(&self.should_process) {
if should_process {
if let Err(e) = state.process_resource_bridge(bridge) {
error!("Failed to process resource bridge: {:#}", e);
error!("Removing that resource bridge from the wait context.");
wait_ctx.delete(bridge).unwrap_or_else(|e| {
error!("Failed to remove faulty resource bridge: {:#}", e)
});
}
}
}
self.reset_should_process();
}
}