blob: cc107b26a5548a178ac135bc425ae1f78bfd4af0 [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 std::marker::PhantomData;
use base::info;
use base::RawDescriptor;
use base::Tube;
use base::WaitContext;
use serde::Deserialize;
use serde::Serialize;
use winapi::um::winuser::GetSystemMetrics;
use winapi::um::winuser::SM_CXSCREEN;
use winapi::um::winuser::SM_CYSCREEN;
use crate::virtio::gpu::parameters::DisplayModeTrait;
use crate::virtio::gpu::Frontend;
use crate::virtio::gpu::ResourceBridgesTrait;
use crate::virtio::gpu::WorkerToken;
const DISPLAY_WIDTH_SOFT_MAX: u32 = 1920;
const DISPLAY_HEIGHT_SOFT_MAX: u32 = 1080;
// This struct is only used for argument parsing.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WinDisplayModeArg {
Windowed,
BorderlessFullScreen,
}
#[derive(Clone, Debug)]
pub enum WinDisplayMode<T> {
Windowed { width: u32, height: u32 },
BorderlessFullScreen(PhantomData<T>),
}
impl DisplayModeTrait<T> for WinDisplayMode<T> {
fn get_virtual_display_size(&self) -> (u32, u32) {
let (width, height) = match self {
Self::Windowed { width, height, .. } => (*width, *height),
Self::BorderlessFullScreen(_) => {
let (width, height) = DisplayDataProvider::get_host_display_size();
adjust_virtual_display_size(width, height)
}
};
info!("Guest display size: {}x{}", width, height);
(width, height)
}
}
/// Trait for returning host display data such as resolution. Tests may overwrite this to specify
/// display data rather than rely on properties of the actual display device.
trait ProvideDisplayData {
fn get_host_display_size() -> (u32, u32);
}
pub struct DisplayDataProvider;
impl ProvideDisplayData for DisplayDataProvider {
fn get_host_display_size() -> (u32, u32) {
// Safe because we're passing valid values and screen size won't exceed u32 range.
let (width, height) = unsafe {
(
GetSystemMetrics(SM_CXSCREEN) as u32,
GetSystemMetrics(SM_CYSCREEN) as u32,
)
};
// Note: This is the size of the host's display. The guest display size given by
// (width, height) may be smaller if we are letterboxing.
info!("Host display size: {}x{}", width, height);
(width, height)
}
}
fn adjust_virtual_display_size(width: u32, height: u32) -> (u32, u32) {
let width = std::cmp::min(width, DISPLAY_WIDTH_SOFT_MAX);
let height = std::cmp::min(height, DISPLAY_HEIGHT_SOFT_MAX);
// Widths that aren't a multiple of 8 break gfxstream: b/156110663.
let width = width - (width % 8);
(width, height)
}
// The resource bridge is not supported on Windows, so this struct simply takes the ownership of
// tubes without actual usage of them.
//
// A skin deep reason we want to get rid of resource bridge is that ResourceResponse is actually a
// wrapper of a dma buffer, and the Tube is not going to support that anyway. The fundamental reason
// is that the dma buffer wrapped inside the ResourceResponse is created by virgl_renderer_execute()
// and ultimately comes from drmPrimeHandleToFD(). There is no easy way to implement that in the
// short term. In addition, the other end of this resource bridge seems to be always a wayland
// device, which will not be used for Windows.
pub(crate) struct WinResourceBridges {
_resource_bridges: Vec<Tube>,
}
impl WinResourceBridges {
pub fn new(resource_bridges: Vec<Tube>) -> Self {
Self {
_resource_bridges: resource_bridges,
}
}
}
impl ResourceBridgesTrait for WinResourceBridges {
fn append_raw_descriptors(&self, _rds: &mut Vec<RawDescriptor>) {}
fn add_to_wait_context(&self, _wait_ctx: &mut WaitContext<WorkerToken>) {}
fn set_should_process(&mut self, _index: usize) {}
fn process_resource_bridges(
&mut self,
_state: &mut Frontend,
_wait_ctx: &mut WaitContext<WorkerToken>,
) {
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn borderless_full_screen_virtual_window_width_should_be_multiple_of_8() {
struct MockDisplayDataProvider;
impl ProvideDisplayData for MockDisplayDataProvider {
fn get_host_display_size() -> (u32, u32) {
(1366, 768)
}
}
let mode = DisplayMode::<MockDisplayDataProvider>::BorderlessFullScreen(PhantomData);
let (width, _) = mode.get_virtual_display_size();
assert_eq!(width % 8, 0);
}
#[test]
fn borderless_full_screen_virtual_window_size_should_be_smaller_than_soft_max() {
struct MockDisplayDataProvider;
impl ProvideDisplayData for MockDisplayDataProvider {
fn get_host_display_size() -> (u32, u32) {
(DISPLAY_WIDTH_SOFT_MAX + 1, DISPLAY_HEIGHT_SOFT_MAX + 1)
}
}
let mode = DisplayMode::<MockDisplayDataProvider>::BorderlessFullScreen(PhantomData);
let (width, height) = mode.get_virtual_display_size();
assert!(width <= DISPLAY_WIDTH_SOFT_MAX);
assert!(height <= DISPLAY_HEIGHT_SOFT_MAX);
}
}